Return-Path: Delivered-To: apmail-db-ojb-dev-archive@www.apache.org Received: (qmail 79571 invoked from network); 30 Sep 2005 21:45:39 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 30 Sep 2005 21:45:39 -0000 Received: (qmail 9352 invoked by uid 500); 30 Sep 2005 21:45:39 -0000 Delivered-To: apmail-db-ojb-dev-archive@db.apache.org Received: (qmail 9284 invoked by uid 500); 30 Sep 2005 21:45:38 -0000 Mailing-List: contact ojb-dev-help@db.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Help: List-Post: List-Id: "OJB Developers List" Reply-To: "OJB Developers List" Delivered-To: mailing list ojb-dev@db.apache.org Received: (qmail 9273 invoked by uid 500); 30 Sep 2005 21:45:37 -0000 Received: (qmail 9069 invoked by uid 99); 30 Sep 2005 21:45:37 -0000 X-ASF-Spam-Status: No, hits=-9.8 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Fri, 30 Sep 2005 14:45:35 -0700 Received: (qmail 79453 invoked by uid 1797); 30 Sep 2005 21:45:15 -0000 Date: 30 Sep 2005 21:45:15 -0000 Message-ID: <20050930214515.79452.qmail@minotaur.apache.org> From: tomdz@apache.org To: db-ojb-cvs@apache.org Subject: cvs commit: db-ojb/src/java/org/apache/ojb/broker/cache CachingStrategyTwoLevelImpl.java X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N tomdz 2005/09/30 14:45:15 Modified: src/java/org/apache/ojb/broker/core PersistenceBrokerImpl.java DelegatingPersistenceBroker.java src/java/org/apache/ojb/broker/util ClassHelper.java src/java/org/apache/ojb/otm/copy MetadataObjectCopyStrategy.java src/java/org/apache/ojb/broker PersistenceBroker.java PersistenceBrokerInternal.java Identity.java src/java/org/apache/ojb/broker/accesslayer JdbcAccessImpl.java RowReaderDefaultImpl.java RowReader.java RsIterator.java src/java/org/apache/ojb/broker/core/factory ObjectCreator.java ObjectFactoryDefaultImpl.java src/java/org/apache/ojb/broker/metadata ClassDescriptor.java RepositoryXmlHandler.java CreationDescriptor.java src/java/org/apache/ojb/broker/cache CachingStrategyTwoLevelImpl.java Added: src/java/org/apache/ojb/broker/metadata EnclosingClassReferenceDescriptor.java Removed: src/java/org/apache/ojb/broker/accesslayer PkEnumeration.java Log: * Added initial support for mapping inner classes using a special reference descriptor for the corresponding this-reference * Removed PKEnumeration Revision Changes Path 1.121 +115 -42 db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java Index: PersistenceBrokerImpl.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java,v retrieving revision 1.120 retrieving revision 1.121 diff -u -r1.120 -r1.121 --- PersistenceBrokerImpl.java 6 Sep 2005 22:19:19 -0000 1.120 +++ PersistenceBrokerImpl.java 30 Sep 2005 21:45:14 -0000 1.121 @@ -20,10 +20,10 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import org.apache.commons.collections.ListUtils; @@ -46,7 +46,6 @@ import org.apache.ojb.broker.accesslayer.JdbcAccess; import org.apache.ojb.broker.accesslayer.OJBIterator; import org.apache.ojb.broker.accesslayer.PagingIterator; -import org.apache.ojb.broker.accesslayer.PkEnumeration; import org.apache.ojb.broker.accesslayer.RelationshipPrefetcherFactory; import org.apache.ojb.broker.accesslayer.RowReader; import org.apache.ojb.broker.accesslayer.RsIteratorFactory; @@ -67,8 +66,10 @@ import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException; import org.apache.ojb.broker.metadata.CollectionDescriptor; import org.apache.ojb.broker.metadata.DescriptorRepository; +import org.apache.ojb.broker.metadata.EnclosingClassReferenceDescriptor; import org.apache.ojb.broker.metadata.FieldDescriptor; import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor; +import org.apache.ojb.broker.metadata.MetadataException; import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; import org.apache.ojb.broker.metadata.SequenceDescriptor; import org.apache.ojb.broker.metadata.fieldaccess.PersistentField; @@ -78,6 +79,7 @@ import org.apache.ojb.broker.query.QueryBySQL; import org.apache.ojb.broker.query.QueryFactoryNew; import org.apache.ojb.broker.util.BrokerHelper; +import org.apache.ojb.broker.util.ClassHelper; import org.apache.ojb.broker.util.IdentityArrayList; import org.apache.ojb.broker.util.ObjectModification; import org.apache.ojb.broker.util.collections.TrackingCollection; @@ -794,14 +796,15 @@ private void deleteReferences(Object obj, List listRds, boolean ignoreReferences) throws PersistenceBrokerException { // get all members of obj that are references and delete them - Iterator i = listRds.iterator(); - while (i.hasNext()) + for (Iterator i = listRds.iterator(); i.hasNext();) { - ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next(); - if ((!ignoreReferences && rds.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT) + ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor)i.next(); + + if ((!ignoreReferences && (rds.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT)) || rds.isSuperReferenceDescriptor()) { Object referencedObject = rds.getPersistentField().get(obj); + if (referencedObject != null) { doDelete(referencedObject, ignoreReferences); @@ -1028,24 +1031,23 @@ { // get all members of obj that are references and store them Collection listRds = cld.getObjectReferenceDescriptors(); - // return if nothing to do - if(listRds == null || listRds.size() == 0) - { - return; - } - Iterator i = listRds.iterator(); - while (i.hasNext()) + + if ((listRds != null) && (listRds.size() > 0)) { - ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next(); - /* - arminw: the super-references (used for table per subclass inheritance) must - be performed in any case. The "normal" 1:1 references can be ignored when - flag "ignoreReferences" is set - */ - if((!ignoreReferences && rds.getCascadingStore() != ObjectReferenceDescriptor.CASCADE_NONE) - || rds.isSuperReferenceDescriptor()) + for (Iterator i = listRds.iterator(); i.hasNext();) { - storeAndLinkOneToOne(false, obj, cld, rds, insert); + ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next(); + /* + arminw: the special references (eg. super-references used for table per subclass + inheritance) must be performed in any case. The "normal" 1:1 references can be + ignored when flag "ignoreReferences" is set + */ + if((!ignoreReferences && rds.getCascadingStore() != ObjectReferenceDescriptor.CASCADE_NONE) + || rds.isSuperReferenceDescriptor() + || (rds instanceof EnclosingClassReferenceDescriptor)) + { + storeAndLinkOneToOne(false, obj, cld, rds, insert); + } } } } @@ -1068,7 +1070,10 @@ Identity oid = serviceIdentity().buildIdentity(superCld, ref); storeToDb(ref, superCld, oid, insert); } - else store(ref); + else + { + store(ref); + } } link(obj, cld, rds, ref, insert); } @@ -1415,6 +1420,92 @@ } /** + * {@inheritDoc} + */ + public Object materializeEnclosingClassReference(ClassDescriptor classDesc, Map rowForInnerObj) + { + Class targetClass = classDesc.getClassOfObject(); + + if (!ClassHelper.isNonStaticInnerClass(targetClass)) + { + return null; + } + + EnclosingClassReferenceDescriptor outerClassRef = classDesc.getEnclosingClassReferenceDescriptor(); + Class outerClass = null; + Object outerObj = null; + + if (outerClassRef != null) + { + ClassDescriptor outerClassDesc = outerClassRef.getItemClassDescriptor(); + + outerClass = outerClassDesc.getClassOfObject(); + + Identity outerId = new Identity(outerClassDesc, + getTopLevelClass(outerClass), + outerClassRef.getForeignKeyFieldDescriptors(classDesc), + rowForInnerObj); + + // TODO: this doGetObjectByIdentity call might lead to problems when the outer + // objects references its inner object; + // solution: put a unmaterialized proxy for the inner object into + // the materializion cache prior to getting the outer object + outerObj = doGetObjectByIdentity(outerId); + + } + // there might be non-persistent outer classes in-between which we simply + // create via reflection + return createDirectEnclosingObject(targetClass, outerClass, outerObj); + } + + /** + * Creates the hierarchy of enclosing objects between the target class and the given persistent outer class + * + * @param targetClass The target inner class (is not instantiated) + * @param directPersistentOuterClass The nearest persistent enclosing class + * @param directPersistentOuterObject The instance of the nearest persistent enclosing class to use + * @return The instance of the direct enclosing class of the target class + */ + private Object createDirectEnclosingObject(Class targetClass, Class directPersistentOuterClass, Object directPersistentOuterObject) + { + Class directEnclosingClass = targetClass.getEnclosingClass(); + + if ((directPersistentOuterClass != null) && directPersistentOuterClass.equals(directEnclosingClass)) + { + return directPersistentOuterObject; + } + else if (directEnclosingClass.getEnclosingClass() != null) + { + // recursively create the direct enclosing object of the direct enclosing class + Object oneLevelAboveOuterObj = createDirectEnclosingObject(directEnclosingClass, directPersistentOuterClass, directPersistentOuterObject); + + try + { + return ClassHelper.newInstance(directEnclosingClass, + new Class[] { directEnclosingClass.getEnclosingClass() }, + new Object[] { oneLevelAboveOuterObj }, + true); + } + catch (Exception ex) + { + throw new MetadataException("Cannot create instance of class "+directEnclosingClass.getName()+" because there is no no-arg constructor", ex); + } + } + else + { + // the direct enclosing class is no inner class itself -> create with no-arg constructor + try + { + return ClassHelper.newInstance(directEnclosingClass, true); + } + catch (Exception ex) + { + throw new MetadataException("Cannot create instance of class "+directEnclosingClass.getName()+" because there is no no-arg constructor", ex); + } + } + } + + /** * Retrieve all References (also Collection-attributes) of a given instance. * Loading is forced, even if the collection- and reference-descriptors differ. * @param pInstance the persistent instance to work with @@ -1885,24 +1976,6 @@ } /** - * Returns an Enumeration of PrimaryKey Objects for objects of class DataClass. - * The Elements returned come from a SELECT ... WHERE Statement - * that is defined by the fields and their coresponding values of listFields - * and listValues. - * Useful for EJB Finder Methods... - * @param primaryKeyClass the pk class for the searched objects - * @param query the query - */ - public Enumeration getPKEnumerationByQuery(Class primaryKeyClass, Query query) throws PersistenceBrokerException - { - if (logger.isDebugEnabled()) logger.debug("getPKEnumerationByQuery " + query); - - query.setFetchSize(1); - ClassDescriptor cld = getClassDescriptor(query.getSearchClass()); - return new PkEnumeration(query, cld, primaryKeyClass, this); - } - - /** * @see org.apache.ojb.broker.PersistenceBroker#update(Object, String[]) */ public void update(Object obj, String[] fields) 1.25 +8 -9 db-ojb/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java Index: DelegatingPersistenceBroker.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/DelegatingPersistenceBroker.java,v retrieving revision 1.24 retrieving revision 1.25 diff -u -r1.24 -r1.25 --- DelegatingPersistenceBroker.java 6 Sep 2005 22:19:19 -0000 1.24 +++ DelegatingPersistenceBroker.java 30 Sep 2005 21:45:14 -0000 1.25 @@ -16,7 +16,7 @@ */ import java.util.Collection; -import java.util.Enumeration; +import java.util.Map; import org.apache.ojb.broker.Identity; import org.apache.ojb.broker.IdentityFactory; @@ -325,7 +325,12 @@ getBroker().retrieveReference(pInstance, pAttributeName); } - public void retrieveAllReferences(Object pInstance) throws PersistenceBrokerException + public Object materializeEnclosingClassReference(ClassDescriptor classDesc, Map rowForInnerObj) + { + return getBroker().materializeEnclosingClassReference(classDesc, rowForInnerObj); + } + + public void retrieveAllReferences(Object pInstance) throws PersistenceBrokerException { getBroker().retrieveAllReferences(pInstance); } @@ -405,12 +410,6 @@ return getBroker().getClassDescriptor(clazz); } - public Enumeration getPKEnumerationByQuery(Class primaryKeyClass, - Query query) throws PersistenceBrokerException - { - return getBroker().getPKEnumerationByQuery(primaryKeyClass, query); - } - public Object getObjectByQuery(Query query) throws PersistenceBrokerException { return getBroker().getObjectByQuery(query); 1.16 +35 -4 db-ojb/src/java/org/apache/ojb/broker/util/ClassHelper.java Index: ClassHelper.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/ClassHelper.java,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- ClassHelper.java 3 Sep 2005 15:28:14 -0000 1.15 +++ ClassHelper.java 30 Sep 2005 21:45:14 -0000 1.16 @@ -150,6 +150,17 @@ } /** + * Determines whether the given class is a non-static inner class. + * + * @param clazz The class + * @return true if the class is a non-static inner class + */ + public static boolean isNonStaticInnerClass(Class clazz) + { + return (clazz.getEnclosingClass() != null) && !Modifier.isStatic(clazz.getModifiers()); + } + + /** * Returns a new instance of the given class, using the default or a no-arg constructor. * * @param target The class to instantiate @@ -409,10 +420,12 @@ /** * Builds a new instance for the class represented by the given class descriptor. * - * @param cld The class descriptor + * @param cld The class descriptor + * @param args The arguments to the constructor or factory method + * @param enclosingObj The enclosing class instance if any * @return The instance */ - public static Object buildNewObjectInstance(ClassDescriptor cld, Object[] args) + public static Object buildNewObjectInstance(ClassDescriptor cld, Object[] args, Object enclosingObj) { Object result = null; @@ -432,7 +445,25 @@ throw new ClassNotPersistenceCapableException( "No useable constructor was found in class '" + cld.getClassNameOfObject() + "'"); } - result = ConstructorHelper.instantiate(con, args); + + // if we have an enclosing object, we have to add it as the first argument + Object[] realArgs = args; + + if (ClassHelper.isNonStaticInnerClass(cld.getClassOfObject())) + { + if ((args == null) || (args.length == 0)) + { + realArgs = new Object[1]; + } + else + { + realArgs = new Object[args.length + 1]; + System.arraycopy(args, 0, realArgs, 1, args.length); + } + realArgs[0] = enclosingObj; + } + + result = ConstructorHelper.instantiate(con, realArgs); } catch (InstantiationException e) { 1.26 +1 -1 db-ojb/src/java/org/apache/ojb/otm/copy/MetadataObjectCopyStrategy.java Index: MetadataObjectCopyStrategy.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/copy/MetadataObjectCopyStrategy.java,v retrieving revision 1.25 retrieving revision 1.26 diff -u -r1.25 -r1.26 --- MetadataObjectCopyStrategy.java 3 Sep 2005 15:28:14 -0000 1.25 +++ MetadataObjectCopyStrategy.java 30 Sep 2005 21:45:14 -0000 1.26 @@ -97,7 +97,7 @@ { args[idx] = _serialize.copy(argFields[idx].getPersistentField().get(toCopy), null); } - retval = broker.getConfiguration().getObjectFactory().newInstance(cld, args); + retval = broker.getConfiguration().getObjectFactory().newInstance(cld, args, null); objMap.put(toCopy,retval); } catch (Exception e) 1.39 +1 -15 db-ojb/src/java/org/apache/ojb/broker/PersistenceBroker.java Index: PersistenceBroker.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/PersistenceBroker.java,v retrieving revision 1.38 retrieving revision 1.39 diff -u -r1.38 -r1.39 --- PersistenceBroker.java 6 Sep 2005 22:19:20 -0000 1.38 +++ PersistenceBroker.java 30 Sep 2005 21:45:14 -0000 1.39 @@ -16,7 +16,6 @@ */ import java.util.Collection; -import java.util.Enumeration; import org.apache.ojb.broker.accesslayer.ConnectionManagerIF; import org.apache.ojb.broker.accesslayer.JdbcAccess; @@ -444,17 +443,4 @@ * I.e perform a SELECT ... FROM ... WHERE ... in an RDBMS */ public Object getObjectByQuery(Query query) throws PersistenceBrokerException; - - /** - * Returns an Enumeration of PrimaryKey Objects for objects of class DataClass. - * The Elements returned come from a SELECT ... WHERE Statement - * that is defined by the fields and their coresponding values of vecFields - * and vecValues. - * Useful for EJB Finder Methods... - * NOT YET AWARE OF EXTENTS ! - * @param PrimaryKeyClass the pk class for the searched objects - * @param query the query - */ - public Enumeration getPKEnumerationByQuery(Class PrimaryKeyClass, Query query) - throws PersistenceBrokerException; } 1.10 +14 -2 db-ojb/src/java/org/apache/ojb/broker/PersistenceBrokerInternal.java Index: PersistenceBrokerInternal.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/PersistenceBrokerInternal.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- PersistenceBrokerInternal.java 27 Aug 2005 12:23:16 -0000 1.9 +++ PersistenceBrokerInternal.java 30 Sep 2005 21:45:14 -0000 1.10 @@ -1,5 +1,7 @@ package org.apache.ojb.broker; +import java.util.Map; + import org.apache.ojb.broker.accesslayer.CollectionCreationContext; import org.apache.ojb.broker.accesslayer.RowReader; import org.apache.ojb.broker.accesslayer.RelationshipPrefetcherFactory; @@ -108,7 +110,17 @@ * @return QueryReferenceBroker */ public QueryReferenceBroker getReferenceBroker(); - + + /** + * Creates the enclosing class instance (hierarchy) by retrieving the necessary data from the database + * (for mapped enclosing classes) or by creating them (for non-mapped enclosing classes). + * + * @param classDesc The class descriptor + * @return The enclosing class instance or null if the target class is + * not a non-static inner class + */ + public Object materializeEnclosingClassReference(ClassDescriptor classDesc, Map rowForInnerObj); + /** * Refresh the references of the specified object if they have enabled * the refresh attribute. 1.45 +27 -1 db-ojb/src/java/org/apache/ojb/broker/Identity.java Index: Identity.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/Identity.java,v retrieving revision 1.44 retrieving revision 1.45 diff -u -r1.44 -r1.45 --- Identity.java 5 Sep 2005 22:46:15 -0000 1.44 +++ Identity.java 30 Sep 2005 21:45:14 -0000 1.45 @@ -21,6 +21,7 @@ import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.Arrays; +import java.util.Map; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -30,6 +31,7 @@ import org.apache.ojb.broker.core.proxy.IndirectionHandler; import org.apache.ojb.broker.metadata.ClassDescriptor; import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException; +import org.apache.ojb.broker.metadata.FieldDescriptor; import org.apache.ojb.broker.util.BrokerHelper; /** @@ -116,6 +118,30 @@ checkForPrimaryKeys(null); } + /** + * Creates an identity object for the given class descriptor by reading the field values from + * the given map. + * + * @param targetClass The target class descriptor + * @param topLevel The highest persistence-capable class + * @param fields The fields to use for building the identity + * @param fieldValues The field values keyed by the field names + */ + public Identity(final ClassDescriptor targetClass, final Class topLevel, final FieldDescriptor[] fields, final Map fieldValues) + { + Object[] values = new Object[fields.length]; + + for (int idx = 0; idx < fields.length; idx++) + { + values[idx] = fieldValues.get(fields[idx].getColumnName()); + } + + m_objectsTopLevelClass = topLevel; + m_objectsRealClass = targetClass.getClassOfObject(); + m_pkValues = values; + checkForPrimaryKeys(null); + } + public Identity(final Object objectToIdentitify, final PersistenceBroker targetBroker) { init(objectToIdentitify, targetBroker, null); 1.37 +7 -2 db-ojb/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java Index: JdbcAccessImpl.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/JdbcAccessImpl.java,v retrieving revision 1.36 retrieving revision 1.37 diff -u -r1.36 -r1.37 --- JdbcAccessImpl.java 30 Sep 2005 01:46:44 -0000 1.36 +++ JdbcAccessImpl.java 30 Sep 2005 21:45:15 -0000 1.37 @@ -696,9 +696,14 @@ { Map row = new HashMap(); RowReader rowReader = broker.getRowReaderFor(cld); + rs_stmt = new ResultSetAndStatement(broker.serviceStatementManager(), stmt, rs, sql); rowReader.readObjectArrayFrom(rs_stmt, row); - return rowReader.readObjectFrom(row); + + // read enclosing class reference first + Object enclosingObj = broker.materializeEnclosingClassReference(cld, row); + + return rowReader.readObjectFrom(row, enclosingObj); } else { 1.41 +21 -17 db-ojb/src/java/org/apache/ojb/broker/accesslayer/RowReaderDefaultImpl.java Index: RowReaderDefaultImpl.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/RowReaderDefaultImpl.java,v retrieving revision 1.40 retrieving revision 1.41 diff -u -r1.40 -r1.41 --- RowReaderDefaultImpl.java 30 Sep 2005 01:46:44 -0000 1.40 +++ RowReaderDefaultImpl.java 30 Sep 2005 21:45:15 -0000 1.41 @@ -30,9 +30,12 @@ import org.apache.ojb.broker.metadata.ClassDescriptor; import org.apache.ojb.broker.metadata.CreationDescriptor; import org.apache.ojb.broker.metadata.CreationParameter; +import org.apache.ojb.broker.metadata.EnclosingClassReferenceDescriptor; import org.apache.ojb.broker.metadata.FieldDescriptor; import org.apache.ojb.broker.metadata.JdbcType; import org.apache.ojb.broker.metadata.MetadataException; +import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor; +import org.apache.ojb.broker.util.ClassHelper; import org.apache.ojb.broker.util.SqlHelper; /** @@ -92,11 +95,11 @@ * same table. * */ - public Object readObjectFrom(Map row) throws PersistenceBrokerException + public Object readObjectFrom(Map row, Object enclosingObj) throws PersistenceBrokerException { // allow to select a specific classdescriptor ClassDescriptor cld = selectClassDescriptor(row); - return buildOrRefreshObject(row, cld, null); + return buildOrRefreshObject(row, cld, null, enclosingObj); } /** @@ -107,7 +110,7 @@ // 1. select target ClassDescriptor ClassDescriptor targetClassDescriptor = selectClassDescriptor(row); // 2. fill all scalar attributes of the existing object - buildOrRefreshObject(row, targetClassDescriptor, instance); + buildOrRefreshObject(row, targetClassDescriptor, instance, null); } /** @@ -120,7 +123,7 @@ * be refreshed. * @throws PersistenceBrokerException if there ewas an error creating the new object */ - protected Object buildOrRefreshObject(Map row, ClassDescriptor targetClassDescriptor, Object targetObject) + protected Object buildOrRefreshObject(Map row, ClassDescriptor targetClassDescriptor, Object targetObject, Object enclosingObj) { Object result = targetObject; FieldDescriptor[] fields = targetClassDescriptor.getFieldDescriptor(true); @@ -129,7 +132,7 @@ // 1. create new object instance if needed if (targetObject == null) { - result = createInstance(row, targetClassDescriptor); + result = createInstance(row, targetClassDescriptor, enclosingObj); if (targetClassDescriptor.getCreationDescriptor().hasParameters()) { fields = filterFieldDescriptors(fields, targetClassDescriptor.getCreationDescriptor()); @@ -165,12 +168,13 @@ /** * Creates a new instance for the given class dscriptor. - * - * @param row The row to get parameter values for the construction - * @param classDesc The class descriptor + * + * @param row The row to get parameter values for the construction + * @param classDesc The class descriptor + * @param enclosingObj The enclosing class instance if any * @return The new instance */ - protected Object createInstance(Map row, ClassDescriptor classDesc) + protected Object createInstance(Map row, ClassDescriptor classDesc, Object enclosingObj) { // determine fields to use in the constructor // remove them from the fields array @@ -204,12 +208,12 @@ } } } - return factory.newInstance(classDesc, args); + return factory.newInstance(classDesc, args, enclosingObj); } /** * Filters the field descriptors so that the fields used as creation parameters are not in the array. - * + * * @param fieldDescs The original field descriptors * @param creationDesc The creation descriptor * @return The filtered list @@ -293,7 +297,7 @@ else { fields = classDescriptor.getFieldDescriptor(true); - } + } } } readValuesFrom(rs_stmt, row, fields); @@ -304,10 +308,10 @@ * @throws PersistenceBrokerException if there is an error accessing the access layer */ public void readPkValuesFrom(ResultSetAndStatement rs_stmt, Map row) - { + { String ojbClass = SqlHelper.getOjbClassName(rs_stmt.m_rs); ClassDescriptor cld; - + if (ojbClass != null) { cld = classDescriptor.getRepository().getDescriptorFor(ojbClass); @@ -324,12 +328,12 @@ private int getColumnIndex(SelectStatementWrapper statementWrapper, FieldDescriptor fld) { int index = JdbcType.MIN_INT; - + if (statementWrapper != null) { index = statementWrapper.getColumnIndex(fld); } - + return index; } 1.13 +6 -6 db-ojb/src/java/org/apache/ojb/broker/accesslayer/RowReader.java Index: RowReader.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/RowReader.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- RowReader.java 30 Sep 2005 01:46:44 -0000 1.12 +++ RowReader.java 30 Sep 2005 21:45:15 -0000 1.13 @@ -23,16 +23,16 @@ */ public interface RowReader extends Serializable { -// static final long serialVersionUID = -1283322922537162249L; - /** * Materialize a single object from the values of the Map row. * the implementor of this class must not care for materializing * references or collection attributes, this is done later! - * @param row the Map containing the new values - * @return a properly created instance. + * + * @param row The map containing the new values + * @param enclosingObj The enclosing object for inner classes + * @return A properly created instance. */ - public Object readObjectFrom(Map row); + public Object readObjectFrom(Map row, Object enclosingObj); /** * refresh an existing instance from the values of the Map row. 1.80 +8 -15 db-ojb/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java Index: RsIterator.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/accesslayer/RsIterator.java,v retrieving revision 1.79 retrieving revision 1.80 diff -u -r1.79 -r1.80 --- RsIterator.java 30 Sep 2005 01:46:44 -0000 1.79 +++ RsIterator.java 30 Sep 2005 21:45:15 -0000 1.80 @@ -36,7 +36,6 @@ import org.apache.ojb.broker.cache.SessionCache; import org.apache.ojb.broker.metadata.ClassDescriptor; import org.apache.ojb.broker.metadata.DescriptorRepository; -import org.apache.ojb.broker.metadata.FieldDescriptor; import org.apache.ojb.broker.metadata.JdbcConnectionDescriptor; import org.apache.ojb.broker.query.Query; import org.apache.ojb.broker.query.QueryByCriteria; @@ -381,19 +380,9 @@ */ protected Identity getIdentityFromResultSet() throws PersistenceBrokerException { - // fill primary key values from Resultset - FieldDescriptor fld; - FieldDescriptor[] pkFields = getQueryObject().getClassDescriptor().getPkFields(); - Object[] pkValues = new Object[pkFields.length]; + ClassDescriptor classDesc = getQueryObject().getClassDescriptor(); - for (int i = 0; i < pkFields.length; i++) - { - fld = pkFields[i]; - pkValues[i] = getRow().get(fld.getColumnName()); - } - - // return identity object build up from primary keys - return new Identity(getQueryObject().getClassDescriptor().getClassOfObject(), getTopLevelClass(), pkValues); + return new Identity(classDesc, getTopLevelClass(), classDesc.getPkFields(), getRow()); } /** @@ -422,9 +411,13 @@ // map all field values from the current result set reader.readObjectArrayFrom(getRsAndStmt(), getRow()); + // 3. If Object is not in cache // materialize Object with primitive attributes filled from current row - result = reader.readObjectFrom(getRow()); + // we however have to first retrieve an enclosing class reference if one exists + Object enclosingObj = getBroker().materializeEnclosingClassReference(getQueryObject().getClassDescriptor(), getRow()); + + result = reader.readObjectFrom(getRow(), enclosingObj); // result may still be null! if (result != null) { 1.3 +8 -6 db-ojb/src/java/org/apache/ojb/broker/core/factory/ObjectCreator.java Index: ObjectCreator.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/factory/ObjectCreator.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ObjectCreator.java 3 Sep 2005 15:28:15 -0000 1.2 +++ ObjectCreator.java 30 Sep 2005 21:45:15 -0000 1.3 @@ -28,21 +28,23 @@ /** * Creates a new instance of the type described by the given class descriptor. * - * @param classDesc The class descriptor - * @param args The arguments + * @param classDesc The class descriptor + * @param args The arguments + * @param enclosingObj The enclosing class instance * @return The new instance * @throws ObjectFactoryException If no new instance could be created */ - public Object newInstance(ClassDescriptor classDesc, Object[] args) throws ObjectFactoryException; + public Object newInstance(ClassDescriptor classDesc, Object[] args, Object enclosingObj) throws ObjectFactoryException; /** * Creates a new instance of the type described by the given class descriptor, that is meant to * be used as an identity object. * - * @param classDesc The class descriptor - * @param args The arguments + * @param classDesc The class descriptor + * @param args The arguments + * @param enclosingObj The enclosing class instance * @return The new instance * @throws ObjectFactoryException If no new instance could be created */ - public Object newIdentityInstance(ClassDescriptor classDesc, Object[] args) throws ObjectFactoryException; + public Object newIdentityInstance(ClassDescriptor classDesc, Object[] args, Object enclosingObj) throws ObjectFactoryException; } 1.4 +13 -13 db-ojb/src/java/org/apache/ojb/broker/core/factory/ObjectFactoryDefaultImpl.java Index: ObjectFactoryDefaultImpl.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/factory/ObjectFactoryDefaultImpl.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- ObjectFactoryDefaultImpl.java 3 Sep 2005 15:28:15 -0000 1.3 +++ ObjectFactoryDefaultImpl.java 30 Sep 2005 21:45:15 -0000 1.4 @@ -33,8 +33,8 @@ /** The registered creators */ private HashMap creators = new HashMap(); - /* (non-Javadoc) - * @see org.apache.ojb.broker.core.factory.ObjectFactory#registerCreator(org.apache.ojb.broker.core.factory.ObjectCreator, java.lang.String) + /** + * {@inheritDoc} */ public void registerCreator(ObjectCreator creator, String type) { @@ -52,8 +52,8 @@ } } - /* (non-Javadoc) - * @see org.apache.ojb.broker.core.factory.ObjectFactory#registerCreator(org.apache.ojb.broker.core.factory.ObjectCreator, java.lang.String[]) + /** + * {@inheritDoc} */ public void registerCreator(ObjectCreator creator, String[] types) { @@ -67,10 +67,10 @@ } } - /* (non-Javadoc) - * @see org.apache.ojb.broker.core.factory.ObjectCreator#newInstance(org.apache.ojb.broker.metadata.ClassDescriptor, java.lang.Object[]) + /** + * {@inheritDoc} */ - public Object newInstance(ClassDescriptor classDesc, Object[] args) throws ObjectFactoryException + public Object newInstance(ClassDescriptor classDesc, Object[] args, Object enclosingObj) throws ObjectFactoryException { try { @@ -79,11 +79,11 @@ if (creator != null) { - obj = creator.newInstance(classDesc, args); + obj = creator.newInstance(classDesc, args, enclosingObj); } else { - obj = ClassHelper.buildNewObjectInstance(classDesc, args); + obj = ClassHelper.buildNewObjectInstance(classDesc, args, enclosingObj); } if (obj instanceof Initializable) @@ -105,11 +105,11 @@ } } - /* (non-Javadoc) - * @see org.apache.ojb.broker.core.factory.ObjectCreator#newIdentityInstance(org.apache.ojb.broker.metadata.ClassDescriptor, java.lang.Object[]) + /** + * {@inheritDoc} */ - public Object newIdentityInstance(ClassDescriptor classDesc, Object[] args) throws ObjectFactoryException + public Object newIdentityInstance(ClassDescriptor classDesc, Object[] args, Object enclosingObj) throws ObjectFactoryException { - return newInstance(classDesc, args); + return newInstance(classDesc, args, enclosingObj); } } 1.112 +19 -1 db-ojb/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java Index: ClassDescriptor.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java,v retrieving revision 1.111 retrieving revision 1.112 diff -u -r1.111 -r1.112 --- ClassDescriptor.java 25 Sep 2005 01:55:44 -0000 1.111 +++ ClassDescriptor.java 30 Sep 2005 21:45:15 -0000 1.112 @@ -28,6 +28,8 @@ import java.util.Map; import java.util.Vector; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.Predicate; import org.apache.commons.collections.set.ListOrderedSet; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.SystemUtils; @@ -480,6 +482,22 @@ return m_objectReferenceDescriptorsNameMap; } + + /** + * Returns the reference to the enclosing persistent class if any. + * + * @return The reference or null if there is no such reference + */ + public EnclosingClassReferenceDescriptor getEnclosingClassReferenceDescriptor() + { + return (EnclosingClassReferenceDescriptor)CollectionUtils.find(m_ObjectReferenceDescriptors, + new Predicate() { + public boolean evaluate(Object input) + { + return input instanceof EnclosingClassReferenceDescriptor; + } + }); + } /** * Get an CollectionDescriptor by name BRJ 1.75 +5 -1 db-ojb/src/java/org/apache/ojb/broker/metadata/RepositoryXmlHandler.java Index: RepositoryXmlHandler.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/RepositoryXmlHandler.java,v retrieving revision 1.74 retrieving revision 1.75 diff -u -r1.74 -r1.75 --- RepositoryXmlHandler.java 6 Sep 2005 22:19:19 -0000 1.74 +++ RepositoryXmlHandler.java 30 Sep 2005 21:45:15 -0000 1.75 @@ -589,6 +589,10 @@ ord = new SuperReferenceDescriptor(m_CurrentCLD); } + else if (name.endsWith(".this")) + { + ord = new EnclosingClassReferenceDescriptor(m_CurrentCLD, name); + } else { ord = new ObjectReferenceDescriptor(m_CurrentCLD); 1.3 +26 -10 db-ojb/src/java/org/apache/ojb/broker/metadata/CreationDescriptor.java Index: CreationDescriptor.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/CreationDescriptor.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- CreationDescriptor.java 5 Sep 2005 21:35:22 -0000 1.2 +++ CreationDescriptor.java 30 Sep 2005 21:45:15 -0000 1.3 @@ -160,7 +160,7 @@ // we're determining the constructor object lazily if ((constructor == null) && TYPE_CONSTRUCTOR.equals(getType())) { - if (!hasParameters()) + if (!hasParameters() && !ClassHelper.isNonStaticInnerClass(getTargetClass())) { try { @@ -178,7 +178,7 @@ for (int idx = 0; idx < constructors.length; idx++) { - if (fitsCreationParameters(constructors[idx].getParameterTypes())) + if (fitsCreationParameters(constructors[idx].getParameterTypes(), getTargetClass().getEnclosingClass())) { constructor = constructors[idx]; break; @@ -276,7 +276,7 @@ for (int idx = 0; idx < methods.length; idx++) { if (methods[idx].getName().equals(factoryMethodName) && - fitsCreationParameters(methods[idx].getParameterTypes())) + fitsCreationParameters(methods[idx].getParameterTypes(), null)) { factoryMethod = methods[idx]; break; @@ -294,24 +294,40 @@ * Determines whether the given method/constructor parameter types fit the * creation parameters. * - * @param paramTypes + * @param paramTypes The parameter types of the constructor/method to check + * @param enclosingClass The optional enclosing instance for non-static inner classes + * which is used as the first parameter for constructors * @return true if the given param types fit */ - private boolean fitsCreationParameters(Class[] paramTypes) + private boolean fitsCreationParameters(Class[] paramTypes, Class enclosingClass) { - if ((paramTypes == null) || (paramTypes.length == 0)) + int numParamTypes = (paramTypes == null ? 0 : paramTypes.length); + int numExpectedParams = parameters.size(); + + if (enclosingClass != null) { - return parameters.isEmpty(); + // first param is the enclosing class + numExpectedParams++; } - else if (paramTypes.length != parameters.size()) + if (numParamTypes != numExpectedParams) { return false; } else { - for (int idx = 0; idx < paramTypes.length; idx++) + int paramOfs = 0; + + if (enclosingClass != null) + { + if (!enclosingClass.equals(paramTypes[0])) + { + return false; + } + paramOfs++; + } + for (int idx = paramOfs; idx < numParamTypes; idx++) { - CreationParameter param = (CreationParameter)parameters.get(idx); + CreationParameter param = (CreationParameter)parameters.get(idx - paramOfs); if ((param.getType() != null) && !param.getType().equals(paramTypes[idx])) 1.1 db-ojb/src/java/org/apache/ojb/broker/metadata/EnclosingClassReferenceDescriptor.java Index: EnclosingClassReferenceDescriptor.java =================================================================== package org.apache.ojb.broker.metadata; /* Copyright 2003-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.lang.reflect.Field; import org.apache.ojb.broker.metadata.fieldaccess.AnonymousPersistentField; import org.apache.ojb.broker.metadata.fieldaccess.PersistentField; import org.apache.ojb.broker.util.logging.Logger; import org.apache.ojb.broker.util.logging.LoggerFactory; /** * Specialized reference that handles references from an inner class (non-static) to an * enclosing class instance which are necessary to create an inner class instance. * * @version $Id: EnclosingClassReferenceDescriptor.java,v 1.1 2005/09/30 21:45:15 tomdz Exp $ */ public class EnclosingClassReferenceDescriptor extends ObjectReferenceDescriptor { /** Unique id for serialization */ private static final long serialVersionUID = -6710982246416814483L; private transient Logger log; public EnclosingClassReferenceDescriptor(ClassDescriptor descriptor, String fieldName) { super(descriptor); super.setPersistentField(new EnclosingReferenceField(this, fieldName)); // needed immutable settings super.setLazy(false); super.setCascadeRetrieve(true); super.setCascadingStore(CASCADE_OBJECT); // we cannot simply delete the enclosing object because it might have other inner objects super.setCascadingDelete(CASCADE_LINK); } /** * {@inheritDoc} */ public void setItemClass(Class c) { Class curClass = getClassDescriptor().getClassOfObject().getEnclosingClass(); while (curClass != null) { if (curClass.equals(c)) { break; } else { curClass = curClass.getEnclosingClass(); } } if (curClass == null) { throw new MetadataException("Class "+c.getName()+" is not an enclosing class of "+getClassDescriptor().getClassNameOfObject()); } super.setItemClass(c); // TODO: we should check that the attribute name matches the respective this reference } /** * {@inheritDoc} */ public void setPersistentField(Class c, String fieldname) { // noop } /** * {@inheritDoc} */ public void setPersistentField(PersistentField pf) { // noop } /** * {@inheritDoc} */ public void setLazy(boolean lazy) { getLog().info("Not allowed to change the lazy property, will ignore setting"); } /** * {@inheritDoc} */ public void setCascadeRetrieve(boolean b) { getLog().info("Not allowed to change the auto-retrieve property, will ignore setting"); } /** * {@inheritDoc} */ public void setCascadeStore(boolean cascade) { getLog().info("Not allowed to change the auto-update property, will ignore setting"); } /** * {@inheritDoc} */ public void setCascadingStore(int cascade) { getLog().info("Not allowed to change the auto-update property, will ignore setting"); } /** * {@inheritDoc} */ public void setCascadingStore(String value) { getLog().info("Not allowed to change the auto-update property, will ignore setting"); } /** * {@inheritDoc} */ public void setCascadeDelete(boolean cascade) { getLog().info("Not allowed to change the auto-delete property, will ignore setting"); } /** * {@inheritDoc} */ public void setCascadingDelete(int cascade) { // TODO: Setting this to CASCADE_OBJECT could be interpreted as: // "Delete enclosing instance if there are no other inner class instances // referencing it" // However this is not simple because there might be different (unrelated) // inner classes, so multiple SELECTs would be necessary getLog().info("Not allowed to change the auto-delete property, will ignore setting"); } /** * {@inheritDoc} */ public void setCascadingDelete(String value) { getLog().info("Not allowed to change the auto-delete property, will ignore setting"); } private Logger getLog() { if (log == null) { log = LoggerFactory.getLogger(EnclosingClassReferenceDescriptor.class); } return log; } private static final class EnclosingReferenceField extends AnonymousPersistentField { private static final long serialVersionUID = 6096992757214847399L; private EnclosingClassReferenceDescriptor enclosingRef; public EnclosingReferenceField(EnclosingClassReferenceDescriptor enclosingRef, String name) { super(name); this.enclosingRef = enclosingRef; } public synchronized Object get(Object anObject) throws MetadataException { // we have to get outwards the enclosing class hierarchy Class targetClass = enclosingRef.getItemClass(); Class curClass = anObject.getClass(); Object curObject = anObject; try { do { // TODO: This actually returns the this reference to the outermost class Field[] declaredFields = curClass.getDeclaredFields(); Field enclosingThisField = null; // we have to find the field this${n} where {n} is the depth of the // enclosing class for (int idx = 0; idx < declaredFields.length; idx++) { if (declaredFields[idx].getName().startsWith("this$")) { enclosingThisField = declaredFields[idx]; break; } } enclosingThisField.setAccessible(true); curObject = enclosingThisField.get(curObject); curClass = curClass.getEnclosingClass(); } while ((curClass != null) && !curClass.equals(targetClass)); } catch (Exception ex) { throw new MetadataException(ex); } return curObject; } public synchronized void set(Object obj, Object value) throws MetadataException { // noop } } } 1.4 +2 -2 db-ojb/src/java/org/apache/ojb/broker/cache/CachingStrategyTwoLevelImpl.java Index: CachingStrategyTwoLevelImpl.java =================================================================== RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/cache/CachingStrategyTwoLevelImpl.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- CachingStrategyTwoLevelImpl.java 25 Sep 2005 01:44:39 -0000 1.3 +++ CachingStrategyTwoLevelImpl.java 30 Sep 2005 21:45:15 -0000 1.4 @@ -158,7 +158,7 @@ ObjectFactory factory = getBroker().getConfiguration().getObjectFactory(); FieldDescriptor[] creationFields = cld.getCreationArgumentFields(); FieldDescriptor[] nonCreationFields = cld.getNonCreationArgumentFields(true); - Object target = factory.newInstance(cld, getFieldValues(source, creationFields)); + Object target = factory.newInstance(cld, getFieldValues(source, creationFields), null); Object[] fieldValues = getFieldValues(source, nonCreationFields); // copy main object values --------------------------------------------------------------------- To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org For additional commands, e-mail: ojb-dev-help@db.apache.org