db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From olegn...@apache.org
Subject cvs commit: db-ojb/src/test/org/apache/ojb/otm Address.java AddressDesc.java DependentTests.java Person.java AllTests.java
Date Thu, 24 Jul 2003 21:55:04 GMT
olegnitz    2003/07/24 14:55:04

  Modified:    src/java/org/apache/ojb/broker/metadata
                        CollectionDescriptor.java
                        ObjectReferenceDescriptor.java
                        RepositoryElements.java RepositoryTags.java
                        RepositoryXmlHandler.java
               src/java/org/apache/ojb/otm/core ConcreteEditingContext.java
               src/schema ojbtest-schema.xml
               src/test/org/apache/ojb repository.dtd repository_junit.xml
               src/test/org/apache/ojb/otm AllTests.java
  Added:       src/test/org/apache/ojb/otm Address.java AddressDesc.java
                        DependentTests.java Person.java
  Log:
  Added the notion of dependent objects to OTM and the test for it.
  Added the "otm-dependent" attribute for collection and reference descriptors
  in repository.xml
  
  Revision  Changes    Path
  1.20      +7 -1      db-ojb/src/java/org/apache/ojb/broker/metadata/CollectionDescriptor.java
  
  Index: CollectionDescriptor.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/CollectionDescriptor.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- CollectionDescriptor.java	2 May 2003 12:24:31 -0000	1.19
  +++ CollectionDescriptor.java	24 Jul 2003 21:55:03 -0000	1.20
  @@ -330,6 +330,12 @@
                result       += "        " + tags.getAttribute(AUTO_DELETE,"true") + eol;
           }
   
  +        //otm-dependent is optional, disabled by default
  +        if (getOtmDependent())
  +        {
  +            result += "        " + tags.getAttribute(OTM_DEPENDENT, "true") + eol;
  +        }
  +
           // close opening tag
           result       += "      >" + eol;
   
  
  
  
  1.29      +25 -2     db-ojb/src/java/org/apache/ojb/broker/metadata/ObjectReferenceDescriptor.java
  
  Index: ObjectReferenceDescriptor.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/ObjectReferenceDescriptor.java,v
  retrieving revision 1.28
  retrieving revision 1.29
  diff -u -r1.28 -r1.29
  --- ObjectReferenceDescriptor.java	13 Jun 2003 18:48:12 -0000	1.28
  +++ ObjectReferenceDescriptor.java	24 Jul 2003 21:55:03 -0000	1.29
  @@ -81,7 +81,8 @@
       private boolean m_CascadeDelete = false;
       private Class m_ProxyOfItems = null;
       private boolean m_LookedUpProxy = false;
  -	
  +    private boolean m_OtmDependent = false;
  +
       /**
        * holds the foreign-key field descriptor array for a specified class
        */
  @@ -343,6 +344,22 @@
           m_CascadeDelete = b;
       }
   
  +    /**
  +     *
  +     */
  +    public boolean getOtmDependent()
  +    {
  +        return m_OtmDependent;
  +    }
  +
  +    /**
  +     *
  +     */
  +    public void setOtmDependent(boolean b)
  +    {
  +        m_OtmDependent = b;
  +    }
  +
       public String toString()
       {
           return new ToStringBuilder(this)
  @@ -407,6 +424,12 @@
               result += "        " + tags.getAttribute(AUTO_DELETE, "true") + eol;
           }
   
  +        //otm-dependent is optional, disabled by default
  +        if (getOtmDependent())
  +        {
  +            result += "        " + tags.getAttribute(OTM_DEPENDENT, "true") + eol;
  +        }
  +
           // close opening tag
           result += "      >" + eol;
   
  @@ -415,7 +438,7 @@
           for (int i = 0; i < getForeignKeyFields().size(); i++)
           {
               Object obj = getForeignKeyFields().get(i);
  -	    if (obj instanceof Integer) 
  +	    if (obj instanceof Integer)
   	    {
           	String fkId = obj.toString();
                   result += "        " + tags.getOpeningTagNonClosingById(FOREIGN_KEY) + " ";
  
  
  
  1.30      +2 -1      db-ojb/src/java/org/apache/ojb/broker/metadata/RepositoryElements.java
  
  Index: RepositoryElements.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/RepositoryElements.java,v
  retrieving revision 1.29
  retrieving revision 1.30
  diff -u -r1.29 -r1.30
  --- RepositoryElements.java	23 Jul 2003 20:07:32 -0000	1.29
  +++ RepositoryElements.java	24 Jul 2003 21:55:03 -0000	1.30
  @@ -102,6 +102,7 @@
       public static final int AUTO_RETRIEVE = 24;
       public static final int AUTO_UPDATE = 25;
       public static final int AUTO_DELETE = 26;
  +    public static final int OTM_DEPENDENT = 102;
       public static final int COLLECTION_DESCRIPTOR = 27;
       public static final int ITEMS_CLASS = 29;
       public static final int INVERSE_FK = 38;
  @@ -165,7 +166,7 @@
       public static final int NAME = 97;
   
       // maintain a next id to keep track where we are
  -    static final int _NEXT = 102;
  +    static final int _NEXT = 103;
   
       // String constants
       public static final String TAG_ACCESS           = "access";
  
  
  
  1.30      +1 -0      db-ojb/src/java/org/apache/ojb/broker/metadata/RepositoryTags.java
  
  Index: RepositoryTags.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/metadata/RepositoryTags.java,v
  retrieving revision 1.29
  retrieving revision 1.30
  diff -u -r1.29 -r1.30
  --- RepositoryTags.java	23 Jul 2003 20:07:32 -0000	1.29
  +++ RepositoryTags.java	24 Jul 2003 21:55:03 -0000	1.30
  @@ -155,6 +155,7 @@
           table.put("refresh", new Integer(REFRESH));
           table.put("proxy", new Integer(PROXY_REFERENCE));
           table.put("sort", new Integer(SORT));
  +        table.put("otm-dependent", new Integer(OTM_DEPENDENT));
   
           table.put("index-descriptor", new Integer(INDEX_DESCRIPTOR));
           table.put("index-column", new Integer(INDEX_COLUMN));
  
  
  
  1.45      +13 -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.44
  retrieving revision 1.45
  diff -u -r1.44 -r1.45
  --- RepositoryXmlHandler.java	23 Jul 2003 20:07:32 -0000	1.44
  +++ RepositoryXmlHandler.java	24 Jul 2003 21:55:03 -0000	1.45
  @@ -521,6 +521,12 @@
                           b = (new Boolean(autoDelete)).booleanValue();
                           m_CurrentORD.setCascadeDelete(b);
   
  +                        //set otm-dependent attribute
  +                        String otmDependent = atts.getValue(tags.getTagById(OTM_DEPENDENT));
  +                        if (isDebug) logger.debug("     " + tags.getTagById(OTM_DEPENDENT) + ": " + otmDependent);
  +                        b = (new Boolean(otmDependent)).booleanValue();
  +                        m_CurrentORD.setOtmDependent(b);
  +
                           break;
                       }
   
  @@ -627,6 +633,12 @@
                           if (isDebug) logger.debug("     " + tags.getTagById(AUTO_DELETE) + ": " + autoDelete);
                           b = (new Boolean(autoDelete)).booleanValue();
                           m_CurrentCOD.setCascadeDelete(b);
  +
  +                        //set otm-dependent attribute
  +                        String otmDependent = atts.getValue(tags.getTagById(OTM_DEPENDENT));
  +                        if (isDebug) logger.debug("     " + tags.getTagById(OTM_DEPENDENT) + ": " + otmDependent);
  +                        b = (new Boolean(otmDependent)).booleanValue();
  +                        m_CurrentCOD.setOtmDependent(b);
   
                           m_CurrentCLD.addCollectionDescriptor(m_CurrentCOD);
   
  
  
  
  1.21      +389 -87   db-ojb/src/java/org/apache/ojb/otm/core/ConcreteEditingContext.java
  
  Index: ConcreteEditingContext.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/core/ConcreteEditingContext.java,v
  retrieving revision 1.20
  retrieving revision 1.21
  diff -u -r1.20 -r1.21
  --- ConcreteEditingContext.java	13 Jul 2003 14:07:16 -0000	1.20
  +++ ConcreteEditingContext.java	24 Jul 2003 21:55:03 -0000	1.21
  @@ -75,7 +75,6 @@
   import java.util.Set;
   
   import org.apache.ojb.broker.Identity;
  -import org.apache.ojb.broker.ManageableCollection;
   import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.PBKey;
   import org.apache.ojb.broker.PersistenceBroker;
  @@ -83,7 +82,6 @@
   import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
   import org.apache.ojb.broker.accesslayer.IndirectionHandler;
   import org.apache.ojb.broker.accesslayer.MaterializationListener;
  -import org.apache.ojb.broker.accesslayer.OJBIterator;
   import org.apache.ojb.broker.cache.ObjectCache;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.CollectionDescriptor;
  @@ -165,11 +163,11 @@
       public void insert(Identity oid, Object obj, int lock)
               throws LockingException
       {
  -        insertInternal(oid, obj, lock, true);
  +        insertInternal(oid, obj, lock, true, false);
       }
   
  -    private ContextEntry insertInternal(Identity oid, Object newObj, int lock, 
  -                                        boolean mainObject)
  +    private ContextEntry insertInternal(Identity oid, Object newObj, int lock,
  +                                        boolean mainObject, boolean isDependent)
               throws LockingException
       {
           ContextEntry entry;
  @@ -211,7 +209,7 @@
               {
                   Object origObj;
   
  -                if (!mainObject || kit.isInsertVerified())
  +                if ((!mainObject  && !isDependent) || kit.isInsertVerified())
                   {
                       origObj = _pb.getObjectByIdentity(oid);
                   }
  @@ -222,19 +220,28 @@
                   }
                   if (origObj == null)
                   {
  -                    entry.state = State.PERSISTENT_NEW;
  -                    if (kit.isEagerInsert(newObj)
  -                            || hasBidirectionalAssociation(newObj.getClass()))
  -                    {
  -                        _pb.store(newObj, entry.state);
  -                        entry.state = State.PERSISTENT_CLEAN;
  -                        origObj = newObj;
  +                    if (mainObject || isDependent)
  +                    {
  +                        entry.state = State.PERSISTENT_NEW;
  +                        if (kit.isEagerInsert(newObj)
  +                                || hasBidirectionalAssociation(newObj.getClass()))
  +                        {
  +                            _pb.store(newObj, entry.state);
  +                            entry.state = State.PERSISTENT_CLEAN;
  +                            origObj = newObj;
  +                        }
  +                    }
  +                    else
  +                    {
  +                        // don't create the object by reachability
  +                        // just invalidate it
  +                        entry.object = null;
                       }
                   }
   
                   if (origObj != null)
                   {
  -                    _original.put(oid, getFields(origObj));
  +                    _original.put(oid, getFields(origObj, false));
                   }
               }
               _objects.put(oid, entry);
  @@ -282,8 +289,7 @@
   
           // perform automatic read lock for all reachable objects
           // if the inserted object is materialized
  -        if ((handler == null) && (newObj != null)
  -                && kit.isImplicitLockingUsed())
  +        if ((handler == null) && (newObj != null))
           {
               lockReachableObjects(newObj);
           }
  @@ -308,7 +314,7 @@
           if (_order.contains(oid)) {
               _order.remove(oid);
           }
  -        entry = insertInternal(oid, object, LockType.WRITE_LOCK, true);
  +        entry = insertInternal(oid, object, LockType.WRITE_LOCK, true, false);
           entry.state = entry.state.deletePersistent();
       }
   
  @@ -342,7 +348,12 @@
               return;
           }
   
  -        _original.put(oid, getFields(object));
  +        // IndirectionHandler doesn't put the materialized objects
  +        // to the cache, I don't know for what reason.
  +        // I think it make sense for efficiency
  +        _pb.serviceObjectCache().cache(oid, object);
  +
  +        _original.put(oid, getFields(object, false));
   
           // replace the proxy object with the real one
           entry.object = object;
  @@ -351,16 +362,13 @@
   
           // perform automatic read lock for all reachable objects
           // if the inserted object is materialized
  -        if (_tx.getKit().isImplicitLockingUsed())
  +        try
           {
  -            try
  -            {
  -                lockReachableObjects(object);
  -            }
  -            catch (LockingException ex)
  -            {
  -                throw new LockingPassthruException(ex);
  -            }
  +            lockReachableObjects(object);
  +        }
  +        catch (LockingException ex)
  +        {
  +            throw new LockingPassthruException(ex);
           }
       }
   
  @@ -407,7 +415,7 @@
           {
               Identity oid = (Identity) iterator.next();
               ContextEntry entry = (ContextEntry) _objects.get(oid);
  -            _checkpointed.put(oid, getFields(entry.object));
  +            _checkpointed.put(oid, getFields(entry.object, false));
           }
       }
   
  @@ -427,12 +435,10 @@
           boolean saveBatchMode = connMan.isBatchMode();
           Swizzling swizzlingStrategy = _tx.getKit().getSwizzlingStrategy();
           LockManager lockManager = LockManager.getInstance();
  -        Identity[] order = (Identity[]) _order.toArray(new Identity[_order.size()]);
  -        Identity[] lockOrder = new Identity[order.length];
  +        Identity[] lockOrder = (Identity[]) _order.toArray(new Identity[_order.size()]);
           ObjectCache cache = _pb.serviceObjectCache();
           boolean isInsertVerified = _tx.getKit().isInsertVerified();
   
  -        System.arraycopy(order, 0, lockOrder, 0, order.length);
           // sort objects in the order of oid.hashCode to avoid deadlocks
           Arrays.sort(lockOrder, new Comparator()
           {
  @@ -449,49 +455,83 @@
   
           try {
               // mark dirty objects and lock them for write
  -            for (int i = 0; i < lockOrder.length; i++)
  -            {
  -                Identity oid = lockOrder[i];
  -                ContextEntry entry = (ContextEntry) _objects.get(oid);
  -                State state = entry.state;
  -                IndirectionHandler handler;
  -
  -                if (entry.object == null) // invalidated
  +            // also handle dependent objects and if there were inserted once,
  +            // repeat this process for their dependants ("cascade create")
  +            ArrayList newObjects = new ArrayList();
  +            int countNewObjects;
  +            do
  +            {
  +                newObjects.clear();
  +                countNewObjects = 0;
  +                for (int i = 0; i < lockOrder.length; i++)
                   {
  -                    continue;
  -                }
  +                    Identity oid = lockOrder[i];
  +                    ContextEntry entry = (ContextEntry) _objects.get(oid);
  +                    State state = entry.state;
  +                    IndirectionHandler handler;
   
  -                if (entry.handler == null) // materialized
  -                {
  -                    if (!state.needsUpdate() && !state.needsInsert()
  -                            && !state.needsDelete())
  +                    if (entry.object == null) // invalidated
                       {
  -                        Object[][] origFields = (Object[][]) _checkpointed.get(oid);
  -                        Object[][] newFields = getFields(entry.object);
  +                        continue;
  +                    }
   
  -                        if ((origFields == null)
  -                                || isModified(origFields[0], newFields[0]))
  +                    if (entry.handler == null) // materialized
  +                    {
  +                        if (!state.needsDelete())
                           {
  -                            entry.state = state.markDirty();
  -                            entry.needsCacheSwizzle = true;
  -                            lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb);
  -                        }
  +                            Object[][] origFields = (Object[][]) _checkpointed.get(oid);
  +                            Object[][] newFields = getFields(entry.object, true);
   
  -                        if ((origFields != null)
  -                                && isModified(origFields[1], newFields[1]))
  -                        {
  -                            // there are modified collections,
  -                            // so we need to lock the object and to swizzle it to cache
  -                            entry.needsCacheSwizzle = true;
  -                            lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb);
  +                            if (origFields == null)
  +                            {
  +                                newObjects.addAll(
  +                                        handleDependentReferences(entry.object,
  +                                        null, newFields[0], newFields[2]));
  +                                newObjects.addAll(
  +                                        handleDependentCollections(entry.object,
  +                                        null, newFields[1], newFields[3]));
  +                            }
  +                            else
  +                            {
  +                                if (isModified(origFields[0], newFields[0]))
  +                                {
  +                                    entry.state = state.markDirty();
  +                                    entry.needsCacheSwizzle = true;
  +                                    lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb);
  +                                    newObjects.addAll(
  +                                            handleDependentReferences(entry.object,
  +                                            origFields[0], newFields[0], newFields[2]));
  +                                }
  +
  +                                if (isModified(origFields[1], newFields[1]))
  +                                {
  +                                    // there are modified collections,
  +                                    // so we need to lock the object and to swizzle it to cache
  +                                    entry.needsCacheSwizzle = !state.needsInsert();
  +                                    lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, _pb);
  +                                    newObjects.addAll(
  +                                            handleDependentCollections(entry.object,
  +                                            origFields[1], newFields[1], newFields[3]));
  +                                }
  +                            }
                           }
                       }
  +                    else
  +                    {
  +                        entry.handler.removeListener(this);
  +                    }
                   }
  -                else
  +                countNewObjects = newObjects.size();
  +                if (countNewObjects > 0)
                   {
  -                    entry.handler.removeListener(this);
  +                    // new objects are not locked, so we don't need to ensure the order
  +                    lockOrder = (Identity[]) newObjects.toArray(
  +                            new Identity[countNewObjects]);
                   }
               }
  +            while (countNewObjects > 0);
  +
  +            Identity[] order = (Identity[]) _order.toArray(new Identity[_order.size()]);
   
               // Swizzle the context objects and the cache objects
               for (int i = 0; i < order.length; i++)
  @@ -516,6 +556,24 @@
                   }
               }
   
  +            // Cascade delete for dependent objects
  +            int countCascadeDeleted;
  +            do
  +            {
  +                countCascadeDeleted = 0;
  +                for (int i = 0; i < order.length; i++)
  +                {
  +                    Identity oid = order[i];
  +                    ContextEntry entry = (ContextEntry) _objects.get(oid);
  +
  +                    if (entry.state.needsDelete())
  +                    {
  +                        countCascadeDeleted += doCascadeDelete(entry.object);
  +                    }
  +                }
  +            }
  +            while (countCascadeDeleted > 0);
  +
               // perform database operations
               connMan.setBatchMode(true);
               try
  @@ -617,6 +675,7 @@
       private void lockReachableObjects(Object object)
           throws LockingException
       {
  +        boolean onlyDependants = !_tx.getKit().isImplicitLockingUsed();
           ClassDescriptor mif = _pb.getClassDescriptor(object.getClass());
   
           // N:1 relations
  @@ -628,13 +687,18 @@
           while (iter.hasNext())
           {
               rds = (ObjectReferenceDescriptor) iter.next();
  +            if (onlyDependants && !rds.getOtmDependent())
  +            {
  +                continue;
  +            }
               relObj = rds.getPersistentField().get(object);
               if (relObj != null)
               {
                   relOid = new Identity(relObj, _pb);
                   if (!_order.contains(relOid))
                   {
  -                    insertInternal(relOid, relObj, LockType.READ_LOCK, false);
  +                    insertInternal(relOid, relObj, LockType.READ_LOCK, false,
  +                                   rds.getOtmDependent());
                   }
               }
           }
  @@ -648,14 +712,14 @@
           while (collections.hasNext())
           {
               collectionDescriptor = (CollectionDescriptor) collections.next();
  +            if (onlyDependants && !collectionDescriptor.getOtmDependent())
  +            {
  +                continue;
  +            }
               col = collectionDescriptor.getPersistentField().get(object);
               if (col != null)
               {
  -                if (col instanceof ManageableCollection)
  -                {
  -                    colIterator = ((ManageableCollection) col).ojbIterator();
  -                }
  -                else if (col instanceof Collection)
  +                if (col instanceof Collection)
                   {
                       colIterator = ((Collection) col).iterator();
                   }
  @@ -667,7 +731,7 @@
                   {
                       throw new OJBRuntimeException(
                           col.getClass()
  -                            + " can not be managed by OJB, use Array, Collection or ManageableCollection instead !");
  +                            + " can not be managed by OJB OTM, use Array or Collection instead !");
                   }
   
                   while (colIterator.hasNext())
  @@ -676,19 +740,14 @@
                       relOid = new Identity(relObj, _pb);
                       if (!_order.contains(relOid))
                       {
  -                        insertInternal(relOid, relObj, LockType.READ_LOCK, false);
  +                        insertInternal(relOid, relObj, LockType.READ_LOCK, false,
  +                                       collectionDescriptor.getOtmDependent());
                       }
                   }
  -
  -                if (colIterator instanceof OJBIterator)
  -                {
  -                    ((OJBIterator) colIterator).releaseDbResources();
  -                }
               }
           }
       }
   
  -
       private void releaseLocks()
       {
           LockManager lockManager = LockManager.getInstance();
  @@ -741,22 +800,33 @@
   
           return false;
       }
  -    
  +
       /**
  -     * Two arrays of field values:
  -     * 1) The class, simple fields, references
  -     * 2) collections
  +     * @return four arrays of field values:
  +     * 1) The class, simple fields, identities of references
  +     * 2) collections of identities
  +     * 3) references (parallel to identities of references in 1)
  +     * 4) collections of objects (parallel to collections of identities in 2)
  +     * if "withObjects" parameter is "false", then returns nulls
  +     * in places of 3) and 4)
        */
  -    private Object[][] getFields(Object obj)
  +    private Object[][] getFields(Object obj, boolean withObjects)
       {
           ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
           FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
  -        Collection refDescsCol = mif.getObjectReferenceDescriptors();
           Collection refDescs = mif.getObjectReferenceDescriptors();
           Collection colDescs = mif.getCollectionDescriptors();
           int count = 0;
           Object[] fields = new Object[1 + fieldDescs.length + refDescs.size()];
           ArrayList[] collections = new ArrayList[colDescs.size()];
  +        Object[] references = null;
  +        ArrayList[] collectionsOfObjects = null;
  +
  +        if (withObjects)
  +        {
  +            references = new Object[refDescs.size()];
  +            collectionsOfObjects = new ArrayList[colDescs.size()];
  +        }
   
           fields[0] = obj.getClass(); // we must notice if the object class changes
           count++;
  @@ -769,7 +839,8 @@
               count++;
           }
   
  -        for (Iterator it = refDescs.iterator(); it.hasNext(); count++)
  +        int countRefs = 0;
  +        for (Iterator it = refDescs.iterator(); it.hasNext(); count++, countRefs++)
           {
               ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next();
               PersistentField f = rds.getPersistentField();
  @@ -777,6 +848,10 @@
               if (relObj != null)
               {
                   fields[count] = new Identity(relObj, _pb);
  +                if (withObjects)
  +                {
  +                    references[countRefs] = relObj;
  +                }
               }
           }
   
  @@ -790,9 +865,16 @@
               if (col != null)
               {
                   ArrayList list = new ArrayList();
  +                ArrayList listOfObjects = null;
                   Iterator colIterator;
   
                   collections[count] = list;
  +                if (withObjects)
  +                {
  +                    listOfObjects = new ArrayList();
  +                    collectionsOfObjects[count] = listOfObjects;
  +                }
  +
                   if (Collection.class.isAssignableFrom(type))
                   {
                       colIterator = ((Collection) col).iterator();
  @@ -808,12 +890,17 @@
   
                   while (colIterator.hasNext())
                   {
  -                    list.add(new Identity(colIterator.next(), _pb));
  +                    Object relObj = colIterator.next();
  +                    list.add(new Identity(relObj, _pb));
  +                    if (withObjects)
  +                    {
  +                        listOfObjects.add(relObj);
  +                    }
                   }
               }
           }
   
  -        return new Object[][] {fields, collections};
  +        return new Object[][] {fields, collections, references, collectionsOfObjects};
       }
   
       private void setFields(Object obj, Object[][] fieldsAndCollections)
  @@ -990,10 +1077,225 @@
           return hasBidirAssc;
       }
   
  +    /**
  +     * @return number of deleted objects: 1 or 0 (if the object is already deleted)
  +     */
  +    private int markDelete(Object oid)
  +    {
  +        ContextEntry entry = (ContextEntry) _objects.get(oid);
  +
  +        if (entry == null)
  +        {
  +            throw new IllegalStateException("markDelete failed: the dependent object "
  +                    + oid + " is not in the editing context");
  +        }
  +
  +        if (entry.state.needsDelete())
  +        {
  +            return 0;
  +        }
  +        else
  +        {
  +            entry.state = entry.state.deletePersistent();
  +            return 1;
  +        }
  +    }
  +
  +    /**
  +     * Insert the object is not in the context and mark as new.
  +     */
  +    private void markNew(Object oid, Object object)
  +    {
  +        ContextEntry entry = new ContextEntry(object);
  +
  +        if (entry.handler != null)
  +        {
  +            throw new IllegalStateException("markNew failed: the dependent object "
  +                + oid + " is proxy");
  +        }
  +
  +        entry.state = State.PERSISTENT_NEW;
  +        _objects.put(oid, entry);
  +        _order.add(oid);
  +    }
  +
  +    /**
  +     * Mark for creation all newly introduced dependent references.
  +     * Mark for deletion all nullified dependent references.
  +     * @return the list of created objects
  +     */
  +    private ArrayList handleDependentReferences(Object obj,
  +            Object[] origFields, Object[] newFields, Object[] newRefs)
  +    {
  +        ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
  +        FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
  +        Collection refDescs = mif.getObjectReferenceDescriptors();
  +        int count = 1 + fieldDescs.length;
  +        ArrayList newObjects = new ArrayList();
  +        int countRefs = 0;
  +
  +        for (Iterator it = refDescs.iterator(); it.hasNext(); count++, countRefs++)
  +        {
  +            ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next();
  +            Object origOid = (origFields == null ? null : origFields[count]);
  +            Object newOid = newFields[count];
  +
  +            if (rds.getOtmDependent())
  +            {
  +                if ((origOid == null) && (newOid != null))
  +                {
  +                    ContextEntry entry = (ContextEntry) _objects.get(newOid);
  +
  +                    if (entry == null)
  +                    {
  +                        Object relObj = newRefs[countRefs];
  +                        markNew(newOid, relObj);
  +                        newObjects.add(newOid);
  +                    }
  +                }
  +                else if ((origOid != null) && (newOid == null))
  +                {
  +                    markDelete(origOid);
  +                }
  +            }
  +        }
  +
  +        return newObjects;
  +    }
  +
  +    /**
  +     * Mark for creation all objects that were included into dependent collections.
  +     * Mark for deletion all objects that were excluded from dependent collections.
  +     */
  +    private ArrayList handleDependentCollections(Object obj,
  +            Object[] origCollections, Object[] newCollections,
  +            Object[] newCollectionsOfObjects)
  +    {
  +        ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
  +        Collection colDescs = mif.getCollectionDescriptors();
  +        ArrayList newObjects = new ArrayList();
  +        int count = 0;
  +
  +        for (Iterator it = colDescs.iterator(); it.hasNext(); count++)
  +        {
  +            CollectionDescriptor cds = (CollectionDescriptor) it.next();
  +
  +            if (cds.getOtmDependent())
  +            {
  +                ArrayList origList = (origCollections == null ? null
  +                                        : (ArrayList) origCollections[count]);
  +                ArrayList newList = (ArrayList) newCollections[count];
  +
  +                if (origList != null)
  +                {
  +                    for (Iterator it2 = origList.iterator(); it2.hasNext(); )
  +                    {
  +                        Object origOid = it2.next();
  +
  +                        if (!newList.contains(origOid))
  +                        {
  +                            markDelete(origOid);
  +                        }
  +                    }
  +                }
  +
  +                int countElem = 0;
  +                for (Iterator it2 = newList.iterator(); it2.hasNext(); countElem++)
  +                {
  +                    Object newOid = it2.next();
  +
  +                    if ((origList == null) || !origList.contains(newOid))
  +                    {
  +                        ContextEntry entry = (ContextEntry) _objects.get(newOid);
  +
  +                        if (entry == null)
  +                        {
  +                            ArrayList relCol = (ArrayList)
  +                                    newCollectionsOfObjects[count];
  +                            Object relObj = relCol.get(countElem);
  +                            markNew(newOid, relObj);
  +                            newObjects.add(newOid);
  +                        }
  +                    }
  +                }
  +            }
  +        }
  +
  +        return newObjects;
  +    }
  +
  +    /**
  +     * Mark for deletion all dependent objects (via references and collections).
  +     * @return the number of deleted objects
  +     */
  +    private int doCascadeDelete(Object obj)
  +    {
  +        ClassDescriptor mif = _pb.getClassDescriptor(obj.getClass());
  +        Collection refDescs = mif.getObjectReferenceDescriptors();
  +        Collection colDescs = mif.getCollectionDescriptors();
  +        int countCascadeDeleted = 0;
  +
  +        for (Iterator it = refDescs.iterator(); it.hasNext(); )
  +        {
  +            ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) it.next();
  +
  +            if (rds.getOtmDependent())
  +            {
  +                PersistentField f = rds.getPersistentField();
  +                Object relObj = f.get(obj);
  +
  +                if (relObj != null)
  +                {
  +                    countCascadeDeleted +=
  +                            markDelete(new Identity(relObj, _pb));
  +                }
  +            }
  +        }
  +
  +        for (Iterator it = colDescs.iterator(); it.hasNext(); )
  +        {
  +            CollectionDescriptor cds = (CollectionDescriptor) it.next();
  +
  +            if (cds.getOtmDependent())
  +            {
  +                PersistentField f = cds.getPersistentField();
  +                Class type = f.getType();
  +                Object col = f.get(obj);
  +
  +                if (col != null)
  +                {
  +                    Iterator colIterator;
  +
  +                    if (Collection.class.isAssignableFrom(type))
  +                    {
  +                        colIterator = ((Collection) col).iterator();
  +                    }
  +                    else if (type.isArray())
  +                    {
  +                        colIterator = new ArrayIterator(col);
  +                    }
  +                    else
  +                    {
  +                        continue;
  +                    }
  +
  +                    while (colIterator.hasNext())
  +                    {
  +
  +                        countCascadeDeleted +=
  +                                markDelete(new Identity(colIterator.next(), _pb));
  +                    }
  +                }
  +            }
  +        }
  +
  +        return countCascadeDeleted;
  +    }
  +
       /*
        * The rest of ObjectCache implementation for swizling
        * All methods except lookup() are never used by swizzling,
  -     * remove() appeared to already exist in this class 
  +     * remove() appeared to already exist in this class
        * with the same signature as in ObjectCache interface,
        * other methods are unsupported.
        */
  @@ -1021,7 +1323,7 @@
            * Handler the proxy object, null if the object is real
            */
           IndirectionHandler handler;
  -        
  +
           /**
            * This flag is used during commit/checkpoint
            */
  
  
  
  1.43      +40 -0     db-ojb/src/schema/ojbtest-schema.xml
  
  Index: ojbtest-schema.xml
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/schema/ojbtest-schema.xml,v
  retrieving revision 1.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- ojbtest-schema.xml	8 Jul 2003 00:34:54 -0000	1.42
  +++ ojbtest-schema.xml	24 Jul 2003 21:55:03 -0000	1.43
  @@ -742,4 +742,44 @@
        <column name="NESTED_DESCRIPTION" type="VARCHAR" size="150"/>
      </table>
   
  +    <!-- ************************************************* -->
  +    <!--      Classes for OTM dependent objects test       -->
  +    <!-- ************************************************* -->
  +
  +  <table name="OTM_PERSON"
  +         javaName="OtmPerson">
  +    <column name="ID" required="true" primaryKey="true" type="INTEGER"
  +            javaName="id"/>
  +    <column name="FIRSTNAME" type="VARCHAR" size="60"
  +            javaName="firstname"/>
  +    <column name="LASTNAME" type="VARCHAR" size="60"
  +            javaName="lastname"/>
  +    <column name="MAIN_ADDRESS_ID" type="INTEGER" required="false"
  +            javaName="mainAddressId"/>
  +  </table>
  +
  +  <table name="OTM_ADDRESS"
  +         javaName="OtmAddress">
  +    <column name="ID" required="true" primaryKey="true" type="INTEGER"
  +            javaName="id"/>
  +    <column name="COUNTRY" type="VARCHAR" size="60"
  +            javaName="country"/>
  +    <column name="CITY" type="VARCHAR" size="60"
  +            javaName="city"/>
  +    <column name="STREET" type="VARCHAR" size="60"
  +            javaName="street"/>
  +  </table>
  +
  +  <table name="OTM_ADDRESS_DESC"
  +         javaName="OtmAddressDesc">
  +    <column name="ID" required="true" primaryKey="true" type="INTEGER"
  +            javaName="id"/>
  +    <column name="DESC" type="VARCHAR" size="60"
  +            javaName="desc"/>
  +    <column name="PERSON_ID" type="INTEGER" required="true"
  +            javaName="personId" />
  +    <column name="ADDRESS_ID" type="INTEGER" required="true"
  +            javaName="addressId"/>
  +  </table>
  +
   </database>
  
  
  
  1.43      +17 -0     db-ojb/src/test/org/apache/ojb/repository.dtd
  
  Index: repository.dtd
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/repository.dtd,v
  retrieving revision 1.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- repository.dtd	22 Jul 2003 21:08:09 -0000	1.42
  +++ repository.dtd	24 Jul 2003 21:55:04 -0000	1.43
  @@ -522,6 +522,12 @@
   	this reference attribute on deleting the persistent object.
   	This attribute must be set to false if using the OTM, ODMG or JDO layer.
   
  +	The otm-dependent attribute specifies whether the OTM layer automatically
  +    creates the referred object or deletes it if the reference field is set to null.
  +    Also otm-dependent references behave as if auto-update and auto-delete
  +    were set to true, but the auto-update and auto-delete attributes themself
  +    must be always set to false for use with OTM layer.
  +
     -->
   <!ATTLIST reference-descriptor
   	name CDATA #REQUIRED
  @@ -533,6 +539,7 @@
   	auto-retrieve (true | false) "true"
   	auto-update (true | false) "false"
   	auto-delete (true | false) "false"
  +	otm-dependent (true | false) "false"
   >
   
   <!--
  @@ -619,6 +626,15 @@
   	The auto-delete attribute specifies whether OJB automatically deletes
   	this reference attribute on deleting the persistent object.
   	This attribute must be set to false if using the OTM, ODMG or JDO layer.
  +
  +	The otm-dependent attribute specifies whether the OTM layer automatically
  +    creates collection elements that were included into the collectionelements
  +    and deletes collection elements that were excluded from the collection.
  +    Also otm-dependent references behave as if auto-update and auto-delete
  +    were set to true, but the auto-update and auto-delete attributes themself
  +    must be always set to false for use with OTM layer.
  +
  +	
     -->
   <!ATTLIST collection-descriptor
   	name CDATA #IMPLIED
  @@ -635,6 +651,7 @@
   	auto-retrieve (true | false) "true"
   	auto-update (true | false) "false"
   	auto-delete (true | false) "false"
  +	otm-dependent (true | false) "false"
   >
   
   <!--
  
  
  
  1.81      +116 -1    db-ojb/src/test/org/apache/ojb/repository_junit.xml
  
  Index: repository_junit.xml
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/repository_junit.xml,v
  retrieving revision 1.80
  retrieving revision 1.81
  diff -u -r1.80 -r1.81
  --- repository_junit.xml	11 Jul 2003 07:43:53 -0000	1.80
  +++ repository_junit.xml	24 Jul 2003 21:55:04 -0000	1.81
  @@ -4418,6 +4418,121 @@
           />
       </class-descriptor>
   
  +    <!-- ************************************************* -->
  +    <!--      Classes for OTM dependent objects test       -->
  +    <!-- ************************************************* -->
   
  +   <class-descriptor
  +      class="org.apache.ojb.otm.Person"
  +      table="OTM_PERSON"
  +   >
  +      <field-descriptor
  +         name="id"
  +         column="ID"
  +         jdbc-type="INTEGER"
  +         primarykey="true"
  +         autoincrement="true"
  +      />
  +      <field-descriptor
  +         name="firstname"
  +         column="FIRSTNAME"
  +         jdbc-type="VARCHAR"
  +      />
  +      <field-descriptor
  +         name="lastname"
  +         column="LASTNAME"
  +         jdbc-type="VARCHAR"
  +      />
  +      <field-descriptor
  +         name="mainAddressId"
  +         column="MAIN_ADDRESS_ID"
  +         jdbc-type="INTEGER"
  +      />
  +      <reference-descriptor
  +         name="mainAddress"
  +         class-ref="org.apache.ojb.otm.Address"
  +         otm-dependent="true"
  +      >
  +         <foreignkey field-ref="mainAddressId"/>
  +      </reference-descriptor>
  +      <collection-descriptor
  +         name="otherAddresses"
  +         element-class-ref="org.apache.ojb.otm.AddressDesc"
  +         collection-class="org.apache.ojb.broker.util.collections.ManageableArrayList"
  +         otm-dependent="true"
  +      >
  +         <inverse-foreignkey field-ref="personId"/>
  +      </collection-descriptor>
  +   </class-descriptor>
   
  -<!-- Mapping of classes used in junit tests and tutorials ends here -->
  \ No newline at end of file
  +   <class-descriptor
  +      class="org.apache.ojb.otm.Address"
  +      table="OTM_ADDRESS"
  +   >
  +      <field-descriptor
  +         name="id"
  +         column="ID"
  +         jdbc-type="INTEGER"
  +         primarykey="true"
  +         autoincrement="true"
  +      />
  +      <field-descriptor
  +         name="country"
  +         column="COUNTRY"
  +         jdbc-type="VARCHAR"
  +      />
  +      <field-descriptor
  +         name="city"
  +         column="CITY"
  +         jdbc-type="VARCHAR"
  +      />
  +      <field-descriptor
  +         name="street"
  +         column="STREET"
  +         jdbc-type="VARCHAR"
  +      />
  +   </class-descriptor>
  +
  +   <class-descriptor
  +      class="org.apache.ojb.otm.AddressDesc"
  +      table="OTM_ADDRESS_DESC"
  +   >
  +      <field-descriptor
  +         name="id"
  +         column="ID"
  +         jdbc-type="INTEGER"
  +         primarykey="true"
  +         autoincrement="true"
  +      />
  +      <field-descriptor
  +         name="desc"
  +         column="DESC"
  +         jdbc-type="VARCHAR"
  +      />
  +      <field-descriptor
  +         name="personId"
  +         column="PERSON_ID"
  +         jdbc-type="INTEGER"
  +      />
  +      <field-descriptor
  +         name="addressId"
  +         column="ADDRESS_ID"
  +         jdbc-type="INTEGER"
  +      />
  +      <reference-descriptor
  +         name="person"
  +         class-ref="org.apache.ojb.otm.Person"
  +      >
  +         <foreignkey field-ref="personId"/>
  +      </reference-descriptor>
  +      <reference-descriptor
  +         name="address"
  +         class-ref="org.apache.ojb.otm.Address"
  +         otm-dependent="true"
  +      >
  +         <foreignkey field-ref="addressId"/>
  +      </reference-descriptor>
  +   </class-descriptor>
  +
  +
  +<!-- Mapping of classes used in junit tests and tutorials ends here -->
  
  
  
  1.9       +1 -0      db-ojb/src/test/org/apache/ojb/otm/AllTests.java
  
  Index: AllTests.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/test/org/apache/ojb/otm/AllTests.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- AllTests.java	7 Jul 2003 22:54:37 -0000	1.8
  +++ AllTests.java	24 Jul 2003 21:55:04 -0000	1.9
  @@ -36,6 +36,7 @@
           suite.addTest(new TestSuite(LockTestSerializable.class));
           suite.addTest(new TestSuite(SwizzleTests.class));
           suite.addTest(new TestSuite(CopyTest.class));
  +        suite.addTest(new TestSuite(DependentTests.class));
           return suite;
       }
   
  
  
  
  1.1                  db-ojb/src/test/org/apache/ojb/otm/Address.java
  
  Index: Address.java
  ===================================================================
  /*
   * ObJectRelationalBridge - Bridging Java Objects and Relational Databases
   * http://objectbridge.sourceforge.net
   * Copyright (C) 2000, 2001 Thomas Mahler, et al.
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
  
  
  package org.apache.ojb.otm;
  
  import java.io.Serializable;
  
  public class Address implements Serializable
  {
  
      private int id;
      private String country;
      private String city;
      private String street;
  
      public Address()
      {
      }
  
      public Address(String country, String city, String street)
      {
          this.country = country;
          this.city = city;
          this.street = street;
      }
  
      public int getId()
      {
          return id;
      }
  
      public void setId(int id)
      {
          this.id = id;
      }
  
      public String getCountry()
      {
          return country;
      }
  
      public void setCountry(String country)
      {
          this.country = country;
      }
  
      public String getCity()
      {
          return city;
      }
  
      public void setCity(String city)
      {
          this.city = city;
      }
  
      public String getStreet()
      {
          return street;
      }
  
      public void setStreet(String street)
      {
          this.street = street;
      }
  }
  
  
  
  1.1                  db-ojb/src/test/org/apache/ojb/otm/AddressDesc.java
  
  Index: AddressDesc.java
  ===================================================================
  /*
   * ObJectRelationalBridge - Bridging Java Objects and Relational Databases
   * http://objectbridge.sourceforge.net
   * Copyright (C) 2000, 2001 Thomas Mahler, et al.
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
  
  
  package org.apache.ojb.otm;
  
  import java.io.Serializable;
  
  public class AddressDesc implements Serializable
  {
  
      private int id;
      private String desc;
      private int personId;
      private Person person;
      private int addressId;
      private Address address;
  
      public AddressDesc()
      {
      }
  
      public AddressDesc(String desc, Address address)
      {
          this.desc = desc;
          this.address = address;
      }
  
      public int getId()
      {
          return id;
      }
  
      public void setId(int id)
      {
          this.id = id;
      }
  
      public String getDesc()
      {
          return desc;
      }
  
      public void setDesc(String desc)
      {
          this.desc = desc;
      }
  
      public int getPersonId()
      {
          return personId;
      }
  
      public void setPersonId(int personId)
      {
          this.personId = personId;
      }
  
      public Person getPerson()
      {
          return person;
      }
  
      public void setPerson(Person person)
      {
          this.person = person;
      }
  
      public int getAddressId()
      {
          return addressId;
      }
  
      public void setAddressId(int addressId)
      {
          this.addressId = addressId;
      }
  
      public Address getAddress()
      {
          return address;
      }
  
      public void setAddress(Address address)
      {
          this.address = address;
      }
  
  }
  
  
  
  1.1                  db-ojb/src/test/org/apache/ojb/otm/DependentTests.java
  
  Index: DependentTests.java
  ===================================================================
  package org.apache.ojb.otm;
  
  import java.util.Iterator;
  import junit.framework.TestCase;
  import org.apache.ojb.broker.Identity;
  import org.apache.ojb.broker.PersistenceBrokerFactory;
  import org.apache.ojb.broker.query.Criteria;
  import org.apache.ojb.broker.query.Query;
  import org.apache.ojb.broker.query.QueryFactory;
  import org.apache.ojb.otm.core.Transaction;
  import org.apache.ojb.otm.core.TransactionException;
  import org.apache.ojb.otm.lock.LockingException;
  
  public class DependentTests extends TestCase
  {
      private static Class CLASS = DependentTests.class;
      private TestKit _kit;
      private OTMConnection _conn;
  
      public void setUp() throws LockingException
      {
          _kit = TestKit.getTestInstance();
          _conn = _kit.acquireConnection(PersistenceBrokerFactory.getDefaultKey());
      }
  
      public void tearDown() throws LockingException
      {
          _conn.close();
          _conn = null;
      }
  
      public static void main(String[] args)
      {
          String[] arr = {CLASS.getName()};
          junit.textui.TestRunner.main(arr);
      }
  
      public void testDependent() throws Exception
      {
          Person person = new Person("Ostap", "Bender");
          Address address1 = new Address("Ukraine", "Odessa", "Deribasovskaya");
          Address address2 = new Address("Ukraine", "Odessa", "Malaya Arnautskaya");
          Address address3 = new Address("Brasil", "Rio de Janeiro", "Rua Professor Azevedo Marques");
          Criteria emptyCriteria = new Criteria();
          Query q;
          Iterator it;
  
          person.setMainAddress(address1);
          person.addOtherAddress("work", address2);
          person.addOtherAddress("dream", address3);
  
          Transaction tx = _kit.getTransaction(_conn);
          tx.begin();
          // Cascade create
          _conn.makePersistent(person);
          tx.commit();
  
          Identity oid = _conn.getIdentity(person);
  
          _conn.invalidateAll();
          tx = _kit.getTransaction(_conn);
          tx.begin();
          person = (Person) _conn.getObjectByIdentity(oid);
          assertTrue("person exists", (person != null));
          assertTrue("main Address exists", (person.getMainAddress() != null));
          assertEquals("main Address is correct", address1.getStreet(), person.getMainAddress().getStreet());
          assertEquals("two other Addresses", 2, person.getOtherAddresses().size());
          AddressDesc desc1 = (AddressDesc) person.getOtherAddresses().get(0);
          assertEquals("1st other Address has correct description", "work", desc1.getDesc());
          assertEquals("1st other Address is correct", address2.getStreet(), desc1.getAddress().getStreet());
          AddressDesc desc2 = (AddressDesc) person.getOtherAddresses().get(1);
          assertEquals("2nd other Address has correct description", "dream", desc2.getDesc());
          assertEquals("2nd other Address is correct", address3.getStreet(), desc2.getAddress().getStreet());
  
          // Delete dependent
          person.setMainAddress(null);
          person.getOtherAddresses().remove(1);
          tx.commit();
  
          _conn.invalidateAll();
          tx = _kit.getTransaction(_conn);
          tx.begin();
          person = (Person) _conn.getObjectByIdentity(oid);
          assertTrue("main Address doesn't exist", (person.getMainAddress() == null));
          assertEquals("one other Address", 1, person.getOtherAddresses().size());
          desc2 = (AddressDesc) person.getOtherAddresses().get(0);
          assertEquals("the other Address has correct description", "work", desc1.getDesc());
          assertEquals("the other Address is correct", address2.getStreet(), desc1.getAddress().getStreet());
  
          // Create dependent
          person.setMainAddress(address1);
          person.addOtherAddress("dream", address3);
          tx.commit();
  
          _conn.invalidateAll();
          tx = _kit.getTransaction(_conn);
          tx.begin();
          person = (Person) _conn.getObjectByIdentity(oid);
          assertTrue("main Address exists", (person.getMainAddress() != null));
          assertEquals("main Address is correct", address1.getStreet(), person.getMainAddress().getStreet());
          assertEquals("two other Addresses", 2, person.getOtherAddresses().size());
          desc1 = (AddressDesc) person.getOtherAddresses().get(0);
          assertEquals("1st other Address has correct description", "work", desc1.getDesc());
          assertEquals("1st other Address is correct", address2.getStreet(), desc1.getAddress().getStreet());
          desc2 = (AddressDesc) person.getOtherAddresses().get(1);
          assertEquals("2nd other Address has correct description", "dream", desc2.getDesc());
          assertEquals("2nd other Address is correct", address3.getStreet(), desc2.getAddress().getStreet());
  
          // Cascade delete
          _conn.deletePersistent(person);
          tx.commit();
  
          _conn.invalidateAll();
          tx = _kit.getTransaction(_conn);
          tx.begin();
          person = (Person) _conn.getObjectByIdentity(oid);
          assertTrue("person doesn't exist", (person == null));
          q = QueryFactory.newQuery(AddressDesc.class, emptyCriteria);
          it = _conn.getIteratorByQuery(q);
          assertTrue("address descriptions don't exist", !it.hasNext());
          q = QueryFactory.newQuery(Address.class, emptyCriteria);
          it = _conn.getIteratorByQuery(q);
          assertTrue("addresses don't exist", !it.hasNext());
          tx.commit();
      }
  }
  
  
  
  1.1                  db-ojb/src/test/org/apache/ojb/otm/Person.java
  
  Index: Person.java
  ===================================================================
  /*
   * ObJectRelationalBridge - Bridging Java Objects and Relational Databases
   * http://objectbridge.sourceforge.net
   * Copyright (C) 2000, 2001 Thomas Mahler, et al.
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
  
  
  package org.apache.ojb.otm;
  
  import java.util.ArrayList;
  import java.io.Serializable;
  
  public class Person implements Serializable
  {
  
      private int id;
      private String firstname;
      private String lastname;
      private Integer mainAddressId;
      private Address mainAddress;
      private ArrayList otherAddresses;
  
      public Person()
      {
      }
  
      public Person(String firstname, String lastname)
      {
          this.firstname = firstname;
          this.lastname = lastname;
      }
  
      public int getId()
      {
          return id;
      }
  
      public void setId(int id)
      {
          this.id = id;
      }
  
      public String getFirstname()
      {
          return firstname;
      }
  
      public void setFirstname(String firstname)
      {
          this.firstname = firstname;
      }
  
      public String getLastname()
      {
          return lastname;
      }
  
      public void setLastname(String lastname)
      {
          this.lastname = lastname;
      }
  
      public Integer getMainAddressId()
      {
          return mainAddressId;
      }
  
      public void setMainAddressId(Integer mainAddressId)
      {
          this.mainAddressId = mainAddressId;
      }
  
      public Address getMainAddress()
      {
          return mainAddress;
      }
  
      public void setMainAddress(Address mainAddress)
      {
          this.mainAddress = mainAddress;
      }
  
      public ArrayList getOtherAddresses()
      {
          return otherAddresses;
      }
  
      public void setOtherAddresses(ArrayList otherAddresses)
      {
          this.otherAddresses = otherAddresses;
      }
  
      public void addOtherAddress(String desc, Address address)
      {
          if (otherAddresses == null)
          {
              otherAddresses = new ArrayList();
          }
          AddressDesc addrDesc = new AddressDesc(desc, address);
          this.otherAddresses.add(addrDesc);
          addrDesc.setPerson(this);
      }
  
  }
  
  
  

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


Mime
View raw message