You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2005/12/04 03:50:30 UTC

cvs commit: db-ojb/src/java/org/apache/ojb/odmg ObjectEnvelope.java ObjectEnvelopeTable.java RuntimeObject.java TransactionImpl.java

arminw      2005/12/03 18:50:30

  Modified:    src/java/org/apache/ojb/odmg Tag: OJB_1_0_RELEASE
                        ObjectEnvelope.java ObjectEnvelopeTable.java
                        RuntimeObject.java TransactionImpl.java
  Log:
  fix problem with persistence by reachability, improvements
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.32.2.19 +173 -128  db-ojb/src/java/org/apache/ojb/odmg/ObjectEnvelope.java
  
  Index: ObjectEnvelope.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/ObjectEnvelope.java,v
  retrieving revision 1.32.2.18
  retrieving revision 1.32.2.19
  diff -u -r1.32.2.18 -r1.32.2.19
  --- ObjectEnvelope.java	6 Sep 2005 11:41:41 -0000	1.32.2.18
  +++ ObjectEnvelope.java	4 Dec 2005 02:50:30 -0000	1.32.2.19
  @@ -86,7 +86,7 @@
       /**
        * beforeImage holds a mapping between field
        * names and values at the start of the transaction.
  -     * afterImage holds the mapping at the
  +     * currentImage holds the mapping at the
        * end of the transaction.
        */
       private Map beforeImage;
  @@ -96,7 +96,6 @@
       private List linkEntryList;
   
       /**
  -     *
        * Create a wrapper by providing an Object.
        */
       public ObjectEnvelope(ObjectEnvelopeTable buffer, Identity oid, Object obj, boolean isNewObject)
  @@ -106,11 +105,13 @@
           this.oid = oid;
           // TODO: do we really need to materialize??
           myObj = ProxyHelper.getRealObject(obj);
  +        prepareInitialState(isNewObject);
           /*
  -        if object is new don't make an image, because we know it needs insert
  +        TODO: is it possible to improve this? Take care that "new"
  +        objects should support "persistence by reachability" too
  +        (detection of new/persistent reference objects after maon object lock)
           */
  -        if(!isNewObject) refreshObjectImage();
  -        prepareInitialState(isNewObject);
  +        beforeImage = buildObjectImage(getBroker());
       }
   
       public PersistenceBrokerInternal getBroker()
  @@ -151,14 +152,16 @@
        * to allow cleanup of used resources, e.g. remove proxy listener objects
        * to avoid invoke of registered objects after tx end.
        */
  -    public void cleanup(boolean reuse)
  +    public void cleanup(boolean reuse, boolean wasInsert)
       {
           if(currentImage != null)
           {
               Iterator iterator = currentImage.values().iterator();
               while(iterator.hasNext())
               {
  -                EqualsBase base =  (EqualsBase) iterator.next();
  +                ImageWrapper base =  (ImageWrapper) iterator.next();
  +                // cleanup image resources, on reuse the ImageWrapper
  +                // decide what to do with the resources
                   if(base != null) base.cleanup(reuse);
               }
           }
  @@ -167,15 +170,22 @@
               Iterator iterator = beforeImage.values().iterator();
               while(iterator.hasNext())
               {
  -                EqualsBase base =  (EqualsBase) iterator.next();
  -                // we always free resources of the old image
  +                ImageWrapper base =  (ImageWrapper) iterator.next();
  +                // we always free all resources of the old image
                   if(base != null) base.cleanup(false);
               }
           }
  -        if(!reuse) myObj = null;
  +        if(reuse)
  +        {
  +            refreshObjectImage(wasInsert);
  +        }
  +        else
  +        {
  +            myObj = null;
  +        }
       }
   
  -    public void refreshObjectImage()
  +    private void refreshObjectImage(boolean wasInsert)
       {
           PersistenceBroker broker = getBroker();
           try
  @@ -201,6 +211,30 @@
               }
               currentImage = null;
               hasChanged = null;
  +            if(wasInsert)
  +            {
  +                /*
  +                on insert we have to replace the PK fields and the version fields, because
  +                they populated after the object was written to DB, thus replace all field image values
  +                */
  +                FieldDescriptor[] flds = getClassDescriptor().getPkFields();
  +                for(int i = 0; i < flds.length; i++)
  +                {
  +                    FieldDescriptor fld = flds[i];
  +                    addFieldImage(beforeImage, fld);
  +                }
  +            }
  +            // TODO: How to handle version fields incremented by the DB?
  +            // always refresh the version fields, because these fields will change when written to DB
  +            if(getClassDescriptor().isLocking())
  +            {
  +                FieldDescriptor[] flds = getClassDescriptor().getLockingFields();
  +                for(int i = 0; i < flds.length; i++)
  +                {
  +                    FieldDescriptor fld = flds[i];
  +                    addFieldImage(beforeImage, fld);
  +                }
  +            }
           }
           catch(Exception ex)
           {
  @@ -208,7 +242,7 @@
               currentImage = null;
               hasChanged = null;
               log.error("Can't refresh object image", ex);
  -            throw new org.odmg.ClassNotPersistenceCapableException(ex.toString());
  +            throw new ImageException(ex);
           }
       }
   
  @@ -306,115 +340,120 @@
        */
       private Map buildObjectImage(PersistenceBroker broker) throws PersistenceBrokerException
       {
  -        Map fieldValues = new HashMap();
  -        ClassDescriptor mif = broker.getClassDescriptor(getObject().getClass());
  +        Map imageMap = new HashMap();
  +        ClassDescriptor cld = broker.getClassDescriptor(getObject().getClass());
           //System.out.println("++++ build image: " + getObject());
  +        // register 1:1 references in image
  +        buildImageForSingleReferences(imageMap, cld);
  +        // put object values to image map
  +        buildImageForFields(imageMap, cld);
  +        // register 1:n and m:n references in image
  +        buildImageForCollectionReferences(imageMap, cld);
  +        return imageMap;
  +    }
   
  -        /**
  -         * MBAIRD
  -         * 1. register all 1:1 references
  -         * field changes to 1:1 mapped objects should also be registered in the map,
  -         * so that alterations to those related objects will trigger an object to be
  -         * marked "dirty", otherwise attaching or detaching a 1:1 referenced object will
  -         * not be updated in ODMG.
  -         */
  -        Iterator iter = mif.getObjectReferenceDescriptors(true).iterator();
  +    private void buildImageForSingleReferences(Map imageMap, ClassDescriptor cld)
  +    {
  +        /*
  +        register all 1:1 references
  +        */
  +        Iterator iter = cld.getObjectReferenceDescriptors(true).iterator();
           ObjectReferenceDescriptor rds;
           while(iter.hasNext())
           {
               Object referenceObject;
  -            EqualsRefHelper erh;
  +            ReferenceImageWrapper erh;
               rds = (ObjectReferenceDescriptor) iter.next();
  -
               /*
  -             synchronize on myObj so the ODMG-layer can take a snapshot only of
  -             fully cached (i.e. with all references + collections) objects
  -             arminw:
  -             The PB-api only return full materialized objects, thus it's not
  -             needed to sync.
  -             */
  -//            synchronized(myObj)
  -//            {
  -//                referenceObject = rds.getPersistentField().get(myObj);
  -//            }
  -            referenceObject = rds.getPersistentField().get(myObj);
  -
  -            /**
  -             * MBAIRD
  -             * In the case of a proxy, we check if it has been materialized
  -             * if it's been materialized, we put it in the map, because it could change.
  -             * if it hasn't been materialized, it hasn't changed.
  -             *
  -             * Also handles virtual proxies.
  -             *
  -             * arminw:
  -             * wrap Object or Identity with a helper class. The main object will get
  -             * dirty when the 1:1 reference change: add or replaced by another object or deleted
  -             */
  -            IndirectionHandler handler = ProxyHelper.getIndirectionHandler(referenceObject);
  -            // if it is a not materialized proxy, use the Identity
  -            if(handler != null)
  -            {
  -                erh = handler.alreadyMaterialized()
  -                        ? new EqualsRefHelper(handler.getRealSubject())
  -                        : new EqualsRefHelper(handler.getIdentity());
  -            }
  -            else
  +            arminw:
  +            if a "super-reference" is matched (a 1:1 reference used to represent a super class)
  +            we don't handle it, because this will be done by the PB-api and could never be change
  +            */
  +            if(!rds.isSuperReferenceDescriptor())
               {
  -                /*
  -                arminw:
  -                if object was serialized and anonymous FK are used in the main object, the FK
  -                values are null, we have to refresh (re-assign) this values before building field images
  -                */
  -                if(referenceObject != null
  -                        && BrokerHelper.hasAnonymousKeyReference(rds.getClassDescriptor(), rds))
  +                referenceObject = rds.getPersistentField().get(myObj);
  +
  +                /**
  +                 * MBAIRD
  +                 * In the case of a proxy, we check if it has been materialized
  +                 * if it's been materialized, we put it in the map, because it could change.
  +                 * if it hasn't been materialized, it hasn't changed.
  +                 *
  +                 * Also handles virtual proxies.
  +                 *
  +                 * arminw:
  +                 * wrap Object or Identity with a helper class. The main object will get
  +                 * dirty when the 1:1 reference change: add or replaced by another object or deleted
  +                 */
  +                IndirectionHandler handler = ProxyHelper.getIndirectionHandler(referenceObject);
  +                // if it is a not materialized proxy, use the Identity
  +                if(handler != null)
                   {
  -                    getBroker().serviceBrokerHelper().link(myObj, rds, false);
  +                    erh = handler.alreadyMaterialized()
  +                            ? new ReferenceImageWrapper(handler.getRealSubject())
  +                            : new ReferenceImageWrapper(handler.getIdentity());
                   }
  -                erh = new EqualsRefHelper(referenceObject);
  +                else
  +                {
  +                    /*
  +                    arminw:
  +                    if object was serialized and anonymous FK are used in the main object, the FK
  +                    values are null, we have to refresh (re-assign) this values before building field images
  +                    */
  +                    if(referenceObject != null
  +                            && BrokerHelper.hasAnonymousKeyReference(rds.getClassDescriptor(), rds))
  +                    {
  +                        getBroker().serviceBrokerHelper().link(myObj, rds, false);
  +                    }
  +                    erh = new ReferenceImageWrapper(referenceObject);
  +                }
  +                /*
  +                register the Identity for 1:1 relations only, if change we have
  +                to update the main object
  +                */
  +            imageMap.put(rds, erh);
               }
  -            /*
  -             register the Identity for 1:1 relations only, if change we have
  -             to update the main object
  -             */
  -            fieldValues.put(rds, erh);
           }
  +    }
   
  -
  -        /**
  -         * MBAIRD
  -         * 2. register all fields of object (with inherited fields) that aren't collections or references
  -         */
  -        FieldDescriptor[] fieldDescs = mif.getFieldDescriptor(true);
  +    private void buildImageForFields(Map imageMap, ClassDescriptor cld)
  +    {
  +        // register all non reference fields of object (with inherited fields)
  +        FieldDescriptor[] fieldDescs = cld.getFieldDescriptor(true);
           for(int i = 0; i < fieldDescs.length; i++)
           {
  -            FieldDescriptor fld = fieldDescs[i];
  -            // map copies of all field values
  -            Object value = fld.getPersistentField().get(myObj);
  -            // get the real sql type value
  -            value = fld.getFieldConversion().javaToSql(value);
  -            // make copy of the sql type value
  -            value = fld.getJdbcType().getFieldType().copy(value);
  -            // buffer in image the field name and the sql type value
  -            // wrapped by a helper class
  -            fieldValues.put(fld.getPersistentField().getName(), new EqualsFieldHelper(fld.getJdbcType().getFieldType(), value));
  +            addFieldImage(imageMap, fieldDescs[i]);
           }
  +    }
   
  +    private void addFieldImage(Map imageMap, FieldDescriptor fld)
  +    {
  +        // map copies of all field values
  +        Object value = fld.getPersistentField().get(myObj);
  +        // get the real sql type value
  +        value = fld.getFieldConversion().javaToSql(value);
  +        // make copy of the sql type value
  +        value = fld.getJdbcType().getFieldType().copy(value);
  +        // buffer in image the field name and the sql type value
  +        // wrapped by a helper class
  +        imageMap.put(fld.getPersistentField().getName(), new FieldImageWrapper(fld.getJdbcType().getFieldType(), value));
  +    }
   
  +    private void buildImageForCollectionReferences(Map imageMap, ClassDescriptor cld)
  +    {
           /**
            * MBAIRD
            * 3. now let's register the collection descriptors
            */
  -        Iterator collections = mif.getCollectionDescriptors(true).iterator();
  +        Iterator collections = cld.getCollectionDescriptors(true).iterator();
           CollectionDescriptor cds;
           while(collections.hasNext())
           {
               cds = (CollectionDescriptor) collections.next();
               Object collectionOrArray = cds.getPersistentField().get(myObj);
  -            EqualsColHelper ech = new EqualsColHelper(cds, collectionOrArray);
  -            fieldValues.put(cds, ech);
  +            CollectionImageWrapper ech = new CollectionImageWrapper(cds, collectionOrArray);
  +            imageMap.put(cds, ech);
           }
  -        return fieldValues;
       }
   
       /**
  @@ -560,7 +599,7 @@
       void markReferenceElements(PersistenceBroker broker)
       {
           // these cases will be handled by ObjectEnvelopeTable#cascadingDependents()
  -        if(getModificationState().needsInsert() || getModificationState().needsDelete()) return;
  +        // if(getModificationState().needsInsert() || getModificationState().needsDelete()) return;
   
           Map oldImage = getBeforeImage();
           Map newImage = getCurrentImage();
  @@ -576,8 +615,8 @@
                   if (entry.getKey() instanceof CollectionDescriptor)
                   {
                       CollectionDescriptor cds = (CollectionDescriptor) entry.getKey();
  -                    EqualsColHelper oldEch = (EqualsColHelper) oldImage.get(cds);
  -                    EqualsColHelper newEch = (EqualsColHelper) entry.getValue();
  +                    CollectionImageWrapper oldEch = (CollectionImageWrapper) oldImage.get(cds);
  +                    CollectionImageWrapper newEch = (CollectionImageWrapper) entry.getValue();
   //System.out.println("");
   //System.out.println("mark-oldEch: " + oldEch);
   //System.out.println("mark-newEch: " + newEch);
  @@ -591,8 +630,8 @@
                       check for new 1:1 reference object
                       */
                       ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) entry.getKey();
  -                    EqualsRefHelper oldEh = (EqualsRefHelper) oldImage.get(rds);
  -                    EqualsRefHelper newEh = (EqualsRefHelper) newImage.get(rds);
  +                    ReferenceImageWrapper oldEh = (ReferenceImageWrapper) oldImage.get(rds);
  +                    ReferenceImageWrapper newEh = (ReferenceImageWrapper) newImage.get(rds);
                       if(!oldEh.equals(newEh))
                       {
                           // the main objects needs link/unlink of the FK to 1:1 reference,
  @@ -644,7 +683,7 @@
       /**
        * Mark object for delete if it's not available in the new Collection.
        */
  -    private void markDelete(CollectionDescriptor cds, EqualsColHelper oldEch, EqualsColHelper newEch)
  +    private void markDelete(CollectionDescriptor cds, CollectionImageWrapper oldEch, CollectionImageWrapper newEch)
       {
           if (oldEch.references.size() == 0)
           {
  @@ -656,11 +695,11 @@
           {
               Map.Entry entry = (Map.Entry) oldIter.next();
               Identity oldOid = (Identity) entry.getKey();
  -            if (!newRefs.containsKey(oldOid) && newEch.status != IS_UNMATERIALIZED_PROXY)
  +            if (newEch.status != IS_UNMATERIALIZED_PROXY && !newRefs.containsKey(oldOid))
               {
                   ObjectEnvelope mod = buffer.getByIdentity(oldOid);
                   // if this object is associated with another object it's
  -                // not allowed to remove it
  +                // not allowed to remove it, thus nothing will change
                   if(!buffer.isNewAssociatedObject(oldOid))
                   {
                       if(mod != null)
  @@ -677,7 +716,9 @@
                           }
                           else
                           {
  -                            // when cascade 'true' we remove all dependent objects, so no need to unlink
  +                            // when cascade 'true' we remove all dependent objects, so no need
  +                            // to unlink, else we have to unlink all referenced objects of this
  +                            // object
                               if(!cascade)
                               {
                                   mod.setModificationState(mod.getModificationState().markDirty());
  @@ -687,7 +728,7 @@
                       }
                       else
                       {
  -                        throw new ImageExcetion("Unexpected behaviour, unregistered object to delete: "
  +                        throw new ImageException("Unexpected behaviour, unregistered object to delete: "
                                   + oldOid + ", main object is " + getIdentity());
                       }
                   }
  @@ -698,7 +739,7 @@
       /**
        * Mark object for insert if it's not available in the old Collection.
        */
  -    private void markNew(CollectionDescriptor cds, EqualsColHelper oldEch, EqualsColHelper newEch)
  +    private void markNew(CollectionDescriptor cds, CollectionImageWrapper oldEch, CollectionImageWrapper newEch)
       {
           if (newEch.references.size() == 0)
           {
  @@ -720,7 +761,12 @@
               if ((oldRefs == null) || !oldRefs.containsKey(newOid))
               {
                   ObjectEnvelope mod = buffer.getByIdentity(newOid);
  -                if(mod == null) mod = buffer.get(newOid, newObj, true);
  +                // if the object isn't registered already, it can be 'new' or already 'persistent'
  +                if(mod == null)
  +                {
  +                    boolean isNew = getTx().isNewObject(null, newObj, newOid);
  +                    mod = buffer.get(newOid, newObj, isNew);
  +                }
                   // if the object was deleted in an previous action, mark as new
                   // to avoid deletion, else mark object as dirty to assign the FK of
                   // the main object
  @@ -833,7 +879,7 @@
       /**
        * Help to compare field values.
        */
  -    abstract class EqualsBase
  +    abstract class ImageWrapper
       {
           /**
            * This method is called before committing the transaction
  @@ -849,12 +895,12 @@
       /**
        * Help to compare field values.
        */
  -    class EqualsFieldHelper extends EqualsBase
  +    final class FieldImageWrapper extends ImageWrapper
       {
  -        FieldType type;
  -        Object value;
  +        final FieldType type;
  +        final Object value;
   
  -        public EqualsFieldHelper(FieldType type, Object value)
  +        public FieldImageWrapper(FieldType type, Object value)
           {
               this.type = type;
               this.value = value;
  @@ -873,9 +919,9 @@
               }
               else
               {
  -                if(valueNew instanceof EqualsFieldHelper)
  +                if(valueNew instanceof FieldImageWrapper)
                   {
  -                    result = type.equals(value, ((EqualsFieldHelper) valueNew).value);
  +                    result = type.equals(value, ((FieldImageWrapper) valueNew).value);
                   }
               }
   //            if(!result)
  @@ -887,7 +933,7 @@
   
           public String toString()
           {
  -            return "EqualsFieldHelper[type=" + type + "->value=" + value + "]";
  +            return "FieldImageWrapper[type=" + type + "->value=" + value + "]";
           }
       }
   
  @@ -897,17 +943,17 @@
       /**
        * Help to compare 1:1 references of the main object.
        */
  -    class EqualsRefHelper extends EqualsBase
  +    final class ReferenceImageWrapper extends ImageWrapper
       {
           Identity oid;
           Object value;
   
  -        public EqualsRefHelper(Object refObject)
  +        public ReferenceImageWrapper(Object refObject)
           {
               this.value = refObject;
           }
   
  -        public EqualsRefHelper(Identity oid)
  +        public ReferenceImageWrapper(Identity oid)
           {
               this.oid = oid;
           }
  @@ -934,9 +980,9 @@
               }
               else
               {
  -                if(toCompare instanceof EqualsRefHelper)
  +                if(toCompare instanceof ReferenceImageWrapper)
                   {
  -                    EqualsRefHelper other = (EqualsRefHelper) toCompare;
  +                    ReferenceImageWrapper other = (ReferenceImageWrapper) toCompare;
                       if(oid == null)
                       {
                           if(value != null)
  @@ -951,7 +997,6 @@
                               other.oid = getBroker().serviceIdentity().buildIdentity(other.value);
                           }
                       }
  -                    // return oid != null ? oid.equals(other.oid) : other.oid == null;
                       result = oid != null ? oid.equals(other.oid) : other.oid == null;
                   }
               }
  @@ -969,14 +1014,14 @@
       /**
        * Help to compare 1:n / m:n references of the main object.
        */
  -    class EqualsColHelper extends EqualsBase implements CollectionProxyListener
  +    class CollectionImageWrapper extends ImageWrapper implements CollectionProxyListener
       {
  -        private CollectionDescriptor des;
  +        private final CollectionDescriptor des;
           private CollectionProxy collectionHandler;
           private int status;
  -        private Map references;
  +        private final Map references;
   
  -        public EqualsColHelper(CollectionDescriptor des, Object collOrArray)
  +        public CollectionImageWrapper(CollectionDescriptor des, Object collOrArray)
           {
               this.des = des;
               references = new HashMap();
  @@ -1002,7 +1047,7 @@
            */
           public boolean equals(Object obj)
           {
  -            return (obj instanceof EqualsColHelper);
  +            return (obj instanceof CollectionImageWrapper);
           }
   
           void cleanup(boolean reuse)
  @@ -1125,23 +1170,23 @@
        * Thrown if something unexpected is happen when handling the
        * object images for state detection.
        */
  -    public static class ImageExcetion extends OJBRuntimeException
  +    public static class ImageException extends OJBRuntimeException
       {
  -        public ImageExcetion()
  +        public ImageException()
           {
           }
   
  -        public ImageExcetion(String msg)
  +        public ImageException(String msg)
           {
               super(msg);
           }
   
  -        public ImageExcetion(Throwable cause)
  +        public ImageException(Throwable cause)
           {
               super(cause);
           }
   
  -        public ImageExcetion(String msg, Throwable cause)
  +        public ImageException(String msg, Throwable cause)
           {
               super(msg, cause);
           }
  
  
  
  1.32.2.25 +38 -36    db-ojb/src/java/org/apache/ojb/odmg/ObjectEnvelopeTable.java
  
  Index: ObjectEnvelopeTable.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/ObjectEnvelopeTable.java,v
  retrieving revision 1.32.2.24
  retrieving revision 1.32.2.25
  diff -u -r1.32.2.24 -r1.32.2.25
  --- ObjectEnvelopeTable.java	27 Oct 2005 18:20:20 -0000	1.32.2.24
  +++ ObjectEnvelopeTable.java	4 Dec 2005 02:50:30 -0000	1.32.2.25
  @@ -244,9 +244,10 @@
           while (iter.hasNext())
           {
               ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next());
  +            boolean insert = false;
               if(needsCommit)
               {
  -                boolean insert = mod.needsInsert();
  +                insert = mod.needsInsert();
                   mod.getModificationState().commit(mod);
                   if(reuse && insert)
                   {
  @@ -258,7 +259,7 @@
               ObjectEnvelope, because this method will e.g. remove proxy listener
               objects for registered objects.
               */
  -            mod.cleanup(reuse);
  +            mod.cleanup(reuse, insert);
           }
           // add m:n indirection table entries
           performM2NLinkEntries();
  @@ -274,7 +275,11 @@
           while (iter.hasNext())
           {
               ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next());
  -            mod.markReferenceElements(broker);
  +            // only non transient objects should be performed
  +            if(!mod.getModificationState().isTransient())
  +            {
  +                mod.markReferenceElements(broker);
  +            }
           }
       }
   
  @@ -291,12 +296,15 @@
               while (iter.hasNext())
               {
                   ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next());
  -                if(needsCommit && (mod.getModificationState() != StateOldClean.getInstance()
  -                        || mod.getModificationState() != StateTransient.getInstance()))
  +                if(!needsCommit || (mod.getModificationState() == StateOldClean.getInstance()
  +                        || mod.getModificationState().isTransient()))
  +                {
  +                    // nothing to do
  +                }
  +                else
                   {
                       mod.setModificationState(mod.getModificationState().markClean());
                   }
  -                mod.refreshObjectImage();
               }
           }
       }
  @@ -310,30 +318,39 @@
       {
           // using clone to avoid ConcurentModificationException
           Iterator iter = ((List) mvOrderOfIds.clone()).iterator();
  +        TransactionImpl tx = getTransaction();
           ObjectEnvelope mod;
           while (iter.hasNext())
           {
               mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next());
  -            /*
  -            now we check if all modified objects has a write lock. On insert of new
  -            objects we don't need a write lock.
  -            */
  -            if(!mod.needsInsert())
  +            // ignore transient objects
  +            if(!mod.getModificationState().isTransient())
               {
  -                if((mod.needsDelete() || mod.needsUpdate()
  -                        || mod.hasChanged(getTransaction().getBroker())))
  +                /*
  +                now we check if all modified objects has a write lock. On insert of new
  +                objects we don't need a write lock.
  +                */
  +                if(!mod.needsInsert())
  +                {
  +                    if((mod.needsDelete() || mod.needsUpdate()
  +                            || mod.hasChanged(tx.getBroker())))
  +                    {
  +                        needsCommit = true;
  +                        // mark object dirty
  +                        mod.setModificationState(mod.getModificationState().markDirty());
  +                        ClassDescriptor cld = mod.getClassDescriptor();
  +                        // if the object isn't already locked, we will do it now
  +                        if(!mod.isWriteLocked())
  +                        {
  +                            tx.doSingleLock(cld, mod.getObject(), mod.getIdentity(), Transaction.WRITE);
  +                        }
  +                    }
  +                }
  +                else
                   {
                       needsCommit = true;
  -                    // mark object dirty
  -                    mod.setModificationState(mod.getModificationState().markDirty());
  -                    ClassDescriptor cld = mod.getClassDescriptor();
  -                    if(!mod.isWriteLocked()) getTransaction().doSingleLock(cld, mod.getObject(), mod.getIdentity(), Transaction.WRITE);
                   }
               }
  -            else
  -            {
  -                needsCommit = true;
  -            }
           }
       }
   
  @@ -835,19 +852,4 @@
               entry.execute(broker);
           }
       }
  -
  -    /**
  -     * Set the specified identity to the last position in the order list.
  -     * Note: The Identity must already exist in order list.
  -     */
  -    void moveToLastInOrderList(Identity oid)
  -    {
  -        int index = mvOrderOfIds.indexOf(oid);
  -        // move entry only if exists
  -        if(index > -1 && index < (mvOrderOfIds.size() - 1))
  -        {
  -            Object id = mvOrderOfIds.remove(index);
  -            mvOrderOfIds.add(id);
  -        }
  -    }
   }
  \ No newline at end of file
  
  
  
  1.1.2.5   +2 -28     db-ojb/src/java/org/apache/ojb/odmg/RuntimeObject.java
  
  Index: RuntimeObject.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/RuntimeObject.java,v
  retrieving revision 1.1.2.4
  retrieving revision 1.1.2.5
  diff -u -r1.1.2.4 -r1.1.2.5
  --- RuntimeObject.java	3 May 2005 17:09:04 -0000	1.1.2.4
  +++ RuntimeObject.java	4 Dec 2005 02:50:30 -0000	1.1.2.5
  @@ -106,33 +106,7 @@
   
       void doIsNewObjectCheck(final TransactionImpl tx)
       {
  -        /*
  -        detection of new objects is costly (select of ID in DB to check if object
  -        already exists) we do:
  -        a. check if the object has nullified PK field
  -        b. check if the object is already registered
  -        c. lookup from cache and if not found, last option select on DB
  -        */
  -        final PersistenceBroker pb = tx.getBroker();
  -        boolean isNew = pb.serviceBrokerHelper().hasNullPKField(cld, obj);
  -        if(!isNew)
  -        {
  -            // use method call to guaratee creation of oid
  -            final Identity oid = getIdentity();
  -            final ObjectEnvelope mod = tx.objectEnvelopeTable.getByIdentity(oid);
  -            if(mod != null)
  -            {
  -                // already registered object, use current state
  -                isNew = mod.needsInsert();
  -            }
  -            else
  -            {
  -                // if object was found cache, assume it's old
  -                // else make costly check against the DB
  -                isNew = pb.serviceObjectCache().lookup(oid) == null
  -                        && !pb.serviceBrokerHelper().doesExist(cld, oid, obj);
  -            }
  -        }
  +        boolean isNew = tx.isNewObject(cld, obj, null);
           this.isNew = isNew ? Boolean.TRUE : Boolean.FALSE;
       }
   
  
  
  
  1.59.2.22 +43 -51    db-ojb/src/java/org/apache/ojb/odmg/TransactionImpl.java
  
  Index: TransactionImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/TransactionImpl.java,v
  retrieving revision 1.59.2.21
  retrieving revision 1.59.2.22
  diff -u -r1.59.2.21 -r1.59.2.22
  --- TransactionImpl.java	27 Oct 2005 18:19:06 -0000	1.59.2.21
  +++ TransactionImpl.java	4 Dec 2005 02:50:30 -0000	1.59.2.22
  @@ -270,7 +270,7 @@
               if(cascade)
               {
                   // if implicite locking is enabled, first add the current object to
  -                // list of registered objects to avoid
  +                // list of registered objects to avoid endless loops on circular objects
                   registeredObjects.add(rtObject.getIdentity());
                   // lock and register 1:1 references first
                   lockAndRegisterReferences(rtObject.getCld(), rtObject.getObj(), lockMode, registeredObjects);
  @@ -1331,6 +1331,47 @@
       }
   
       /**
  +     * Detect new objects.
  +     */
  +    protected boolean isNewObject(ClassDescriptor cld, Object obj, Identity oid)
  +    {
  +        /*
  +        detection of new objects is costly (select of ID in DB to check if object
  +        already exists) we do:
  +        a. check if the object has nullified PK field
  +        b. check if the object is already registered
  +        c. lookup from cache and if not found, last option select on DB
  +        */
  +        final PersistenceBroker pb = getBroker();
  +        if(cld == null)
  +        {
  +            cld = pb.getClassDescriptor(obj.getClass());
  +        }
  +        boolean isNew = pb.serviceBrokerHelper().hasNullPKField(cld, obj);
  +        if(!isNew)
  +        {
  +            if(oid == null)
  +            {
  +                oid = pb.serviceIdentity().buildIdentity(cld, obj);
  +            }
  +            final ObjectEnvelope mod = objectEnvelopeTable.getByIdentity(oid);
  +            if(mod != null)
  +            {
  +                // already registered object, use current state
  +                isNew = mod.needsInsert();
  +            }
  +            else
  +            {
  +                // if object was found cache, assume it's old
  +                // else make costly check against the DB
  +                isNew = pb.serviceObjectCache().lookup(oid) == null
  +                        && !pb.serviceBrokerHelper().doesExist(cld, oid, obj);
  +            }
  +        }
  +        return isNew;
  +    }
  +
  +    /**
        * Allows to change the <em>cascading delete</em> behavior of the specified reference
        * of the target class while this transaction is in use.
        *
  @@ -1411,27 +1452,6 @@
               arminw: Here we use the auto-delete flag defined in metadata
               */
               result = ord.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT;
  -/*
  -arminw:
  -these settings are nonsense (my fault), it dosen't make sense to differ cascade delete
  -on the used reference type.
  -*/
  -//            if(ord instanceof CollectionDescriptor)
  -//            {
  -//                CollectionDescriptor cds = (CollectionDescriptor) ord;
  -//                if(cds.isMtoNRelation())
  -//                {
  -//                    result = implementation.cascadingDeleteMtoN;
  -//                }
  -//                else
  -//                {
  -//                    result = implementation.cascadingDeleteOnetoN;
  -//                }
  -//            }
  -//            else
  -//            {
  -//                result = implementation.cascadingDeleteOnetoOne;
  -//            }
           }
           else
           {
  @@ -1469,34 +1489,6 @@
           this.ordering = ordering;
       }
   
  -//    /**
  -//     * @see ImplementationExt#isNoteUserOrder()
  -//     */
  -//    public boolean isNoteUserOrder()
  -//    {
  -//        return noteUserOrdering;
  -//    }
  -//
  -//    /**
  -//     * @see ImplementationExt#setNoteUserOrder(boolean)
  -//     */
  -//    public void setNoteUserOrder(boolean noteUserOrder)
  -//    {
  -//        this.noteUserOrdering = noteUserOrder;
  -//    }
  -//
  -//    /**
  -//     * Move the specified {@link org.apache.ojb.broker.Identity} to the
  -//     * last position in the order list if {@link #isNoteUserOrder()} returns <em>true</em>.
  -//     * @param oid The object identity to move.
  -//     */
  -//    public void moveToLastInOrderList(Identity oid)
  -//    {
  -//        if(isNoteUserOrder())
  -//        {
  -//            objectEnvelopeTable.moveToLastInOrderList(oid);
  -//        }
  -//    }
   
       //============================================================
       // inner class
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org