Source Code Cross Referenced for PersistenceCapableMapping.java in  » Database-ORM » JPOX » org » jpox » store » mapping » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Database ORM » JPOX » org.jpox.store.mapping 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**********************************************************************
0002:        Copyright (c) 2002 Mike Martin (TJDO) and others. All rights reserved. 
0003:        Licensed under the Apache License, Version 2.0 (the "License");
0004:        you may not use this file except in compliance with the License.
0005:        You may obtain a copy of the License at
0006:
0007:            http://www.apache.org/licenses/LICENSE-2.0
0008:
0009:        Unless required by applicable law or agreed to in writing, software
0010:        distributed under the License is distributed on an "AS IS" BASIS,
0011:        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012:        See the License for the specific language governing permissions and
0013:        limitations under the License.
0014:         
0015:
0016:        Contributors:
0017:        2003 Erik Bengtson - Important changes regarding the application identity
0018:                             support when fetching PreparedStatements. Added an
0019:                             inner class that should be moved away.
0020:        2004 Erik Bengtson - added commentary and Localisation
0021:        2004 Andy Jefferson - added capability to handle Abstract PC fields for
0022:                              both SingleFieldIdentity and AID
0023:        2007 Andy Jefferson - implement RelationMappingCallbacks
0024:            ...
0025:         **********************************************************************/package org.jpox.store.mapping;
0026:
0027:        import java.lang.reflect.Field;
0028:        import java.math.BigDecimal;
0029:        import java.sql.ResultSet;
0030:        import java.sql.SQLException;
0031:        import java.util.Collection;
0032:
0033:        import javax.jdo.JDOObjectNotFoundException;
0034:        import javax.jdo.spi.PersistenceCapable;
0035:
0036:        import org.jpox.ClassLoaderResolver;
0037:        import org.jpox.FetchPlan;
0038:        import org.jpox.ObjectManager;
0039:        import org.jpox.ObjectManagerHelper;
0040:        import org.jpox.StateManager;
0041:        import org.jpox.api.ApiAdapter;
0042:        import org.jpox.exceptions.JPOXDataStoreException;
0043:        import org.jpox.exceptions.JPOXException;
0044:        import org.jpox.exceptions.JPOXObjectNotFoundException;
0045:        import org.jpox.exceptions.JPOXUserException;
0046:        import org.jpox.identity.OID;
0047:        import org.jpox.metadata.AbstractClassMetaData;
0048:        import org.jpox.metadata.AbstractMemberMetaData;
0049:        import org.jpox.metadata.ClassMetaData;
0050:        import org.jpox.metadata.ColumnMetaData;
0051:        import org.jpox.metadata.IdentityStrategy;
0052:        import org.jpox.metadata.IdentityType;
0053:        import org.jpox.metadata.InheritanceStrategy;
0054:        import org.jpox.metadata.MetaDataManager;
0055:        import org.jpox.metadata.Relation;
0056:        import org.jpox.sco.SCOCollection;
0057:        import org.jpox.store.DatastoreAdapter;
0058:        import org.jpox.store.DatastoreClass;
0059:        import org.jpox.store.DatastoreContainerObject;
0060:        import org.jpox.store.DatastoreElementContainer;
0061:        import org.jpox.store.DatastoreField;
0062:        import org.jpox.store.DatastoreIdentifier;
0063:        import org.jpox.store.FieldValues;
0064:        import org.jpox.store.IdentifierFactory;
0065:        import org.jpox.store.MappedStoreManager;
0066:        import org.jpox.store.StatementExpressionIndex;
0067:        import org.jpox.store.StoreManager;
0068:        import org.jpox.store.exceptions.NotYetFlushedException;
0069:        import org.jpox.store.exceptions.ReachableObjectNotCascadedException;
0070:        import org.jpox.store.expression.LogicSetExpression;
0071:        import org.jpox.store.expression.ObjectExpression;
0072:        import org.jpox.store.expression.ObjectLiteral;
0073:        import org.jpox.store.expression.QueryExpression;
0074:        import org.jpox.store.expression.ScalarExpression;
0075:        import org.jpox.util.ClassUtils;
0076:        import org.jpox.util.JPOXLogger;
0077:        import org.jpox.util.StringUtils;
0078:
0079:        /**
0080:         * Maps a java field to a PersistenceCapable class. 
0081:         * For PersistenceCapable classes using datastore identity most of the necessary behaviour
0082:         * is coded in the OIDMapping super class.
0083:         * TODO Split this from OIDMapping since a PCMapping may represent an application
0084:         * identity object instead of a datastore identity object
0085:         *
0086:         * @version $Revision: 1.154 $ 
0087:         */
0088:        public class PersistenceCapableMapping extends OIDMapping implements 
0089:                MappingCallbacks {
0090:            /** Mappings for all fields necessary to represent the id of the PC object. */
0091:            protected JavaTypeMapping[] javaTypeMappings = new JavaTypeMapping[0];
0092:
0093:            //----------------------- convenience fields to improve performance ----------------------// 
0094:            /** ClassMetaData for the represented class. Create a new one on each getObject invoke is expensive **/
0095:            private AbstractClassMetaData cmd;
0096:
0097:            /** number of DatastoreField - convenience field to improve performance **/
0098:            private int numberOfDatastoreFields = 0;
0099:
0100:            /**
0101:             * Create a new empty PersistenceCapableMapping.
0102:             * The caller must call one of the initialize methods to initialize the instance with the
0103:             * DatastoreAdapter and its type.
0104:             */
0105:            public PersistenceCapableMapping() {
0106:            }
0107:
0108:            /**
0109:             * Initialize this JavaTypeMapping with the given DatastoreAdapter for
0110:             * the given FieldMetaData.
0111:             *  
0112:             * @param dba The Datastore Adapter that this Mapping should use.
0113:             * @param fmd FieldMetaData for the field to be mapped (if any)
0114:             * @param container The datastore container storing this mapping (if any)
0115:             * @param clr the ClassLoaderResolver
0116:             */
0117:            public void initialize(DatastoreAdapter dba,
0118:                    AbstractMemberMetaData fmd,
0119:                    DatastoreContainerObject container, ClassLoaderResolver clr) {
0120:                super .initialize(dba, fmd, container, clr);
0121:                prepareDatastoreMapping(clr);
0122:            }
0123:
0124:            /**
0125:             * Add a new JavaTypeMapping
0126:             * @param mapping the JavaTypeMapping
0127:             */
0128:            public void addJavaTypeMapping(JavaTypeMapping mapping) {
0129:                if (mapping == null) {
0130:                    throw new JPOXException(
0131:                            "mapping argument in PersistenceCapableMapping.addJavaTypeMapping is null")
0132:                            .setFatal();
0133:                }
0134:                JavaTypeMapping[] jtm = javaTypeMappings;
0135:                javaTypeMappings = new JavaTypeMapping[jtm.length + 1];
0136:                System.arraycopy(jtm, 0, javaTypeMappings, 0, jtm.length);
0137:                javaTypeMappings[jtm.length] = mapping;
0138:            }
0139:
0140:            /**
0141:             * Method to prepare the PC mapping and add its associated datastore mappings.
0142:             */
0143:            protected void prepareDatastoreMapping() {
0144:                // Does nothing - added to prevent column creation by the method in OIDMapping
0145:                // If we change the inheritance so this doesnt extend OIDMapping, then this can be deleted
0146:            }
0147:
0148:            /**
0149:             * Method to prepare the PC mapping and add its associated datastore mappings.
0150:             * @param clr The ClassLoaderResolver
0151:             */
0152:            protected void prepareDatastoreMapping(ClassLoaderResolver clr) {
0153:                // Either one end of a 1-1 relation, or the N end of a N-1
0154:                StoreManager storeMgr = datastoreContainer.getStoreManager();
0155:                AbstractClassMetaData refCmd = storeMgr.getMetaDataManager()
0156:                        .getMetaDataForClass(fmd.getType(), clr);
0157:                JavaTypeMapping referenceMapping = null;
0158:                if (refCmd.getInheritanceMetaData().getStrategyValue() == InheritanceStrategy.SUBCLASS_TABLE) {
0159:                    // Find the actual tables storing the other end (can be multiple subclasses)
0160:                    AbstractClassMetaData[] cmds = storeMgr
0161:                            .getClassesManagingTableForClass(refCmd, clr);
0162:                    if (cmds != null && cmds.length > 0) {
0163:                        if (cmds.length > 1) {
0164:                            JPOXLogger.PERSISTENCE
0165:                                    .warn("Field "
0166:                                            + fmd.getFullFieldName()
0167:                                            + " represents either a 1-1 relation, "
0168:                                            + "or a N-1 relation where the other end uses \"subclass-table\" inheritance strategy and more "
0169:                                            + "than 1 subclasses with a table. This is not fully supported by JPOX");
0170:                        }
0171:                    } else {
0172:                        // No subclasses of the class using "subclasses-table" so no mapping!
0173:                        // TODO Throw an exception ?
0174:                        return;
0175:                    }
0176:                    // TODO We need a mapping for each of the possible subclass tables
0177:                    referenceMapping = storeMgr.getDatastoreClass(
0178:                            cmds[0].getFullClassName(), clr).getIDMapping();
0179:                } else {
0180:                    referenceMapping = storeMgr.getDatastoreClass(
0181:                            fmd.getType().getName(), clr).getIDMapping();
0182:                }
0183:
0184:                // Generate a mapping from the columns of the referenced object to this mapping's ColumnMetaData
0185:                CorrespondentColumnsMapper correspondentColumnsMapping = new CorrespondentColumnsMapper(
0186:                        fmd, referenceMapping, true);
0187:
0188:                // Find any related field where this is part of a bidirectional relation
0189:                int relationType = fmd.getRelationType(clr);
0190:                boolean createDatastoreMappings = true;
0191:                if (relationType == Relation.MANY_TO_ONE_BI) {
0192:                    AbstractMemberMetaData[] relatedMmds = fmd
0193:                            .getRelatedMemberMetaData(clr);
0194:                    // TODO Cater for more than 1 related field
0195:                    createDatastoreMappings = (relatedMmds[0].getJoinMetaData() == null);
0196:                } else if (relationType == Relation.ONE_TO_ONE_BI) {
0197:                    // Put the FK at the end without "mapped-by"
0198:                    createDatastoreMappings = (fmd.getMappedBy() == null);
0199:                }
0200:
0201:                // Loop through the datastore fields in the referenced class and create a datastore field for each
0202:                for (int i = 0; i < referenceMapping
0203:                        .getNumberOfDatastoreFields(); i++) {
0204:                    DatastoreMapping refDatastoreMapping = referenceMapping
0205:                            .getDataStoreMapping(i);
0206:                    JavaTypeMapping mapping = dba.getMapping(
0207:                            refDatastoreMapping.getJavaTypeMapping()
0208:                                    .getJavaType(), storeMgr);
0209:                    this .addJavaTypeMapping(mapping);
0210:
0211:                    // Create physical datastore columns where we require a FK link to the related table.
0212:                    if (createDatastoreMappings) {
0213:                        // Find the Column MetaData that maps to the referenced datastore field
0214:                        ColumnMetaData colmd = correspondentColumnsMapping
0215:                                .getColumnMetaDataByIdentifier(refDatastoreMapping
0216:                                        .getDatastoreField().getIdentifier());
0217:                        if (colmd == null) {
0218:                            throw new JPOXUserException(LOCALISER.msg("041038",
0219:                                    refDatastoreMapping.getDatastoreField()
0220:                                            .getIdentifier(), toString()))
0221:                                    .setFatal();
0222:                        }
0223:
0224:                        // Create a Datastore field to equate to the referenced classes datastore field
0225:                        MappingManager mmgr = datastoreContainer
0226:                                .getStoreManager().getMappingManager();
0227:                        DatastoreField col = mmgr.createDatastoreField(fmd,
0228:                                datastoreContainer, mapping, colmd,
0229:                                refDatastoreMapping.getDatastoreField(), clr);
0230:
0231:                        // Add its datastore mapping
0232:                        DatastoreMapping datastoreMapping = mmgr
0233:                                .createDatastoreMapping(
0234:                                        mapping,
0235:                                        storeMgr,
0236:                                        col,
0237:                                        refDatastoreMapping
0238:                                                .getJavaTypeMapping()
0239:                                                .getJavaTypeForDatastoreMapping(
0240:                                                        i));
0241:                        this .addDataStoreMapping(datastoreMapping);
0242:                    } else {
0243:                        mapping.setReferenceMapping(referenceMapping);
0244:                    }
0245:                }
0246:            }
0247:
0248:            /**
0249:             * Accessor for the Java type mappings
0250:             * @return The Java type mappings
0251:             */
0252:            public JavaTypeMapping[] getJavaTypeMapping() {
0253:                return javaTypeMappings;
0254:            }
0255:
0256:            /**
0257:             * Accessor for the number of datastore fields.
0258:             * Zero datastore fields implies that the mapping uses a FK in the associated class
0259:             * to reference back.
0260:             * @return Number of datastore fields for this PC mapping.
0261:             */
0262:            public int getNumberOfDatastoreFields() {
0263:                if (numberOfDatastoreFields == 0) {
0264:                    for (int i = 0; i < javaTypeMappings.length; i++) {
0265:                        numberOfDatastoreFields += javaTypeMappings[i]
0266:                                .getNumberOfDatastoreFields();
0267:                    }
0268:                }
0269:                return numberOfDatastoreFields;
0270:            }
0271:
0272:            /**
0273:             * Accessor for a datastore mapping.
0274:             * This method works through the java type mappings, and for each mapping through its datastore mappings
0275:             * incrementing the index with each datastore mapping.
0276:             * @param index The position of the mapping.
0277:             * @return The datastore mapping.
0278:             */
0279:            public DatastoreMapping getDataStoreMapping(int index) {
0280:                int currentIndex = 0;
0281:                int numberJavaMappings = javaTypeMappings.length;
0282:                for (int i = 0; i < numberJavaMappings; i++) {
0283:                    int numberDatastoreMappings = javaTypeMappings[i]
0284:                            .getNumberOfDatastoreFields();
0285:                    for (int j = 0; j < numberDatastoreMappings; j++) {
0286:                        if (currentIndex == index) {
0287:                            return javaTypeMappings[i].getDataStoreMapping(j);
0288:                        }
0289:                        currentIndex++;
0290:                    }
0291:                }
0292:                // TODO Localise this message
0293:                throw new JPOXException("Invalid index " + index
0294:                        + " for DataStoreMapping.").setFatal();
0295:            }
0296:
0297:            /**
0298:             * Method to set an object in the datastore.
0299:             * @param om The ObjectManager
0300:             * @param ps The Prepared Statement
0301:             * @param param The parameter ids in the statement
0302:             * @param value The value to put in the statement at these ids
0303:             * @throws NotYetFlushedException
0304:             */
0305:            public void setObject(ObjectManager om, Object ps, int[] param,
0306:                    Object value) {
0307:                setObject(om, ps, param, value, null, -1);
0308:            }
0309:
0310:            /**
0311:             * Method to set an object reference (FK) in the datastore.
0312:             * @param om The Object Manager
0313:             * @param ps The Prepared Statement
0314:             * @param param The parameter ids in the statement
0315:             * @param value The value to put in the statement at these ids
0316:             * @param ownerSM StateManager for the owner object
0317:             * @param ownerFieldNumber Field number of this PC object in the owner
0318:             * @throws NotYetFlushedException
0319:             */
0320:            public void setObject(ObjectManager om, Object ps, int[] param,
0321:                    Object value, StateManager ownerSM, int ownerFieldNumber) {
0322:                if (value == null) {
0323:                    setObjectAsNull(om, ps, param);
0324:                } else {
0325:                    setObjectAsValue(om, ps, param, value, ownerSM,
0326:                            ownerFieldNumber);
0327:                }
0328:            }
0329:
0330:            /**
0331:             * Populates the PreparedStatement with a null value for the mappings of this PersistenceCapableMapping.
0332:             * @param om the Object Manager
0333:             * @param ps the Prepared Statement
0334:             * @param param The parameter ids in the statement
0335:             */
0336:            private void setObjectAsNull(ObjectManager om, Object ps,
0337:                    int[] param) {
0338:                // Null out the PC object
0339:                int n = 0;
0340:                for (int i = 0; i < javaTypeMappings.length; i++) {
0341:                    JavaTypeMapping mapping = javaTypeMappings[i];
0342:                    if (mapping.getNumberOfDatastoreFields() > 0) {
0343:                        // Only populate the PreparedStatement for the object if it has any datastore mappings
0344:                        int[] posMapping = new int[mapping
0345:                                .getNumberOfDatastoreFields()];
0346:                        for (int j = 0; j < posMapping.length; j++) {
0347:                            posMapping[j] = param[n++];
0348:                        }
0349:                        mapping.setObject(om, ps, posMapping, null);
0350:                    }
0351:                }
0352:            }
0353:
0354:            /**
0355:             * Check if one of the primary key fields of the PC has value attributed by the datastore
0356:             * @param mdm the {@link MetaDataManager}
0357:             * @param srm the {@link StoreManager}
0358:             * @param clr the {@link ClassLoaderResolver}
0359:             * @return true if one of the primary key fields of the PC has value attributed by the datastore
0360:             */
0361:            private boolean hasDatastoreAttributedPrimaryKeyValues(
0362:                    MetaDataManager mdm, StoreManager srm,
0363:                    ClassLoaderResolver clr) {
0364:                boolean hasDatastoreAttributedPrimaryKeyValues = false;
0365:                if (this .fmd != null) {
0366:                    // Object is associated to a field (i.e not a join table)
0367:                    AbstractClassMetaData acmd = mdm.getMetaDataForClass(
0368:                            this .fmd.getType(), clr);
0369:                    if (acmd.getIdentityType() == IdentityType.APPLICATION) {
0370:                        for (int i = 0; i < acmd.getPKMemberPositions().length; i++) {
0371:                            IdentityStrategy strategy = acmd
0372:                                    .getMetaDataForManagedMemberAtAbsolutePosition(
0373:                                            acmd.getPKMemberPositions()[i])
0374:                                    .getValueStrategy();
0375:                            if (strategy != null) {
0376:                                //if strategy is null, then it's user attributed value
0377:                                hasDatastoreAttributedPrimaryKeyValues |= srm
0378:                                        .isStrategyDatastoreAttributed(
0379:                                                strategy, false);
0380:                            }
0381:                        }
0382:                    }
0383:                }
0384:                return hasDatastoreAttributedPrimaryKeyValues;
0385:            }
0386:
0387:            /**
0388:             * Method to set an object reference (FK) in the datastore.
0389:             * @param om The Object Manager
0390:             * @param ps The Prepared Statement
0391:             * @param param The parameter ids in the statement
0392:             * @param value The value to put in the statement at these ids
0393:             * @param ownerSM StateManager for the owner object
0394:             * @param ownerFieldNumber Field number of this PC object in the owner
0395:             * @throws NotYetFlushedException Just put "null" in and throw "NotYetFlushedException", 
0396:             *                                to be caught by ParameterSetter and will signal to the PC object being inserted
0397:             *                                that it needs to inform this object when it is inserted.
0398:             */
0399:            private void setObjectAsValue(ObjectManager om, Object ps,
0400:                    int[] param, Object value, StateManager ownerSM,
0401:                    int ownerFieldNumber) {
0402:                Object id;
0403:
0404:                ApiAdapter api = om.getApiAdapter();
0405:                if (!api.isPersistable(value)) {
0406:                    throw new JPOXException(LOCALISER.msg("041016", value
0407:                            .getClass(), value)).setFatal();
0408:                }
0409:
0410:                StateManager sm = om.findStateManager(value);
0411:
0412:                try {
0413:                    ClassLoaderResolver clr = om.getClassLoaderResolver();
0414:
0415:                    // Check if the field is attributed in the datastore
0416:                    boolean hasDatastoreAttributedPrimaryKeyValues = hasDatastoreAttributedPrimaryKeyValues(
0417:                            om.getMetaDataManager(), om.getStoreManager(), clr);
0418:
0419:                    boolean inserted = false;
0420:                    if (ownerFieldNumber >= 0) {
0421:                        // Field mapping : is this field of the related object present in the datastore?
0422:                        inserted = om.isInserted(value, ownerFieldNumber);
0423:                    } else if (fmd == null) {
0424:                        // Identity mapping : is the object inserted far enough to be considered of this mapping type?
0425:                        inserted = om.isInserted(value, type);
0426:                    }
0427:
0428:                    if (sm != null) {
0429:                        if (om.getApiAdapter().isDetached(value)
0430:                                && sm.getReferencedPC() != null
0431:                                && ownerSM != null && fmd != null) {
0432:                            // 1-1, N-1 mapping
0433:                            // The value is really still detached but has a temporary StateManager whilst attaching so
0434:                            // replace this field reference to be for the newly attached object
0435:                            // Note that we have "fmd != null" here hence omitting any M-N relations where this is a join table 
0436:                            // mapping
0437:                            ownerSM.replaceField(ownerFieldNumber, sm
0438:                                    .getReferencedPC(), true);
0439:                        }
0440:
0441:                        if (sm.isWaitingToBeFlushedToDatastore()) {
0442:                            // Related object is not yet flushed to the datastore so flush it so we can set the FK
0443:                            sm.flush();
0444:                        }
0445:                    }
0446:
0447:                    // we can execute this block when
0448:                    // 1) the pc has been inserted; OR
0449:                    // 2) is not in process of being inserted; OR
0450:                    // 3) is being inserted yet is inserted enough to use this mapping; OR
0451:                    // 4) the PC PK values are not attributed by the database and this mapping is for a PK field (compound identity)
0452:                    if (inserted
0453:                            || !om.isInserting(value)
0454:                            || (!hasDatastoreAttributedPrimaryKeyValues && (this .fmd != null && this .fmd
0455:                                    .isPrimaryKey()))) {
0456:                        // The PC is either already inserted, or inserted down to the level we need, or not inserted at all,
0457:                        // or the field is a PK and identity not attributed by the datastore
0458:
0459:                        // Object either already exists, or is not yet being inserted.
0460:                        id = api.getIdForObject(value);
0461:
0462:                        // Check if the PersistenceCapable exists in this datastore
0463:                        boolean requiresPersisting = false;
0464:                        if (om.getApiAdapter().isDetached(value)
0465:                                && ownerSM != null) {
0466:                            // Detached object so needs attaching
0467:                            if (ownerSM.isInserting()) {
0468:                                // Inserting other object, and this object is detached but if detached from this datastore
0469:                                // we can just return the value now and attach later (in InsertRequest)
0470:                                if (!om.getOMFContext()
0471:                                        .getPersistenceConfiguration()
0472:                                        .getAttachSameDatastore()) {
0473:                                    if (om.getObjectFromCache(api
0474:                                            .getIdForObject(value)) != null) {
0475:                                        // Object is in cache so exists for this datastore, so no point checking
0476:                                    } else {
0477:                                        try {
0478:                                            Object obj = om.findObject(api
0479:                                                    .getIdForObject(value),
0480:                                                    true, false, value
0481:                                                            .getClass()
0482:                                                            .getName());
0483:                                            if (obj != null) {
0484:                                                // Make sure this object is not retained in cache etc
0485:                                                StateManager objSM = om
0486:                                                        .findStateManager(obj);
0487:                                                if (objSM != null) {
0488:                                                    om
0489:                                                            .evictFromTransaction(objSM);
0490:                                                }
0491:                                                om
0492:                                                        .removeObjectFromCache(
0493:                                                                value,
0494:                                                                api
0495:                                                                        .getIdForObject(value),
0496:                                                                true, true);
0497:                                            }
0498:                                        } catch (JPOXObjectNotFoundException onfe) {
0499:                                            // Object doesnt yet exist
0500:                                            requiresPersisting = true;
0501:                                        }
0502:                                    }
0503:                                }
0504:                            } else {
0505:                                requiresPersisting = true;
0506:                            }
0507:                        } else if (id == null) {
0508:                            // Transient object, so we need to persist it
0509:                            requiresPersisting = true;
0510:                        } else {
0511:                            ObjectManager pcPM = ObjectManagerHelper
0512:                                    .getObjectManager(value);
0513:                            if (pcPM != null && om != pcPM) {
0514:                                throw new JPOXUserException(LOCALISER
0515:                                        .msg("041015"), id);
0516:                            }
0517:                        }
0518:
0519:                        if (requiresPersisting) {
0520:                            // PERSISTENCE-BY-REACHABILITY
0521:                            // This PC object needs persisting (new or detached) to do the "set"
0522:                            if (fmd != null && !fmd.isCascadePersist()
0523:                                    && !om.getApiAdapter().isDetached(value)) {
0524:                                // Related PC object not persistent, but cant do cascade-persist so throw exception
0525:                                if (JPOXLogger.REACHABILITY.isDebugEnabled()) {
0526:                                    JPOXLogger.REACHABILITY.debug(LOCALISER
0527:                                            .msg("007006", fmd
0528:                                                    .getFullFieldName()));
0529:                                }
0530:                                throw new ReachableObjectNotCascadedException(
0531:                                        fmd.getFullFieldName(), value);
0532:                            }
0533:
0534:                            if (JPOXLogger.REACHABILITY.isDebugEnabled()) {
0535:                                JPOXLogger.REACHABILITY.debug(LOCALISER.msg(
0536:                                        "007007", fmd != null ? fmd
0537:                                                .getFullFieldName() : null));
0538:                            }
0539:
0540:                            try {
0541:                                Object pcNew = om.persistObjectInternal(value,
0542:                                        null, null, -1, StateManager.PC);
0543:                                if (hasDatastoreAttributedPrimaryKeyValues) {
0544:                                    om.flushInternal(false);
0545:                                }
0546:                                id = api.getIdForObject(pcNew);
0547:                                if (om.getApiAdapter().isDetached(value)
0548:                                        && ownerSM != null) {
0549:                                    // Update any detached reference to refer to the attached variant
0550:                                    ownerSM.replaceField(ownerFieldNumber,
0551:                                            pcNew, true);
0552:                                    int relationType = fmd.getRelationType(clr);
0553:                                    if (relationType == Relation.MANY_TO_ONE_BI) {
0554:                                        // TODO Update the container to refer to the attached object
0555:                                        if (JPOXLogger.PERSISTENCE
0556:                                                .isInfoEnabled()) {
0557:                                            JPOXLogger.PERSISTENCE
0558:                                                    .info("PCMapping.setObject : object "
0559:                                                            + ownerSM
0560:                                                                    .getInternalObjectId()
0561:                                                            + " has field "
0562:                                                            + ownerFieldNumber
0563:                                                            + " that is 1-N bidirectional."
0564:                                                            + " Have just attached the N side so should really update the reference in the 1 side collection"
0565:                                                            + " to refer to this attached object. Not yet implemented");
0566:                                        }
0567:                                    } else if (relationType == Relation.ONE_TO_ONE_BI) {
0568:                                        AbstractMemberMetaData[] relatedMmds = fmd
0569:                                                .getRelatedMemberMetaData(clr);
0570:                                        // TODO Cater for more than 1 related field
0571:                                        StateManager relatedSM = om
0572:                                                .findStateManager(pcNew);
0573:                                        relatedSM.replaceField(relatedMmds[0]
0574:                                                .getAbsoluteFieldNumber(),
0575:                                                ownerSM.getObject(), true);
0576:                                    }
0577:                                }
0578:                            } catch (NotYetFlushedException e) {
0579:                                setObjectAsNull(om, ps, param);
0580:                                throw new NotYetFlushedException(value);
0581:                            }
0582:                        }
0583:
0584:                        if (sm != null) {
0585:                            sm.setStoringPC();
0586:                        }
0587:
0588:                        // If the field doesnt map to any datastore fields, omit the set process
0589:                        if (getNumberOfDatastoreFields() > 0) {
0590:                            if (id instanceof  OID) {
0591:                                super .setObject(om, ps, param, id);
0592:                            } else {
0593:                                // TODO Factor out this PersistenceCapable reference
0594:                                ((PersistenceCapable) value)
0595:                                        .jdoCopyKeyFieldsFromObjectId(
0596:                                                new AppIDObjectIdFieldConsumer(
0597:                                                        param, om, ps,
0598:                                                        javaTypeMappings), id);
0599:                            }
0600:                        }
0601:                    } else {
0602:                        if (sm != null) {
0603:                            sm.setStoringPC();
0604:                        }
0605:
0606:                        if (getNumberOfDatastoreFields() > 0) {
0607:                            // Object is in the process of being inserted so we cant use its id currently and we need to store
0608:                            // a foreign key to it (which we cant yet do). Just put "null" in and throw "NotYetFlushedException",
0609:                            // to be caught by ParameterSetter and will signal to the PC object being inserted that it needs 
0610:                            // to inform this object when it is inserted.
0611:                            setObjectAsNull(om, ps, param);
0612:                            throw new NotYetFlushedException(value);
0613:                        }
0614:                    }
0615:                } finally {
0616:                    if (sm != null) {
0617:                        sm.unsetStoringPC();
0618:                    }
0619:                }
0620:            }
0621:
0622:            /**
0623:             * Returns a instance of a PersistenceCapable class.
0624:             * Processes a FK field and converts the id stored firstly into an OID/AID
0625:             * and then into the object that the FK id relates to.
0626:             * @param om The Object Manager
0627:             * @param rs The ResultSet
0628:             * @param param Array of parameter ids in the ResultSet to retrieve
0629:             * @return The Persistence Capable object
0630:             */
0631:            public Object getObject(ObjectManager om, final Object rs,
0632:                    int[] param) {
0633:                // Check for null FK
0634:                try {
0635:                    //if the first param is null, then the field is null
0636:                    // TODO Factor this out - using RDBMS-specific code
0637:                    if (((ResultSet) rs).getObject(param[0]) == null) {
0638:                        return null;
0639:                    }
0640:                } catch (SQLException e) {
0641:                    throw new JPOXDataStoreException(e.getMessage(), e);
0642:                }
0643:
0644:                if (cmd == null) {
0645:                    cmd = om.getMetaDataManager().getMetaDataForClass(
0646:                            getType(), om.getClassLoaderResolver());
0647:                }
0648:
0649:                // Return the object represented by this mapping
0650:                if (cmd.getIdentityType() == IdentityType.DATASTORE) {
0651:                    return getObjectForDatastoreIdentity(om, rs, param, cmd);
0652:                } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
0653:                    return getObjectForApplicationIdentity(om, rs, param, cmd);
0654:                } else {
0655:                    return null;
0656:                }
0657:            }
0658:
0659:            // ---------------------------- JDOQL Query Methods --------------------------------------
0660:
0661:            public ScalarExpression newLiteral(QueryExpression qs, Object value) {
0662:                ScalarExpression expr = new ObjectLiteral(qs, this , value,
0663:                        getType());
0664:                return expr;
0665:            }
0666:
0667:            public ScalarExpression newScalarExpression(QueryExpression qs,
0668:                    LogicSetExpression te) {
0669:                if (getNumberOfDatastoreFields() > 0) {
0670:                    return new ObjectExpression(qs, this , te);
0671:                } else {
0672:                    ClassLoaderResolver clr = qs.getClassLoaderResolver();
0673:                    MappedStoreManager srm = (MappedStoreManager) qs
0674:                            .getStoreManager();
0675:                    int relationType = fmd.getRelationType(clr);
0676:                    if (relationType == Relation.ONE_TO_ONE_BI) {
0677:                        // Create an expression joining to the related field in the related table
0678:                        DatastoreClass targetTable = srm.getDatastoreClass(fmd
0679:                                .getTypeName(), clr);
0680:                        AbstractMemberMetaData[] relatedMmds = fmd
0681:                                .getRelatedMemberMetaData(clr);
0682:                        // TODO Cater for more than one related field
0683:                        JavaTypeMapping refMapping = targetTable
0684:                                .getFieldMapping(relatedMmds[0]);
0685:                        JavaTypeMapping selectMapping = targetTable
0686:                                .getIDMapping();
0687:                        DatastoreIdentifier targetTableIdentifier = srm
0688:                                .getIdentifierFactory().newIdentifier(
0689:                                        IdentifierFactory.TABLE,
0690:                                        "RELATED"
0691:                                                + fmd.getAbsoluteFieldNumber());
0692:                        LogicSetExpression targetTe = qs.newTableExpression(
0693:                                targetTable, targetTableIdentifier);
0694:                        return new ObjectExpression(qs, this , te, refMapping,
0695:                                targetTe, selectMapping);
0696:                    } else if (relationType == Relation.MANY_TO_ONE_BI) {
0697:                        AbstractMemberMetaData[] relatedMmds = fmd
0698:                                .getRelatedMemberMetaData(clr);
0699:                        // TODO Cater for more than one related field
0700:                        if (fmd.getJoinMetaData() != null
0701:                                || relatedMmds[0].getJoinMetaData() != null) {
0702:                            // Join table relation - only allows for Collection/Array
0703:                            // Create an expression this table to the join table on the element id, selecting the owner id
0704:                            DatastoreContainerObject targetTable = srm
0705:                                    .getDatastoreContainerObject(relatedMmds[0]);
0706:                            JavaTypeMapping refMapping = null;
0707:                            JavaTypeMapping selectMapping = null;
0708:                            DatastoreElementContainer elementTable = (DatastoreElementContainer) targetTable;
0709:                            refMapping = elementTable.getElementMapping();
0710:                            selectMapping = elementTable.getOwnerMapping();
0711:                            DatastoreIdentifier targetTableIdentifier = srm
0712:                                    .getIdentifierFactory()
0713:                                    .newIdentifier(
0714:                                            IdentifierFactory.TABLE,
0715:                                            "JOINTABLE"
0716:                                                    + fmd
0717:                                                            .getAbsoluteFieldNumber());
0718:                            LogicSetExpression targetTe = qs
0719:                                    .newTableExpression(targetTable,
0720:                                            targetTableIdentifier);
0721:                            return new ObjectExpression(qs, this , te,
0722:                                    refMapping, targetTe, selectMapping);
0723:                        }
0724:                    }
0725:                }
0726:
0727:                // TODO Throw an exception since should be impossible
0728:                return null;
0729:            }
0730:
0731:            // ------------------------------------- Utility Methods ------------------------------------------
0732:
0733:            /**
0734:             * Get the object instance for a class using datastore identity
0735:             * @param om the ObjectManager
0736:             * @param rs the ResultSet
0737:             * @param param the parameters
0738:             * @param cmd the AbstractClassMetaData
0739:             * @return the id
0740:             */
0741:            private Object getObjectForDatastoreIdentity(ObjectManager om,
0742:                    final Object rs, int[] param, AbstractClassMetaData cmd) {
0743:                // Datastore Identity - retrieve the OID for the class.
0744:                // Note that this is a temporary OID that is simply formed from the type of base class in the relationship
0745:                // and the id stored in the FK. The real OID for the object may be of a different class.
0746:                // For that reason we get the object by checking the inheritance (final param in getObjectById())
0747:                Object oid = super .getObject(om, rs, param);
0748:                ApiAdapter api = om.getApiAdapter();
0749:                if (api.isPersistable(oid)) //why check this?
0750:                {
0751:                    return oid;
0752:                }
0753:                return oid == null ? null : om.findObject(oid, false, true,
0754:                        null);
0755:            }
0756:
0757:            /**
0758:             * Create a SingleFieldIdentity instance
0759:             * @param om the ObjectManager
0760:             * @param rs the ResultSet
0761:             * @param param the parameters
0762:             * @param cmd the AbstractClassMetaData
0763:             * @param objectIdClass the object id class
0764:             * @param pcClass the PersistenceCapable class
0765:             * @return the id
0766:             */
0767:            private Object createSingleFieldIdentity(ObjectManager om,
0768:                    final Object rs, int[] param, AbstractClassMetaData cmd,
0769:                    Class objectIdClass, Class pcClass) {
0770:                // SingleFieldIdentity
0771:                int paramNumber = param[0];
0772:                try {
0773:                    // TODO Factor this out - using RDBMS-specific code
0774:                    Object idObj = ((ResultSet) rs).getObject(paramNumber);
0775:                    if (idObj == null) {
0776:                        throw new JPOXException(LOCALISER.msg("041039"))
0777:                                .setFatal();
0778:                    } else {
0779:                        // Make sure the key type is correct for the type of SingleFieldIdentity
0780:                        Class keyType = om.getApiAdapter()
0781:                                .getKeyTypeForSingleFieldIdentityType(
0782:                                        objectIdClass);
0783:                        idObj = ClassUtils.convertValue(idObj, keyType);
0784:                    }
0785:                    return om.getApiAdapter().getNewSingleFieldIdentity(
0786:                            objectIdClass, pcClass, idObj);
0787:                } catch (Exception e) {
0788:                    JPOXLogger.PERSISTENCE.error(LOCALISER.msg("041036", cmd
0789:                            .getObjectidClass(), e));
0790:                    return null;
0791:                }
0792:            }
0793:
0794:            /**
0795:             * Create an object id instance and fill the fields using reflection
0796:             * @param om the ObjectManager
0797:             * @param rs the ResultSet
0798:             * @param param the parameters
0799:             * @param cmd the AbstractClassMetaData
0800:             * @param objectIdClass the object id class
0801:             * @return the id
0802:             */
0803:            private Object createObjectIdInstanceReflection(ObjectManager om,
0804:                    final Object rs, int[] param, AbstractClassMetaData cmd,
0805:                    Class objectIdClass) {
0806:                // Users own AID
0807:                Object fieldValue = null;
0808:                try {
0809:                    // Create an AID
0810:                    Object id = objectIdClass.newInstance();
0811:
0812:                    // Set the fields of the AID
0813:                    int paramIndex = 0;
0814:                    for (int i = 0; i < cmd.getPKMemberPositions().length; ++i) {
0815:                        AbstractMemberMetaData fmd = cmd
0816:                                .getMetaDataForManagedMemberAtAbsolutePosition(cmd
0817:                                        .getPKMemberPositions()[i]);
0818:                        Field field = objectIdClass.getField(fmd.getName());
0819:
0820:                        JavaTypeMapping m = om.getStoreManager()
0821:                                .getDatastoreClass(cmd.getFullClassName(),
0822:                                        om.getClassLoaderResolver())
0823:                                .getFieldMapping(fmd);
0824:                        // NOTE This assumes that each field has one datastore column.
0825:                        for (int j = 0; j < m.getNumberOfDatastoreFields(); j++) {
0826:                            // TODO Factor this out - using RDBMS-specific code
0827:                            Object obj = ((ResultSet) rs)
0828:                                    .getObject(param[paramIndex++]);
0829:                            if ((obj instanceof  BigDecimal)) {
0830:                                BigDecimal bigDecimal = (BigDecimal) obj;
0831:                                // Oracle 10g returns BigDecimal for NUMBER columns,
0832:                                // resulting in IllegalArgumentException when reflective 
0833:                                // setter is invoked for incompatible field type
0834:                                // (see http://www.jpox.org/servlet/jira/browse/CORE-2624)
0835:                                Class keyType = om.getApiAdapter()
0836:                                        .getKeyTypeForSingleFieldIdentityType(
0837:                                                field.getType());
0838:                                obj = ClassUtils.convertValue(bigDecimal,
0839:                                        keyType);
0840:                                if (!bigDecimal.subtract(
0841:                                        new BigDecimal("" + obj)).equals(
0842:                                        new BigDecimal("0"))) {
0843:                                    throw new JPOXException(
0844:                                            "Cannot convert retrieved BigInteger value to field of object id class!")
0845:                                            .setFatal();
0846:                                }
0847:                            }
0848:                            // field with multiple columns should have values returned from db merged here
0849:                            fieldValue = obj;
0850:                        }
0851:                        field.set(id, fieldValue);
0852:                    }
0853:                    return id;
0854:                } catch (Exception e) {
0855:                    JPOXLogger.PERSISTENCE.error(LOCALISER.msg("041037", cmd
0856:                            .getObjectidClass(), fmd == null ? null : fmd
0857:                            .getName(), fieldValue, e));
0858:                    return null;
0859:                }
0860:            }
0861:
0862:            /**
0863:             * Create an object id instance and fill the fields using reflection
0864:             * @param om the ObjectManager
0865:             * @param rs the ResultSet
0866:             * @param param the parameters
0867:             * @param cmd the AbstractClassMetaData
0868:             * @return the id
0869:             */
0870:            private Object getObjectForAbstractClass(ObjectManager om,
0871:                    final Object rs, int[] param, AbstractClassMetaData cmd) {
0872:                ClassLoaderResolver clr = om.getClassLoaderResolver();
0873:
0874:                // Abstract class, so we need to generate an AID before proceeding
0875:                Class objectIdClass = clr.classForName(cmd.getObjectidClass());
0876:                Class pcClass = clr.classForName(cmd.getFullClassName());
0877:                Object id;
0878:                if (cmd.usesSingleFieldIdentityClass()) {
0879:                    id = createSingleFieldIdentity(om, rs, param, cmd,
0880:                            objectIdClass, pcClass);
0881:                } else {
0882:                    id = createObjectIdInstanceReflection(om, rs, param, cmd,
0883:                            objectIdClass);
0884:                }
0885:                return om.findObject(id, false, true, null);
0886:            }
0887:
0888:            /**
0889:             * Get the object instance for a class using application identity
0890:             * @param om the ObjectManager
0891:             * @param rs the ResultSet
0892:             * @param param the parameters
0893:             * @param cmd the AbstractClassMetaData
0894:             * @return the id
0895:             */
0896:            private Object getObjectForApplicationIdentity(ObjectManager om,
0897:                    final Object rs, int[] param, AbstractClassMetaData cmd) {
0898:                ClassLoaderResolver clr = om.getClassLoaderResolver();
0899:
0900:                // Abstract class
0901:                if (((ClassMetaData) cmd).isAbstractPersistenceCapable()
0902:                        && cmd.getObjectidClass() != null) {
0903:                    return getObjectForAbstractClass(om, rs, param, cmd);
0904:                }
0905:
0906:                // Concrete class
0907:                int totalFieldCount = cmd.getNoOfManagedMembers()
0908:                        + cmd.getNoOfInheritedManagedMembers();
0909:                final StatementExpressionIndex[] statementExpressionIndex = new StatementExpressionIndex[totalFieldCount];
0910:                int paramIndex = 0;
0911:
0912:                DatastoreClass datastoreClass = om.getStoreManager()
0913:                        .getDatastoreClass(cmd.getFullClassName(), clr);
0914:                final int[] pkFieldNumbers = cmd.getPKMemberPositions();
0915:
0916:                for (int i = 0; i < pkFieldNumbers.length; ++i) {
0917:                    AbstractMemberMetaData fmd = cmd
0918:                            .getMetaDataForManagedMemberAtAbsolutePosition(pkFieldNumbers[i]);
0919:                    JavaTypeMapping m = datastoreClass.getFieldMapping(fmd);
0920:                    statementExpressionIndex[fmd.getAbsoluteFieldNumber()] = new StatementExpressionIndex();
0921:                    statementExpressionIndex[fmd.getAbsoluteFieldNumber()]
0922:                            .setMapping(m);
0923:                    int expressionsIndex[] = new int[m
0924:                            .getNumberOfDatastoreFields()];
0925:                    for (int j = 0; j < expressionsIndex.length; j++) {
0926:                        expressionsIndex[j] = param[paramIndex++];
0927:                    }
0928:                    statementExpressionIndex[fmd.getAbsoluteFieldNumber()]
0929:                            .setExpressionIndex(expressionsIndex);
0930:                }
0931:
0932:                final MappedStoreManager storeMgr = (MappedStoreManager) om
0933:                        .getStoreManager();
0934:                return om.findObjectUsingAID(clr.classForName(cmd
0935:                        .getFullClassName()), new FieldValues() {
0936:                    // StateManager calls the fetchFields method
0937:                    public void fetchFields(StateManager sm) {
0938:                        sm.replaceFields(pkFieldNumbers, storeMgr
0939:                                .getFieldManagerForResultProcessing(sm, rs,
0940:                                        statementExpressionIndex));
0941:                    }
0942:
0943:                    public void fetchNonLoadedFields(StateManager sm) {
0944:                        sm.replaceNonLoadedFields(pkFieldNumbers, storeMgr
0945:                                .getFieldManagerForResultProcessing(sm, rs,
0946:                                        statementExpressionIndex));
0947:                    }
0948:
0949:                    public FetchPlan getFetchPlanForLoading() {
0950:                        return null;
0951:                    }
0952:                }, false, true);
0953:            }
0954:
0955:            // ----------------------- Implementation of MappingCallbacks --------------------------
0956:
0957:            /**
0958:             * Method executed just after a fetch of the owning object, allowing any necessary action
0959:             * to this field and the object stored in it.
0960:             * @param sm StateManager for the owner.
0961:             */
0962:            public void postFetch(StateManager sm) {
0963:            }
0964:
0965:            /**
0966:             * Method executed just after the insert of the owning object, allowing any necessary action
0967:             * to this field and the object stored in it.
0968:             * @param sm StateManager for the owner
0969:             */
0970:            public void postInsert(StateManager sm) {
0971:                Object pc = sm.provideField(fmd.getAbsoluteFieldNumber());
0972:                if (pc == null) {
0973:                    // Has been set to null so nothing to do
0974:                    return;
0975:                }
0976:
0977:                ClassLoaderResolver clr = sm.getObjectManager()
0978:                        .getClassLoaderResolver();
0979:                AbstractMemberMetaData[] relatedMmds = fmd
0980:                        .getRelatedMemberMetaData(clr);
0981:                int relationType = fmd.getRelationType(clr);
0982:                if (pc != null) {
0983:                    if (relationType == Relation.ONE_TO_ONE_BI) {
0984:                        StateManager otherSM = sm.getObjectManager()
0985:                                .findStateManager(pc);
0986:                        AbstractMemberMetaData relatedMmd = fmd
0987:                                .getRelatedMemberMetaDataForObject(clr, sm
0988:                                        .getObject(), pc);
0989:                        Object relatedValue = otherSM.provideField(relatedMmd
0990:                                .getAbsoluteFieldNumber());
0991:                        if (relatedValue == null) {
0992:                            // Managed Relations : Other side not set so update it in memory
0993:                            if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
0994:                                JPOXLogger.PERSISTENCE.debug(LOCALISER.msg(
0995:                                        "041018", StringUtils.toJVMIDString(sm
0996:                                                .getObject()), fmd
0997:                                                .getFullFieldName(),
0998:                                        StringUtils.toJVMIDString(pc),
0999:                                        relatedMmd.getFullFieldName()));
1000:                            }
1001:                            otherSM.replaceField(relatedMmd
1002:                                    .getAbsoluteFieldNumber(), sm.getObject(),
1003:                                    false);
1004:                        } else if (relatedValue != sm.getObject()) {
1005:                            // Managed Relations : Other side is inconsistent so throw exception
1006:                            throw new JPOXUserException(LOCALISER.msg("041020",
1007:                                    StringUtils.toJVMIDString(sm.getObject()),
1008:                                    fmd.getFullFieldName(), StringUtils
1009:                                            .toJVMIDString(pc), StringUtils
1010:                                            .toJVMIDString(relatedValue)));
1011:                        }
1012:                    } else if (relationType == Relation.MANY_TO_ONE_BI
1013:                            && relatedMmds[0].hasCollection()) {
1014:                        // TODO Make sure we have this PC in the collection at the other side
1015:                        StateManager otherSM = sm.getObjectManager()
1016:                                .findStateManager(pc);
1017:                        if (otherSM != null) {
1018:                            // Managed Relations : add to the collection on the other side
1019:                            Collection relatedColl = (Collection) otherSM
1020:                                    .provideField(relatedMmds[0]
1021:                                            .getAbsoluteFieldNumber());
1022:                            if (relatedColl != null
1023:                                    && !(relatedColl instanceof  SCOCollection)) {
1024:                                // TODO Make sure the collection is a wrapper
1025:                                boolean contained = relatedColl.contains(sm
1026:                                        .getObject());
1027:                                if (!contained) {
1028:                                    JPOXLogger.PERSISTENCE.info(LOCALISER.msg(
1029:                                            "041022", StringUtils
1030:                                                    .toJVMIDString(sm
1031:                                                            .getObject()), fmd
1032:                                                    .getFullFieldName(),
1033:                                            StringUtils.toJVMIDString(pc),
1034:                                            relatedMmds[0].getFullFieldName()));
1035:                                    // TODO Enable this. CUrrently causes issues with
1036:                                    // PMImplTest, InheritanceStrategyTest, TCK "inheritance1.conf"
1037:                                    /*relatedColl.add(sm.getObject());*/
1038:                                }
1039:                            }
1040:                        }
1041:                    }
1042:                }
1043:            }
1044:
1045:            /**
1046:             * Method executed just afer any update of the owning object, allowing any necessary action
1047:             * to this field and the object stored in it.
1048:             * @param sm StateManager for the owner
1049:             */
1050:            public void postUpdate(StateManager sm) {
1051:                Object pc = sm.provideField(fmd.getAbsoluteFieldNumber());
1052:                if (pc == null) {
1053:                    // Has been set to null so nothing to do
1054:                    return;
1055:                }
1056:
1057:                if (pc != null) {
1058:                    StateManager otherSM = sm.getObjectManager()
1059:                            .findStateManager(pc);
1060:                    if (otherSM == null) {
1061:                        ClassLoaderResolver clr = sm.getObjectManager()
1062:                                .getClassLoaderResolver();
1063:                        int relationType = fmd.getRelationType(clr);
1064:                        if (relationType == Relation.ONE_TO_ONE_BI
1065:                                || relationType == Relation.MANY_TO_ONE_BI) {
1066:                            // Related object is not yet persisted (e.g 1-1 with FK at other side) so persist it
1067:                            sm.getObjectManager().persistObjectInternal(pc,
1068:                                    null, null, -1, StateManager.PC);
1069:                        }
1070:                    }
1071:                }
1072:            }
1073:
1074:            /**
1075:             * Method executed just before the owning object is deleted, allowing tidying up of any
1076:             * relation information.
1077:             * @param sm StateManager for the owner
1078:             */
1079:            public void preDelete(StateManager sm) {
1080:                // makes sure field is loaded
1081:                int fieldNumber = fmd.getAbsoluteFieldNumber();
1082:                try {
1083:                    sm.getObjectManager().getApiAdapter().isLoaded(sm,
1084:                            fieldNumber);
1085:                } catch (JDOObjectNotFoundException onfe) {
1086:                    // Already deleted so just return
1087:                    return;
1088:                }
1089:
1090:                Object pc = sm.provideField(fieldNumber);
1091:                if (pc == null) {
1092:                    // Null value so nothing to do
1093:                    return;
1094:                }
1095:
1096:                // Check if the field has a FK defined
1097:                ClassLoaderResolver clr = sm.getObjectManager()
1098:                        .getClassLoaderResolver();
1099:                AbstractMemberMetaData[] relatedMmds = fmd
1100:                        .getRelatedMemberMetaData(clr);
1101:                // TODO Cater for more than 1 related field
1102:                boolean dependent = fmd.isDependent();
1103:                boolean hasFK = false;
1104:                if (!dependent) {
1105:                    // Not dependent, so check if the datastore has a FK and will take care of it for us
1106:                    if (fmd.getForeignKeyMetaData() != null) {
1107:                        hasFK = true;
1108:                    }
1109:                    if (relatedMmds != null
1110:                            && relatedMmds[0].getForeignKeyMetaData() != null) {
1111:                        hasFK = true;
1112:                    }
1113:                    if (sm.getObjectManager().getOMFContext()
1114:                            .getPersistenceConfiguration().getDeletionPolicy()
1115:                            .equals("JDO2")) {
1116:                        // JDO2 doesnt currently (2.0 spec) take note of foreign-key
1117:                        hasFK = false;
1118:                    }
1119:                }
1120:
1121:                // Basic rules for the following :-
1122:                // 1. If it is dependent then we delete it (maybe after nulling).
1123:                // 2. If it is not dependent and they have defined no FK then null it, else delete it
1124:                // 3. If it is not dependent and they have a FK, let the datastore handle the delete
1125:                // There may be some corner cases that this code doesnt yet cater for
1126:                int relationType = fmd.getRelationType(clr);
1127:                if (pc != null) {
1128:                    if (relationType == Relation.ONE_TO_ONE_UNI
1129:                            || (relationType == Relation.ONE_TO_ONE_BI && fmd
1130:                                    .getMappedBy() == null)) {
1131:                        // 1-1 with FK at this side (owner of the relation)
1132:                        if (dependent) {
1133:                            boolean relatedObjectDeleted = sm
1134:                                    .getObjectManager().getApiAdapter()
1135:                                    .isDeleted(pc);
1136:                            if (isNullable() && !relatedObjectDeleted) {
1137:                                // Other object not yet deleted - just null out the FK
1138:                                // TODO Not doing this would cause errors in 1-1 uni relations (e.g AttachDetachTest)
1139:                                // TODO Log this since it affects the resultant objects
1140:                                sm.replaceField(fieldNumber, null, true);
1141:                                sm.getStoreManager().updateObject(sm,
1142:                                        new int[] { fieldNumber });
1143:                            }
1144:                            if (!relatedObjectDeleted) {
1145:                                // Mark the other object for deletion since not yet tagged
1146:                                sm.getObjectManager().deleteObjectInternal(pc);
1147:                            }
1148:                        } else {
1149:                            // We're deleting the FK at this side so shouldnt be an issue
1150:                            AbstractMemberMetaData relatedMmd = fmd
1151:                                    .getRelatedMemberMetaDataForObject(clr, sm
1152:                                            .getObject(), pc);
1153:                            if (relatedMmd != null) {
1154:                                StateManager otherSM = sm.getObjectManager()
1155:                                        .findStateManager(pc);
1156:                                if (otherSM != null) {
1157:                                    // Managed Relations : 1-1 bidir, so null out the object at the other
1158:                                    if (JPOXLogger.PERSISTENCE.isDebugEnabled()) {
1159:                                        JPOXLogger.PERSISTENCE
1160:                                                .debug(LOCALISER
1161:                                                        .msg(
1162:                                                                "041019",
1163:                                                                StringUtils
1164:                                                                        .toJVMIDString(pc),
1165:                                                                relatedMmd
1166:                                                                        .getFullFieldName(),
1167:                                                                StringUtils
1168:                                                                        .toJVMIDString(sm
1169:                                                                                .getObject())));
1170:                                    }
1171:                                    otherSM.replaceField(relatedMmd
1172:                                            .getAbsoluteFieldNumber(), null,
1173:                                            true);
1174:                                }
1175:                            }
1176:                        }
1177:                    } else if (relationType == Relation.ONE_TO_ONE_BI
1178:                            && fmd.getMappedBy() != null) {
1179:                        // 1-1 with FK at other side
1180:                        DatastoreClass relatedTable = sm.getStoreManager()
1181:                                .getDatastoreClass(
1182:                                        relatedMmds[0].getClassName(), clr);
1183:                        JavaTypeMapping relatedMapping = relatedTable
1184:                                .getFieldMapping(relatedMmds[0]);
1185:                        boolean isNullable = relatedMapping.isNullable();
1186:                        StateManager otherSM = sm.getObjectManager()
1187:                                .findStateManager(pc);
1188:                        if (dependent) {
1189:                            if (isNullable) {
1190:                                // Null out the FK in the datastore using a direct update (since we are deleting)
1191:                                otherSM.replaceField(relatedMmds[0]
1192:                                        .getAbsoluteFieldNumber(), null, true);
1193:                                otherSM.getStoreManager().updateObject(
1194:                                        otherSM,
1195:                                        new int[] { relatedMmds[0]
1196:                                                .getAbsoluteFieldNumber() });
1197:                            }
1198:                            // Mark the other object for deletion
1199:                            sm.getObjectManager().deleteObjectInternal(pc);
1200:                        } else if (!hasFK) {
1201:                            if (isNullable()) {
1202:                                // Null out the FK in the datastore using a direct update (since we are deleting)
1203:                                otherSM.replaceField(relatedMmds[0]
1204:                                        .getAbsoluteFieldNumber(), null, true);
1205:                                otherSM.getStoreManager().updateObject(
1206:                                        otherSM,
1207:                                        new int[] { relatedMmds[0]
1208:                                                .getAbsoluteFieldNumber() });
1209:                            } else {
1210:                                // TODO Remove it
1211:                            }
1212:                        } else {
1213:                            // User has a FK defined (in MetaData) so let the datastore take care of it
1214:                        }
1215:                    } else if (relationType == Relation.MANY_TO_ONE_BI) {
1216:                        StateManager otherSM = sm.getObjectManager()
1217:                                .findStateManager(pc);
1218:                        if (relatedMmds[0].getJoinMetaData() == null) {
1219:                            // N-1 with FK at this side
1220:                            if (otherSM.isDeleting()) {
1221:                                // Other object is being deleted too but this side has the FK so just delete this object
1222:                            } else {
1223:                                // Other object is not being deleted so delete it if necessary
1224:                                if (dependent) {
1225:                                    if (isNullable()) {
1226:                                        // TODO Datastore nullability info can be unreliable so try to avoid this call
1227:                                        // Null out the FK in the datastore using a direct update (since we are deleting)
1228:                                        sm
1229:                                                .replaceField(fieldNumber,
1230:                                                        null, true);
1231:                                        sm.getStoreManager().updateObject(sm,
1232:                                                new int[] { fieldNumber });
1233:                                    }
1234:
1235:                                    if (sm.getObjectManager().getApiAdapter()
1236:                                            .isDeleted(pc)) {
1237:                                        // Object is already tagged for deletion but we're deleting the FK so leave til flush()
1238:                                    } else {
1239:                                        // Mark the other object for deletion
1240:                                        sm.getObjectManager()
1241:                                                .deleteObjectInternal(pc);
1242:                                    }
1243:                                } else {
1244:                                    // Managed Relations : remove element from collection/map
1245:                                    if (relatedMmds[0].hasCollection()) {
1246:                                        Collection otherColl = (Collection) otherSM
1247:                                                .provideField(relatedMmds[0]
1248:                                                        .getAbsoluteFieldNumber());
1249:                                        if (otherColl != null) {
1250:                                            // TODO Remove from any cached SCO collection
1251:                                        }
1252:                                    } else if (relatedMmds[0].hasMap()) {
1253:                                        // TODO Cater for maps, but what is the key/value pair ?
1254:                                    }
1255:                                }
1256:                            }
1257:                        } else {
1258:                            // N-1 with join table so no FK here so need to remove from Collection/Map first? (managed relations)
1259:                            if (dependent) {
1260:                                // Mark the other object for deletion
1261:                                sm.getObjectManager().deleteObjectInternal(pc);
1262:                            } else {
1263:                                // Managed Relations : remove element from collection/map
1264:                                if (relatedMmds[0].hasCollection()) {
1265:                                    Collection otherColl = (Collection) otherSM
1266:                                            .provideField(relatedMmds[0]
1267:                                                    .getAbsoluteFieldNumber());
1268:                                    if (otherColl != null) {
1269:                                        // TODO Add log message
1270:                                        otherColl.remove(sm.getObject());
1271:                                    }
1272:                                } else if (relatedMmds[0].hasMap()) {
1273:                                    // TODO Cater for maps, but what is the key/value pair ?
1274:                                }
1275:                            }
1276:                        }
1277:                    } else {
1278:                        // No relation so what is this field ?
1279:                    }
1280:                }
1281:            }
1282:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.