001: /**********************************************************************
002: Copyright (c) 2005 Andy Jefferson 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: 2007 Andy Jefferson - implement RelationMappingCallbacks
017: ...
018: ***********************************************************************/package org.jpox.store.mapping;
019:
020: import org.jpox.ClassLoaderResolver;
021: import org.jpox.StateManager;
022: import org.jpox.metadata.AbstractClassMetaData;
023: import org.jpox.metadata.AbstractMemberMetaData;
024: import org.jpox.metadata.InheritanceStrategy;
025: import org.jpox.metadata.MetaDataUtils;
026: import org.jpox.store.DatastoreAdapter;
027: import org.jpox.store.DatastoreContainerObject;
028: import org.jpox.store.DatastoreField;
029: import org.jpox.store.StoreManager;
030: import org.jpox.store.expression.LogicSetExpression;
031: import org.jpox.store.expression.ObjectLiteral;
032: import org.jpox.store.expression.QueryExpression;
033: import org.jpox.store.expression.ReferenceExpression;
034: import org.jpox.store.expression.ScalarExpression;
035: import org.jpox.util.JPOXLogger;
036:
037: /**
038: * Mapping for a reference type.
039: * This can be used for things like interfaces, or Object which are simply a reference to
040: * some specific (PersistenceCapable) class. All fields of this type have a list of
041: * possible "implementations" of the reference type. A column is created for each possible
042: * implementation of the reference as a FK to the implementation table.
043: *
044: * @version $Revision: 1.33 $
045: */
046: public abstract class ReferenceMapping extends MultiMapping implements
047: MappingCallbacks {
048: /**
049: * Initialize this JavaTypeMapping with the given DatastoreAdapter for
050: * the given FieldMetaData.
051: *
052: * @param dba The Datastore Adapter that this Mapping should use.
053: * @param fmd FieldMetaData for the field to be mapped (if any)
054: * @param container The datastore container storing this mapping (if any)
055: * @param clr the ClassLoaderResolver
056: */
057: public void initialize(DatastoreAdapter dba,
058: AbstractMemberMetaData fmd,
059: DatastoreContainerObject container, ClassLoaderResolver clr) {
060: super .initialize(dba, fmd, container, clr);
061: createColumns(datastoreContainer, fmd, clr);
062: }
063:
064: /**
065: * Convenience method to create a column for each implementation type of this reference.
066: * @param datastoreContainer Table to use
067: * @param fmd MetaData for the field
068: * @param clr The ClassLoaderResolver
069: */
070: protected void createColumns(
071: DatastoreContainerObject datastoreContainer,
072: AbstractMemberMetaData fmd, ClassLoaderResolver clr) {
073: // Create columns for each possible implementation type of the reference field
074: if (fmd.getMappedBy() == null) {
075: datastoreContainer
076: .getStoreManager()
077: .createDatastoreColumnsForReferenceField(
078: this ,
079: datastoreContainer,
080: fmd,
081: clr,
082: fmd.isEmbedded()
083: || fmd.getElementMetaData() != null);
084: } else {
085: // Either one end of a 1-1 relation, or the N end of a N-1
086: StoreManager storeMgr = datastoreContainer
087: .getStoreManager();
088: AbstractClassMetaData refCmd = storeMgr
089: .getMetaDataManager().getMetaDataForInterface(
090: fmd.getType(), clr);
091: JavaTypeMapping referenceMapping = null;
092: if (refCmd != null
093: && refCmd.getInheritanceMetaData()
094: .getStrategyValue() == InheritanceStrategy.SUBCLASS_TABLE) {
095: // TODO Is this block actually reachable ? Would we specify "inheritance" under "interface" elements?
096: // Find the actual tables storing the other end (can be multiple subclasses)
097: AbstractClassMetaData[] cmds = storeMgr
098: .getClassesManagingTableForClass(refCmd, clr);
099: if (cmds != null && cmds.length > 0) {
100: if (cmds.length > 1) {
101: JPOXLogger.PERSISTENCE
102: .warn("Field "
103: + fmd.getFullFieldName()
104: + " represents either a 1-1 relation, or a N-1 relation "
105: + "where the other end uses \"subclass-table\" inheritance strategy and more than 1 subclasses with a table. "
106: + "This is not fully supported by JPOX");
107: }
108: } else {
109: // No subclasses of the class using "subclasses-table" so no mapping!
110: // TODO Throw an exception ?
111: return;
112: }
113: // TODO We need a mapping for each of the possible subclass tables
114: referenceMapping = storeMgr.getDatastoreClass(
115: cmds[0].getFullClassName(), clr).getIDMapping();
116: } else {
117: String[] implTypes = MetaDataUtils.getInstance()
118: .getImplementationNamesForReferenceField(fmd,
119: DatastoreField.ROLE_FIELD, clr);
120: for (int j = 0; j < implTypes.length; j++) {
121: referenceMapping = storeMgr.getDatastoreClass(
122: implTypes[j], clr).getIDMapping();
123: JavaTypeMapping mapping = dba.getMapping(clr
124: .classForName(implTypes[j]), storeMgr);
125: mapping.setReferenceMapping(referenceMapping);
126: this .addJavaTypeMapping(mapping);
127: }
128: }
129: }
130: }
131:
132: /* (non-Javadoc)
133: * @see org.jpox.store.mapping.JavaTypeMapping#getJavaType()
134: */
135: public Class getJavaType() {
136: return null;
137: }
138:
139: /* (non-Javadoc)
140: * @see org.jpox.store.mapping.Mapping#getSampleValue()
141: */
142: public Object getSampleValue(ClassLoaderResolver clr) {
143: throw new UnsupportedOperationException("Not yet implemented");
144: }
145:
146: // ---------------------------------- JDOQL Query Methods -------------------------------------
147:
148: /* (non-Javadoc)
149: * @see org.jpox.store.mapping.Mapping#newLiteral(org.jpox.store.QueryStatement, java.lang.Object)
150: */
151: public ScalarExpression newLiteral(QueryExpression qs, Object value) {
152: ScalarExpression expr = new ObjectLiteral(qs, this , value,
153: value.getClass().getName());
154: return expr;
155: }
156:
157: public ScalarExpression newScalarExpression(QueryExpression qs,
158: LogicSetExpression te) {
159: ScalarExpression expr = new ReferenceExpression(qs, this , te);
160: return expr;
161: }
162:
163: // -------------------------- MappingCallbacks methods ----------------------------
164:
165: /**
166: * Method executed just after a fetch of the owning object, allowing any necessary action
167: * to this field and the object stored in it.
168: * @param sm StateManager for the owner.
169: */
170: public void postFetch(StateManager sm) {
171: }
172:
173: /**
174: * Method executed just after the insert of the owning object, allowing any necessary action
175: * to this field and the object stored in it.
176: * @param sm StateManager for the owner
177: */
178: public void postInsert(StateManager sm) {
179: }
180:
181: /**
182: * Method executed just afer any update of the owning object, allowing any necessary action
183: * to this field and the object stored in it.
184: * @param sm StateManager for the owner
185: */
186: public void postUpdate(StateManager sm) {
187: }
188:
189: /**
190: * Method executed just before the owning object is deleted, allowing tidying up of any
191: * relation information.
192: * @param sm StateManager for the owner
193: */
194: public void preDelete(StateManager sm) {
195: boolean isDependentElement = fmd.isDependent();
196: if (!isDependentElement) {
197: // Not dependent so do nothing, or should we null here ?
198: return;
199: }
200:
201: // Loop through all implementations
202: for (int i = 0; i < javaTypeMappings.length; i++) {
203: final JavaTypeMapping mapping = javaTypeMappings[i];
204: if (mapping instanceof PersistenceCapableMapping) {
205: // makes sure field is loaded
206: int fieldNumber = getFieldMetaData()
207: .getAbsoluteFieldNumber();
208: sm.getObjectManager().getApiAdapter().isLoaded(sm,
209: fieldNumber);
210: Object pc = sm.provideField(fieldNumber);
211: if (pc != null) {
212: // Null out the FK in the datastore using a direct update (since we are deleting)
213: sm.replaceField(fieldNumber, null, true);
214: sm.getStoreManager().updateObject(sm,
215: new int[] { fieldNumber });
216:
217: // delete object
218: sm.getObjectManager().deleteObjectInternal(pc);
219: }
220: }
221: }
222: }
223: }
|