001: /**********************************************************************
002: Copyright (c) 2004 Barry Haddow and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015: Contributors:
016: 2004 Erik Bengtson - nearly all
017: 2007 Andy Jefferson - bypass getObject for normal persistence cases
018: ***********************************************************************/package org.jpox.store.mapping;
019:
020: import org.jpox.ClassLoaderResolver;
021: import org.jpox.ObjectManager;
022: import org.jpox.exceptions.JPOXObjectNotFoundException;
023: import org.jpox.identity.OID;
024: import org.jpox.identity.OIDFactory;
025: import org.jpox.metadata.AbstractMemberMetaData;
026: import org.jpox.store.DatastoreAdapter;
027: import org.jpox.store.DatastoreContainerObject;
028: import org.jpox.store.exceptions.NullValueException;
029: import org.jpox.util.StringUtils;
030:
031: /**
032: * Mapping for Interface fields.
033: *
034: * @version $Revision: 1.38 $
035: */
036: public class InterfaceMapping extends ReferenceMapping {
037: /** JPOX extension - if a field is declared with implementation-classes. Comma-separated list of implementation classes. **/
038: private String implementationClasses;
039:
040: /**
041: * Initialisation.
042: * @param dba Datastore adapter
043: * @param fmd MetaData for the field/property
044: * @param container datastore container (table)
045: * @param clr ClassLoader resolver
046: */
047: public void initialize(DatastoreAdapter dba,
048: AbstractMemberMetaData fmd,
049: DatastoreContainerObject container, ClassLoaderResolver clr) {
050: super .initialize(dba, fmd, container, clr);
051:
052: if (fmd.getType().isInterface() && fmd.getFieldTypes() != null
053: && fmd.getFieldTypes().length == 1) {
054: // Field is an interface but field-type is specified with one value only so try to impose that
055: // This is of particular use where the JDO2 TCK has fields defined as interfaces and the field-type
056: // as the persistent-interface type, forcing the persistence of the property.
057: Class fieldTypeCls = clr
058: .classForName(fmd.getFieldTypes()[0]);
059: if (fieldTypeCls.isInterface()) {
060: type = fmd.getFieldTypes()[0];
061: }
062: }
063: }
064:
065: /**
066: * Set the implementation classes. If the field defined what the implementation
067: * classes are, this mapping will only use it
068: * @param implementationClasses the implementation classes string
069: */
070: public void setImplementationClasses(String implementationClasses) {
071: this .implementationClasses = implementationClasses;
072: }
073:
074: /**
075: * Method to retrieve an object of this type from the ResultSet.
076: * @param om ObjectManager
077: * @param rs The ResultSet
078: * @param pos The parameter positions
079: * @return The object
080: */
081: public Object getObject(ObjectManager om, final Object rs, int[] pos) {
082: if (om.getMetaDataManager().isPersistentInterface(type)) {
083: // ********* This code is for the "persistent-interfaces" JDO feature **********
084: // It does not work for normal interfaces and should be left well alone IMHO
085: // The method MultiMapping.getObject() should be used for all normal persistence cases
086: // and one day someone needs to comment on why this code exists and what it is trying to do that is
087: // different from MultiMapping.getObject()
088: String[] implTypes = null;
089: if (this .implementationClasses != null) {
090: // Use the implementations specified by the user for this field
091: implTypes = StringUtils.split(implementationClasses,
092: ",");
093: } else {
094: // Use the available implementation types
095: implTypes = om.getMetaDataManager()
096: .getClassesImplementingInterface(getType(),
097: om.getClassLoaderResolver());
098: }
099:
100: // Go through the possible types for this field and find a non-null value (if there is one)
101: int n = 0;
102: for (int i = 0; i < implTypes.length; i++) {
103: JavaTypeMapping mapping;
104: if (implTypes.length > javaTypeMappings.length) {
105: // all mappings stored to the same column(s), so same FK
106: PersistenceCapableMapping m = ((PersistenceCapableMapping) javaTypeMappings[0]);
107: mapping = dba
108: .getMapping(om.getClassLoaderResolver()
109: .classForName(implTypes[i]), om
110: .getStoreManager());
111: for (int j = 0; j < m.getDataStoreMappings().length; j++) {
112: mapping.addDataStoreMapping(m
113: .getDataStoreMappings()[j]);
114: }
115: for (int j = 0; j < m.getJavaTypeMapping().length; j++) {
116: ((PersistenceCapableMapping) mapping)
117: .addJavaTypeMapping(m
118: .getJavaTypeMapping()[j]);
119: }
120: ((PersistenceCapableMapping) mapping)
121: .setReferenceMapping(m
122: .getReferenceMapping());
123: } else {
124: mapping = javaTypeMappings[i];
125: }
126: int[] posMapping;
127: if (n >= pos.length) {
128: // this means we store all implementations to the same columns,
129: // so we reset the index
130: n = 0;
131: }
132: if (mapping.getReferenceMapping() != null) {
133: posMapping = new int[mapping.getReferenceMapping()
134: .getNumberOfDatastoreFields()];
135: } else {
136: posMapping = new int[mapping
137: .getNumberOfDatastoreFields()];
138: }
139: for (int j = 0; j < posMapping.length; j++) {
140: posMapping[j] = pos[n++];
141: }
142: Object value = null;
143: try {
144: // Retrieve the value (PC object) for this mappings' object
145: value = mapping.getObject(om, rs, posMapping);
146: } catch (NullValueException e) {
147: // expected if implementation object is null and has primitive
148: // fields in the primary key
149: } catch (JPOXObjectNotFoundException onfe) {
150: // expected, will try next implementation
151: }
152: if (value != null) {
153: if (value instanceof OID) {
154: // What situation is this catering for exactly ?
155: String className;
156: if (mapping.getReferenceMapping() != null) {
157: className = mapping.getReferenceMapping()
158: .getDataStoreMapping(0)
159: .getDatastoreField()
160: .getStoredJavaType();
161: } else {
162: className = mapping.getDataStoreMapping(0)
163: .getDatastoreField()
164: .getStoredJavaType();
165: }
166: value = OIDFactory.getInstance(om, className,
167: ((OID) value).getKeyValue());
168: return om.findObject(value, false, true, null);
169: } else if (om.getClassLoaderResolver()
170: .classForName(getType()).isAssignableFrom(
171: value.getClass())) {
172: return value;
173: }
174: }
175: }
176: return null;
177: } else {
178: // Normal persistence goes via MultiMapping.getObject()
179: return super.getObject(om, rs, pos);
180: }
181: }
182: }
|