You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ol...@apache.org on 2003/06/09 20:55:27 UTC

cvs commit: db-ojb/src/java/org/apache/ojb/otm/states Hollow.java Transient.java

olegnitz    2003/06/09 11:55:26

  Modified:    src/java/org/apache/ojb/otm EditingContext.java
                        OTMConnection.java OTMKit.java
               src/java/org/apache/ojb/otm/cache/store
                        HashMapObjectStore.java ObjectStore.java
               src/java/org/apache/ojb/otm/core BaseConnection.java
                        ConcreteEditingContext.java RequestContext.java
                        Transaction.java TransactionAbortedException.java
               src/java/org/apache/ojb/otm/kit SimpleKit.java
               src/java/org/apache/ojb/otm/lock IsolationFactory.java
                        LockManager.java
               src/java/org/apache/ojb/otm/states Hollow.java
                        Transient.java
  Log:
  Changes to the locking/updating semantics: read lock is treated as optimistic lock,
  it will be upgraded to write lock during commit if the object appears to be modified;
  only modified objects are updated in the database.
  Read or write lock of some object causes the automatic read lock for all related objects.
  
  Revision  Changes    Path
  1.5       +3 -2      db-ojb/src/java/org/apache/ojb/otm/EditingContext.java
  
  Index: EditingContext.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/EditingContext.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- EditingContext.java	25 May 2003 20:58:33 -0000	1.4
  +++ EditingContext.java	9 Jun 2003 18:55:26 -0000	1.5
  @@ -55,6 +55,7 @@
    */
   
   import org.apache.ojb.broker.Identity;
  +import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.otm.lock.LockingException;
   
   /**
  @@ -74,7 +75,7 @@
        *
        * Insert the given object into the EditingContext, acquiring the specified lock.
        *
  -     * @param conn                  the current OTMConnection
  +     * @param pb                    the current PersistentBroker
        * @param oid                   the identity of the object to be inserted
        * @param object                the object to insert
        * @param lock                  the lock to be acquired.
  @@ -82,7 +83,7 @@
        *                              could be re-attempted if the lock fails.
        *
        */
  -    public void insert (OTMConnection conn, Identity oid, Object object, int lock)
  +    public void insert (PersistenceBroker pb, Identity oid, Object object, int lock)
               throws LockingException;
   
       /**
  
  
  
  1.4       +11 -11    db-ojb/src/java/org/apache/ojb/otm/OTMConnection.java
  
  Index: OTMConnection.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/OTMConnection.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- OTMConnection.java	16 Mar 2003 18:13:06 -0000	1.3
  +++ OTMConnection.java	9 Jun 2003 18:55:26 -0000	1.4
  @@ -72,16 +72,16 @@
        *
        *
        */
  -    public void invalidate (Identity oid);
  +    public void invalidate(Identity oid);
   
       /**
  -     * 
  +     *
        *  Make the given object persistent by inserting it into the database.
        *
        *  @param object       the object to be made persistent
        *
        */
  -    public void makePersistent (Object object)
  +    public void makePersistent(Object object)
           throws LockingException;
   
       /**
  @@ -92,7 +92,7 @@
        *  @param obj      the object to delete
        *
        */
  -    public void deletePersistent (Object obj)
  +    public void deletePersistent(Object obj)
           throws LockingException;
   
       /**
  @@ -103,7 +103,7 @@
        *  @param object       the object to be locked for write.
        *
        */
  -    public void lockForWrite (Object object)
  +    public void lockForWrite(Object object)
           throws LockingException;
   
       /**
  @@ -117,7 +117,7 @@
        *                              re-submitted.
        *
        */
  -    public Object getObjectByIdentity (Identity oid)
  +    public Object getObjectByIdentity(Identity oid)
           throws LockingException;
   
       /**
  @@ -130,17 +130,17 @@
        * @throws LockingException     thrown by the LockManager to avoid a deadlock.
        *
        */
  -    public Object getObjectByIdentity (Identity oid, int lock)
  +    public Object getObjectByIdentity(Identity oid, int lock)
           throws LockingException;
  -    
  +
       /**
        * Get the identity of the object
        * @param object The object
        * @return the identity of the object
        */
  -    public Identity getIdentity (Object object);
  +    public Identity getIdentity(Object object);
   
  -    public ClassDescriptor getDescriptorFor (Class clazz);
  +    public ClassDescriptor getDescriptorFor(Class clazz);
   
       /**
        *
  @@ -151,5 +151,5 @@
        *  @return                     EditingContext associated with current Transaction
        *
        */
  -    public EditingContext getEditingContext ();
  +    public EditingContext getEditingContext();
   }
  
  
  
  1.5       +17 -12    db-ojb/src/java/org/apache/ojb/otm/OTMKit.java
  
  Index: OTMKit.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/OTMKit.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- OTMKit.java	19 Mar 2003 06:48:59 -0000	1.4
  +++ OTMKit.java	9 Jun 2003 18:55:26 -0000	1.5
  @@ -74,11 +74,8 @@
    */
   public abstract class OTMKit
   {
  -    protected OTMKit ()
  -    {
  -    }
  -
  -    public OTMConnection acquireConnection (PBKey pbKey)
  +    
  +    public OTMConnection acquireConnection(PBKey pbKey)
       {
           TransactionFactory txFactory = getTransactionFactory();
           return txFactory.acquireConnection(pbKey);
  @@ -96,18 +93,26 @@
       // Abstract Methods
       ////////////////////////////
   
  -    protected abstract TransactionFactory getTransactionFactory ();
  +    protected abstract TransactionFactory getTransactionFactory();
  +
  +    public abstract Swizzling getSwizzlingStrategy();
   
  -    public abstract Swizzling getSwizzlingStrategy ();
  +    public abstract LockWaitStrategy getLockWaitStrategy();
   
  -    public abstract LockWaitStrategy getLockWaitStrategy ();
  +    public abstract LockMap getLockMap();
   
  -    public abstract LockMap getLockMap ();
  +    public abstract ObjectCopyStrategy getCopyStrategy(Identity oid);
   
  -    public abstract ObjectCopyStrategy getCopyStrategy (Identity oid);
  +    public abstract ObjectStore getCacheStore();
   
  -    public abstract ObjectStore getCacheStore ();
  +    public abstract GlobalCache getGlobalCache();
   
  -    public abstract GlobalCache getGlobalCache ();
  +    /**
  +     * Should OTM implicitely read lock all objects that are reachable
  +     * from the explicitely locked object? The updates to the read locked
  +     * objects are automatically stored to the database at the end
  +     * of transaction.
  +     **/
  +    public abstract boolean isImplicitLockingUsed();
   
   }
  
  
  
  1.3       +32 -4     db-ojb/src/java/org/apache/ojb/otm/cache/store/HashMapObjectStore.java
  
  Index: HashMapObjectStore.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/cache/store/HashMapObjectStore.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- HashMapObjectStore.java	19 Mar 2003 06:48:59 -0000	1.2
  +++ HashMapObjectStore.java	9 Jun 2003 18:55:26 -0000	1.3
  @@ -65,8 +65,10 @@
    * @author <a href="mailto:olegnitz@apache.org">Oleg Nitz</a>
    *
    */
  -public class HashMapObjectStore extends ObjectStore
  +public class HashMapObjectStore implements ObjectStore
   {
  +    private long _lastTimestamp = 0;
  +
       HashMap _store = new HashMap();
   
       /**
  @@ -74,9 +76,10 @@
        *  Store the given object identified by the given identity
        *
        */
  -    public void store(Identity oid, Object obj)
  +    public synchronized void store(Identity oid, Object obj)
       {
  -        _store.put(oid, obj);
  +        _lastTimestamp++;
  +        _store.put(oid, new Entry(obj, _lastTimestamp));
       }
   
       /**
  @@ -86,7 +89,19 @@
        */
       public Object retrieve(Identity oid)
       {
  -        return _store.get(oid);
  +        Entry entry = ((Entry) _store.get(oid));
  +        return (entry == null ? null : entry._object);
  +    }
  +
  +    /**
  +     *
  +     *  Retrieve the object's timestamp for the given Identity
  +     *  @return the timestamp if object found, NO_TIMESTAMP if not.
  +     *
  +     */
  +    public long getTimestamp(Identity oid)
  +    {
  +        return ((Entry) _store.get(oid))._timestamp;
       }
   
       /**
  @@ -107,5 +122,18 @@
       public void removeAll()
       {
           _store.clear();
  +    }
  +
  +    private static class Entry
  +    {
  +        Object _object;
  +
  +        long _timestamp;
  +
  +        Entry(Object object, long timestamp)
  +        {
  +            _object = object;
  +            _timestamp = timestamp;
  +        }
       }
   }
  
  
  
  1.4       +16 -6     db-ojb/src/java/org/apache/ojb/otm/cache/store/ObjectStore.java
  
  Index: ObjectStore.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/cache/store/ObjectStore.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- ObjectStore.java	19 Mar 2003 06:48:59 -0000	1.3
  +++ ObjectStore.java	9 Jun 2003 18:55:26 -0000	1.4
  @@ -63,34 +63,44 @@
    * @author <a href="mailto:rraghuram@hotmail.com">Raghu Rajah</a>
    *
    */
  -public abstract class ObjectStore
  +public interface ObjectStore
   {
   
  +    public static long NO_TIMESTAMP = -1;
  +
       /**
        *
        *  Store the given object identified by the given identity
        *
        */
  -    public abstract void store (Identity oid, Object obj);
  +    public void store(Identity oid, Object obj);
   
       /**
        *
        *  Retrieve the object identified by the given Identity
        *
        */
  -    public abstract Object retrieve (Identity oid);
  +    public Object retrieve(Identity oid);
  +
  +    /**
  +     *
  +     *  Retrieve the object's timestamp for the given Identity
  +     *  @return the timestamp if object found, NO_TIMESTAMP if not.
  +     *
  +     */
  +    public long getTimestamp(Identity oid);
   
       /**
        *
        *  Remove the object from the store
        *
        */
  -    public abstract void remove (Identity oid);
  +    public void remove(Identity oid);
   
       /**
  -     * 
  +     *
        * Remove all objects from the cache
        *
        */
  -    public abstract void removeAll ();
  +    public void removeAll();
   }
  
  
  
  1.8       +3 -3      db-ojb/src/java/org/apache/ojb/otm/core/BaseConnection.java
  
  Index: BaseConnection.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/core/BaseConnection.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- BaseConnection.java	2 Jun 2003 12:52:29 -0000	1.7
  +++ BaseConnection.java	9 Jun 2003 18:55:26 -0000	1.8
  @@ -184,7 +184,7 @@
           Identity oid = new Identity(object, _kernel);
           ConcreteEditingContext editingContext = getTransaction().getContext();
   
  -        editingContext.insert(this, oid, object, LockType.WRITE_LOCK);
  +        editingContext.insert(_kernel, oid, object, LockType.WRITE_LOCK);
       }
   
       /**
  @@ -196,7 +196,7 @@
           Identity oid = new Identity(object, _kernel);
           ConcreteEditingContext editingContext = getTransaction().getContext();
   
  -        editingContext.insert(this, oid, object, LockType.WRITE_LOCK);
  +        editingContext.insert(_kernel, oid, object, LockType.READ_LOCK);
       }
   
       /**
  @@ -208,7 +208,7 @@
           Identity oid = new Identity(object, _kernel);
           ConcreteEditingContext editingContext = getTransaction().getContext();
   
  -        editingContext.deletePersistent(this, oid, object);
  +        editingContext.deletePersistent(_kernel, oid, object);
       }
   
       public EditingContext getEditingContext()
  
  
  
  1.8       +354 -47   db-ojb/src/java/org/apache/ojb/otm/core/ConcreteEditingContext.java
  
  Index: ConcreteEditingContext.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/core/ConcreteEditingContext.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- ConcreteEditingContext.java	25 May 2003 20:58:33 -0000	1.7
  +++ ConcreteEditingContext.java	9 Jun 2003 18:55:26 -0000	1.8
  @@ -54,16 +54,41 @@
    * <http://www.apache.org/>.
    */
   
  +//#ifdef JDK13
  +import java.lang.reflect.Proxy;
  +//#else
  +/*
  +import com.develop.java.lang.reflect.Proxy;
  +*/
  +//#endif
  +import java.math.BigDecimal;
   import java.util.ArrayList;
  +import java.util.Arrays;
  +import java.util.Collection;
  +import java.util.Comparator;
   import java.util.Iterator;
   import java.util.HashMap;
  +import java.util.Map;
  +import java.util.Date;
   
   import org.apache.ojb.broker.Identity;
  +import org.apache.ojb.broker.ManageableCollection;
  +import org.apache.ojb.broker.OJBRuntimeException;
   import org.apache.ojb.broker.PersistenceBroker;
  +import org.apache.ojb.broker.VirtualProxy;
  +import org.apache.ojb.broker.accesslayer.CollectionProxy;
   import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
  +import org.apache.ojb.broker.accesslayer.IndirectionHandler;
  +import org.apache.ojb.broker.accesslayer.MaterializationListener;
  +import org.apache.ojb.broker.metadata.ClassDescriptor;
  +import org.apache.ojb.broker.metadata.CollectionDescriptor;
  +import org.apache.ojb.broker.metadata.FieldDescriptor;
  +import org.apache.ojb.broker.metadata.ObjectReferenceDescriptor;
  +import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
  +import org.apache.ojb.broker.util.ArrayIterator;
   import org.apache.ojb.otm.EditingContext;
  -import org.apache.ojb.otm.OTMConnection;
   import org.apache.ojb.otm.OTMKit;
  +import org.apache.ojb.otm.cache.GlobalCache;
   import org.apache.ojb.otm.lock.LockManager;
   import org.apache.ojb.otm.lock.LockType;
   import org.apache.ojb.otm.lock.LockingException;
  @@ -78,7 +103,8 @@
    * @see     org.apache.ojb.otm.EditingContext
    *
    */
  -public class ConcreteEditingContext implements EditingContext
  +public class ConcreteEditingContext
  +        implements EditingContext, MaterializationListener
   {
       private HashMap _objects;
       private ArrayList _order;
  @@ -102,31 +128,32 @@
       /**
        * @see org.apache.ojb.otm.EditingContext#insert(Object, int)
        */
  -    public void insert(OTMConnection conn, Identity oid, Object insertedObject, 
  -                       int lock)
  +    public void insert(PersistenceBroker pb, Identity oid, Object obj, int lock)
               throws LockingException
       {
  -        ContextEntry entry = insertInternal(conn, oid, insertedObject, lock);
  -
  -        if (lock == LockType.WRITE_LOCK)
  -        {
  -            entry.state = entry.state.markDirty();
  -        }
  +        insertInternal(pb, oid, obj, lock);
       }
   
  -    private ContextEntry insertInternal(OTMConnection conn, Identity oid,
  -                                        Object insertedObject, int lock)
  +    private ContextEntry insertInternal(PersistenceBroker pb, Identity oid, Object obj, int lock)
               throws LockingException
       {
  -        ContextEntry entry = (ContextEntry) _objects.get(oid);
  -        OTMKit kit = _tx.getKit();
  +        ContextEntry entry;
  +        OTMKit kit;
  +
  +        if (lock == LockType.NO_LOCK)
  +        {
  +            return null;
  +        }
  +
  +        entry = (ContextEntry) _objects.get(oid);
  +        kit = _tx.getKit();
   
           if (entry == null)
           {
               LockManager lockManager = LockManager.getInstance();
  -            lockManager.ensureLock(oid, _tx, lock, conn);
  +            lockManager.ensureLock(oid, _tx, lock, pb);
               Swizzling swizzlingStrategy = kit.getSwizzlingStrategy();
  -            Object swizzledObject = swizzlingStrategy.swizzle(insertedObject, null);
  +            Object swizzledObject = swizzlingStrategy.swizzle(obj, null);
               entry = new ContextEntry(swizzledObject);
               _objects.put(oid, entry);
           }
  @@ -137,23 +164,40 @@
   
                   // A similar or the same object is present in the context
               Object contextObject = entry.object;
  -            if (swizzlingStrategy.isSameInstance(contextObject, insertedObject))
  +            if (swizzlingStrategy.isSameInstance(contextObject, obj))
               {
                       // The object in context is the same object attempted an insert on
                       // Ensure we have the correct lock level
  -                lockManager.ensureLock(oid, _tx, lock, conn);
  +                lockManager.ensureLock(oid, _tx, lock, pb);
               }
               else
               {
                       // It is a similar but different object
  -                lockManager.ensureLock(oid, _tx, lock, conn);
  +                lockManager.ensureLock(oid, _tx, lock, pb);
   
  -                Object swizzledObject = swizzlingStrategy.swizzle(insertedObject, contextObject);
  +                Object swizzledObject = swizzlingStrategy.swizzle(obj, contextObject);
                   entry.object = swizzledObject;
               }
           }
  +        
           if (!_order.contains(oid)) {
               _order.add(oid);
  +
  +            // perform automatic read lock for all reachable objects
  +            // if the inserted object is materialized
  +            if (kit.isImplicitLockingUsed())
  +            {
  +                IndirectionHandler handler = getIndirectionHandler(obj);
  +
  +                if (handler == null || handler.alreadyMaterialized())
  +                {
  +                    lockReachableObjects(obj, pb);
  +                }
  +                else
  +                {
  +                    handler.addListener(this);
  +                }
  +            }
           }
           return entry;
       }
  @@ -167,10 +211,7 @@
           _order.remove(oid);
       }
   
  -    /**
  -     * @see org.apache.ojb.otm.EditingContext#remove(Identity)
  -     */
  -    public void deletePersistent(OTMConnection conn, Identity oid, 
  +    public void deletePersistent(PersistenceBroker pb, Identity oid,
                                    Object object)
               throws LockingException
       {
  @@ -179,7 +220,7 @@
           if (_order.contains(oid)) {
               _order.remove(oid);
           }
  -        entry = insertInternal(conn, oid, object, LockType.WRITE_LOCK);
  +        entry = insertInternal(pb, oid, object, LockType.WRITE_LOCK);
           entry.state = entry.state.deletePersistent();
       }
   
  @@ -193,19 +234,53 @@
           return (entry == null ? null : entry.object);
       }
   
  -    public Object getFromGlobalCache(OTMConnection conn, Identity oid, int lock)
  +    public Object getFromGlobalCache(PersistenceBroker pb, Identity oid, int lock)
               throws LockingException
       {
           Object object = _tx.getKit().getGlobalCache().lookup(oid);
   
           if (object != null)
           {
  -            insertInternal(conn, oid, object, lock);
  +            ContextEntry entry = (ContextEntry) _objects.get(oid);
  +            
  +            if (entry == null) 
  +            {
  +                insertInternal(pb, oid, object, lock);
  +            }
           }
   
           return object;
       }
   
  +    //////////////////////////////////////////
  +    // MaterializationListener interface
  +    //////////////////////////////////////////
  +
  +    public void beforeMaterialization(IndirectionHandler handler, Identity oid)
  +    {
  +        //noop
  +    }
  +
  +    public void afterMaterialization(IndirectionHandler handler, Object materializedObject)
  +    {
  +        // perform automatic read lock for all reachable objects
  +        // if the inserted object is materialized
  +        if (_tx.getKit().isImplicitLockingUsed())
  +        {
  +            handler.removeListener(this);
  +            try 
  +            {
  +                lockReachableObjects(materializedObject,
  +                                     handler.getMaterializingBroker());
  +            }
  +            catch (LockingException ex)
  +            {
  +                throw new LockingPassthruException(ex);
  +            }
  +        }
  +    }
  +
  +
   
       //////////////////////////////////////////
       // Other operations
  @@ -221,39 +296,99 @@
        *                      into the persistent store.
        *
        */
  -    public void commit(PersistenceBroker pb)
  +    public void commit(PersistenceBroker pb) throws TransactionAbortedException
       {
  +        if (_order.size() == 0)
  +        {
  +            return;
  +        }
  +
           ConnectionManagerIF connMan = pb.serviceConnectionManager();
           boolean saveBatchMode = connMan.isBatchMode();
  -        Swizzling swizzlingStrategy = _tx.getKit().getSwizzlingStrategy();
  +        OTMKit kit = _tx.getKit();
  +        Swizzling swizzlingStrategy = kit.getSwizzlingStrategy();
  +        GlobalCache cache = kit.getGlobalCache();
  +        LockManager lockManager = LockManager.getInstance();
  +        Identity[] order = (Identity[]) _order.toArray(new Identity[_order.size()]);
  +        Identity[] lockOrder = new Identity[order.length];
   
  -        connMan.setBatchMode(true);
  -        try
  +        System.arraycopy(order, 0, lockOrder, 0, order.length);
  +        // sort objects in the order of oid.hashCode to avoid deadlocks
  +        Arrays.sort(lockOrder, new Comparator()
           {
  -            for (Iterator iterator = _order.iterator(); iterator.hasNext();)
  +            public int compare(Object o1, Object o2)
               {
  -                ContextEntry entry = (ContextEntry) _objects.get(iterator.next());
  -                Object realTarget = swizzlingStrategy.getRealTarget(entry.object);
  +                return o1.hashCode() - o1.hashCode();
  +            }
  +
  +            public boolean equals(Object obj)
  +            {
  +                return false;
  +            }
  +        });
  +        try {
  +            // mark dirty objects and lock them for write
  +            for (int i = 0; i < lockOrder.length; i++)
  +            {
  +                Identity oid = lockOrder[i];
  +                ContextEntry entry = (ContextEntry) _objects.get(oid);
                   State state = entry.state;
  +                IndirectionHandler handler = getIndirectionHandler(entry.object);
   
  -                if (state.needsUpdate() || state.needsInsert())
  +                if (handler == null || handler.alreadyMaterialized())
                   {
  -                    pb.store(realTarget /*, state*/);
  +                    if (!state.needsUpdate() && !state.needsInsert()
  +                            && !state.needsDelete())
  +                    {
  +                        Object object = cache.lookup(oid);
  +
  +                        if ((object == null) || isModified(entry.object, object, pb))
  +                        {
  +                            entry.state = state.markDirty();
  +                            lockManager.ensureLock(oid, _tx, LockType.WRITE_LOCK, pb);
  +                        }
  +                    }
                   }
  -                else if (state.needsDelete())
  +                else
                   {
  -                    pb.delete(realTarget);
  +                    handler.removeListener(this);
                   }
  -                entry.state = state.commit();
               }
  -            connMan.executeBatch();
  -            releaseLocks();
  -            _objects.clear();
  -            _order.clear();
  -        }
  -        finally
  -        {
  -            connMan.setBatchMode(saveBatchMode);
  +
  +            // perform database operations
  +            connMan.setBatchMode(true);
  +            try
  +            {
  +                for (int i = 0; i < order.length; i++)
  +                {
  +                    ContextEntry entry = (ContextEntry) _objects.get(order[i]);
  +                    State state = entry.state;
  +                    Object realTarget;
  +
  +                    if (state.needsUpdate() || state.needsInsert())
  +                    {
  +                        realTarget = swizzlingStrategy.getRealTarget(entry.object);
  +                        pb.store(realTarget /*, state*/);
  +                    }
  +                    else if (state.needsDelete())
  +                    {
  +                        realTarget = swizzlingStrategy.getRealTarget(entry.object);
  +                        pb.delete(realTarget);
  +                    }
  +                    entry.state = state.commit();
  +                }
  +                connMan.executeBatch();
  +                releaseLocks();
  +                _objects.clear();
  +                _order.clear();
  +            }
  +            finally
  +            {
  +                connMan.setBatchMode(saveBatchMode);
  +            }
  +        } catch (Throwable ex) {
  +            //ex.printStackTrace();
  +            throw new TransactionAbortedException(ex);
           }
       }
   
  @@ -275,6 +410,106 @@
           _order.clear();
       }
   
  +    /**
  +     * @return IndirectionHandler for the proxy object or null
  +     */
  +    private IndirectionHandler getIndirectionHandler(Object object)
  +    {
  +        if (Proxy.isProxyClass(object.getClass()))
  +        {
  +            return (IndirectionHandler) Proxy.getInvocationHandler(object);
  +        }
  +        else if (object instanceof VirtualProxy)
  +        {
  +            return VirtualProxy.getIndirectionHandler((VirtualProxy) object);
  +        }
  +        else
  +        {
  +            return null;
  +        }
  +    }
  +
  +    /**
  +     * Read lock all objects reachable via 1:N and N:1 relations
  +     */
  +    private void lockReachableObjects(Object object, PersistenceBroker pb)
  +        throws LockingException
  +    {
  +        ClassDescriptor mif = pb.getClassDescriptor(object.getClass());
  +
  +        // N:1 relations
  +        Iterator iter = mif.getObjectReferenceDescriptors().iterator();
  +        ObjectReferenceDescriptor rds = null;
  +        Object relObj = null;
  +        Identity relOid;
  +
  +        while (iter.hasNext())
  +        {
  +            rds = (ObjectReferenceDescriptor) iter.next();
  +            relObj = rds.getPersistentField().get(object);
  +            if (relObj != null)
  +            {
  +                relOid = new Identity(relObj, pb);
  +                if (!_order.contains(relOid))
  +                {
  +                    insertInternal(pb, relOid, relObj, LockType.READ_LOCK);
  +                }
  +            }
  +        }
  +
  +        // 1:N relations
  +        Iterator collections = mif.getCollectionDescriptors().iterator();
  +        CollectionDescriptor collectionDescriptor;
  +        Object col;
  +        Iterator colIterator;
  +
  +        while (collections.hasNext())
  +        {
  +            collectionDescriptor = (CollectionDescriptor) collections.next();
  +            col = collectionDescriptor.getPersistentField().get(object);
  +            if (col != null)
  +            {
  +                if (col instanceof CollectionProxy)
  +                {
  +                    if (!((CollectionProxy) col).isLoaded())
  +                    {
  +                        continue;
  +                    }
  +                }
  +
  +                if (col instanceof ManageableCollection)
  +                {
  +                    colIterator = ((ManageableCollection) col).ojbIterator();
  +                }
  +                else if (col instanceof Collection)
  +                {
  +                    colIterator = ((Collection) col).iterator();
  +                }
  +                else if (col.getClass().isArray())
  +                {
  +                    colIterator = new ArrayIterator(col);
  +                }
  +                else
  +                {
  +                    throw new OJBRuntimeException(
  +                        col.getClass()
  +                            + " can not be managed by OJB, use Array, Collection or ManageableCollection instead !");
  +                }
  +
  +                while (colIterator.hasNext())
  +                {
  +                    relObj = colIterator.next();
  +                    relOid = new Identity(relObj, pb);
  +                    if (!_order.contains(relOid))
  +                    {
  +                        insertInternal(pb, relOid, relObj, LockType.READ_LOCK);
  +                    }
  +                }
  +            }
  +        }
  +    }
  +
  +
       private void releaseLocks()
       {
           LockManager lockManager = LockManager.getInstance();
  @@ -284,6 +519,78 @@
               Identity oid = (Identity) it.next();
               lockManager.releaseLock(oid, _tx);
           }
  +    }
  +
  +    /**
  +     * This method compared simple field values:
  +     * there are some tricks...
  +     */
  +    private boolean isEqual(Object fld1, Object fld2)
  +    {
  +        if (fld1 == null || fld2 == null)
  +        {
  +            return (fld1 == fld2);
  +        }
  +        else if (fld1 instanceof BigDecimal)
  +        {
  +            return (((BigDecimal) fld1).compareTo(fld2) == 0);
  +        }
  +        else if ((fld1 instanceof Date) && (fld2 instanceof Date))
  +        {
  +            return (((Date) fld1).getTime() == ((Date) fld2).getTime());
  +        }
  +        else
  +        {
  +            return fld1.equals(fld2);
  +        }
  +    }
  +
  +    private boolean isModified(Object newObj, Object oldObj, PersistenceBroker pb)
  +    {
  +        ClassDescriptor mif = pb.getClassDescriptor(newObj.getClass());
  +
  +        FieldDescriptor[] fieldDescs = mif.getFieldDescriptions();
  +        for (int i = 0; i < fieldDescs.length; i++)
  +        {
  +            FieldDescriptor fd = fieldDescs[i];
  +            PersistentField f = fd.getPersistentField();
  +            if (!isEqual(f.get(newObj), f.get(oldObj)))
  +            {
  +                return true;
  +            }
  +        }
  +
  +        Iterator iter = mif.getObjectReferenceDescriptors().iterator();
  +        ObjectReferenceDescriptor rds = null;
  +        while (iter.hasNext())
  +        {
  +            rds = (ObjectReferenceDescriptor) iter.next();
  +            PersistentField f = rds.getPersistentField();
  +            Object newRef = f.get(newObj);
  +            Object oldRef = f.get(oldObj);
  +
  +            if (newRef == null || oldRef == null)
  +            {
  +                if (newRef != oldRef)
  +                {
  +                    return true;
  +                }
  +                else
  +                {
  +                    continue;
  +                }
  +            }
  +            
  +            Identity newOid = new Identity(newRef, pb);
  +            Identity oldOid = new Identity(oldRef, pb);
  +
  +            if (!newOid.equals(oldOid))
  +            {
  +                return true;
  +            }
  +        }
  +        
  +        return false;
       }
   
   
  
  
  
  1.9       +2 -1      db-ojb/src/java/org/apache/ojb/otm/core/RequestContext.java
  
  Index: RequestContext.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/core/RequestContext.java,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- RequestContext.java	25 May 2003 20:58:33 -0000	1.8
  +++ RequestContext.java	9 Jun 2003 18:55:26 -0000	1.9
  @@ -167,7 +167,8 @@
   
           try
           {
  -            return editingContext.getFromGlobalCache(_connection, oid, lock);
  +            return editingContext.getFromGlobalCache(
  +                    _connection.getKernelBroker(), oid, lock);
           }
           catch (LockingException ex)
           {
  
  
  
  1.5       +5 -6      db-ojb/src/java/org/apache/ojb/otm/core/Transaction.java
  
  Index: Transaction.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/core/Transaction.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Transaction.java	25 May 2003 20:58:33 -0000	1.4
  +++ Transaction.java	9 Jun 2003 18:55:26 -0000	1.5
  @@ -143,9 +143,7 @@
               throw new TransactionNotInProgressException(
                   "Transaction not in progress, nothing to commit");
           }
  -        
  -        _isInProgress = false;
  -        
  +
           for (Iterator iterator = _listeners.iterator(); iterator.hasNext();)
           {
               TransactionListener listener = (TransactionListener) iterator.next();
  @@ -166,14 +164,15 @@
           }
   
           _connections.clear();
  +        _isInProgress = false;
       }
   
       /**
        *
        * Rollback this transaction. A rollback on the transaction, notifies all its listeners. It,
        * then initiates a rollback on all associated connections.
  -     * 
  -     */    
  +     *
  +     */
       public void rollback ()
           throws TransactionException
       {
  @@ -184,7 +183,6 @@
           }
           
           _context.rollback();
  -        _isInProgress = false;
   
           for (Iterator iterator = _listeners.iterator(); iterator.hasNext();)
           {
  @@ -200,6 +198,7 @@
           }
   
           _connections.clear();
  +        _isInProgress = false;
       }
   
       public boolean isInProgress ()
  
  
  
  1.2       +1 -1      db-ojb/src/java/org/apache/ojb/otm/core/TransactionAbortedException.java
  
  Index: TransactionAbortedException.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/core/TransactionAbortedException.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TransactionAbortedException.java	1 Feb 2003 18:39:55 -0000	1.1
  +++ TransactionAbortedException.java	9 Jun 2003 18:55:26 -0000	1.2
  @@ -57,7 +57,7 @@
    /**
     * @author matthew.baird
     */
  -public class TransactionAbortedException extends Exception
  +public class TransactionAbortedException extends TransactionException
   {
   	/**
   	 * Constructor for TransactionAbortedException.
  
  
  
  1.7       +12 -0     db-ojb/src/java/org/apache/ojb/otm/kit/SimpleKit.java
  
  Index: SimpleKit.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/kit/SimpleKit.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- SimpleKit.java	18 May 2003 15:10:49 -0000	1.6
  +++ SimpleKit.java	9 Jun 2003 18:55:26 -0000	1.7
  @@ -171,4 +171,16 @@
       {
           return _globalCache;
       }
  +
  +    /**
  +     * Should OTM implicitely lock all objects that are reachable
  +     * from the explicitely locked object? The updates to the locked
  +     * objects are automatically stored to the database at the end
  +     * of transaction.
  +     **/
  +    public boolean isImplicitLockingUsed()
  +    {
  +        return true;
  +    }
  +
   }
  
  
  
  1.6       +5 -5      db-ojb/src/java/org/apache/ojb/otm/lock/IsolationFactory.java
  
  Index: IsolationFactory.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/lock/IsolationFactory.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- IsolationFactory.java	2 Jun 2003 12:52:28 -0000	1.5
  +++ IsolationFactory.java	9 Jun 2003 18:55:26 -0000	1.6
  @@ -56,7 +56,7 @@
   
   import org.apache.ojb.broker.metadata.ClassDescriptor;
   import org.apache.ojb.broker.metadata.IsolationLevels;
  -import org.apache.ojb.otm.OTMConnection;
  +import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.otm.lock.isolation.ReadCommittedIsolation;
   import org.apache.ojb.otm.lock.isolation.ReadUncommittedIsolation;
   import org.apache.ojb.otm.lock.isolation.RepeatableReadIsolation;
  @@ -66,9 +66,9 @@
   /**
    *
    * <javadoc>
  - * 
  + *
    * @author <a href="mailto:rraghuram@hotmail.com">Raghu Rajah</a>
  - * 
  + *
    */
   public class IsolationFactory
   {
  @@ -88,11 +88,11 @@
        * Fetches the isolation level of given class from its ClassDescriptor.
        *
        */
  -    public static TransactionIsolation getIsolationLevel (OTMConnection conn,
  +    public static TransactionIsolation getIsolationLevel (PersistenceBroker pb,
                                                             ObjectLock lock)
       {
           Class clazz = lock.getTargetIdentity().getObjectsClass();
  -        ClassDescriptor classDescriptor = conn.getDescriptorFor(clazz);
  +        ClassDescriptor classDescriptor = pb.getClassDescriptor(clazz);
           int isolationLevel = classDescriptor.getIsolationLevel();
   
           TransactionIsolation isolation = null;
  
  
  
  1.6       +3 -3      db-ojb/src/java/org/apache/ojb/otm/lock/LockManager.java
  
  Index: LockManager.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/lock/LockManager.java,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -r1.5 -r1.6
  --- LockManager.java	25 May 2003 20:58:33 -0000	1.5
  +++ LockManager.java	9 Jun 2003 18:55:26 -0000	1.6
  @@ -55,7 +55,7 @@
    */
   
   import org.apache.ojb.broker.Identity;
  -import org.apache.ojb.otm.OTMConnection;
  +import org.apache.ojb.broker.PersistenceBroker;
   import org.apache.ojb.otm.core.Transaction;
   import org.apache.ojb.otm.lock.isolation.TransactionIsolation;
   import org.apache.ojb.otm.lock.map.LockMap;
  @@ -82,14 +82,14 @@
       }
   
       public void ensureLock(Identity oid, Transaction tx, int lock,
  -                           OTMConnection conn)
  +                           PersistenceBroker pb)
           throws LockingException
       {
           LockMap lockMap = tx.getKit().getLockMap();
           ObjectLock objectLock = lockMap.getLock(oid);
           TransactionIsolation isolation;
   
  -        isolation = IsolationFactory.getIsolationLevel(conn, objectLock);
  +        isolation = IsolationFactory.getIsolationLevel(pb, objectLock);
   
           if (lock == LockType.READ_LOCK)
           {
  
  
  
  1.2       +6 -0      db-ojb/src/java/org/apache/ojb/otm/states/Hollow.java
  
  Index: Hollow.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/states/Hollow.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Hollow.java	16 Mar 2003 18:13:06 -0000	1.1
  +++ Hollow.java	9 Jun 2003 18:55:26 -0000	1.2
  @@ -102,4 +102,10 @@
       {
           return State.PERSISTENT_DELETED;
       }
  +
  +    public State rollback()
  +            throws IllegalObjectStateException
  +    {
  +        return this;
  +    }
   }
  
  
  
  1.2       +5 -0      db-ojb/src/java/org/apache/ojb/otm/states/Transient.java
  
  Index: Transient.java
  ===================================================================
  RCS file: /home/cvs/db-ojb/src/java/org/apache/ojb/otm/states/Transient.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Transient.java	16 Mar 2003 18:13:06 -0000	1.1
  +++ Transient.java	9 Jun 2003 18:55:26 -0000	1.2
  @@ -84,4 +84,9 @@
           return State.PERSISTENT_NEW;
       }
   
  +    public State rollback()
  +            throws IllegalObjectStateException
  +    {
  +        return this;
  +    }
   }