db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From arm...@apache.org
Subject cvs commit: db-ojb release-notes.txt
Date Fri, 18 Mar 2005 19:25:06 GMT
arminw      2005/03/18 11:25:06

  Modified:    src/java/org/apache/ojb/broker/core Tag: OJB_1_0_RELEASE
                        MtoNBroker.java PersistenceBrokerImpl.java
               src/java/org/apache/ojb/broker/util Tag: OJB_1_0_RELEASE
                        BrokerHelper.java
               src/java/org/apache/ojb/broker Tag: OJB_1_0_RELEASE
                        MtoNImplementor.java
               src/java/org/apache/ojb/odmg/collections Tag:
                        OJB_1_0_RELEASE DListImpl.java DListImpl_2.java
                        DSetImpl.java
               src/java/org/apache/ojb/odmg/oql Tag: OJB_1_0_RELEASE
                        OQLQueryImpl.java
               src/java/org/apache/ojb/odmg/states Tag: OJB_1_0_RELEASE
                        StateOldDelete.java
               src/java/org/apache/ojb/odmg Tag: OJB_1_0_RELEASE
                        ImplementationImpl.java J2EETransactionImpl.java
                        NarrowTransaction.java ObjectEnvelope.java
                        ObjectEnvelopeTable.java TransactionExt.java
                        TransactionImpl.java
               .        Tag: OJB_1_0_RELEASE release-notes.txt
  Log:
  refactoring of the odmg-api
  - expects now auto-update/delete 'none'
  - cascading delete is configurable in OJB.properties and at runtime
  - all known issues are fixed, one new issue arise
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.10.2.5  +3 -3      db-ojb/src/java/org/apache/ojb/broker/core/MtoNBroker.java
  
  Index: MtoNBroker.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/MtoNBroker.java,v
  retrieving revision 1.10.2.4
  retrieving revision 1.10.2.5
  diff -u -r1.10.2.4 -r1.10.2.5
  --- MtoNBroker.java	27 Jan 2005 00:11:18 -0000	1.10.2.4
  +++ MtoNBroker.java	18 Mar 2005 19:25:05 -0000	1.10.2.5
  @@ -256,9 +256,9 @@
           DescriptorRepository dr = pb.getDescriptorRepository();
   
           Object leftObject = m2nImpl.getLeftObject();
  -        Class leftClass = leftObject.getClass();
  +        Class leftClass = m2nImpl.getLeftClass();
           Object rightObject = m2nImpl.getRightObject();
  -        Class rightClass = rightObject.getClass();
  +        Class rightClass = m2nImpl.getRightClass();
   
           //are written per class, maybe referencing abstract classes or interfaces
           //so let's look for collection descriptors on the left class and try to
  
  
  
  1.83.2.14 +2 -2      db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java
  
  Index: PersistenceBrokerImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java,v
  retrieving revision 1.83.2.13
  retrieving revision 1.83.2.14
  diff -u -r1.83.2.13 -r1.83.2.14
  --- PersistenceBrokerImpl.java	4 Mar 2005 18:07:23 -0000	1.83.2.13
  +++ PersistenceBrokerImpl.java	18 Mar 2005 19:25:05 -0000	1.83.2.14
  @@ -1071,7 +1071,7 @@
        * @param referencedObject referenced object or proxy
        * @param insert Show if "linking" is done while insert or update.
        */
  -    protected void link(Object targetObject, ClassDescriptor cld, ObjectReferenceDescriptor rds, Object referencedObject, boolean insert)
  +    public void link(Object targetObject, ClassDescriptor cld, ObjectReferenceDescriptor rds, Object referencedObject, boolean insert)
       {
           // MBAIRD: we have 'disassociated' this object from the referenced object,
           // the object represented by the reference descriptor is now null, so set
  
  
  
  No                   revision
  No                   revision
  1.57.2.9  +45 -2     db-ojb/src/java/org/apache/ojb/broker/util/BrokerHelper.java
  
  Index: BrokerHelper.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/util/BrokerHelper.java,v
  retrieving revision 1.57.2.8
  retrieving revision 1.57.2.9
  diff -u -r1.57.2.8 -r1.57.2.9
  --- BrokerHelper.java	13 Mar 2005 03:53:30 -0000	1.57.2.8
  +++ BrokerHelper.java	18 Mar 2005 19:25:05 -0000	1.57.2.9
  @@ -34,6 +34,7 @@
   import org.apache.ojb.broker.PBKey;
   import org.apache.ojb.broker.PersistenceBrokerException;
   import org.apache.ojb.broker.PersistenceBrokerSQLException;
  +import org.apache.ojb.broker.MtoNImplementor;
   import org.apache.ojb.broker.accesslayer.StatementManagerIF;
   import org.apache.ojb.broker.accesslayer.sql.SqlExistStatement;
   import org.apache.ojb.broker.core.PersistenceBrokerImpl;
  @@ -869,7 +870,49 @@
               ord.getPersistentField().set(obj, null);
           }        
       }
  -    
  +
  +    public void unlink(Object obj, CollectionDescriptor cds, List referencesToUnlink)
  +    {
  +        for(int i = 0; i < referencesToUnlink.size(); i++)
  +        {
  +            unlink(obj, cds, referencesToUnlink.get(i));
  +        }
  +    }
  +
  +    public void unlink(Object obj, CollectionDescriptor cds, Object referenceToUnlink)
  +    {
  +        if(cds.isMtoNRelation())
  +        {
  +            m_broker.deleteMtoNImplementor(new MtoNImplementor(obj, referenceToUnlink));
  +        }
  +        else
  +        {
  +            ClassDescriptor cld = m_broker.getClassDescriptor(referenceToUnlink.getClass());
  +            m_broker.unlinkFK(referenceToUnlink, cld, cds);
  +        }
  +    }
  +
  +    public void link(Object obj, CollectionDescriptor cds, List referencesToLink)
  +    {
  +        for(int i = 0; i < referencesToLink.size(); i++)
  +        {
  +            link(obj, cds, referencesToLink.get(i));
  +        }
  +    }
  +
  +    public void link(Object obj, CollectionDescriptor cds, Object referenceToLink)
  +    {
  +        if(cds.isMtoNRelation())
  +        {
  +            m_broker.addMtoNImplementor(new MtoNImplementor(obj, referenceToLink));
  +        }
  +        else
  +        {
  +            ClassDescriptor cld = m_broker.getClassDescriptor(referenceToLink.getClass());
  +            m_broker.link(referenceToLink, cld, cds, obj, false);
  +        }
  +    }
  +
   
       /**
        * Returns an Iterator instance for {@link java.util.Collection}, object Array or
  
  
  
  No                   revision
  No                   revision
  1.7.2.2   +144 -135  db-ojb/src/java/org/apache/ojb/broker/MtoNImplementor.java
  
  Index: MtoNImplementor.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/broker/MtoNImplementor.java,v
  retrieving revision 1.7.2.1
  retrieving revision 1.7.2.2
  diff -u -r1.7.2.1 -r1.7.2.2
  --- MtoNImplementor.java	15 Nov 2004 18:04:55 -0000	1.7.2.1
  +++ MtoNImplementor.java	18 Mar 2005 19:25:05 -0000	1.7.2.2
  @@ -16,171 +16,180 @@
    */
   
   
  -import java.util.Collection;
  -
  -import org.apache.commons.lang.builder.EqualsBuilder;
  -import org.apache.commons.lang.builder.HashCodeBuilder;
   import org.apache.ojb.broker.core.proxy.ProxyHelper;
  -import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.CollectionDescriptor;
  -import org.apache.ojb.broker.util.BrokerHelper;
   
   /**
  + * Helper class to handle single m:n relation entries (m:n indirection table entries).
    *
    * @author <a href="leandro@ibnetwork.com.br">Leandro Rodrigo Saad Cruz</a>
    * @version $Id$
    */
   public class MtoNImplementor
   {
  -    private Object _left;
  -    private Object _right;
  -	private CollectionDescriptor _collectionDesc;
  -	private PersistenceBroker _pb;
  +    private Object leftObject;
  +    private Object rightObject;
  +    private Class leftClass;
  +    private Class rightClass;
  +    //private CollectionDescriptor collectionDesc;
  +    //private PersistenceBroker broker;
  +
  +    /**
  +     * @deprecated
  +     */
  +    public MtoNImplementor(PersistenceBroker pb, CollectionDescriptor cod, Object left, Object right)
  +    {
  +        init(left, right);
  +    }
   
       /**
  -     *
  +     * @deprecated
        */
  -    public MtoNImplementor(PersistenceBroker pb , CollectionDescriptor cod, Object left, Object right)
  +    public MtoNImplementor(PersistenceBroker pb, String collectionName, Object left, Object right)
  +    {
  +        //CollectionDescriptor cod = pb.getClassDescriptor(ProxyHelper.getRealClass(leftObject)).getCollectionDescriptorByName(collectionName);
  +        init(left, right);
  +    }
  +
  +    public MtoNImplementor(Object leftObject, Object rightObject)
  +    {
  +        init(leftObject, rightObject);
  +    }
  +
  +    private void init(Object left, Object right)
       {
           if(left == null || right == null)
           {
               throw new IllegalArgumentException("both objects must exist");
           }
   
  -        _pb = pb;
  -        _collectionDesc = cod;
  -        _left = left;
  -        _right = right;
  -
  +        //broker = pb;
  +        //collectionDesc = cod;
  +        leftObject = left;
  +        rightObject = right;
  +        leftClass = ProxyHelper.getRealClass(leftObject);
  +        rightClass = ProxyHelper.getRealClass(rightObject);
       }
   
  -	public MtoNImplementor(PersistenceBroker pb , String collectionName, Object left, Object right)
  -	{
  -		if(left == null || right == null)
  -		{
  -			throw new IllegalArgumentException("both objects must exist");
  -		}
  -        _pb = pb;
  -        _left = left;
  -        _right = right;
  -        _collectionDesc = pb.getClassDescriptor(
  -                ProxyHelper.getRealObject(_left).getClass()).getCollectionDescriptorByName(collectionName);
  -
  -	}
  -
  -
  -    public Object getLeftObject()
  +    public Class getLeftClass()
       {
  -        return _left;
  +        return leftClass;
       }
   
  -    public Object getRightObject()
  +    public Class getRightClass()
       {
  -        return _right;
  +        return rightClass;
       }
   
  -    public CollectionDescriptor getCollectionDescriptor()
  +    public Object getLeftObject()
       {
  -    	return _collectionDesc;
  -    }
  -
  -	/**
  -	 *
  -	 * @param mnKeys
  -	 * @return
  -	 */
  -    public String getInsertStmt(Collection mnKeys)
  -    {
  -		_left = ProxyHelper.getRealObject(_left);
  -		String[] leftPkColumns = _collectionDesc.getFksToThisClass();
  -		String[] rightPkColumns = _collectionDesc.getFksToItemClass();
  -		String table = _collectionDesc.getIndirectionTable();
  -		Key key = new Key(getRightPkValues());
  -
  -		if (mnKeys.contains(key))
  -		{
  -			return null;
  -		}
  -
  -		return _pb.serviceSqlGenerator().getInsertMNStatement(table, leftPkColumns, rightPkColumns);
  +        return leftObject;
       }
   
  -
  -	/**
  -	 *
  -	 * @return an Object Array with the primary key values of the left object
  -	 */
  -	public Object[] getLeftPkValues()
  -	{
  -		ClassDescriptor leftCld = _pb.getDescriptorRepository().getDescriptorFor(_left.getClass());
  -        BrokerHelper bh = _pb.serviceBrokerHelper();
  -		return bh.extractValueArray(bh.getKeyValues(leftCld, _left));
  -	}
  -
  -	/**
  -	 *
  -	 * @return an Object Array with the primary key values of the right object
  -	 */
  -	public Object[] getRightPkValues()
  -	{
  -		ClassDescriptor rightCld = _pb.getDescriptorRepository().getDescriptorFor(_right.getClass());
  -        BrokerHelper bh = _pb.serviceBrokerHelper();
  -		return bh.extractValueArray(bh.getKeyValues(rightCld, _right));
  -	}
  -
  -    /**
  -     * Inner class to model the key
  -     */
  -    private static final class Key
  +    public Object getRightObject()
       {
  -
  -        final Object[] m_key;
  -
  -        Key(final Object[] aKey)
  -        {
  -            m_key = new Object[aKey.length];
  -
  -            for (int i = 0; i < aKey.length; i++)
  -            {
  -                // BRJ:
  -                // convert all Numbers to Long to simplify equals
  -                // could lead to problems when Floats are used as key
  -                if (aKey[i] instanceof Number)
  -                {
  -                    m_key[i] = new Long(((Number)aKey[i]).longValue());
  -                }
  -                else
  -                {
  -                    m_key[i] = aKey[i];
  -                }
  -            }
  -        }
  -
  -        public boolean equals(Object other)
  -        {
  -            if (other == this)
  -            {
  -                return true;
  -            }
  -            if (!(other instanceof Key))
  -            {
  -                return false;
  -            }
  -
  -            Key otherKey = (Key) other;
  -            EqualsBuilder eb = new EqualsBuilder();
  -
  -            eb.append(m_key, otherKey.m_key);
  -            return eb.isEquals();
  -        }
  -
  -        public int hashCode()
  -        {
  -            HashCodeBuilder hb = new HashCodeBuilder();
  -            hb.append(m_key);
  -
  -            return hb.toHashCode();
  -        }
  +        return rightObject;
       }
  +
  +//    public CollectionDescriptor getCollectionDescriptor()
  +//    {
  +//        return collectionDesc;
  +//    }
  +
  +//	/**
  +//	 *
  +//	 * @param mnKeys
  +//	 * @return
  +//	 */
  +//    public String getInsertStmt(Collection mnKeys)
  +//    {
  +//		String[] leftPkColumns = collectionDesc.getFksToThisClass();
  +//		String[] rightPkColumns = collectionDesc.getFksToItemClass();
  +//		String table = collectionDesc.getIndirectionTable();
  +//		Key key = new Key(getRightPkValues());
  +//		if (mnKeys.contains(key))
  +//		{
  +//			return null;
  +//		}
  +//		return broker.serviceSqlGenerator().getInsertMNStatement(table, leftPkColumns, rightPkColumns);
  +//    }
  +
  +
  +//	/**
  +//	 *
  +//	 * @return an Object Array with the primary key values of the left object
  +//	 */
  +//	public Object[] getLeftPkValues()
  +//	{
  +//		ClassDescriptor leftCld = broker.getClassDescriptor(leftClass);
  +//        BrokerHelper bh = broker.serviceBrokerHelper();
  +//		return bh.extractValueArray(bh.getKeyValues(leftCld, leftObject));
  +//	}
  +//
  +//	/**
  +//	 *
  +//	 * @return an Object Array with the primary key values of the right object
  +//	 */
  +//	public Object[] getRightPkValues()
  +//	{
  +//		ClassDescriptor rightCld = broker.getClassDescriptor(rightClass);
  +//        BrokerHelper bh = broker.serviceBrokerHelper();
  +//		return bh.extractValueArray(bh.getKeyValues(rightCld, rightObject));
  +//	}
  +
  +//    /**
  +//     * Inner class to model the key
  +//     */
  +//    private static final class Key
  +//    {
  +//
  +//        final Object[] m_key;
  +//
  +//        Key(final Object[] aKey)
  +//        {
  +//            m_key = new Object[aKey.length];
  +//
  +//            for (int i = 0; i < aKey.length; i++)
  +//            {
  +//                // BRJ:
  +//                // convert all Numbers to Long to simplify equals
  +//                // could lead to problems when Floats are used as key
  +//                if (aKey[i] instanceof Number)
  +//                {
  +//                    m_key[i] = new Long(((Number)aKey[i]).longValue());
  +//                }
  +//                else
  +//                {
  +//                    m_key[i] = aKey[i];
  +//                }
  +//            }
  +//        }
  +//
  +//        public boolean equals(Object other)
  +//        {
  +//            if (other == this)
  +//            {
  +//                return true;
  +//            }
  +//            if (!(other instanceof Key))
  +//            {
  +//                return false;
  +//            }
  +//
  +//            Key otherKey = (Key) other;
  +//            EqualsBuilder eb = new EqualsBuilder();
  +//
  +//            eb.append(m_key, otherKey.m_key);
  +//            return eb.isEquals();
  +//        }
  +//
  +//        public int hashCode()
  +//        {
  +//            HashCodeBuilder hb = new HashCodeBuilder();
  +//            hb.append(m_key);
  +//
  +//            return hb.toHashCode();
  +//        }
  +//    }
   }
   
  
  
  
  No                   revision
  No                   revision
  1.27.2.1  +1 -1      db-ojb/src/java/org/apache/ojb/odmg/collections/DListImpl.java
  
  Index: DListImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/collections/DListImpl.java,v
  retrieving revision 1.27
  retrieving revision 1.27.2.1
  diff -u -r1.27 -r1.27.2.1
  --- DListImpl.java	4 Apr 2004 23:53:39 -0000	1.27
  +++ DListImpl.java	18 Mar 2005 19:25:06 -0000	1.27.2.1
  @@ -407,7 +407,7 @@
           // 1.build complete OQL statement
           String oql = "select all from java.lang.Object where " + predicate;
           /* @todo Use a ObjectFactory to instantiate OQLQuery? */
  -        OQLQuery predicateQuery = new OQLQueryImpl(pbKey);
  +        OQLQuery predicateQuery = new OQLQueryImpl(pbKey, this.getClass());
           predicateQuery.create(oql);
           Query pQ = ((OQLQueryImpl) predicateQuery).getQuery();
           Criteria pCrit = pQ.getCriteria();
  
  
  
  1.6.2.1   +2 -2      db-ojb/src/java/org/apache/ojb/odmg/collections/Attic/DListImpl_2.java
  
  Index: DListImpl_2.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/collections/Attic/DListImpl_2.java,v
  retrieving revision 1.6
  retrieving revision 1.6.2.1
  diff -u -r1.6 -r1.6.2.1
  --- DListImpl_2.java	4 Apr 2004 23:53:39 -0000	1.6
  +++ DListImpl_2.java	18 Mar 2005 19:25:06 -0000	1.6.2.1
  @@ -395,7 +395,7 @@
           // 1.build complete OQL statement
           String oql = "select all from java.lang.Object where " + predicate;
           /*TODO: Use a ObjectFactory to instantiate OQLQuery? */
  -        OQLQuery predicateQuery = new OQLQueryImpl(pbKey);
  +        OQLQuery predicateQuery = new OQLQueryImpl(pbKey, this.getClass());
           predicateQuery.create(oql);
           Query pQ = ((OQLQueryImpl) predicateQuery).getQuery();
           Criteria pCrit = pQ.getCriteria();
  
  
  
  1.21.2.1  +1 -1      db-ojb/src/java/org/apache/ojb/odmg/collections/DSetImpl.java
  
  Index: DSetImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/collections/DSetImpl.java,v
  retrieving revision 1.21
  retrieving revision 1.21.2.1
  diff -u -r1.21 -r1.21.2.1
  --- DSetImpl.java	4 Apr 2004 23:53:39 -0000	1.21
  +++ DSetImpl.java	18 Mar 2005 19:25:06 -0000	1.21.2.1
  @@ -279,7 +279,7 @@
       {
           // 1.build complete OQL statement
           String oql = "select all from java.lang.Object where " + predicate;
  -        OQLQuery predicateQuery = new OQLQueryImpl(pbKey);
  +        OQLQuery predicateQuery = new OQLQueryImpl(pbKey, this.getClass());
   
           Transaction tx = getTransaction();
           PBCapsule capsule = new PBCapsule(pbKey, tx);
  
  
  
  No                   revision
  No                   revision
  1.18.2.1  +24 -13    db-ojb/src/java/org/apache/ojb/odmg/oql/OQLQueryImpl.java
  
  Index: OQLQueryImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/oql/OQLQueryImpl.java,v
  retrieving revision 1.18
  retrieving revision 1.18.2.1
  diff -u -r1.18 -r1.18.2.1
  --- OQLQueryImpl.java	4 Apr 2004 23:53:40 -0000	1.18
  +++ OQLQueryImpl.java	18 Mar 2005 19:25:06 -0000	1.18.2.1
  @@ -15,6 +15,12 @@
    * limitations under the License.
    */
   
  +import java.io.StringReader;
  +import java.util.Enumeration;
  +import java.util.Iterator;
  +import java.util.ListIterator;
  +import java.util.Vector;
  +
   import antlr.RecognitionException;
   import antlr.TokenStreamException;
   import org.apache.ojb.broker.ManageableCollection;
  @@ -28,26 +34,21 @@
   import org.apache.ojb.broker.query.ReportQuery;
   import org.apache.ojb.broker.query.SelectionCriteria;
   import org.apache.ojb.broker.util.collections.ManageableArrayList;
  -import org.apache.ojb.broker.util.configuration.Configurable;
  -import org.apache.ojb.broker.util.configuration.Configuration;
  -import org.apache.ojb.broker.util.configuration.ConfigurationException;
   import org.apache.ojb.broker.util.logging.Logger;
   import org.apache.ojb.broker.util.logging.LoggerFactory;
  +import org.apache.ojb.broker.util.configuration.Configuration;
  +import org.apache.ojb.broker.util.configuration.ConfigurationException;
  +import org.apache.ojb.broker.util.configuration.Configurable;
   import org.apache.ojb.odmg.OdmgConfiguration;
   import org.apache.ojb.odmg.PBCapsule;
   import org.apache.ojb.odmg.TxManagerFactory;
   import org.odmg.QueryInvalidException;
   import org.odmg.Transaction;
   
  -import java.io.StringReader;
  -import java.util.Enumeration;
  -import java.util.Iterator;
  -import java.util.ListIterator;
  -import java.util.Vector;
  -
   /**
  - * Insert the type's description here.
  - * Creation date: (08.05.01 13:12:58)
  + * The OQL query interface implementation.
  + *
  + * @version $Id$
    */
   public class OQLQueryImpl implements EnhancedOQLQuery, Configurable
   {
  @@ -64,9 +65,19 @@
       private ListIterator bindIterator = null;
       private PBKey pbKey;
   
  -    public OQLQueryImpl(PBKey key)
  +    public OQLQueryImpl(PBKey key, Class collectionClass)
       {
           this.pbKey = key;
  +        this.collectionClass = collectionClass;
  +    }
  +
  +    /**
  +     * @deprecated
  +     * @param pbKey
  +     */
  +    public OQLQueryImpl(PBKey pbKey)
  +    {
  +        this.pbKey = pbKey;
       }
   
   
  @@ -378,7 +389,7 @@
           this.bindIterator = bindIterator;
       }
   
  -    /*
  +    /**
        * @see Configurable#configure(Configuration)
        */
       public void configure(Configuration pConfig) throws ConfigurationException
  
  
  
  No                   revision
  No                   revision
  1.5.2.2   +1 -1      db-ojb/src/java/org/apache/ojb/odmg/states/StateOldDelete.java
  
  Index: StateOldDelete.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/states/StateOldDelete.java,v
  retrieving revision 1.5.2.1
  retrieving revision 1.5.2.2
  diff -u -r1.5.2.1 -r1.5.2.2
  --- StateOldDelete.java	16 Nov 2004 17:45:35 -0000	1.5.2.1
  +++ StateOldDelete.java	18 Mar 2005 19:25:06 -0000	1.5.2.2
  @@ -69,7 +69,7 @@
        */
       public ModificationState markNew()
       {
  -        return StateNewDelete.getInstance();
  +        return StateOldDirty.getInstance();
       }
   
       /**
  
  
  
  No                   revision
  No                   revision
  1.1.2.4   +22 -10    db-ojb/src/java/org/apache/ojb/odmg/ImplementationImpl.java
  
  Index: ImplementationImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/ImplementationImpl.java,v
  retrieving revision 1.1.2.3
  retrieving revision 1.1.2.4
  diff -u -r1.1.2.3 -r1.1.2.4
  --- ImplementationImpl.java	23 Dec 2004 22:03:24 -0000	1.1.2.3
  +++ ImplementationImpl.java	18 Mar 2005 19:25:06 -0000	1.1.2.4
  @@ -21,8 +21,10 @@
   import org.apache.ojb.broker.PersistenceBrokerFactory;
   import org.apache.ojb.broker.util.configuration.ConfigurationException;
   import org.apache.ojb.broker.util.configuration.Configurator;
  +import org.apache.ojb.broker.util.configuration.Configuration;
   import org.apache.ojb.broker.util.logging.Logger;
   import org.apache.ojb.broker.util.logging.LoggerFactory;
  +import org.apache.ojb.broker.util.collections.ManageableArrayList;
   import org.apache.ojb.odmg.collections.DCollectionFactory;
   import org.apache.ojb.odmg.oql.EnhancedOQLQuery;
   import org.apache.ojb.odmg.oql.OQLQueryImpl;
  @@ -58,6 +60,10 @@
       private DatabaseImpl currentDatabase;
       private Configurator configurator;
       private OJBTxManager ojbTxManager;
  +    private Class oqlCollectionClass;
  +    protected boolean cascadingDeleteOnetoOne;
  +    protected boolean cascadingDeleteOnetoN;
  +    protected boolean cascadingDeleteMtoN;
   
       /**
        * private Constructor: use static factory method
  @@ -67,6 +73,12 @@
       {
           ojbTxManager = TxManagerFactory.instance();
           setConfigurator(PersistenceBrokerFactory.getConfigurator());
  +        Configuration conf = getConfigurator().getConfigurationFor(null);
  +        // read settings for cascading delete behavior
  +        cascadingDeleteOnetoOne = conf.getBoolean("cascadingDeleteOneToOne", false);
  +        cascadingDeleteOnetoN = conf.getBoolean("cascadingDeleteOneToN", false);
  +        cascadingDeleteMtoN = conf.getBoolean("cascadingDeleteMToN", false);
  +        oqlCollectionClass = conf.getClass("OqlCollectionClass", ManageableArrayList.class);
       }
   
       protected OJBTxManager getTxManager()
  @@ -171,15 +183,7 @@
           {
               throw new DatabaseClosedException("Database is not open");
           }
  -        OQLQueryImpl query = new OQLQueryImpl(this.getCurrentPBKey());
  -        try
  -        {
  -            getConfigurator().configure(query);
  -        }
  -        catch (ConfigurationException e)
  -        {
  -            throw new ODMGRuntimeException("Error in configuration of OQLQueryImpl instance: " + e.getMessage());
  -        }
  +        OQLQueryImpl query = new OQLQueryImpl(this.getCurrentPBKey(), getOqlCollectionClass());
           return query;
   
       }
  @@ -333,5 +337,13 @@
   		((TransactionExt)currentTransaction()).setImplicitLocking(value);
   	}
   
  +    public Class getOqlCollectionClass()
  +    {
  +        return oqlCollectionClass;
  +    }
   
  +    public void setOqlCollectionClass(Class oqlCollectionClass)
  +    {
  +        this.oqlCollectionClass = oqlCollectionClass;
  +    }
   }
  
  
  
  1.25.2.3  +2 -2      db-ojb/src/java/org/apache/ojb/odmg/J2EETransactionImpl.java
  
  Index: J2EETransactionImpl.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/J2EETransactionImpl.java,v
  retrieving revision 1.25.2.2
  retrieving revision 1.25.2.3
  diff -u -r1.25.2.2 -r1.25.2.3
  --- J2EETransactionImpl.java	27 Nov 2004 23:46:07 -0000	1.25.2.2
  +++ J2EETransactionImpl.java	18 Mar 2005 19:25:06 -0000	1.25.2.3
  @@ -148,7 +148,7 @@
                       log.debug("Synchronization#beforeCompletion: Prepare for commit");
                   }
                   // write objects to database
  -                prepare();
  +                prepareCommit();
               }
           }
           catch(Exception e)
  
  
  
  1.10.2.2  +9 -0      db-ojb/src/java/org/apache/ojb/odmg/NarrowTransaction.java
  
  Index: NarrowTransaction.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/NarrowTransaction.java,v
  retrieving revision 1.10.2.1
  retrieving revision 1.10.2.2
  diff -u -r1.10.2.1 -r1.10.2.2
  --- NarrowTransaction.java	14 Aug 2004 23:42:37 -0000	1.10.2.1
  +++ NarrowTransaction.java	18 Mar 2005 19:25:06 -0000	1.10.2.2
  @@ -151,4 +151,13 @@
       	tx.setImplicitLocking(value);
       }
   
  +    public void setCascadingDelete(Class target, String referenceField, boolean doCascade)
  +    {
  +        tx.setCascadingDelete(target, referenceField, doCascade);
  +    }
  +
  +    public void setCascadingDelete(Class target, boolean doCascade)
  +    {
  +        tx.setCascadingDelete(target, doCascade);
  +    }
   }
  
  
  
  1.32.2.9  +349 -126  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.8
  retrieving revision 1.32.2.9
  diff -u -r1.32.2.8 -r1.32.2.9
  --- ObjectEnvelope.java	13 Mar 2005 03:53:30 -0000	1.32.2.8
  +++ ObjectEnvelope.java	18 Mar 2005 19:25:06 -0000	1.32.2.9
  @@ -21,9 +21,6 @@
    *
    */
   
  -import java.util.ArrayList;
  -import java.util.Arrays;
  -import java.util.Collection;
   import java.util.HashMap;
   import java.util.Iterator;
   import java.util.Map;
  @@ -32,6 +29,7 @@
   import org.apache.ojb.broker.Identity;
   import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.PersistenceBrokerException;
  +import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.core.proxy.CollectionProxy;
   import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
   import org.apache.ojb.broker.core.proxy.CollectionProxyListener;
  @@ -60,8 +58,9 @@
   public class ObjectEnvelope implements ObjectModification
   {
       static final long serialVersionUID = -829177767933340522L;
  -    static final int MATERIALIZED_OBJECT = 11;
  -    static final int IS_PROXY = 13;
  +    static final int IS_MATERIALIZED_OBJECT = 11;
  +    static final int IS_MATERIALIZED_PROXY = 13;
  +    static final int IS_UNMATERIALIZED_PROXY = 17;
       private Logger log = LoggerFactory.getLogger(ObjectEnvelope.class);
   
       /**
  @@ -96,7 +95,10 @@
           this.oid = oid;
           // TODO: do we really need to materialize??
           myObj = ProxyHelper.getRealObject(obj);
  -        refreshObjectImage();
  +        /*
  +        if object is new don't make an image, because we know it needs insert
  +        */
  +        if(!isNewObject) refreshObjectImage();
           prepareInitialState(isNewObject);
       }
   
  @@ -117,23 +119,79 @@
   
       public Map getBeforeImage()
       {
  -        if(beforeImage == null) beforeImage = getMap(getBroker());
  +        if(beforeImage == null)
  +        {
  +            beforeImage = buildObjectImage(getBroker());
  +            //prepareToCompare();
  +        }
           return beforeImage;
       }
   
       public Map getCurrentImage()
       {
  -        if(currentImage == null) currentImage = getMap(getBroker());
  +        if(currentImage == null)
  +        {
  +            currentImage = buildObjectImage(getBroker());
  +            //prepareToCompare();
  +        }
           return currentImage;
       }
   
       public void close()
       {
  +        if(currentImage != null)
  +        {
  +            Iterator iterator = currentImage.values().iterator();
  +            while(iterator.hasNext())
  +            {
  +                EqualsBase base =  (EqualsBase) iterator.next();
  +                if(base != null) base.close();
  +            }
  +        }
  +        if(beforeImage != null)
  +        {
  +            Iterator iterator = beforeImage.values().iterator();
  +            while(iterator.hasNext())
  +            {
  +                EqualsBase base =  (EqualsBase) iterator.next();
  +                if(base != null) base.close();
  +            }
  +        }
           myObj = null;
  -        currentImage = null;
  -        beforeImage = null;
       }
   
  +//    /**
  +//     * This method should be called once before the object image comparison
  +//     * starts to allow {@link org.apache.ojb.odmg.ObjectEnvelope.EqualsBase}
  +//     * objects to prepare.
  +//     */
  +//    public void prepareToCompare()
  +//    {
  +//        if(currentImage != null)
  +//        {
  +//            Iterator iterator = currentImage.values().iterator();
  +//            Object obj;
  +//            while(iterator.hasNext())
  +//            {
  +//                obj = iterator.next();
  +//                if(obj != null)
  +//                {
  +//                    EqualsBase base =  (EqualsBase) obj;
  +//                    base.prepareForCompare();
  +//                }
  +//            }
  +//        }
  +//        if(beforeImage != null)
  +//        {
  +//            Iterator iterator = beforeImage.values().iterator();
  +//            while(iterator.hasNext())
  +//            {
  +//                EqualsBase base =  (EqualsBase) iterator.next();
  +//                if(base != null) base.prepareForCompare();
  +//            }
  +//        }
  +//    }
  +
       public void refreshObjectImage()
       {
           PersistenceBroker broker = getBroker();
  @@ -155,7 +213,7 @@
               {
                   if(beforeImage == null)
                   {
  -                    beforeImage = getMap(getBroker());
  +                    beforeImage = buildObjectImage(getBroker());
                   }
               }
               currentImage = null;
  @@ -256,12 +314,13 @@
       }
   
       /**
  -     * getMap() will return the image of the Object.
  +     * buildObjectImage() will return the image of the Object.
        */
  -    private Map getMap(PersistenceBroker broker) throws PersistenceBrokerException
  +    private Map buildObjectImage(PersistenceBroker broker) throws PersistenceBrokerException
       {
           Map fieldValues = new HashMap();
           ClassDescriptor mif = broker.getClassDescriptor(getObject().getClass());
  +        //System.out.println("++++ build image: " + getObject());
   
           /**
            * MBAIRD
  @@ -273,9 +332,10 @@
            */
           Iterator iter = mif.getObjectReferenceDescriptors().iterator();
           ObjectReferenceDescriptor rds = null;
  -        Object temp = null;
           while(iter.hasNext())
           {
  +            Object referenceObject = null;
  +            EqualsRefHelper erh;
               rds = (ObjectReferenceDescriptor) iter.next();
   
               /*
  @@ -284,7 +344,7 @@
                */
               synchronized(myObj)
               {
  -                temp = rds.getPersistentField().get(myObj);
  +                referenceObject = rds.getPersistentField().get(myObj);
               }
               /**
                * MBAIRD
  @@ -298,24 +358,24 @@
                * 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(temp);
  +            IndirectionHandler handler = ProxyHelper.getIndirectionHandler(referenceObject);
               // if it is a not materialized proxy, use the Identity
               if(handler != null)
               {
  -                temp = handler.alreadyMaterialized()
  +                erh = handler.alreadyMaterialized()
                           ? new EqualsRefHelper(handler.getRealSubject())
                           : new EqualsRefHelper(handler.getIdentity());
               }
               else
               {
  -                temp = new EqualsRefHelper(temp);
  +                erh = new EqualsRefHelper(referenceObject);
               }
               /*
               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(handler == null && temp != null && BrokerHelper.hasAnonymousKeyReference(mif, rds))
  +            if(handler == null && referenceObject != null && BrokerHelper.hasAnonymousKeyReference(mif, rds))
               {
                   getBroker().serviceBrokerHelper().link(myObj, rds, false);
               }
  @@ -323,7 +383,7 @@
                register the Identity for 1:1 relations only, if change we have
                to update the main object
                */
  -            fieldValues.put(rds, temp);
  +            fieldValues.put(rds, erh);
           }
   
   
  @@ -348,41 +408,18 @@
   
   
           /**
  -         * TODO: fix bug, proxy collections will always be materialized
            * MBAIRD
            * 3. now let's register the collection descriptors
            * How do we handle proxied collections and collections of proxies
            */
           Iterator collections = mif.getCollectionDescriptors().iterator();
  -        CollectionDescriptor collectionDescriptor = null;
  +        CollectionDescriptor cds = null;
           while(collections.hasNext())
           {
  -            collectionDescriptor = (CollectionDescriptor) collections.next();
  -            Object collectionOrArray = collectionDescriptor.getPersistentField().get(myObj);
  -            if(collectionOrArray != null)
  -            {
  -                Collection referencesId = null;
  -                // no special treatment for CollectionProxies required,
  -                // their size() method does not materialize the elements.
  -                /**
  -                 * MBAIRD
  -                 * size isn't the safest thing to use as the dirty bit. This will
  -                 * need to be fixed.
  -                 */
  -                if(collectionOrArray instanceof Collection)
  -                {
  -                    referencesId = new ArrayList((Collection) collectionOrArray);
  -                }
  -                else if(collectionOrArray.getClass().isArray())
  -                {
  -                    referencesId = Arrays.asList((Object[]) collectionOrArray);
  -                }
  -                fieldValues.put(collectionDescriptor, referencesId);
  -            }
  -            else
  -            {
  -                fieldValues.put(collectionDescriptor, null);
  -            }
  +            cds = (CollectionDescriptor) collections.next();
  +            Object collectionOrArray = cds.getPersistentField().get(myObj);
  +            EqualsColHelper ech = new EqualsColHelper(cds, collectionOrArray);
  +            fieldValues.put(cds, ech);
           }
           return fieldValues;
       }
  @@ -514,32 +551,34 @@
       }
   
       /**
  -     * Mark new or deleted collection elements
  +     * Mark new or deleted reference elements
        * @param broker
        */
  -    void markCollectionElements(PersistenceBroker broker)
  +    void markReferenceElements(PersistenceBroker broker)
       {
  -        Map currentImage = getCurrentImage();
  +        if(getModificationState().needsInsert() || getModificationState().needsDelete()) return;
   
  -        Iterator iter = currentImage.entrySet().iterator();
  +        Map oldImage = getBeforeImage();
  +        Map newImage = getCurrentImage();
  +
  +        Iterator iter = newImage.entrySet().iterator();
           while (iter.hasNext())
           {
               Map.Entry entry = (Map.Entry) iter.next();
  +            // CollectionDescriptor extends ObjectReferenceDescriptor
               if(entry.getKey() instanceof ObjectReferenceDescriptor)
               {
                   if (entry.getKey() instanceof CollectionDescriptor)
                   {
                       CollectionDescriptor cds = (CollectionDescriptor) entry.getKey();
  -                    Collection oldCol = (Collection) beforeImage.get(cds);
  -                    Collection newCol = (Collection) entry.getValue();
  +                    EqualsColHelper oldEch = (EqualsColHelper) oldImage.get(cds);
  +                    EqualsColHelper newEch = (EqualsColHelper) entry.getValue();
  +//System.out.println("");
  +//System.out.println("mark-oldEch: " + oldEch);
  +//System.out.println("mark-newEch: " + newEch);
   
  -                    if (!cds.isMtoNRelation())
  -                    {
  -                        markDelete(oldCol, newCol);
  -                    }
  -
  -                    // requires fix in InvocationHandler
  -                    markNew(oldCol, newCol);
  +                    markDelete(cds, oldEch, newEch);
  +                    markNew(cds, oldEch, newEch);
                   }
                   else
                   {
  @@ -547,16 +586,41 @@
                       check for new 1:1 reference object
                       */
                       ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) entry.getKey();
  -                    EqualsRefHelper oldEh = (EqualsRefHelper) beforeImage.get(rds);
  -                    EqualsRefHelper newEh = (EqualsRefHelper) currentImage.get(rds);
  +                    EqualsRefHelper oldEh = (EqualsRefHelper) oldImage.get(rds);
  +                    EqualsRefHelper newEh = (EqualsRefHelper) newImage.get(rds);
                       if(!oldEh.equals(newEh))
                       {
  +                        // the main objects needs link/unlink of the FK to 1:1 reference,
  +                        // so mark this dirty
  +                        setModificationState(getModificationState().markDirty());
                           // if the new reference helper value is not null
                           // lock the object, because it can be a new unregistered object.
  +                        // in other cases it can be an unmaterialized proxy and we
  +                        // don't need to materialize
                           if(newEh.value != null)
                           {
                               getTx().lock(newEh.value, TransactionExt.WRITE);
                           }
  +                        // if the new image doesn't contain a reference object, the
  +                        // reference is deleted, so lookup the old reference object
  +                        // and mark for delete
  +                        else if(newEh.isNull())
  +                        {
  +                            ObjectEnvelope oldRefMod = buffer.getByIdentity(oldEh.oid);
  +                            // only delete when the reference wasn't assigned with another object
  +                            if(!buffer.isNewAssociatedObject(oldEh.oid))
  +                            {
  +                                // if cascading delete is enabled, remove the 1:1 reference
  +                                // because it was removed from the main object
  +                                if(buffer.getTransaction().cascadeDeleteFor(rds))
  +                                {
  +                                    oldRefMod.setModificationState(oldRefMod.getModificationState().markDelete());
  +                                }
  +                                // in any case we have to unlink the main object
  +                                getBroker().serviceBrokerHelper()
  +                                        .unlink(getObject(), rds, getModificationState().needsInsert());
  +                            }
  +                        }
                       }
                   }
               }
  @@ -565,72 +629,101 @@
   
       /**
        * Mark object for delete if it's not available in the new Collection.
  -     * @param oldCol
  -     * @param newCol
        */
  -    private void markDelete(Collection oldCol, Collection newCol)
  +    private void markDelete(CollectionDescriptor cds, EqualsColHelper oldEch, EqualsColHelper newEch)
       {
  -        if (oldCol == null || oldCol.size() == 0)
  +        if (oldEch.references.size() == 0)
           {
               return;
           }
  -
  -        Iterator oldIter = oldCol.iterator();
  +        Iterator oldIter = oldEch.references.entrySet().iterator();
  +        Map newRefs = newEch.references;
           while (oldIter.hasNext())
           {
  -            Object oldObj = oldIter.next();
  -            if ((newCol != null) && (!newCol.contains(oldObj)))
  -            {
  -                ObjectEnvelope mod = buffer.get(oldObj, false);
  -                mod.setModificationState(mod.getModificationState().markDelete());
  +            Map.Entry entry = (Map.Entry) oldIter.next();
  +            Identity oldOid = (Identity) entry.getKey();
  +            if (!newRefs.containsKey(oldOid) && newEch.status != IS_UNMATERIALIZED_PROXY)
  +            {
  +                ObjectEnvelope mod = buffer.getByIdentity(oldOid);
  +                // if this object is associated with another object it's
  +                // not allowed to remove it
  +                if(!buffer.isNewAssociatedObject(oldOid))
  +                {
  +                    if(mod != null)
  +                    {
  +                        boolean cascade = buffer.getTransaction().cascadeDeleteFor(cds);
  +                        if(cascade)
  +                        {
  +                            mod.setModificationState(mod.getModificationState().markDelete());
  +                            buffer.addForDeletionDependent(mod);
  +                        }
  +                        if(cds.isMtoNRelation())
  +                        {
  +                            buffer.addM2NUnlinkEntry(cds, getObject(), entry.getValue());
  +                        }
  +                        else
  +                        {
  +                            // when cascade 'true' we remove all dependent objects, so no need to unlink
  +                            if(!cascade) getBroker().serviceBrokerHelper().unlink(getObject(), cds, entry.getValue());
  +                        }
  +                    }
  +                    else
  +                    {
  +                        throw new ImageExcetion("Unexpected behaviour, unregistered object to delete: "
  +                                + oldOid + ", main object is " + getIdentity());
  +                    }
  +                }
               }
           }
       }
   
       /**
        * Mark object for insert if it's not available in the old Collection.
  -     * @param oldCol
  -     * @param newCol
        */
  -    private void markNew(Collection oldCol, Collection newCol)
  +    private void markNew(CollectionDescriptor cds, EqualsColHelper oldEch, EqualsColHelper newEch)
       {
  -        if (newCol == null)
  +        if (newEch.references.size() == 0)
           {
               return;
           }
   
  -        Iterator newIter = newCol.iterator();
  +        Iterator newIter = newEch.references.entrySet().iterator();
  +        Map oldRefs = oldEch.references;
           while (newIter.hasNext())
           {
  -            Object newObj = newIter.next();
  +            Map.Entry entry = (Map.Entry) newIter.next();
  +            Identity newOid = (Identity) entry.getKey();
  +            Object newObj = entry.getValue();
  +
               /*
  -            arminw:
  -            workaround, if the new object is an proxy object we have to
  -            compare the Identity objects
  +            search for new objects: if in the old reference collection an object
  +            of the new reference collection is not contained
               */
  -            if(oldCol != null && ProxyHelper.isProxy(newObj))
  +            if ((oldRefs == null) || !oldRefs.containsKey(newOid))
               {
  -                Identity oidNew = ProxyHelper.getIndirectionHandler(newObj).getIdentity();
  -                boolean isNew = true;
  -                for(Iterator iterator = oldCol.iterator(); iterator.hasNext();)
  +                ObjectEnvelope mod = buffer.getByIdentity(newOid);
  +                if(mod == null) mod = buffer.get(newObj, true);
  +                // 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
  +                if(mod.needsDelete())
                   {
  -                    Identity oidOld =  getBroker().serviceIdentity().buildIdentity(iterator.next());
  -                    if(oidNew.equals(oidOld))
  -                    {
  -                        isNew = false;
  -                        break;
  -                    }
  +                    mod.setModificationState(mod.getModificationState().markNew());
                   }
  -                if(isNew)
  +                else
                   {
  -                    ObjectEnvelope mod = buffer.get(newObj, true);
  -                    mod.setModificationState(mod.getModificationState().markNew());
  +                    mod.setModificationState(mod.getModificationState().markDirty());
                   }
  -            }
  -            else if ((oldCol == null) || (!oldCol.contains(newObj)))
  -            {
  -                ObjectEnvelope mod = buffer.get(newObj, true);
  -                mod.setModificationState(mod.getModificationState().markNew());
  +                // buffer this object as "new" in a list to prevent deletion
  +                // when object was moved from one collection to another
  +                buffer.addNewAssociatedIdentity(newOid);
  +                // new referenced object found, so register all m:n relation for "linking"
  +                if(cds.isMtoNRelation())
  +                {
  +                    buffer.addM2NLinkEntry(cds, getObject(), newObj);
  +                }
  +                if(mod.needsInsert()) buffer.addForInsertDependent(mod);
  +                // System.out.println("*** new object for " + getIdentity() + " / " + mod.getIdentity());
               }
           }
       }
  @@ -662,7 +755,19 @@
       /**
        * Help to compare field values.
        */
  -    class EqualsFieldHelper
  +    abstract class EqualsBase
  +    {
  +        abstract void close();
  +        abstract void prepareForCompare();
  +    }
  +
  +    //====================================================
  +    // inner class
  +    //====================================================
  +    /**
  +     * Help to compare field values.
  +     */
  +    class EqualsFieldHelper extends EqualsBase
       {
           FieldType type;
           Object value;
  @@ -673,6 +778,14 @@
               this.value = value;
           }
   
  +        void close()
  +        {
  +        }
  +
  +        void prepareForCompare()
  +        {
  +        }
  +
           public boolean equals(Object valueNew)
           {
               boolean result = false;
  @@ -687,10 +800,10 @@
                       result = type.equals(value, ((EqualsFieldHelper) valueNew).value);
                   }
               }
  -            if(!result)
  -            {
  -                System.out.println("** changed field: " + getIdentity() + ", this="+this + ", other=" + valueNew);
  -            }
  +//            if(!result)
  +//            {
  +//                System.out.println("** changed field: " + getIdentity() + ", this="+this + ", other=" + valueNew);
  +//            }
               return result;
           }
   
  @@ -706,7 +819,7 @@
       /**
        * Help to compare 1:1 references of the main object.
        */
  -    class EqualsRefHelper
  +    class EqualsRefHelper extends EqualsBase
       {
           Identity oid;
           Object value;
  @@ -721,6 +834,23 @@
               this.oid = oid;
           }
   
  +        void close()
  +        {
  +        }
  +
  +        void prepareForCompare()
  +        {
  +        }
  +
  +        /**
  +         * The reference is <em>null</em> when both Identity and Object attribute
  +         * is null.
  +         */
  +        public boolean isNull()
  +        {
  +            return oid == null && value == null;
  +        }
  +
           public boolean equals(Object toCompare)
           {
               boolean result = false;
  @@ -751,10 +881,10 @@
                       result = oid != null ? oid.equals(other.oid) : other.oid == null;
                   }
               }
  -            if(!result)
  -            {
  -                System.out.println("** changed 1:1: " + getIdentity() + ", ref: " + oid);
  -            }
  +//            if(!result)
  +//            {
  +//                System.out.println("** changed 1:1: " + getIdentity() + ", ref: " + oid);
  +//            }
               return result;
           }
       }
  @@ -765,13 +895,48 @@
       /**
        * Help to compare 1:1 references of the main object.
        */
  -    class EqualsColHelper implements CollectionProxyListener
  +    class EqualsColHelper extends EqualsBase implements CollectionProxyListener
       {
  +        private CollectionDescriptor des;
           private CollectionProxy collectionHandler;
           private int status;
           private Map references;
  +       // private Collection proxyData;
  +
  +        public EqualsColHelper(CollectionDescriptor des, Object collOrArray)
  +        {
  +            this.des = des;
  +            references = new HashMap();
  +            assignReferenceObject(collOrArray);
  +            //System.out.println("** Create " + this);
  +        }
  +
  +        public String toString()
  +        {
  +            return new ToStringBuilder(this)
  +                    .append("main class", des.getClassDescriptor().getClassNameOfObject())
  +                    .append("reference name", des.getPersistentField().getName())
  +                    .append("reference class", des.getItemClassName())
  +                    .append("status", status)
  +                    .append("references", references)
  +                    .toString();
  +        }
   
  -        void destroy()
  +        /**
  +         * Always returns true, because changes in 1:n or m:n relations
  +         * do not influence main object, no need for update main object
  +         * thus return always true.
  +         */
  +        public boolean equals(Object obj)
  +        {
  +            return (obj instanceof EqualsColHelper) ? true : false;
  +        }
  +
  +        void prepareForCompare()
  +        {
  +        }
  +
  +        void close()
           {
               if(collectionHandler != null)
               {
  @@ -787,17 +952,17 @@
               {
                   if(colProxy.isLoaded())
                   {
  -                    status = MATERIALIZED_OBJECT;
  +                    status = IS_MATERIALIZED_PROXY;
                       /*
                       TODO: avoid dependency to CollectionProxyDefaultImpl
                       e.g. change CollectionProxy interface - CollectionProxy should
                       extend Collection to support Iterator
                       */
  -                    handleCollectionProxy((CollectionProxyDefaultImpl) colProxy);
  +                    handleCollectionOrArray(((CollectionProxyDefaultImpl) colProxy).getData());
                   }
                   else
                   {
  -                    status = IS_PROXY;
  +                    status = IS_UNMATERIALIZED_PROXY;
   // TODO: ObjectEnvelopeTable#register take care of proxy objects/collection, no need to handle proxy objects??
                       colProxy.addListener(this);
                       collectionHandler = colProxy;
  @@ -805,29 +970,31 @@
               }
               else
               {
  -                status = MATERIALIZED_OBJECT;
  +                status = IS_MATERIALIZED_OBJECT;
                   handleCollectionOrArray(collOrArray);
               }
           }
   
           public void beforeLoading(CollectionProxyDefaultImpl colProxy)
           {
  +            //noop
           }
   
           public void afterLoading(CollectionProxyDefaultImpl colProxy)
           {
  -            handleCollectionProxy(colProxy);
  -            status = MATERIALIZED_OBJECT;
  -            colProxy.removeListener(this);
  -            collectionHandler = null;
  +            if(status == IS_UNMATERIALIZED_PROXY)
  +            {
  +                //System.out.println("**** materialize " + this + " ->> data: " + colProxy.getData());
  +                // reference to the proxy data
  +                handleMaterializedCollectionProxy(colProxy);
  +                status = IS_MATERIALIZED_PROXY;
  +                colProxy.removeListener(this);
  +                collectionHandler = null;
  +            }
           }
   
           void addReference(Identity oid, Object obj)
           {
  -            if(references == null)
  -            {
  -                references = new HashMap();
  -            }
               references.put(oid, obj);
           }
   
  @@ -843,7 +1010,7 @@
               }
           }
   
  -        void handleCollectionProxy(CollectionProxyDefaultImpl colProxy)
  +        void handleMaterializedCollectionProxy(CollectionProxyDefaultImpl colProxy)
           {
               if(colProxy.getData() == null || colProxy.getData().size() == 0)
               {
  @@ -880,4 +1047,60 @@
               }
           }
       }
  +
  +    /**
  +     * Thrown if something unexpected is happen when handling the
  +     * object images for state detection.
  +     */
  +    public static class ImageExcetion extends OJBRuntimeException
  +    {
  +        public ImageExcetion()
  +        {
  +        }
  +
  +        public ImageExcetion(String msg)
  +        {
  +            super(msg);
  +        }
  +
  +        public ImageExcetion(Throwable cause)
  +        {
  +            super(cause);
  +        }
  +
  +        public ImageExcetion(String msg, Throwable cause)
  +        {
  +            super(msg, cause);
  +        }
  +    }
  +
  +    //            /*
  +//            arminw:
  +//            workaround, if the new object is an proxy object we have to
  +//            compare the Identity objects
  +//            */
  +//            if(oldRefs != null && ProxyHelper.isProxy(newObj))
  +//            {
  +//                Identity oidNew = ProxyHelper.getIndirectionHandler(newObj).getIdentity();
  +//                boolean isNew = true;
  +//                for(Iterator iterator = oldRefs.iterator(); iterator.hasNext();)
  +//                {
  +//                    Identity oidOld =  getBroker().serviceIdentity().buildIdentity(iterator.next());
  +//                    if(oidNew.equals(oidOld))
  +//                    {
  +//                        isNew = false;
  +//                        break;
  +//                    }
  +//                }
  +//                if(isNew)
  +//                {
  +//                    ObjectEnvelope mod = buffer.get(newObj, true);
  +//                    mod.setModificationState(mod.getModificationState().markNew());
  +//                }
  +//            }
  +//            else if ((oldRefs == null) || oldRefs.get(newOid) != null)
  +//            {
  +//                ObjectEnvelope mod = buffer.get(newObj, true);
  +//                mod.setModificationState(mod.getModificationState().markNew());
  +//            }
   }
  \ No newline at end of file
  
  
  
  1.32.2.11 +411 -28   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.10
  retrieving revision 1.32.2.11
  diff -u -r1.32.2.10 -r1.32.2.11
  --- ObjectEnvelopeTable.java	13 Mar 2005 03:53:30 -0000	1.32.2.10
  +++ ObjectEnvelopeTable.java	18 Mar 2005 19:25:06 -0000	1.32.2.11
  @@ -34,6 +34,7 @@
   import org.apache.ojb.broker.core.proxy.CollectionProxy;
   import org.apache.ojb.broker.core.proxy.IndirectionHandler;
   import org.apache.ojb.broker.core.proxy.ProxyHelper;
  +import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.CollectionDescriptor;
   import org.apache.ojb.broker.metadata.FieldDescriptor;
  @@ -65,6 +66,18 @@
       private TransactionImpl transaction;
   
       /**
  +     * A list of {@link org.apache.ojb.broker.Identity} objects which are
  +     * new associated with an object and should be protected from being marked
  +     * as "delete". E.g. if a collection reference C is moved from object A1 to A2,
  +     * then A1 wants to "delete" C and A2 wants to mark the new C object as "new".
  +     */
  +    private List newAssociatedIdentites = new ArrayList();
  +    private List m2nLinkList = new ArrayList();
  +    private List m2nUnlinkList = new ArrayList();
  +    private List markedForDeletionList = new ArrayList();
  +    private List markedForInsertList = new ArrayList();
  +
  +    /**
        * the internal table mapping Objects to their ObjectTransactionWrappers
        */
       private Map mhtObjectEnvelopes = new HashMap();
  @@ -101,13 +114,26 @@
       {
           needsCommit = false;
           mhtObjectEnvelopes = new HashMap();
  -        mvOrderOfIds.clear();
  +        mvOrderOfIds = new ArrayList();
  +        afterWriteCleanup();
  +    }
  +
  +    void afterWriteCleanup()
  +    {
  +        m2nLinkList.clear();
  +        m2nUnlinkList.clear();
  +        newAssociatedIdentites.clear();
  +        markedForDeletionList.clear();
  +        markedForInsertList.clear();
       }
   
       /**
  -     * perform commit on all tx-states
  +     * Perform write to DB on all registered object wrapper ({@link ObjectEnvelope})
  +     *
  +     * @param needsReusePrepare When all registered objects be re-used after writing to
  +     * DB set <em>true</em>, else set <em>false</em> to improve performance.
        */
  -    public void commit() throws TransactionAbortedException, LockNotGrantedException
  +    public void writeObjects(boolean needsReusePrepare) throws TransactionAbortedException, LockNotGrantedException
       {
           PersistenceBroker broker = transaction.getBroker();
           ConnectionManagerIF connMan = broker.serviceConnectionManager();
  @@ -138,23 +164,32 @@
               // 0. turn on the batch mode
               connMan.setBatchMode(true);
   
  -            // 0.5 mark objects no longer available in collection for delete
  +            // 1. mark objects no longer available in collection
  +            // for delete and add new found objects
               checkAllEnvelopes(broker);
   
  -            // 1. upgrade implicit locks.
  +            // 2. mark all dependend objects for cascading insert/delete
  +            cascadingDependents();
  +            // clear list of new associated objects, TODO: is this needed here?
  +            newAssociatedIdentites.clear();
  +
  +            // 3. upgrade implicit locks.
               upgradeImplicitLocksAndCheckIfCommitIsNeeded();
   
  -            // 2. Reorder objects
  +            // 4. Reorder objects
               reorder();
   
  -            // 3. commit objects.
  -            commitAllEnvelopes(broker);
  +            // 5. write objects.
  +            writeAllEnvelopes(broker);
   
  -            // 4. execute batch
  +            // 6. execute batch
               connMan.executeBatch();
   
  -            // 5.Update all Envelopes to new CleanState
  -            setCleanState();
  +            // 7. Update all Envelopes to new CleanState
  +            cleanupEnvelopes(needsReusePrepare);
  +
  +            // 6. commit cleanup
  +            afterWriteCleanup();
   
           }
           catch (Exception e)
  @@ -190,10 +225,13 @@
        * commit all envelopes against the current broker
        * @param broker the PB to persist all objects
        */
  -    private void commitAllEnvelopes(PersistenceBroker broker)
  +    private void writeAllEnvelopes(PersistenceBroker broker)
       {
           if (needsCommit)
           {
  +            // remove m:n indirection table entries first
  +            performM2NUnlinkEntries();
  +
               Iterator iter;
               // using clone to avoid ConcurentModificationException
               iter = ((List) mvOrderOfIds.clone()).iterator();
  @@ -209,6 +247,17 @@
                   mod.getModificationState().commit(mod);
                   assignCollectionFKs(broker, broker.getClassDescriptor(mod.getObject().getClass()), mod.getObject());
               }
  +
  +            // add m:n indirection table entries
  +            performM2NLinkEntries();
  +        }
  +        // if no objects changed, perform only the m:n stuff
  +        else
  +        {
  +            // remove m:n indirection table entries first
  +            performM2NUnlinkEntries();
  +            // add m:n indirection table entries
  +            performM2NLinkEntries();
           }
       }
   
  @@ -222,7 +271,7 @@
           while (iter.hasNext())
           {
               ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next());
  -            mod.markCollectionElements(broker);
  +            mod.markReferenceElements(broker);
           }
       }
   
  @@ -351,24 +400,25 @@
           }
       }
   
  -
   	/**
   	 *
   	 */
  -	private void setCleanState()
  +	private void cleanupEnvelopes(boolean needsReusePrepare)
   	{
  -          Iterator iter;
  -          // using clone to avoid ConcurentModificationException
  -          iter = ((List) mvOrderOfIds.clone()).iterator();
  -          while (iter.hasNext())
  -          {
  -                ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next());
  -                mod.refreshObjectImage();
  -                if(needsCommit && mod.getModificationState() != StateOldClean.getInstance())
  -                {
  -                    mod.setModificationState(StateOldClean.getInstance());
  -                }
  -          }
  +        // if we don't re-use ObjectEnvelope entries, don't cleanup
  +        if(!needsReusePrepare) return;
  +
  +        // using clone to avoid ConcurentModificationException
  +        Iterator iter = ((List) mvOrderOfIds.clone()).iterator();
  +        while (iter.hasNext())
  +        {
  +            ObjectEnvelope mod = (ObjectEnvelope) mhtObjectEnvelopes.get(iter.next());
  +            mod.refreshObjectImage();
  +            if(needsCommit && mod.getModificationState() != StateOldClean.getInstance())
  +            {
  +                mod.setModificationState(mod.getModificationState().markClean());
  +            }
  +        }
   	}
   
       /**
  @@ -400,7 +450,7 @@
   					if (useImplicitLocking)
   					{
   						// implicitely acquire a write lock !
  -						transaction.lock(mod.getObject(), Transaction.UPGRADE);
  +						transaction.lock(mod.getObject(), Transaction.WRITE);
   						// objects needs commit action, thus set markDirty to true:
   						markDirty = true;
   					}
  @@ -454,6 +504,7 @@
           {
               needsCommit = false;
           }
  +        afterWriteCleanup();
       }
   
       /**
  @@ -584,4 +635,336 @@
           return config;
       }
   
  +    void cascadingDependents()
  +    {
  +        Iterator it = mhtObjectEnvelopes.values().iterator();
  +        ObjectEnvelope mod;
  +        // first we search for all deleted/insert objects
  +        while(it.hasNext())
  +        {
  +            mod =  (ObjectEnvelope) it.next();
  +            if(mod.needsDelete())
  +            {
  +                addForDeletionDependent(mod);
  +            }
  +            if(mod.needsInsert())
  +            {
  +                addForInsertDependent(mod);
  +            }
  +        }
  +        // then start cascade work
  +        cascadeMarkedForDeletion();
  +        cascadeMarkedForInsert();
  +    }
  +
  +    void addNewAssociatedIdentity(Identity oid)
  +    {
  +        newAssociatedIdentites.add(oid);
  +    }
  +
  +    boolean isNewAssociatedObject(Identity oid)
  +    {
  +        return newAssociatedIdentites.contains(oid);
  +    }
  +
  +    void addForInsertDependent(ObjectEnvelope mod)
  +    {
  +        markedForInsertList.add(mod);
  +    }
  +
  +    private void cascadeMarkedForInsert()
  +    {
  +        List alreadyPrepared = new ArrayList();
  +        for(int i = 0; i < markedForInsertList.size(); i++)
  +        {
  +            ObjectEnvelope mod =  (ObjectEnvelope) markedForInsertList.get(i);
  +            // only if a new object was found we cascade to register the dependent objects
  +            if(mod.needsInsert())
  +            {
  +                cascadeInsertFor(mod, alreadyPrepared);
  +            }
  +        }
  +        markedForInsertList.clear();
  +    }
  +
  +    private void cascadeInsertFor(ObjectEnvelope mod, List alreadyPrepared)
  +    {
  +        if(mod == null || alreadyPrepared == null)
  +        {
  +            System.out.println("#### mod=" + mod + ", list="+alreadyPrepared);
  +            try{throw new Exception();}catch(Exception e)
  +            {
  +            e.printStackTrace();
  +            }
  +        }
  +        // avoid endless recursion
  +        if(alreadyPrepared.contains(mod.getIdentity())) return;
  +
  +        alreadyPrepared.add(mod.getIdentity());
  +
  +        ClassDescriptor cld = getTransaction().getBroker().getClassDescriptor(mod.getObject().getClass());
  +
  +        List refs = cld.getObjectReferenceDescriptors();
  +        cascadeInsertSingleReferences(mod, refs, alreadyPrepared);
  +
  +        List colls = cld.getCollectionDescriptors();
  +        cascadeInsertCollectionReferences(mod, colls, alreadyPrepared);
  +    }
  +
  +    private void cascadeInsertSingleReferences(ObjectEnvelope source, List descriptor, List alreadyPrepared)
  +    {
  +        for(int i = 0; i < descriptor.size(); i++)
  +        {
  +            ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descriptor.get(i);
  +            Object depObj = ord.getPersistentField().get(source.getObject());
  +            if(depObj != null && ProxyHelper.isMaterialized(depObj))
  +            {
  +                Identity oid = getTransaction().getBroker().serviceIdentity().buildIdentity(depObj);
  +                if(true || !alreadyPrepared.contains(oid))
  +                {
  +                    ObjectEnvelope depMod = getByIdentity(oid);
  +                    // if the object isn't registered, do so
  +                    // else we have nothing to do
  +                    if(depMod == null)
  +                    {
  +                        getTransaction().lock(depObj, Transaction.WRITE);
  +                        depMod = getByIdentity(oid);
  +                    }
  +                    if(depMod == null)
  +                    {
  +                        // should never occur
  +                        throw new RuntimeException("Unexpected behavior");
  +                    }
  +                    cascadeInsertFor(depMod, alreadyPrepared);
  +                }
  +            }
  +        }
  +    }
  +
  +    private void cascadeInsertCollectionReferences(ObjectEnvelope source, List descriptor, List alreadyPrepared)
  +    {
  +        PersistenceBroker pb = getTransaction().getBroker();
  +        for(int i = 0; i < descriptor.size(); i++)
  +        {
  +            CollectionDescriptor col = (CollectionDescriptor) descriptor.get(i);
  +            Object collOrArray = col.getPersistentField().get(source.getObject());
  +            CollectionProxy proxy = ProxyHelper.getCollectionProxy(collOrArray);
  +            // on insert we perform only materialized collection objects
  +            if(proxy == null && collOrArray != null)
  +            {
  +                Iterator it = BrokerHelper.getCollectionIterator(collOrArray);
  +                while(it.hasNext())
  +                {
  +                    Object colObj =  it.next();
  +                    if(colObj != null)
  +                    {
  +                        Identity oid = pb.serviceIdentity().buildIdentity(colObj);
  +                        if(true || !alreadyPrepared.contains(oid))
  +                        {
  +                            ObjectEnvelope oe = getByIdentity(oid);
  +                            // found a unregistered object, register it
  +                            if(oe == null)
  +                            {
  +                                getTransaction().lock(colObj, Transaction.WRITE);
  +                                oe = getByIdentity(oid);
  +                            }
  +                            /*
  +                            the ObjectEnvelope can be still 'null', because unmaterialized proxy objects
  +                            will not be added to ObjectEnvelopeTable, not until the object materialize
  +
  +                            arminw:
  +                            TODO: what is the valid way to go, when the collection object itself is
  +                            a unmaterialized proxy object. Think in this case we should materialize the
  +                            object when the main object needs insert, because we have to assign the FK values
  +                            to the main object
  +                            */
  +                            // check if the collection reference object is materialized
  +                            boolean isMaterialized = ProxyHelper.isMaterialized(colObj);
  +                            if(source.needsInsert() && !isMaterialized)
  +                            {
  +                                colObj = ProxyHelper.getRealObject(colObj);
  +                                isMaterialized = true;
  +                            }
  +                            if(col.isMtoNRelation() && isMaterialized && oe.needsInsert())
  +                            {
  +                                addM2NLinkEntry(col, source.getObject(), colObj);
  +                            }
  +                            if(isMaterialized)
  +                            {
  +                                cascadeInsertFor(oe, alreadyPrepared);
  +                            }
  +                        }
  +                    }
  +                }
  +            }
  +        }
  +    }
  +
  +    void addForDeletionDependent(ObjectEnvelope mod)
  +    {
  +        markedForDeletionList.add(mod);
  +    }
  +
  +    private void cascadeMarkedForDeletion()
  +    {
  +        List alreadyPrepared = new ArrayList();
  +        for(int i = 0; i < markedForDeletionList.size(); i++)
  +        {
  +            ObjectEnvelope mod =  (ObjectEnvelope) markedForDeletionList.get(i);
  +            // if the object wasn't associated with another object, start cascade delete
  +            if(!isNewAssociatedObject(mod.getIdentity()))
  +            {
  +                cascadeDeleteFor(mod, alreadyPrepared);
  +            }
  +        }
  +        markedForDeletionList.clear();
  +    }
  +
  +    private void cascadeDeleteFor(ObjectEnvelope mod, List alreadyPrepared)
  +    {
  +        // avoid endless recursion
  +        if(alreadyPrepared.contains(mod.getIdentity())) return;
  +
  +        alreadyPrepared.add(mod.getIdentity());
  +
  +        ClassDescriptor cld = getTransaction().getBroker().getClassDescriptor(mod.getObject().getClass());
  +
  +        List refs = cld.getObjectReferenceDescriptors();
  +        cascadeDeleteSingleReferences(mod, refs, alreadyPrepared);
  +
  +        List colls = cld.getCollectionDescriptors();
  +        cascadeDeleteCollectionReferences(mod, colls, alreadyPrepared);
  +    }
  +
  +    private void cascadeDeleteSingleReferences(ObjectEnvelope source, List descriptor, List alreadyPrepared)
  +    {
  +        for(int i = 0; i < descriptor.size(); i++)
  +        {
  +            ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descriptor.get(i);
  +            if(getTransaction().cascadeDeleteFor(ord))
  +            {
  +                Object depObj = ord.getPersistentField().get(source.getObject());
  +                Identity oid = getTransaction().getBroker().serviceIdentity().buildIdentity(depObj);
  +                // if(!isNewAssociatedObject(oid) && !alreadyPrepared.contains(oid))
  +                if(!isNewAssociatedObject(oid))
  +                {
  +                    ObjectEnvelope depMod = get(oid, depObj, false);
  +                    depMod.setModificationState(depMod.getModificationState().markDelete());
  +                    cascadeDeleteFor(depMod, alreadyPrepared);
  +                }
  +            }
  +        }
  +    }
  +
  +    private void cascadeDeleteCollectionReferences(ObjectEnvelope source, List descriptor, List alreadyPrepared)
  +    {
  +        PersistenceBroker pb = getTransaction().getBroker();
  +        for(int i = 0; i < descriptor.size(); i++)
  +        {
  +            CollectionDescriptor col = (CollectionDescriptor) descriptor.get(i);
  +            boolean cascadeDelete = getTransaction().cascadeDeleteFor(col);
  +            Object collOrArray = col.getPersistentField().get(source.getObject());
  +            // TODO: remove cast
  +            CollectionProxyDefaultImpl proxy = (CollectionProxyDefaultImpl) ProxyHelper.getCollectionProxy(collOrArray);
  +            // on delete we have to materialize dependent objects
  +            if(proxy != null)
  +            {
  +                collOrArray = proxy.getData();
  +            }
  +            if(collOrArray != null)
  +            {
  +                Iterator it = BrokerHelper.getCollectionIterator(collOrArray);
  +                while(it.hasNext())
  +                {
  +                    Object colObj =  ProxyHelper.getRealObject(it.next());
  +                    Identity oid = pb.serviceIdentity().buildIdentity(colObj);
  +                    ObjectEnvelope colMod = get(oid, colObj, false);
  +                    if(cascadeDelete)
  +                    {
  +                        colMod.setModificationState(colMod.getModificationState().markDelete());
  +                        cascadeDeleteFor(colMod, alreadyPrepared);
  +                    }
  +                    else
  +                    {
  +                        if(!col.isMtoNRelation())
  +                        {
  +                            pb.serviceBrokerHelper().unlink(source.getObject(), col, colObj);
  +                            colMod.setModificationState(colMod.getModificationState().markDirty());
  +                        }
  +                    }
  +                    if(col.isMtoNRelation())
  +                    {
  +                        addM2NUnlinkEntry(col, source.getObject(), colObj);
  +                    }
  +                }
  +            }
  +        }
  +    }
  +
  +    void addM2NLinkEntry(CollectionDescriptor cld, Object leftSource, Object rightSource)
  +    {
  +        m2nLinkList.add(new M2NLinkEntry(cld, leftSource, rightSource));
  +    }
  +
  +    void performM2NLinkEntries()
  +    {
  +        PersistenceBroker broker = getTransaction().getBroker();
  +        M2NLinkEntry entry = null;
  +        for(int i = 0; i < m2nLinkList.size(); i++)
  +        {
  +            entry = (M2NLinkEntry) m2nLinkList.get(i);
  +            broker.serviceBrokerHelper().link(entry.leftSource, entry.cld, entry.rightSource);
  +        }
  +    }
  +
  +    void addM2NUnlinkEntry(CollectionDescriptor cld, Object leftSource, Object rightSource)
  +    {
  +        m2nUnlinkList.add(new M2NUnlinkEntry(cld, leftSource, rightSource));
  +    }
  +
  +    void performM2NUnlinkEntries()
  +    {
  +        PersistenceBroker broker = getTransaction().getBroker();
  +        M2NUnlinkEntry entry;
  +        for(int i = 0; i < m2nUnlinkList.size(); i++)
  +        {
  +            entry = (M2NUnlinkEntry) m2nUnlinkList.get(i);
  +            broker.serviceBrokerHelper().unlink(entry.leftSource, entry.cld, entry.rightSource);
  +        }
  +    }
  +
  +    //==============================================
  +    // inner class
  +    //==============================================
  +    static class M2NLinkEntry
  +    {
  +        CollectionDescriptor cld;
  +        Object leftSource;
  +        Object rightSource;
  +
  +        public M2NLinkEntry(CollectionDescriptor cld, Object leftSource, Object rightSource)
  +        {
  +            this.cld = cld;
  +            this.leftSource = leftSource;
  +            this.rightSource = rightSource;
  +        }
  +
  +        public String toString()
  +        {
  +            return new ToStringBuilder(this)
  +                    .append("cld", cld)
  +                    .append("leftObj", leftSource)
  +                    .append("rightObj", rightSource)
  +                    .toString();
  +        }
  +    }
  +
  +    static class M2NUnlinkEntry extends M2NLinkEntry
  +    {
  +        public M2NUnlinkEntry(CollectionDescriptor cld, Object leftSource, Object rightSource)
  +        {
  +            super(cld, leftSource, rightSource);
  +        }
  +    }
  +
   }
  \ No newline at end of file
  
  
  
  1.4.2.1   +19 -0     db-ojb/src/java/org/apache/ojb/odmg/TransactionExt.java
  
  Index: TransactionExt.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/odmg/TransactionExt.java,v
  retrieving revision 1.4
  retrieving revision 1.4.2.1
  diff -u -r1.4 -r1.4.2.1
  --- TransactionExt.java	4 Apr 2004 23:53:39 -0000	1.4
  +++ TransactionExt.java	18 Mar 2005 19:25:06 -0000	1.4.2.1
  @@ -57,4 +57,23 @@
        *        if false, implicit locking is disabled.
        **/
       public void setImplicitLocking(boolean value);
  +
  +    /**
  +     * Allows to change the <em>cascading delete</em> behavior of the specified reference
  +     * of the target class while this transaction is in use.
  +     *
  +     * @param target The class to change cascading delete behavior of the references.
  +     * @param referenceField The field name of the 1:1, 1:n or 1:n reference.
  +     * @param doCascade If <em>true</em> cascading delete is enabled, <em>false</em> disabled.
  +     */
  +    public void setCascadingDelete(Class target, String referenceField, boolean doCascade);
  +
  +    /**
  +     * Allows to change the <em>cascading delete</em> behavior of all references of the
  +     * specified class while this transaction is in use.
  +     *
  +     * @param target The class to change cascading delete behavior of all references.
  +     * @param doCascade If <em>true</em> cascading delete is enabled, <em>false</em> disabled.
  +     */
  +    public void setCascadingDelete(Class target, boolean doCascade);
   }
  
  
  
  1.59.2.9  +138 -10   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.8
  retrieving revision 1.59.2.9
  diff -u -r1.59.2.8 -r1.59.2.9
  --- TransactionImpl.java	19 Dec 2004 14:03:52 -0000	1.59.2.8
  +++ TransactionImpl.java	18 Mar 2005 19:25:06 -0000	1.59.2.9
  @@ -21,6 +21,8 @@
   import java.util.Enumeration;
   import java.util.Hashtable;
   import java.util.Iterator;
  +import java.util.HashMap;
  +import java.util.List;
   
   import org.apache.commons.lang.SystemUtils;
   import org.apache.ojb.broker.Identity;
  @@ -28,6 +30,7 @@
   import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.broker.PersistenceBrokerException;
   import org.apache.ojb.broker.PersistenceBrokerFactory;
  +import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.core.proxy.CollectionProxy;
   import org.apache.ojb.broker.core.proxy.CollectionProxyDefaultImpl;
   import org.apache.ojb.broker.core.proxy.CollectionProxyListener;
  @@ -312,7 +315,7 @@
        * I don't know what we should do if we are in a checkpoint and
        * we need to abort.
        */
  -    protected synchronized void doWriteObjects() throws TransactionAbortedException, LockNotGrantedException
  +    protected synchronized void doWriteObjects(boolean isFlush) throws TransactionAbortedException, LockNotGrantedException
       {
           /*
           arminw:
  @@ -328,7 +331,7 @@
           performTransactionAwareBeforeCommit();
   
           // Now perfom the real work
  -        objectEnvelopeTable.commit();
  +        objectEnvelopeTable.writeObjects(isFlush);
       }
   
       /**
  @@ -437,7 +440,7 @@
           try
           {
               checkOpen();
  -            doWriteObjects();
  +            doWriteObjects(true);
               // do commit on PB
               if (hasBroker() && broker.isInTransaction()) broker.commitTransaction();
           }
  @@ -470,7 +473,7 @@
           try
           {
               checkOpen();
  -            doWriteObjects();
  +            doWriteObjects(true);
           }
           catch (Throwable t)
           {
  @@ -494,6 +497,8 @@
       public void markDelete(Object anObject)
       {
           ObjectEnvelope otw = objectEnvelopeTable.get(anObject, false);
  +        // not needed on delete - or?
  +        //otw.refreshObjectIfNeeded(anObject);
           otw.setModificationState(otw.getModificationState().markDelete());
       }
   
  @@ -564,7 +569,7 @@
           checkOpen();
           try
           {
  -            prepare();
  +            prepareCommit();
               checkForCommit();
   
               txStatus = Status.STATUS_COMMITTING;
  @@ -615,7 +620,7 @@
        *  not in the proper state to perform this operation
        * @throws TransactionNotInProgressException if the transaction is closed.
        */
  -    protected void prepare() throws TransactionAbortedException, LockNotGrantedException
  +    protected void prepareCommit() throws TransactionAbortedException, LockNotGrantedException
       {
           if (txStatus == Status.STATUS_MARKED_ROLLBACK)
           {
  @@ -628,7 +633,7 @@
           try
           {
               txStatus = Status.STATUS_PREPARING;
  -            doWriteObjects();
  +            doWriteObjects(false);
               txStatus = Status.STATUS_PREPARED;
           }
           catch (RuntimeException e)
  @@ -1047,7 +1052,9 @@
           // we have to loop through this vector to avoid index proplems.
           for (int i = registeredIndirectionHandlers.size() - 1; i >= 0; i--)
           {
  -            unregisterFromIndirectionHandler((IndirectionHandler) registeredIndirectionHandlers.get(i));
  +            // we can't use unregister method, because it remove the handler too, so
  +            // make direct call
  +            ((IndirectionHandler) registeredIndirectionHandlers.get(i)).removeListener(this);
           }
       }
   
  @@ -1055,7 +1062,9 @@
       {
           for (int i = registeredCollectionProxies.size() - 1; i >= 0; i--)
           {
  -            unregisterFromCollectionProxy((CollectionProxy) registeredCollectionProxies.get(i));
  +            // we can't use unregister method, because it remove the handler too, so
  +            // make direct call
  +            ((CollectionProxy) registeredCollectionProxies.get(i)).removeListener(this);
           }
       }
   
  @@ -1252,4 +1261,123 @@
                       " - exception will be skipped.", e);
           }
       }
  +
  +    /**
  +     * Allows to change the <em>cascading delete</em> behavior of the specified reference
  +     * of the target class while this transaction is in use.
  +     *
  +     * @param target The class to change cascading delete behavior of the references.
  +     * @param referenceField The field name of the 1:1, 1:n or 1:n reference.
  +     * @param doCascade If <em>true</em> cascading delete is enabled, <em>false</em> disabled.
  +     */
  +    public void setCascadingDelete(Class target, String referenceField, boolean doCascade)
  +    {
  +        ClassDescriptor cld = getBroker().getClassDescriptor(target);
  +        ObjectReferenceDescriptor ord = cld.getObjectReferenceDescriptorByName(referenceField);
  +        if(ord == null)
  +        {
  +            ord = cld.getCollectionDescriptorByName(referenceField);
  +        }
  +        if(ord == null)
  +        {
  +            throw new CascadeSettingException("Invalid reference field name '" + referenceField
  +                    + "', can't find 1:1, 1:n or m:n relation with that name in " + target);
  +        }
  +        runtimeCascadeDeleteMap.put(ord, (doCascade ? Boolean.TRUE : Boolean.FALSE));
  +    }
  +
  +    /**
  +     * Allows to change the <em>cascading delete</em> behavior of all references of the
  +     * specified class while this transaction is in use.
  +     *
  +     * @param target The class to change cascading delete behavior of all references.
  +     * @param doCascade If <em>true</em> cascading delete is enabled, <em>false</em> disabled.
  +     */
  +    public void setCascadingDelete(Class target, boolean doCascade)
  +    {
  +        ClassDescriptor cld = getBroker().getClassDescriptor(target);
  +        Boolean result = doCascade ? Boolean.TRUE : Boolean.FALSE;
  +        List singleRefs = cld.getObjectReferenceDescriptors();
  +        for(int i = 0; i < singleRefs.size(); i++)
  +        {
  +            Object o = singleRefs.get(i);
  +            runtimeCascadeDeleteMap.put(o, result);
  +        }
  +        List collectionRefs = cld.getCollectionDescriptors();
  +        for(int i = 0; i < collectionRefs.size(); i++)
  +        {
  +            Object o =  collectionRefs.get(i);
  +            runtimeCascadeDeleteMap.put(o, result);
  +        }
  +    }
  +
  +    private HashMap runtimeCascadeDeleteMap = new HashMap();
  +    /**
  +     * Returns <em>true</em> if cascading delete is enabled for the specified
  +     * single or collection descriptor.
  +     */
  +    protected boolean cascadeDeleteFor(ObjectReferenceDescriptor ord)
  +    {
  +        boolean result = false;
  +        Boolean runtimeSetting = (Boolean) runtimeCascadeDeleteMap.get(ord);
  +//        ord.setCascadingStore(ObjectReferenceDescriptor.CASCADE_NONE);
  +//        ord.setCascadingDelete(ObjectReferenceDescriptor.CASCADE_NONE);
  +        if(runtimeSetting == null)
  +        {
  +            if(ord instanceof CollectionDescriptor)
  +            {
  +                CollectionDescriptor cds = (CollectionDescriptor) ord;
  +//                if(cds.isMtoNRelation())
  +//                {
  +//                    ord.setCascadingStore(ObjectReferenceDescriptor.CASCADE_NONE);
  +//                    ord.setCascadingDelete(ObjectReferenceDescriptor.CASCADE_NONE);
  +//                }
  +                if(cds.isMtoNRelation())
  +                {
  +                    result = implementation.cascadingDeleteMtoN;
  +                }
  +                else
  +                {
  +                    result = implementation.cascadingDeleteOnetoN;
  +                }
  +            }
  +            else
  +            {
  +                result = implementation.cascadingDeleteOnetoOne;
  +            }
  +        }
  +        else
  +        {
  +            result = runtimeSetting.booleanValue();
  +        }
  +        return result;
  +    }
  +
  +    //============================================================
  +    // inner class
  +    //============================================================
  +    /**
  +     * This was thrown when something wrong with the cascading delete setting.
  +     */
  +    static class CascadeSettingException extends OJBRuntimeException
  +    {
  +        public CascadeSettingException()
  +        {
  +        }
  +
  +        public CascadeSettingException(String msg)
  +        {
  +            super(msg);
  +        }
  +
  +        public CascadeSettingException(Throwable cause)
  +        {
  +            super(cause);
  +        }
  +
  +        public CascadeSettingException(String msg, Throwable cause)
  +        {
  +            super(msg, cause);
  +        }
  +    }
   }
  
  
  
  No                   revision
  No                   revision
  1.54.2.36 +24 -17    db-ojb/release-notes.txt
  
  Index: release-notes.txt
  ===================================================================
  RCS file: /home/cvs/db-ojb/release-notes.txt,v
  retrieving revision 1.54.2.35
  retrieving revision 1.54.2.36
  diff -u -r1.54.2.35 -r1.54.2.36
  --- release-notes.txt	16 Mar 2005 17:51:18 -0000	1.54.2.35
  +++ release-notes.txt	18 Mar 2005 19:25:06 -0000	1.54.2.36
  @@ -24,6 +24,9 @@
     removed and OracleConnection unwrapping have been adjusted to be compatible with 10g JDBC.
   
   NOTES:
  +- ODMG-api refactoring. All known issues in test suite are fixed. But the refactored odmg-api
  +  version needs changes in auto-xxx settings in metadata and changed OJB.properties settings.
  +  Please read carefully the 'CHANGES notes' below.
   - Don't forget to replace the old repository.dtd and OJB.properties file (both files changed).
   - If you plan to use OJB with an J2SE version older than 1.4, then you have to
     replace the Geronimo jars with the corresponding ones from Sun's J2EE SDK. This
  @@ -81,6 +84,9 @@
     will be handled by OJB in same way as without usage of database identity column.
   - odmg-api: Introduced new object reordering implementation (replaces old algorithm
     in ObjectEnvelopeTable).
  +- odmg-api: Change used 'OqlCollectionClass' in OJB.properties from a DList impl to ArrayList impl
  +  to improve performance. If you need the additional features of odmg DList comment in the DList impl.
  +- odmg-api: All m:n relations need auto-update/delete setting 'none' to proper work.
   
   BUG FIXES:
   Please refer to our Bug tracking site (http://issues.apache.org/scarab/servlet/scarab/)
  @@ -125,31 +131,32 @@
     were locked.
   - odmg-api: Mixing of pessimistic and optimistic locking should be possible. Now all lock calls on objects
     with optimistic locking enabled will be ignored.
  +- odmg-api: Fixed: If a user exchange already existing objects in 1:n references without changing the size
  +  of the collection, the main object will not become dirty and the FK values of the exchanged objects
  +  will not be updated. This is fixed.
  +- odmg-api: Fixed: Creation of m:n relation only works when objects created step by step (or use PB-api
  +  as workaround), persist a whole object graph seems not to work proper. This is fixed.
  +
   
   KNOWN ISSUES:
  -- odmg-api: If a user exchange already existing objects in 1:n references without changing the size
  -  of the collection, the main object will not become dirty and the FK values of the exchanged objects
  -  will not be updated.
  -  E.g. two objects obj_1 anf obj_2 with 1:n reference to ref objects, each with one
  -  existing/persistent reference object, obj_1{ref_1} and obj_2{ref_2}.
  -  Lock objects and exchange the references in collection obj_1{ref_2}
  -  and obj_2{ref_1} and commit --> FK values of ref_1 and ref_2 will not be updated.
  -- odmg-api: Creation of m:n relation only works when objects created step by step (or use PB-api
  -  as workaround), persist a whole object graph seems not to work proper.
  +- Auto-Detection for insert/update objects checks to avoid DB queries the PK fields of the object.
  +  If at least one PK field is 'NULL' or if primitive field '0', OJB assume the object is new and
  +  needs insert. This will be configurable in next upcoming version. Workaround for PB-api: use method
  +  PB#store(Object obj, ObjectModification mod) to state update or insert.
   - Batch handling doesn't work proper with optimistic locking. This will be fixed
     in version 1.1
   - Subqueries are not extent aware. see QueryTest#testSubQueryAgainstExtents
  -- odmg-api: Mapping classes on multiple joined tables was not supported in
  -  ODMG-API implementation (PB-api support this kind of inheritance).
   - When a class mapped on multiple joined tables was used in a reference only objects
  -  of the base type class will be instantiated, e.g. a Company class with
  -  a 1:n reference 'employees' to base class Employee and class Manager extends Employee,
  +  of the base type class will be instantiated, e.g. a Company class has
  +  a 1:n reference 'employees' to a base class Employee and class Manager extends Employee,
     then 'employees' only contains objects of type Employee even if the real type was Manager.
     See in OJB test suite ...broker.InheritanceMultipleTableTest#testInheritancedObjectsInCollectionReferences
   - Managed Environment: When run OJB in managed environment and using PBStateListener, the call of
  -  PBStateListener#beforeClose(PBStateEvent event) is made twice (will be fixed in OJB 1.1) when
  -  a PB instance was closed in a JTA-tx (for the first time when PB.close() was called in bean, second
  -  time when the JTA-tx completes)
  +  PBStateListener#beforeClose(PBStateEvent event) is made twice when
  +  a PB instance was closed in a JTA-tx (for the first time when PB.close() was called in bean on the PB handle
  +  , second time when the JTA-tx completes)
  +- odmg-api: Mapping classes on multiple joined tables was not supported in
  +  ODMG-API implementation (PB-api support this kind of inheritance with restrictions - see known issues).
   - otm-api: The OTM API has a known caching issue and should not be considered for code used
     in production environments. The future of the OTM layer will be subject for discussion on the
     OJB developers list, if you are using it - please subscribe to ojb-dev and make your voice heard.
  
  
  

---------------------------------------------------------------------
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