You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by ar...@apache.org on 2006/07/15 16:20:27 UTC
svn commit: r422231 [2/4] - in /db/ojb/trunk/src/java/org/apache/ojb/broker:
./ accesslayer/ accesslayer/sql/ cache/ core/ locking/ metadata/
metadata/fieldaccess/
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java?rev=422231&r1=422230&r2=422231&view=diff
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/core/PersistenceBrokerImpl.java Sat Jul 15 07:20:25 2006
@@ -1,6 +1,6 @@
package org.apache.ojb.broker.core;
-/* Copyright 2003-2004 The Apache Software Foundation
+/* Copyright 2003-2006 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
*/
import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -29,6 +28,8 @@
import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang.SystemUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.ojb.broker.Identity;
import org.apache.ojb.broker.IdentityFactory;
import org.apache.ojb.broker.ManageableCollection;
@@ -41,6 +42,8 @@
import org.apache.ojb.broker.TransactionAbortedException;
import org.apache.ojb.broker.TransactionInProgressException;
import org.apache.ojb.broker.TransactionNotInProgressException;
+import org.apache.ojb.broker.TransientObjectException;
+import org.apache.ojb.broker.lob.LobHelper;
import org.apache.ojb.broker.accesslayer.ChainingIterator;
import org.apache.ojb.broker.accesslayer.CollectionCreationContext;
import org.apache.ojb.broker.accesslayer.ConnectionManagerIF;
@@ -107,6 +110,15 @@
{
private Logger logger = LoggerFactory.getLogger(PersistenceBrokerImpl.class);
+ /**
+ * A stack trace of this broker user.
+ * Used when broker leak detection is enabled.
+ */
+ protected String brokerStackTrace;
+ /**
+ * Returns <em>true</em> if broker leak detection is enabled.
+ */
+ protected boolean brokerLeakDetection;
protected PersistenceConfiguration persistenceConfiguration;
protected BrokerHelper brokerHelper;
protected MtoNBroker mtoNBroker;
@@ -151,6 +163,8 @@
private SqlGenerator sqlGenerator;
private IdentityFactory identityFactory;
private RelationshipPrefetcherFactory relationshipPrefetcherFactory;
+ private LobHelper lobHelper;
+ private PBKey pbKey;
/**
* List of objects being stored now, allows to avoid infinite
@@ -162,12 +176,12 @@
with user implemented equals/hashCode methods of persistence capable objects
(e.g. objects are equals but PK fields not)
*/
- private List nowStoring = new IdentityArrayList();
+ private IdentityArrayList nowStoring = new IdentityArrayList();
/**
* Lists for object registration during delete operations.
* We reuse these list to avoid excessive object creation.
- * @see #clearRegistrationLists
+ * @see #refreshRegistrationLists
*/
/*
arminw: list was cleared before delete method end. Internal we only
@@ -177,7 +191,13 @@
with user implemented equals/hashCode methods of persistence capable objects
(e.g. objects are equals but PK fields not)
*/
- private List markedForDelete = new IdentityArrayList();
+ private IdentityArrayList markedForDelete = new IdentityArrayList();
+
+ /**
+ * Used for performance optimization of method
+ * {@link #refreshRelationships(Object, org.apache.ojb.broker.Identity, org.apache.ojb.broker.metadata.ClassDescriptor)}
+ */
+ private IdentityArrayList skipRefreshRelationship = new IdentityArrayList();
/**
* The set of identities of all deleted objects during current transaction
@@ -254,6 +274,12 @@
proxyFactory = (ProxyFactory)subContainer.getSingletonInstance(ProxyFactory.class);
queryFactory = (QueryFactoryNew)subContainer.getSingletonInstance(QueryFactoryNew.class);
relationshipPrefetcherFactory = new RelationshipPrefetcherFactory(this);
+ lobHelper = (LobHelper)subContainer.getSingletonInstance(LobHelper.class);
+ }
+
+ public LobHelper serviceLobHelper()
+ {
+ return lobHelper;
}
public BatchManager serviceBatchManager()
@@ -324,7 +350,17 @@
{
return proxyFactory;
}
-
+
+ public boolean isBrokerLeakDetection()
+ {
+ return brokerLeakDetection;
+ }
+
+ public void setBrokerLeakDetection(boolean brokerLeakDetection)
+ {
+ this.brokerLeakDetection = brokerLeakDetection;
+ }
+
public boolean isClosed()
{
return this.isClosed;
@@ -332,11 +368,19 @@
public void setClosed(boolean closed)
{
+ // When lookup the PB instance from pool method setClosed(false)
+ // was called before returning instance from pool, in this case
+ // OJB have to refresh the instance.
if (!closed)
{
refresh();
+ if(brokerLeakDetection)
+ {
+ brokerStackTrace = ExceptionUtils.getFullStackTrace(
+ new Exception("PersistenceBroker caller stack"));
+ }
}
- isClosed = closed;
+ this.isClosed = closed;
}
/**
@@ -360,7 +404,7 @@
/**
* Returns the maximum number of sql columns.
- *
+ *
* @return The sql limit
*/
public int getSqlInLimit()
@@ -394,7 +438,7 @@
*/
public void destroy()
{
- logger.info("Destroy and cleanup this PB instance. " + this);
+ if(logger.isEnabledFor(Logger.INFO)) logger.info("Destroy and cleanup this PB instance. " + this);
removeAllListeners();
if (connectionManager != null)
{
@@ -435,8 +479,8 @@
/**
* Creates a proxy instance.
- *
- * @param baseClassForProxy The base class that the Proxy should extend. For dynamic Proxies, the method of
+ *
+ * @param baseClassForProxy The base class that the Proxy should extend. For dynamic Proxies, the method of
* generation is dependent on the ProxyFactory implementation.
* @param realSubjectsIdentity The identity of the subject
* @return An instance of the proxy subclass
@@ -456,11 +500,11 @@
return constructor.newInstance(new Object[]{ handler });
}
else
- {
+ {
return getProxyFactory().createProxy(baseClassForProxy,handler);
}
-
+
}
catch (Exception ex)
{
@@ -489,7 +533,7 @@
try
{
fireBrokerEvent(BEFORE_CLOSE_EVENT);
- clearRegistrationLists();
+ refreshRegistrationLists();
referencesBroker.removePrefetchingListeners();
if (connectionManager != null)
{
@@ -509,6 +553,7 @@
}
finally
{
+ if(skipRefreshRelationship.size() > 0) skipRefreshRelationship.clear();
// reset flag indicating use in managed environment
setManaged(false);
serviceSessionCache().evictAll(SessionCache.LEVEL_SESSION);
@@ -530,7 +575,7 @@
{
fireBrokerEvent(BEFORE_ROLLBACK_EVENT);
setInTransaction(false);
- clearRegistrationLists();
+ refreshRegistrationLists();
referencesBroker.removePrefetchingListeners();
/*
arminw:
@@ -579,7 +624,7 @@
}
fireBrokerEvent(BEFORE_COMMIT_EVENT);
setInTransaction(false);
- clearRegistrationLists();
+ refreshRegistrationLists();
referencesBroker.removePrefetchingListeners();
/*
arminw:
@@ -654,15 +699,15 @@
// only delete if object is not null
if (obj != null)
{
+ // replace specified object with the real one
obj = getProxyFactory().getRealObject(obj);
- /**
- * MBAIRD
- * 1. if we are marked for delete already, avoid recursing on this object
- *
- * arminw:
- * use object instead Identity object in markedForDelete List,
- * because using objects we get a better performance. I can't find
- * side-effects in doing so.
+
+ /*
+ MBAIRD
+ 1. if we are marked for delete already, avoid recursing on this object
+ arminw:
+ use object identity based list, because using objects we get a
+ better performance. I can't find side-effects in doing so.
*/
if (markedForDelete.contains(obj))
{
@@ -670,10 +715,14 @@
}
ClassDescriptor cld = getClassDescriptor(obj.getClass());
+ Identity oid = serviceIdentity().buildIdentity(cld, obj);
+
//BRJ: check for valid pk
- if (!serviceBrokerHelper().assertValidPkForDelete(cld, obj))
+ //if (!serviceBrokerHelper().assertValidPkForDelete(cld, obj))
+ // TODO: arminw: this simple check should do the same - verify
+ if (oid.isTransient())
{
- String msg = "Cannot delete object without valid PKs. " + obj;
+ String msg = "Cannot delete object without valid PKs: " + obj;
logger.error(msg);
return;
}
@@ -683,40 +732,14 @@
* 2. register object in markedForDelete map.
*/
markedForDelete.add(obj);
- Identity oid = serviceIdentity().buildIdentity(cld, obj);
// Invoke events on PersistenceBrokerAware instances and listeners
BEFORE_DELETE_EVENT.setTarget(obj);
fireBrokerEvent(BEFORE_DELETE_EVENT);
BEFORE_DELETE_EVENT.setTarget(null);
- // 1. delete dependend collections
- if (!ignoreReferences && cld.getCollectionDescriptors().size() > 0)
- {
- deleteCollections(obj, cld.getCollectionDescriptors());
- }
- // 2. delete object from directly mapped table
- try
- {
- dbAccess.executeDelete(cld, obj); // use obj not oid to delete, BRJ
- }
- catch(OptimisticLockException e)
- {
- // ensure that the outdated object be removed from cache
- sessionCache.evict(oid, SessionCache.LEVEL_DEEP);
- throw e;
- }
-
- // 3. Add OID to the set of deleted objects
- deletedDuringTransaction.add(oid);
-
- // 4. delete dependend upon objects last to avoid FK violations
- if (cld.getObjectReferenceDescriptors().size() > 0)
- {
- deleteReferences(obj, cld.getObjectReferenceDescriptors(), ignoreReferences);
- }
- // remove obj from the object cache:
- sessionCache.evict(oid, SessionCache.LEVEL_DEEP);
+ // now perform deletion
+ performDeletion(cld, obj, oid, ignoreReferences);
// Invoke events on PersistenceBrokerAware instances and listeners
AFTER_DELETE_EVENT.setTarget(obj);
@@ -726,6 +749,41 @@
}
/**
+ * This method perform the delete of the specified object
+ * based on the {@link org.apache.ojb.broker.metadata.ClassDescriptor}.
+ */
+ private void performDeletion(final ClassDescriptor cld, final Object obj, final Identity oid, final boolean ignoreReferences) throws PersistenceBrokerException
+ {
+ // 1. delete dependend collections
+ if (!ignoreReferences && cld.getCollectionDescriptors().size() > 0)
+ {
+ deleteCollections(obj, cld.getCollectionDescriptors());
+ }
+ // 2. delete object from directly mapped table
+ try
+ {
+ dbAccess.executeDelete(cld, obj); // use obj not oid to delete, BRJ
+ }
+ catch(OptimisticLockException e)
+ {
+ // ensure that the outdated object be removed from cache
+ sessionCache.evict(oid, SessionCache.LEVEL_DEEP);
+ throw e;
+ }
+
+ // 3. Add OID to the set of deleted objects
+ deletedDuringTransaction.add(oid);
+
+ // 4. delete dependend upon objects last to avoid FK violations
+ if (cld.getObjectReferenceDescriptors().size() > 0)
+ {
+ deleteReferences(cld, obj, oid, ignoreReferences);
+ }
+ // remove obj from the object cache:
+ sessionCache.evict(oid, SessionCache.LEVEL_DEEP);
+ }
+
+ /**
* Extent aware Delete by Query
* @param query
* @param cld
@@ -749,29 +807,40 @@
if (query instanceof QueryByIdentity)
{
Identity oid = getIdentity((QueryByIdentity) query);
- query = referencesBroker.getPKQuery(oid);
- }
-
- if (cld.isMappedToTable())
- {
- dbAccess.executeDelete(query, cld);
+ try
+ {
+ query = referencesBroker.getPKQuery(oid);
+ }
+ catch(TransientObjectException e)
+ {
+ query = null;
+ logger.error("Can't delete transient objects from datastore", e);
+ }
}
- // if class is an extent, we have to delete all extent classes too
- String lastUsedTable = cld.getFullTableName();
- if (cld.isExtent())
+ if(query != null)
{
- Iterator extents = getDescriptorRepository().getAllConcreteSubclassDescriptors(cld).iterator();
+ if (cld.isMappedToTable())
+ {
+ dbAccess.executeDelete(query, cld);
+ }
- while (extents.hasNext())
+ // if class is an extent, we have to delete all extent classes too
+ String lastUsedTable = cld.getFullTableName();
+ if (cld.isExtent())
{
- ClassDescriptor extCld = (ClassDescriptor) extents.next();
+ Iterator extents = getDescriptorRepository().getAllConcreteSubclassDescriptors(cld).iterator();
- // read same table only once
- if (!extCld.getFullTableName().equals(lastUsedTable))
+ while (extents.hasNext())
{
- lastUsedTable = extCld.getFullTableName();
- dbAccess.executeDelete(query, extCld);
+ ClassDescriptor extCld = (ClassDescriptor) extents.next();
+
+ // read same table only once
+ if (!extCld.getFullTableName().equals(lastUsedTable))
+ {
+ lastUsedTable = extCld.getFullTableName();
+ this.dbAccess.executeDelete(query, extCld);
+ }
}
}
}
@@ -793,29 +862,44 @@
* will be deleted if auto-delete is true <b>AND</b>
* the member field containing the object reference is NOT null.
*
+ * @param cld The {@link org.apache.ojb.broker.metadata.ClassDescriptor} of the object
+ * or of a super class.
* @param obj Object which we will delete references for
- * @param listRds list of ObjectRederenceDescriptors
+ * @param oid The {@link Identity} of the object.
* @param ignoreReferences With this flag the automatic deletion/unlinking
* of references can be suppressed (independent of the used auto-delete setting in metadata),
* except {@link org.apache.ojb.broker.metadata.SuperReferenceDescriptor}
* these kind of reference (descriptor) will always be performed.
* @throws PersistenceBrokerException if some goes wrong - please see the error message for details
*/
- private void deleteReferences(Object obj, List listRds, boolean ignoreReferences) throws PersistenceBrokerException
+ private void deleteReferences(ClassDescriptor cld, Object obj, Identity oid, boolean ignoreReferences) throws PersistenceBrokerException
{
+ List listRds = cld.getObjectReferenceDescriptors();
// get all members of obj that are references and delete them
for (Iterator i = listRds.iterator(); i.hasNext();)
{
ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor)i.next();
-
- if ((!ignoreReferences && (rds.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT))
+ if ((!ignoreReferences && rds.getCascadingDelete() == ObjectReferenceDescriptor.CASCADE_OBJECT)
|| rds.isSuperReferenceDescriptor())
{
Object referencedObject = rds.getPersistentField().get(obj);
-
if (referencedObject != null)
{
- doDelete(referencedObject, ignoreReferences);
+ if(rds.isSuperReferenceDescriptor())
+ {
+ ClassDescriptor base = cld.getSuperClassDescriptor();
+ /*
+ arminw: If "table-per-subclass" inheritance is used we have to
+ guarantee that all super-class table entries are deleted too.
+ Thus we have to perform the recursive deletion of all super-class
+ table entries.
+ */
+ performDeletion(base, referencedObject, oid, ignoreReferences);
+ }
+ else
+ {
+ doDelete(referencedObject, ignoreReferences);
+ }
}
}
}
@@ -878,12 +962,14 @@
if(obj == null) return;
ClassDescriptor cld = getClassDescriptor(obj.getClass());
+ Identity oid = serviceIdentity().buildIdentity(cld, obj);
/*
if one of the PK fields was null, we assume the objects
was new and needs insert
*/
- boolean insert = serviceBrokerHelper().hasNullPKField(cld, obj);
- Identity oid = serviceIdentity().buildIdentity(cld, obj);
+ // boolean insert = serviceBrokerHelper().hasNullPKField(cld, obj);
+ // TODO: arminw: this should do the same - verify
+ boolean insert = oid.isTransient();
/*
if PK values are set, lookup cache or db to see whether object
needs insert or update
@@ -1039,7 +1125,7 @@
{
// get all members of obj that are references and store them
Collection listRds = cld.getObjectReferenceDescriptors();
-
+ // skip if nothing to do
if ((listRds != null) && (listRds.size() > 0))
{
for (Iterator i = listRds.iterator(); i.hasNext();)
@@ -1047,7 +1133,7 @@
ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next();
/*
arminw: the special references (eg. super-references used for table per subclass
- inheritance) must be performed in any case. The "normal" 1:1 references can be
+ inheritance) must be performed in any case. The "normal" 1:1 references can be
ignored when flag "ignoreReferences" is set
*/
if((!ignoreReferences && rds.getCascadingStore() != ObjectReferenceDescriptor.CASCADE_NONE)
@@ -1096,15 +1182,15 @@
Object obj = iter.next();
ClassDescriptor cld = getClassDescriptor(obj.getClass());
if (serviceBrokerHelper().assertValidPkForDelete(cld, obj))
- {
+ {
delete(obj);
- }
+ }
}
tc.clearDeletedObjects();
tc.clearNewObjects();
}
}
-
+
/**
* Store/Link collections of objects poiting to <b>obj</b>.
* More info please see comments in source.
@@ -1142,7 +1228,7 @@
if (referencedObjects instanceof TrackingCollection)
{
afterStore((TrackingCollection) referencedObjects, cod);
- }
+ }
}
}
}
@@ -1250,8 +1336,17 @@
while(it.hasNext())
{
refObj = it.next();
- // set FK in refObj if it is materialized
- if(getProxyFactory().isMaterialized(refObj))
+ /*
+ TODO: Check this!
+ arminw:
+ When it's necessary to 'link' (set the FK) the 1:n reference objects?
+ 1. set FK in refObj if it is materialized
+ 2. if the referenced object is a proxy AND the main object needs insert
+ we have to materialize the real object, because the user may move a collection
+ of proxy objects from object A to new object B. In this case we have to replace the
+ FK in the proxy object with new key of object B.
+ */
+ if(insert || getProxyFactory().isMaterialized(refObj))
{
ClassDescriptor refCld = getClassDescriptor(getProxyFactory().getRealClass(refObj));
// get the real object before linking
@@ -1464,7 +1559,7 @@
/**
* Creates the hierarchy of enclosing objects between the target class and the given persistent outer class
- *
+ *
* @param targetClass The target inner class (is not instantiated)
* @param directPersistentOuterClass The nearest persistent enclosing class
* @param directPersistentOuterObject The instance of the nearest persistent enclosing class to use
@@ -1486,7 +1581,7 @@
{
// recursively create the direct enclosing object of the direct enclosing class
Object oneLevelAboveOuterObj = createDirectEnclosingObject(directEnclosingClass, directPersistentOuterClass, directPersistentOuterObject);
-
+
try
{
return ClassHelper.newInstance(directEnclosingClass,
@@ -1527,13 +1622,14 @@
/**
* Retrieve all References (also Collection-attributes) of a given instance.
* Loading is forced, even if the collection- and reference-descriptors differ.
- * @param pInstance the persistent instance to work with
+ * @param obj the persistent instance to work with
+ * @param force Force the loading of references
*/
private void retrieveAllReferences(Object obj, boolean force) throws PersistenceBrokerException
{
if (logger.isDebugEnabled())
{
- logger.debug("Manually retrieving all references for object " + serviceIdentity().buildIdentity(obj));
+ logger.debug("Manually retrieving all references for object " + serviceIdentity().buildIdentity(obj));
}
ClassDescriptor cld = getClassDescriptor(obj.getClass());
try
@@ -1620,8 +1716,7 @@
public void refreshRelationships(Object obj, ClassDescriptor cld)
{
- Identity oid = serviceIdentity().buildIdentity(cld, obj);
- refreshRelationships(obj, oid, cld);
+ refreshRelationships(obj, serviceIdentity().buildIdentity(obj), cld);
}
/**
@@ -1635,6 +1730,8 @@
*/
public void refreshRelationships(Object obj, Identity oid, ClassDescriptor cld)
{
+ if(skipRefreshRelationship.contains(cld)) return;
+
Iterator iter;
CollectionDescriptor cds;
ObjectReferenceDescriptor rds;
@@ -1651,6 +1748,7 @@
}
try
{
+ boolean needsRelationshipRefresh = false;
serviceSessionCache().enableMaterializationCache();
if(tmp == null)
{
@@ -1664,6 +1762,7 @@
if (cds.isRefresh())
{
referencesBroker.retrieveCollection(obj, cld, cds, false);
+ needsRelationshipRefresh = true;
}
}
iter = cld.getObjectReferenceDescriptors().iterator();
@@ -1673,9 +1772,14 @@
if (rds.isRefresh())
{
referencesBroker.retrieveReference(obj, cld, rds, false);
+ needsRelationshipRefresh = true;
}
}
serviceSessionCache().disableMaterializationCache();
+ if(!needsRelationshipRefresh)
+ {
+ skipRefreshRelationship.add(cld);
+ }
}
catch(RuntimeException e)
{
@@ -1705,7 +1809,7 @@
/**
* Retrieves the collection described by the given creation context.
- *
+ *
* @param context The creation context
* @return The collection
*/
@@ -1753,8 +1857,8 @@
}
return newObj;
}
-
-
+
+
/**
* Retrieve an full materialized (dependent on the metadata settings)
* object by it's identity from the database, as well as caching the
@@ -1776,7 +1880,7 @@
}
ClassDescriptor cld = getClassDescriptor(c);
- Object newObj = getPlainDBObject(cld,oid);
+ Object newObj = getPlainDBObject(cld,oid);
// loading references is useful only when the Object could be found in db:
if (newObj != null)
@@ -1838,7 +1942,7 @@
}
}
}
-
+
/**
* returns an Iterator that iterates Objects of class c if calling the .next()
* method. The Elements returned come from a SELECT ... WHERE Statement
@@ -1867,7 +1971,6 @@
{
result = new PagingIterator(result, query.getStartAtIndex(), query.getEndAtIndex());
}
-
return result;
}
@@ -1928,6 +2031,11 @@
{
refreshInstance(obj, id, cld);
}
+ else
+ {
+ // refresh LOB-fields
+ serviceLobHelper().internalAutoRefresh(obj, cld);
+ }
// now refresh all references
refreshRelationships(obj, id, cld);
}
@@ -1977,7 +2085,19 @@
if (query instanceof QueryByIdentity)
{
Identity oid = getIdentity((QueryByIdentity) query);
- result = getObjectByIdentity(oid);
+ // only non-transient objects can be found in DB
+ if(oid.isTransient())
+ {
+ if(logger.isEnabledFor(Logger.INFO)) logger.info(
+ "The object to query was detected as transient, will only lookup the cache for object instance. Identity="
+ + oid + ", the query object was " + query);
+ // transient objects can only be found in session cache
+ result = serviceSessionCache().lookup(oid, SessionCache.LEVEL_SESSION);
+ }
+ else
+ {
+ result = getObjectByIdentity(oid);
+ }
}
else
{
@@ -2234,14 +2354,19 @@
*
* @param obj
* @param cld
- * @param oid
+ * @param oid
* @param insert
* @param ignoreReferences
*/
private void storeToDb(Object obj, ClassDescriptor cld, Identity oid, boolean insert, boolean ignoreReferences)
{
// 1. link and store 1:1 references
- storeReferences(obj, cld, insert, ignoreReferences);
+ // we can skip handling for 1:1 references if
+ // it's enabled and the class has no super-reference
+ if(!(ignoreReferences && cld.getSuperReference() == null))
+ {
+ storeReferences(obj, cld, insert, ignoreReferences);
+ }
Object[] pkValues = oid.getPrimaryKeyValues();
if (!serviceBrokerHelper().assertValidPksForStore(cld.getPkFields(), pkValues))
@@ -2281,6 +2406,11 @@
if (insert)
{
dbAccess.executeInsert(cld, obj);
+ if(oid.isTransient())
+ {
+ // Create a new Identity based on the current set of primary key values.
+ oid = serviceIdentity().buildIdentity(cld, obj);
+ }
}
// else use UPDATE
else
@@ -2296,12 +2426,10 @@
throw e;
}
}
- // Create a new Identity based on the current set of primary key values.
- Identity newOid = serviceIdentity().buildIdentity(cld, obj);
// cache object for symmetry with getObjectByXXX()
// Add the object to the cache.
- serviceSessionCache().cache(newOid, obj, SessionCache.TYPE_WRITE, SessionCache.LEVEL_DEEP);
- // 3. store 1:n and m:n associations
+ serviceSessionCache().cache(oid, obj, SessionCache.TYPE_WRITE, SessionCache.LEVEL_DEEP);
+ // 3. store 1:n and m:n associations except if we have to skip
if(!ignoreReferences) storeCollections(obj, cld, insert);
}
@@ -2449,7 +2577,7 @@
{
query.setFetchSize(1);
query.preprocess(this);
-
+
if (query instanceof QueryBySQL)
{
if(logger.isDebugEnabled()) logger.debug("Creating SQL-RsIterator for class ["+cld.getClassNameOfObject()+"]");
@@ -2470,12 +2598,12 @@
ChainingIterator chainingIter = new ChainingIterator();
Collection cldInfos = serviceBrokerHelper().getExtentsDescriptors(cld);
Iterator extents = cldInfos.iterator();
-
+
while (extents.hasNext())
{
BrokerHelper.CldInfo cldInfo = (BrokerHelper.CldInfo) extents.next();
Query theQuery = serviceBrokerHelper().setConcreteClassCriteria(this, (QueryByCriteria)query, cldInfo);
-
+
if(logger.isDebugEnabled()) logger.debug("Adding RsIterator of class ["+ cldInfo.cld.getClassNameOfObject()+"] to ChainingIterator");
// add the iterator to the chaining iterator.
@@ -2520,13 +2648,40 @@
return persistenceConfiguration.getModel();
}
+ protected void finalize()
+ {
+ try
+ {
+ super.finalize();
+ // if not closed ==> broker leak detected
+ if (!isClosed)
+ {
+ String msg = "Garbage collection: Unclosed PersistenceBroker instance detected, check code for PB leaks.";
+ if(brokerLeakDetection)
+ {
+ logger.error(msg + " Broker caller stack is: "
+ + SystemUtils.LINE_SEPARATOR + brokerStackTrace);
+ }
+ else
+ {
+ logger.warn(msg);
+ }
+ close();
+ }
+ }
+ catch(Throwable ignore)
+ {
+ // ignore
+ }
+ }
+
/**
* clean up the maps for reuse by the next transaction.
*/
- private void clearRegistrationLists()
+ private void refreshRegistrationLists()
{
- nowStoring.clear();
- deletedDuringTransaction.clear();
+ if(nowStoring.size() > 0) nowStoring = new IdentityArrayList();
+ if(deletedDuringTransaction.size() > 0) deletedDuringTransaction.clear();
/*
arminw:
for better performance I don't register MtoNBroker as listner,
@@ -2550,7 +2705,7 @@
{
mtoNBroker.storeMtoNImplementor(m2n);
}
-
+
/**
* Get the Identity out of the Query.
* @param aQuery
@@ -2559,21 +2714,21 @@
private Identity getIdentity(QueryByIdentity aQuery)
{
Object obj = aQuery.getIdentityObject();
- Identity oid = null;
-
+ Identity oid ;
if (obj instanceof Identity)
{
oid = (Identity) obj;
}
else
{
- // TODO: This workaround doesn't allow 'null' for PK fields
- if (!serviceBrokerHelper().hasNullPKField(getClassDescriptor(obj.getClass()), obj))
- {
- oid = serviceIdentity().buildIdentity(obj);
- }
+// if (!serviceBrokerHelper().hasNullPKField(getClassDescriptor(obj.getClass()), obj))
+// {
+// oid = serviceIdentity().buildIdentity(obj);
+// }
+ // TODO: Check this! The above check is no longer needed, because "new objects" will automatic
+ // have transient Identity objects
+ oid = serviceIdentity().buildIdentity(obj);
}
-
return oid;
}
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/core/QueryReferenceBroker.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/core/QueryReferenceBroker.java?rev=422231&r1=422230&r2=422231&view=diff
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/core/QueryReferenceBroker.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/core/QueryReferenceBroker.java Sat Jul 15 07:20:25 2006
@@ -27,6 +27,7 @@
import org.apache.ojb.broker.ManageableCollection;
import org.apache.ojb.broker.PBLifeCycleEvent;
import org.apache.ojb.broker.PersistenceBrokerException;
+import org.apache.ojb.broker.TransientObjectException;
import org.apache.ojb.broker.accesslayer.CollectionCreationContext;
import org.apache.ojb.broker.accesslayer.OJBIterator;
import org.apache.ojb.broker.accesslayer.PagingIterator;
@@ -50,6 +51,7 @@
import org.apache.ojb.broker.util.BrokerHelper;
import org.apache.ojb.broker.util.logging.Logger;
import org.apache.ojb.broker.util.logging.LoggerFactory;
+import org.apache.commons.lang.SystemUtils;
/**
* Encapsulates 1:1 and 1:n references and collection references stuff.
@@ -85,7 +87,7 @@
throws ClassNotPersistenceCapableException, PersistenceBrokerException
{
ManageableCollection collection = pb.getConfiguration().getCollectionFactory().createCollection(context);
- Query query = context.getQuery();
+ Query query = context.getQuery();
if (query == null)
{
@@ -152,11 +154,12 @@
else
{
//warn the user
- log.warn("Candidate object ["+candidate
- +"] class ["+candidate.getClass().getName()
- +"] is not a subtype of ["+itemClass.getName()
- +"] or any type of proxy. NOT INCLUDED in result collection");
- }
+ if(log.isEnabledFor(Logger.WARN)) log.warn(SystemUtils.LINE_SEPARATOR
+ + "Candidate object ["+candidate + "]"
+ +" of "+candidate.getClass() + SystemUtils.LINE_SEPARATOR
+ +"is not a subtype of "+itemClass +" or any type of proxy - e.g. this can be the result of a"
+ + SystemUtils.LINE_SEPARATOR +"'declared' extent in "+itemClass + "."
+ + " This can cause side-effects and will NOT INCLUDED in the current generated collection result"); }
if (prefetchProxies && (handler != null)
&& (cld.getProxyPrefetchingLimit() > 0)
&& addRetrievalTask(candidate, this))
@@ -166,6 +169,7 @@
}
}
}
+
if (isRetrievalTasksCreated)
{
// turn off auto prefetching for related proxies
@@ -200,6 +204,7 @@
// catch runtime exc. to guarantee clearing of
// materialization cache on failure
pb.serviceSessionCache().clearMaterializationCache();
+ log.error(e);
throw e;
}
finally
@@ -273,7 +278,7 @@
}
catch (Throwable e)
{
- e.printStackTrace();
+ log.error(e);
throw new PersistenceBrokerException("Can't query for collection",e);
}
}
@@ -325,7 +330,8 @@
}
ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) key;
- if (ord.isSuperReferenceDescriptor() || ord.isLazy() || (ord.getItemProxyClass() != null))
+// if (ord.isSuperReferenceDescriptor() || ord.isLazy() || (ord.getItemProxyClass() != null))
+ if (ord.isLazy() || (ord.getItemProxyClass() != null))
{
continue;
}
@@ -369,12 +375,12 @@
else if ( pb.serviceSessionCache().lookup(id) != null )
{
refObj = pb.getObjectByIdentity(id);
- if (rds.isSuperReferenceDescriptor())
+ if (rds.isSuperReferenceDescriptor())
{
// walk the super-references
ClassDescriptor superCld = cld.getRepository().getDescriptorFor(rds.getItemClass());
retrieveReferences(refObj, superCld, false);
- retrieveCollections(refObj, superCld, false);
+ retrieveCollections(refObj, superCld, false);
}
}
else if ((m_retrievalTasks != null)
@@ -422,6 +428,52 @@
}
/**
+ * Retrieve a single Reference.
+ * This implementation retrieves a referenced object from the data backend
+ * if <b>cascade-retrieve</b> is true or if <b>forced</b> is true.
+ *
+ * @param obj - object that will have it's field set with a referenced object.
+ * @param cld - the ClassDescriptor describring obj
+ * @param rds - the ObjectReferenceDescriptor of the reference attribute to be loaded
+ * @param forced - if set to true, the reference is loaded even if the rds differs.
+ */
+ public void retrieveProxyReference(Object obj, ClassDescriptor cld, ObjectReferenceDescriptor rds, boolean forced)
+ {
+ PersistentField refField;
+ Object refObj = null;
+
+ pb.serviceSessionCache().enableMaterializationCache();
+ try
+ {
+ Identity id = getReferencedObjectIdentity(obj, rds, cld);
+ if (id != null){
+ refObj = pb.createProxy(rds.getItemClass(), id);
+ }
+ refField = rds.getPersistentField();
+ refField.set(obj, refObj);
+
+ if ((refObj != null) && prefetchProxies
+ && (m_retrievalTasks != null)
+ && (rds.getProxyPrefetchingLimit() > 0))
+ {
+ IndirectionHandler handler = pb.getProxyFactory().getIndirectionHandler(refObj);
+
+ if ((handler != null) && addRetrievalTask(obj, rds))
+ {
+ new PBMaterializationListener(obj, m_retrievalTasks, rds, rds.getProxyPrefetchingLimit(), pb.getProxyFactory());
+ }
+ }
+ pb.serviceSessionCache().disableMaterializationCache();
+ }
+ catch(RuntimeException e)
+ {
+ pb.serviceSessionCache().clearMaterializationCache();
+ throw e;
+ }
+
+ }
+
+ /**
* Retrieve all References
*
* @param newObj the instance to be loaded or refreshed
@@ -459,6 +511,43 @@
}
}
+ /**
+ * Retrieve all References
+ *
+ * @param newObj the instance to be loaded or refreshed
+ * @param cld the ClassDescriptor of the instance
+ * @param forced if set to true loading is forced even if cld differs.
+ */
+ public void retrieveProxyReferences(Object newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
+ {
+ Iterator i = cld.getObjectReferenceDescriptors().iterator();
+
+ // turn off auto prefetching for related proxies
+ final Class saveClassToPrefetch = classToPrefetch;
+ classToPrefetch = null;
+
+ pb.serviceSessionCache().enableMaterializationCache();
+ try
+ {
+ while (i.hasNext())
+ {
+ ObjectReferenceDescriptor rds = (ObjectReferenceDescriptor) i.next();
+ retrieveProxyReference(newObj, cld, rds, forced);
+ }
+
+ pb.serviceSessionCache().disableMaterializationCache();
+ }
+ catch(RuntimeException e)
+ {
+ pb.serviceSessionCache().clearMaterializationCache();
+ throw e;
+ }
+ finally
+ {
+ classToPrefetch = saveClassToPrefetch;
+ }
+ }
+
/**
* retrieves an Object reference's Identity.
* <br>
@@ -491,7 +580,7 @@
else
{
// ensure that top-level extents are used for Identities
- return new Identity(rds.getItemClass(), pb.getTopLevelClass(rds.getItemClass()), fkValues);
+ return pb.serviceIdentity().buildIdentity(rds.getItemClass(), pb.getTopLevelClass(rds.getItemClass()), fkValues);
}
return null;
}
@@ -559,8 +648,15 @@
}
catch (Exception e)
{
- log.error("Error instantiating obj: " + e.getMessage(), e);
- throw new PersistenceBrokerException(e);
+ log.error("Error while instantiate object " + id + ", msg: "+ e.getMessage(), e);
+ if(e instanceof PersistenceBrokerException)
+ {
+ throw (PersistenceBrokerException) e;
+ }
+ else
+ {
+ throw new PersistenceBrokerException(e);
+ }
}
}
else
@@ -582,6 +678,27 @@
*/
public void retrieveCollection(Object obj, ClassDescriptor cld, CollectionDescriptor cds, boolean forced)
{
+ doRetrieveCollection(obj, cds, forced);
+ }
+
+ /**
+ * Retrieve a single Proxied Collection on behalf of <b>obj</b>.
+ * The Collection is retrieved only if <b>cascade.retrieve is true</b>
+ * or if <b>forced</b> is set to true. *
+ *
+ * @param obj - the object to be updated
+ * @param cld - the ClassDescriptor describing obj
+ * @param cds - the CollectionDescriptor describing the collection attribute to be loaded
+ * @param forced - if set to true a proxy will be placed, even if cds differs.
+ *
+ */
+ public void retrieveProxyCollection(Object obj, ClassDescriptor cld, CollectionDescriptor cds, boolean forced)
+ {
+ doRetrieveCollection(obj, cds, forced);
+ }
+
+ private void doRetrieveCollection(Object obj, CollectionDescriptor cds, boolean forced)
+ {
if (forced || cds.getCascadeRetrieve())
{
if ((m_retrievalTasks != null) && !cds.isLazy()
@@ -768,9 +885,16 @@
*
* @param oid the Identity of the Object to retrieve
* @return The resulting query
+ * @throws TransientObjectException If the specified {@link org.apache.ojb.broker.Identity}
+ * is <em>transient</em> this exception will be thrown, because it's not possible to build
+ * a valid query.
*/
- public Query getPKQuery(Identity oid)
+ public Query getPKQuery(Identity oid) throws TransientObjectException
{
+ if(oid.isTransient())
+ {
+ throw new TransientObjectException("Not allowed to build PK Query for a transient object");
+ }
Object[] values = oid.getPrimaryKeyValues();
ClassDescriptor cld = pb.getClassDescriptor(oid.getObjectsTopLevelClass());
FieldDescriptor[] fields = cld.getPkFields();
@@ -794,6 +918,24 @@
*/
public void retrieveCollections(Object newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
{
+ doRetrieveCollections(newObj, cld, forced, false);
+ }
+
+ /**
+ * Retrieve all Collection attributes of a given instance, and make all of the Proxy Collections
+ *
+ * @param newObj the instance to be loaded or refreshed
+ * @param cld the ClassDescriptor of the instance
+ * @param forced if set to true, loading is forced even if cld differs
+ *
+ */
+ public void retrieveProxyCollections(Object newObj, ClassDescriptor cld, boolean forced) throws PersistenceBrokerException
+ {
+ doRetrieveCollections(newObj, cld, forced, true);
+ }
+
+ private void doRetrieveCollections(Object newObj, ClassDescriptor cld, boolean forced, boolean forceProxyCollection) throws PersistenceBrokerException
+ {
Iterator i = cld.getCollectionDescriptors().iterator();
// turn off auto prefetching for related proxies
@@ -806,7 +948,14 @@
while (i.hasNext())
{
CollectionDescriptor cds = (CollectionDescriptor) i.next();
- retrieveCollection(newObj, cld, cds, forced);
+ if(forceProxyCollection)
+ {
+ retrieveProxyCollection(newObj, cld, cds, forced);
+ }
+ else
+ {
+ retrieveCollection(newObj, cld, cds, forced);
+ }
}
pb.serviceSessionCache().disableMaterializationCache();
}
@@ -858,7 +1007,7 @@
PBMaterializationListener(Object owner,
- HashMap retrievalTasks, Object key, int limit, ProxyFactory proxyFactory)
+ HashMap retrievalTasks, Object key, int limit, ProxyFactory proxyFactory)
{
super(owner, retrievalTasks, key, limit, proxyFactory);
}
@@ -918,7 +1067,7 @@
protected ProxyFactory _proxyFactory;
PBPrefetchingListener(Object owner, HashMap retrievalTasks,
- Object key, int limit, ProxyFactory proxyFactory)
+ Object key, int limit, ProxyFactory proxyFactory)
{
_retrievalTasks = retrievalTasks;
_key = key;
@@ -997,7 +1146,7 @@
CollectionProxy _listenedCollection;
PBCollectionProxyListener(Object owner,
- HashMap retrievalTasks, CollectionDescriptor key, int limit, ProxyFactory proxyFactory)
+ HashMap retrievalTasks, CollectionDescriptor key, int limit, ProxyFactory proxyFactory)
{
super(owner, retrievalTasks, key, limit, proxyFactory);
}
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/core/ValueContainer.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/core/ValueContainer.java?rev=422231&r1=422230&r2=422231&view=diff
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/core/ValueContainer.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/core/ValueContainer.java Sat Jul 15 07:20:25 2006
@@ -103,7 +103,7 @@
public String toString()
{
return "[" + ClassUtils.getShortClassName(this.getClass()) + ": jdbcType="
- + jdbcType.getTypeAsString()
+ + jdbcType
+ ", value=" + value + "]";
}
}
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/locking/IsolationLevels.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/locking/IsolationLevels.java?rev=422231&r1=422230&r2=422231&view=diff
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/locking/IsolationLevels.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/locking/IsolationLevels.java Sat Jul 15 07:20:25 2006
@@ -176,7 +176,7 @@
/**
* Literal constant representing that no isolation level is used.
*/
- public final static String LITERAL_IL_NO_LOCKING = "no-lock";
+ public final static String LITERAL_IL_NO_LOCKING = "none";
/**
* Literal constant representing the uncommited read isolation level.
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockIsolation.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockIsolation.java?rev=422231&r1=422230&r2=422231&view=diff
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockIsolation.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockIsolation.java Sat Jul 15 07:20:25 2006
@@ -15,12 +15,13 @@
* limitations under the License.
*/
+import java.io.Serializable;
/**
* This interface defines method that a Locking Strategy must implement
* according to the isolation level it represents.
*/
-abstract class LockIsolation
+abstract class LockIsolation implements Serializable
{
/**
* Returns the isolation level identity.
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockIsolationManager.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockIsolationManager.java?rev=422231&r1=422230&r2=422231&view=diff
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockIsolationManager.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockIsolationManager.java Sat Jul 15 07:20:25 2006
@@ -15,14 +15,14 @@
* limitations under the License.
*/
-
+import java.io.Serializable;
/**
* Factory class used to obtain the proper {@link LockIsolation} level.
*
* @version $Id$
*/
-class LockIsolationManager
+class LockIsolationManager implements Serializable
{
private LockIsolation readUncommitedStrategy;
private LockIsolation readCommitedStrategy;
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockManager.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockManager.java?rev=422231&r1=422230&r2=422231&view=diff
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockManager.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockManager.java Sat Jul 15 07:20:25 2006
@@ -1,6 +1,6 @@
package org.apache.ojb.broker.locking;
-/* Copyright 2002-2004 The Apache Software Foundation
+/* Copyright 2002-2005 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -53,15 +53,16 @@
/**
* The maximal time to wait for acquire a lock.
*
- * @return The time to wait for aquire a lock.
+ * @return The time to wait for aquire a lock in milliseconds.
*/
public long getBlockTimeout();
/**
- * Set the maximal time to wait for acquire a lock in milliseconds.
+ * Set the maximal time to wait for acquire a lock.
+ * <br/>
* All so called <em>non-blocking</em> implementation will ignore this setting.
*
- * @param timeout The time to wait for acquire a lock.
+ * @param timeout The time to wait for acquire a lock in milliseconds.
*/
public void setBlockTimeout(long timeout);
Modified: db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockManagerCommonsImpl.java
URL: http://svn.apache.org/viewvc/db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockManagerCommonsImpl.java?rev=422231&r1=422230&r2=422231&view=diff
==============================================================================
--- db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockManagerCommonsImpl.java (original)
+++ db/ojb/trunk/src/java/org/apache/ojb/broker/locking/LockManagerCommonsImpl.java Sat Jul 15 07:20:25 2006
@@ -1,13 +1,5 @@
package org.apache.ojb.broker.locking;
-import org.apache.commons.lang.SystemUtils;
-import org.apache.commons.transaction.locking.GenericLock;
-import org.apache.commons.transaction.locking.GenericLockManager;
-import org.apache.commons.transaction.locking.LockException;
-import org.apache.commons.transaction.util.LoggerFacade;
-import org.apache.ojb.broker.util.logging.Logger;
-import org.apache.ojb.broker.util.logging.LoggerFactory;
-
/* Copyright 2002-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,6 +15,14 @@
* limitations under the License.
*/
+import org.apache.commons.lang.SystemUtils;
+import org.apache.commons.transaction.locking.GenericLock;
+import org.apache.commons.transaction.locking.GenericLockManager;
+import org.apache.commons.transaction.locking.LockException;
+import org.apache.commons.transaction.util.LoggerFacade;
+import org.apache.ojb.broker.util.logging.Logger;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
+
/**
* A {@link LockManager} implementation based on apache's commons-transaction
* locking part.
@@ -30,7 +30,6 @@
* The timeout of locks is currently (OJB 1.0.2) not supported, maybe
* in further versions.
*
- * @author <a href="mailto:arminw@apache.org">Armin Waibel</a>
* @version $Id$
*/
public class LockManagerCommonsImpl implements LockManager
@@ -49,12 +48,11 @@
public LockManagerCommonsImpl()
{
- LoggerFacade logFacade = new LoggerFacadeImpl();
// default lock timeout
this.lockTimeout = DEFAULT_LOCK_TIMEOUT;
// default time to wait for a lock
this.blockTimeout = DEFAULT_BLOCK_TIMEOUT;
- lm = new OJBLockManager(logFacade, blockTimeout, GenericLockManager.DEFAULT_CHECK_THRESHHOLD);
+ lm = new OJBLockManager(new LoggerFacadeImpl(), blockTimeout, GenericLockManager.DEFAULT_CHECK_THRESHHOLD);
}
public long getLockTimeout()
---------------------------------------------------------------------
To unsubscribe, e-mail: ojb-dev-unsubscribe@db.apache.org
For additional commands, e-mail: ojb-dev-help@db.apache.org