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;
+ }
}