You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by jr...@apache.org on 2012/03/28 18:10:35 UTC
svn commit: r1306449 - in /openjpa/trunk:
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/
openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/
openjpa-jdbc/src/test/java/org...
Author: jrbauer
Date: Wed Mar 28 16:10:35 2012
New Revision: 1306449
URL: http://svn.apache.org/viewvc?rev=1306449&view=rev
Log:
OPENJPA-2165 Added support for non-db-ordered list proxies that provide the ability to do non-indexed add or remove operations without loading the collection from the database. Testcases and documentation will follow in future commits.
Added:
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedArrayListProxy.java (with props)
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedCollectionChangeTrackerImpl.java (with props)
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedProxy.java (with props)
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java
openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestUpdateManagerFlushException.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CollectionChangeTrackerImpl.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyCollections.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManager.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java Wed Mar 28 16:10:35 2012
@@ -242,7 +242,7 @@ public class JDBCStoreManager implements
}
protected DataSource getDataSource() {
- return _ds;
+ return _ds;
}
public boolean exists(OpenJPAStateManager sm, Object context) {
@@ -641,31 +641,37 @@ public class JDBCStoreManager implements
&& mapping.customLoad(sm, this, null, jfetch))
removeLoadedFields(sm, fields);
+
//### select is kind of a big object, and in some cases we don't
//### use it... would it be worth it to have a small shell select
//### object that only creates a real select when actually used?
-
- Select sel = _sql.newSelect();
- if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch,
- EagerFetchModes.EAGER_JOIN, true, false)) {
- sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
- if (_log.isTraceEnabled()) {
- _log.trace("load: "+mapping.getDescribedType()+" oid: "+sm.getObjectId());
- }
- res = sel.execute(this, jfetch, lockLevel);
- try {
- if (isEmptyResult(res))
- return false;
- load(mapping, sm, jfetch, res);
- } finally {
- res.close();
- }
+ //### Delayed proxy specific optimization: If the only fields that
+ //### need to be loaded are delayed proxies, building the select is
+ //### not necessary.
+
+ if (!isDelayedLoadOnly(sm, fields, mapping)) {
+ Select sel = _sql.newSelect();
+ if (select(sel, mapping, Select.SUBS_EXACT, sm, fields, jfetch,
+ EagerFetchModes.EAGER_JOIN, true, false)) {
+ sel.wherePrimaryKey(sm.getObjectId(), mapping, this);
+ if (_log.isTraceEnabled()) {
+ _log.trace("load: "+mapping.getDescribedType()+" oid: "+sm.getObjectId());
+ }
+ res = sel.execute(this, jfetch, lockLevel);
+ try {
+ if (isEmptyResult(res))
+ return false;
+ load(mapping, sm, jfetch, res);
+ } finally {
+ res.close();
+ }
+ }
}
// now allow the fields to load themselves individually too
FieldMapping[] fms = mapping.getFieldMappings();
for (int i = 0; i < fms.length; i++)
- if (fields.get(i) && !sm.getLoaded().get(i)) {
+ if (fields.get(i) && (!sm.getLoaded().get(i) || sm.isDelayed(i))) {
if (_log.isTraceEnabled()) {
_log.trace("load field: '"+ fms[i].getName() + "' for oid="+sm.getObjectId()
+" "+mapping.getDescribedType());
@@ -681,6 +687,30 @@ public class JDBCStoreManager implements
}
}
+ private boolean isDelayedLoadOnly(OpenJPAStateManager sm, BitSet fields, ClassMapping mapping) {
+ if (!sm.getContext().getConfiguration().getProxyManagerInstance().getDelayCollectionLoading()) {
+ return false;
+ }
+ boolean allDelayed = false;
+ if (!fields.isEmpty()) {
+ FieldMapping[] fms = mapping.getFieldMappings();
+ int fCount = 0;
+ int dfCount = 0;
+ for (int i = fields.nextSetBit(0); i < fms.length; i++) {
+ if (fields.get(i)) {
+ fCount++;
+ if (!(fms[i].isDelayCapable() && (!sm.getLoaded().get(i) || sm.isDelayed(i)))) {
+ break;
+ } else {
+ dfCount++;
+ }
+ }
+ }
+ allDelayed = (fCount == dfCount);
+ }
+ return allDelayed;
+ }
+
/**
* Return a list formed by removing all loaded fields from the given one.
*/
@@ -1080,10 +1110,10 @@ public class JDBCStoreManager implements
eagerToMany = fms[i];
else
fms[i].loadEagerJoin(sm, this,
- fetch.traverseJDBC(fms[i]), res);
+ fetch.traverseJDBC(fms[i]), res);
} else if (eres != null) {
processed = fms[i].loadEagerParallel(sm, this,
- fetch.traverseJDBC(fms[i]), eres);
+ fetch.traverseJDBC(fms[i]), eres);
if (processed != eres)
res.putEager(fms[i], processed);
} else {
@@ -1332,18 +1362,18 @@ public class JDBCStoreManager implements
if (esel != null) {
if (esel == sel)
fms[i].selectEagerJoin(sel, sm, this,
- fetch.traverseJDBC(fms[i]), eager);
+ fetch.traverseJDBC(fms[i]), eager);
else
fms[i].selectEagerParallel(esel, sm, this,
- fetch.traverseJDBC(fms[i]), eager);
+ fetch.traverseJDBC(fms[i]), eager);
seld = Math.max(0, seld);
} else if (requiresSelect(fms[i], sm, fields, fetch)) {
fseld = fms[i].select(sel, sm, this,
- fetch.traverseJDBC(fms[i]), eager);
+ fetch.traverseJDBC(fms[i]), eager);
seld = Math.max(fseld, seld);
} else if (optSelect(fms[i], sel, sm, fetch)) {
fseld = fms[i].select(sel, sm, this,
- fetch.traverseJDBC(fms[i]), EagerFetchModes.EAGER_NONE);
+ fetch.traverseJDBC(fms[i]), EagerFetchModes.EAGER_NONE);
// don't upgrade seld to > 0 based on these fields, since
// they're not in the calculated field set
@@ -1425,12 +1455,12 @@ public class JDBCStoreManager implements
fms = subMappings[i].getDefinedFieldMappings();
for (int j = 0; j < fms.length; j++) {
// make sure in one of configured fetch groups
- if (fetch.requiresFetch(fms[j]) != FetchConfiguration.FETCH_LOAD
+ if (fetch.requiresFetch(fms[j]) != FetchConfiguration.FETCH_LOAD
&& ((!fms[j].isInDefaultFetchGroup()
&& fms[j].isDefaultFetchGroupExplicit())
|| fms[j].supportsSelect(sel, Select.TYPE_TWO_PART, sm, this,
fetch) <= 0))
- continue;
+ continue;
// if we can join to the subclass, do so; much better chance
// that the field will be able to select itself without joins
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java Wed Mar 28 16:10:35 2012
@@ -1359,4 +1359,9 @@ public class FieldMapping
public boolean hasMapsIdCols() {
return _hasMapsIdCols;
}
+
+ @Override
+ public boolean isDelayCapable() {
+ return (getOrderColumn() == null && super.isDelayCapable());
+ }
}
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/EmbedFieldStrategy.java Wed Mar 28 16:10:35 2012
@@ -1252,6 +1252,21 @@ public class EmbedFieldStrategy
public Object replaceObjectField(PersistenceCapable pc, int field) {
throw new InternalException();
}
+
+ @Override
+ public boolean isDelayed(int field) {
+ return false;
+ }
+
+ @Override
+ public void setDelayed(int field, boolean delay) {
+ throw new InternalException();
+ }
+
+ @Override
+ public void loadDelayedField(int field) {
+ throw new UnsupportedOperationException();
+ }
}
/**
Modified: openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/StoreCollectionFieldStrategy.java Wed Mar 28 16:10:35 2012
@@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.apache.openjpa.enhance.FieldManager;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCStore;
@@ -42,13 +43,13 @@ import org.apache.openjpa.jdbc.sql.Selec
import org.apache.openjpa.jdbc.sql.Union;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StateManagerImpl;
-import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.ChangeTracker;
import org.apache.openjpa.util.Id;
import org.apache.openjpa.util.OpenJPAId;
import org.apache.openjpa.util.Proxy;
+import org.apache.openjpa.util.DelayedProxy;
/**
* Base class for strategies that are stored as a collection, even if
@@ -491,8 +492,20 @@ public abstract class StoreCollectionFie
public void load(final OpenJPAStateManager sm, final JDBCStore store,
final JDBCFetchConfiguration fetch)
throws SQLException {
+
+ Object coll = null;
+ boolean delayed = sm.isDelayed(field.getIndex());
+ if (!delayed && field.isDelayCapable()) {
+ coll = sm.newProxy(field.getIndex());
+ if (coll instanceof DelayedProxy) {
+ sm.storeObject(field.getIndex(), coll);
+ sm.setDelayed(field.getIndex(), true);
+ return;
+ }
+ }
+
if (field.isLRS()) {
- Proxy coll = newLRSProxy();
+ Proxy pcoll = newLRSProxy();
// if this is ordered we need to know the next seq to use in case
// objects are added to the collection
@@ -513,13 +526,13 @@ public abstract class StoreCollectionFie
Result res = sel.execute(store, fetch);
try {
res.next();
- coll.getChangeTracker().setNextSequence
+ pcoll.getChangeTracker().setNextSequence
(res.getInt(field) + 1);
} finally {
res.close();
}
}
- sm.storeObjectField(field.getIndex(), coll);
+ sm.storeObjectField(field.getIndex(), pcoll);
return;
}
@@ -537,14 +550,27 @@ public abstract class StoreCollectionFie
});
// create proxy
- Object coll;
ChangeTracker ct = null;
- if (field.getTypeCode() == JavaTypes.ARRAY)
- coll = new ArrayList();
- else {
- coll = sm.newProxy(field.getIndex());
+ if (delayed) {
+ if (sm.isDetached() || sm.getOwner() == null) {
+ sm.getPersistenceCapable().pcProvideField(field.getIndex());
+ coll =
+ ((FieldManager)sm.getPersistenceCapable().pcGetStateManager()).fetchObjectField(field.getIndex());
+ } else {
+ coll = sm.fetchObjectField(field.getIndex());
+ }
if (coll instanceof Proxy)
ct = ((Proxy) coll).getChangeTracker();
+ } else {
+ if (field.getTypeCode() == JavaTypes.ARRAY)
+ coll = new ArrayList();
+ else {
+ if (coll == null) {
+ coll = sm.newProxy(field.getIndex());
+ }
+ if (coll instanceof Proxy)
+ ct = ((Proxy) coll).getChangeTracker();
+ }
}
// load values
@@ -564,12 +590,14 @@ public abstract class StoreCollectionFie
res.close();
}
- // set into sm
- if (field.getTypeCode() == JavaTypes.ARRAY)
- sm.storeObject(field.getIndex(), JavaTypes.toArray
- ((Collection) coll, field.getElement().getType()));
- else
- sm.storeObject(field.getIndex(), coll);
+ // if not a delayed collection, set into sm
+ if (!delayed) {
+ if (field.getTypeCode() == JavaTypes.ARRAY)
+ sm.storeObject(field.getIndex(), JavaTypes.toArray
+ ((Collection) coll, field.getElement().getType()));
+ else
+ sm.storeObject(field.getIndex(), coll);
+ }
}
/**
Modified: openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestUpdateManagerFlushException.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestUpdateManagerFlushException.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestUpdateManagerFlushException.java (original)
+++ openjpa/trunk/openjpa-jdbc/src/test/java/org/apache/openjpa/jdbc/kernel/TestUpdateManagerFlushException.java Wed Mar 28 16:10:35 2012
@@ -690,6 +690,18 @@ public class TestUpdateManagerFlushExcep
public String fetchStringField(int fieldIndex) {
return null;
}
+
+ @Override
+ public boolean isDelayed(int field) {
+ return false;
+ }
+
+ @Override
+ public void setDelayed(int field, boolean delay) {
+ }
+
+ public void loadDelayedField(int field) {
+ }
}
/*
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedStateManager.java Wed Mar 28 16:10:35 2012
@@ -995,4 +995,19 @@ public class DetachedStateManager
if (_lock != null)
_lock.unlock();
}
+
+ @Override
+ public boolean isDelayed(int field) {
+ return false;
+ }
+
+ @Override
+ public void setDelayed(int field, boolean delay) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void loadDelayedField(int field) {
+ throw new UnsupportedOperationException();
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DetachedValueStateManager.java Wed Mar 28 16:10:35 2012
@@ -595,5 +595,20 @@ public class DetachedValueStateManager
public Object replaceObjectField(PersistenceCapable pc, int idx) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public boolean isDelayed(int field) {
+ return false;
+ }
+
+ @Override
+ public void setDelayed(int field, boolean delay) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void loadDelayedField(int field) {
+ throw new UnsupportedOperationException();
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ObjectIdStateManager.java Wed Mar 28 16:10:35 2012
@@ -739,4 +739,19 @@ public class ObjectIdStateManager
Reflection.set(_oid, Reflection.findSetter(_oid.getClass(),
fmd.getName(), fmd.getDeclaredType(), true), val);
}
+
+ @Override
+ public boolean isDelayed(int field) {
+ return false;
+ }
+
+ @Override
+ public void setDelayed(int field, boolean delay) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void loadDelayedField(int field) {
+ throw new UnsupportedOperationException();
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/OpenJPAStateManager.java Wed Mar 28 16:10:35 2012
@@ -498,5 +498,37 @@ public interface OpenJPAStateManager
* @since 0.3.1
*/
public void setRemote (int field, Object value);
+
+ /**
+ * Some field types (collection proxies) support delayed loading. Delayed loading
+ * is a step beyond lazy loading. Delayed load allows an instance of a field to be
+ * returned without actually loading it.
+ *
+ * @param field
+ * @return true if the field is setup for delayed access
+ */
+ public boolean isDelayed(int field);
+
+ /**
+ * Some field types (collection proxies) support delayed loading. Delayed loading
+ * is a step beyond lazy loading. Delayed load allows an instance of a field to be
+ * returned without actually loading it.
+ *
+ * @param field
+ */
+ public void setDelayed(int field, boolean delay);
+
+ /**
+ * If a field was marked delayed in a previous load operation this method can be
+ * used to load the field.
+ * @param field
+ */
+ public void loadDelayedField(int field);
+
+ /**
+ * Fetch an object field by index.
+ * @param field
+ */
+ public Object fetchObjectField(int field);
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java Wed Mar 28 16:10:35 2012
@@ -118,6 +118,7 @@ public class StateManagerImpl
protected BitSet _loaded = null;
private BitSet _dirty = null;
private BitSet _flush = null;
+ private BitSet _delayed = null;
private int _flags = 0;
// id is the state manager identity; oid is the persistent identity. oid
@@ -1600,6 +1601,58 @@ public class StateManagerImpl
}
}
+ public boolean isDelayed(int field) {
+ if (_delayed == null) {
+ return false;
+ }
+ return _delayed.get(field);
+ }
+
+ public void setDelayed(int field, boolean delay) {
+ if (_delayed == null) {
+ _delayed = new BitSet();
+ }
+ if (delay) {
+ _delayed.set(field);
+ } else {
+ _delayed.clear(field);
+ }
+ }
+
+ /**
+ * Loads a delayed access field.
+ * @param field
+ */
+ public void loadDelayedField(int field) {
+ if (!isDelayed(field)) {
+ return;
+ }
+
+ try {
+ beforeRead(field);
+ } catch (RuntimeException re) {
+ throw translate(re);
+ }
+ lock();
+ try {
+ boolean active = _broker.isActive();
+ int lockLevel = calculateLockLevel(active, false, null);
+ BitSet fields = new BitSet();
+ fields.set(field);
+ if (!_broker.getStoreManager().load(this, fields, _broker.getFetchConfiguration(), lockLevel, null)) {
+ throw new ObjectNotFoundException(_loc.get("del-instance", _meta.getDescribedType(), _oid)).
+ setFailedObject(getManagedInstance());
+ }
+ // Cleared the delayed bit
+ _delayed.clear(field);
+ obtainLocks(active, false, lockLevel, null, null);
+ } catch (RuntimeException re) {
+ throw translate(re);
+ } finally {
+ unlock();
+ }
+ }
+
/**
* Load the given field before access.
*/
@@ -3420,4 +3473,8 @@ public class StateManagerImpl
public void setPc(PersistenceCapable pc) {
_pc = pc;
}
+
+ public void setBroker(BrokerImpl ctx) {
+ _broker = ctx;
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FieldMetaData.java Wed Mar 28 16:10:35 2012
@@ -61,6 +61,7 @@ import org.apache.openjpa.util.Exception
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.MetaDataException;
import org.apache.openjpa.util.OpenJPAException;
+import org.apache.openjpa.util.ProxyManager;
import org.apache.openjpa.util.UnsupportedException;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.UserException;
@@ -222,6 +223,7 @@ public class FieldMetaData
private boolean _persistentCollection = false;
+ private Boolean _delayCapable = null;
/**
* Constructor.
*
@@ -2405,4 +2407,27 @@ public class FieldMetaData
return _relationType;
}
private class Unknown{};
+
+ public boolean isDelayCapable() {
+ if (_delayCapable != null) {
+ return _delayCapable.booleanValue();
+ }
+ if (getTypeCode() != JavaTypes.COLLECTION || isLRS()) {
+ _delayCapable = Boolean.FALSE;
+ return _delayCapable;
+ } else {
+ // Verify the proxy manager is configured to handle delay loading
+ ProxyManager pm = getRepository().getConfiguration().getProxyManagerInstance();
+ if (pm != null) {
+ _delayCapable = pm.getDelayCollectionLoading();
+ } else {
+ _delayCapable = Boolean.FALSE;
+ }
+ }
+ return _delayCapable;
+ }
+
+ public void setDelayCapable(Boolean delayCapable) {
+ _delayCapable = delayCapable;
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CollectionChangeTrackerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CollectionChangeTrackerImpl.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CollectionChangeTrackerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/CollectionChangeTrackerImpl.java Wed Mar 28 16:10:35 2012
@@ -31,9 +31,9 @@ public class CollectionChangeTrackerImpl
extends AbstractChangeTracker
implements CollectionChangeTracker {
- private final Collection _coll;
- private final boolean _dups;
- private final boolean _order;
+ protected final Collection _coll;
+ protected final boolean _dups;
+ protected final boolean _order;
/**
* Constructor.
Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedArrayListProxy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedArrayListProxy.java?rev=1306449&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedArrayListProxy.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedArrayListProxy.java Wed Mar 28 16:10:35 2012
@@ -0,0 +1,430 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.util;
+
+import java.io.ObjectStreamException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+
+import org.apache.openjpa.kernel.AutoDetach;
+import org.apache.openjpa.kernel.Broker;
+import org.apache.openjpa.kernel.BrokerFactory;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+
+public class DelayedArrayListProxy extends ArrayList
+ implements ProxyCollection, DelayedProxy
+{
+ private transient OpenJPAStateManager sm;
+ private transient OpenJPAStateManager _ownerSm;
+ private transient int field;
+ private transient CollectionChangeTracker changeTracker;
+ private transient Class<?> elementType;
+ private transient boolean _directAccess = false;
+ private transient BrokerFactory _brokerFactory = null;
+ private transient Broker _broker = null;
+ private transient OpenJPAStateManager _delayedSm;
+ private transient int _delayedField;
+ private transient boolean dirtyCollection = true;
+
+ public DelayedArrayListProxy()
+ {
+ }
+
+ public DelayedArrayListProxy(Collection paramCollection)
+ {
+ super(paramCollection);
+ }
+
+ public DelayedArrayListProxy(int paramInt)
+ {
+ super(paramInt);
+ }
+
+ public void setOwner(OpenJPAStateManager paramOpenJPAStateManager, int paramInt)
+ {
+ // If clearing the owner of this proxy, store away what is necessary for
+ // delayed loading
+ if (paramOpenJPAStateManager == null && paramInt == -1 && sm != null) {
+ _delayedSm = sm;
+ _delayedField = field;
+ }
+
+ this.sm = paramOpenJPAStateManager;
+ if (sm != null && sm.getPersistenceCapable() != null) {
+ _ownerSm = (OpenJPAStateManager) sm.getPersistenceCapable().pcGetStateManager();
+ }
+ this.field = paramInt;
+ if (sm != null && sm.getContext() != null) {
+ _brokerFactory = sm.getContext().getBroker().getBrokerFactory();
+ }
+ }
+
+ public int getDelayedField() {
+ if (field == -1) {
+ return _delayedField;
+ }
+ return field;
+ }
+
+ public OpenJPAStateManager getDelayedOwner() {
+ if (sm == null) {
+ return _delayedSm;
+ }
+ return sm;
+ }
+
+ public OpenJPAStateManager getOwner()
+ {
+ return sm;
+ }
+
+ public int getOwnerField()
+ {
+ return field;
+ }
+
+ public Object clone()
+ {
+ if (isDirectAccess()) {
+ return super.clone();
+ }
+ if (isDelayLoad()) {
+ load();
+ }
+ Proxy localProxy = (Proxy)super.clone();
+ localProxy.setOwner(null, 0);
+ return localProxy;
+ }
+
+ public ChangeTracker getChangeTracker()
+ {
+ return this.changeTracker;
+ }
+
+ protected void setChangeTracker(CollectionChangeTracker ct) {
+ changeTracker = ct;
+ }
+
+ public Object copy(Object paramObject)
+ {
+ return new ArrayList((Collection)paramObject);
+ }
+
+ public Class getElementType()
+ {
+ return this.elementType;
+ }
+
+ protected void setElementType(Class<?> elemType) {
+ elementType = elemType;
+ }
+
+ @Override
+ public ProxyCollection newInstance(Class paramClass, Comparator paramComparator, boolean paramBoolean1,
+ boolean paramBoolean2)
+ {
+ DelayedArrayListProxy proxy = new DelayedArrayListProxy();
+ proxy.elementType = paramClass;
+ proxy.changeTracker = new DelayedCollectionChangeTrackerImpl(proxy, true, true, paramBoolean2);
+ return proxy;
+ }
+
+ public boolean add(Object paramObject)
+ {
+ if (_directAccess) {
+ return super.add(paramObject);
+ }
+ ProxyCollections.beforeAdd(this, paramObject);
+ boolean bool = super.add(paramObject);
+ return ProxyCollections.afterAdd(this, paramObject, bool);
+ }
+
+ public void add(int paramInt, Object paramObject)
+ {
+ if (!_directAccess) {
+ if (isDelayLoad()) {
+ load();
+ }
+ }
+ ProxyCollections.beforeAdd(this, paramInt, paramObject);
+ super.add(paramInt, paramObject);
+ }
+
+ public void clear()
+ {
+ if (!_directAccess) {
+ if (isDelayLoad()) {
+ load();
+ }
+ ProxyCollections.beforeClear(this);
+ }
+ super.clear();
+ }
+
+ public boolean addAll(int paramInt, Collection paramCollection)
+ {
+ if (isDelayLoad()) {
+ load();
+ }
+ return ProxyCollections.addAll(this, paramInt, paramCollection);
+ }
+
+ public boolean addAll(Collection paramCollection)
+ {
+ if (_directAccess) {
+ return super.addAll(paramCollection);
+ }
+ return ProxyCollections.addAll(this, paramCollection);
+ }
+
+ public boolean remove(Object paramObject)
+ {
+ if (_directAccess) {
+ return super.remove(paramObject);
+ }
+ ProxyCollections.beforeRemove(this, paramObject);
+ setDirectAccess(true);
+ boolean bool = super.remove(paramObject);
+ setDirectAccess(false);
+ return ProxyCollections.afterRemove(this, paramObject, bool);
+ }
+
+ public Object remove(int paramInt)
+ {
+ if (_directAccess) {
+ return super.remove(paramInt);
+ }
+ if (isDelayLoad()) {
+ load();
+ }
+ ProxyCollections.beforeRemove(this, paramInt);
+ Object localObject = super.remove(paramInt);
+ return ProxyCollections.afterRemove(this, paramInt, localObject);
+ }
+
+ public Object set(int paramInt, Object paramObject)
+ {
+ if (_directAccess) {
+ return super.set(paramInt, paramObject);
+ }
+ if (isDelayLoad()) {
+ load();
+ }
+ ProxyCollections.beforeSet(this, paramInt, paramObject);
+ Object localObject = super.set(paramInt, paramObject);
+ return ProxyCollections.afterSet(this, paramInt, paramObject, localObject);
+ }
+
+ public Iterator iterator()
+ {
+ if (_directAccess) {
+ return super.iterator();
+ }
+ if (isDelayLoad()) {
+ load();
+ }
+ Iterator localIterator = super.iterator();
+ return ProxyCollections.afterIterator(this, localIterator);
+ }
+
+ public ListIterator listIterator(int paramInt)
+ {
+ if (_directAccess) {
+ return super.listIterator(paramInt);
+ }
+ if (isDelayLoad()) {
+ load();
+ }
+ ListIterator localListIterator = super.listIterator(paramInt);
+ return ProxyCollections.afterListIterator(this, paramInt, localListIterator);
+ }
+
+ public ListIterator listIterator()
+ {
+ if (_directAccess) {
+ return super.listIterator();
+ }
+ if (isDelayLoad()) {
+ load();
+ }
+ ListIterator localListIterator = super.listIterator();
+ return ProxyCollections.afterListIterator(this, localListIterator);
+ }
+
+ public boolean removeAll(Collection paramCollection)
+ {
+ if (_directAccess) {
+ return super.removeAll(paramCollection);
+ }
+ if (isDelayLoad()) {
+ load();
+ }
+ return ProxyCollections.removeAll(this, paramCollection);
+ }
+
+ public boolean retainAll(Collection paramCollection)
+ {
+ if (_directAccess) {
+ return super.retainAll(paramCollection);
+ }
+ if (isDelayLoad()) {
+ load();
+ }
+ return ProxyCollections.retainAll(this, paramCollection);
+ }
+
+ protected Object writeReplace()
+ throws ObjectStreamException
+ {
+ if (isDelayLoad()) {
+ load();
+ }
+ return Proxies.writeReplace(this, true);
+ }
+
+ public boolean isDelayLoad() {
+ return ProxyCollections.isDelayed(this);
+ }
+
+ @Override
+ public Object get(int location) {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.get(location);
+ }
+
+
+@Override
+ public int indexOf(Object object) {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.indexOf(object);
+ }
+
+ @Override
+ public int lastIndexOf(Object object) {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.lastIndexOf(object);
+ }
+
+ @Override
+ public List subList(int start, int end) {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.subList(start, end);
+ }
+
+ @Override
+ public boolean contains(Object object) {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.contains(object);
+ }
+
+ @Override
+ public boolean containsAll(Collection collection) {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.containsAll(collection);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.isEmpty();
+ }
+
+ @Override
+ public int size() {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.size();
+ }
+
+ @Override
+ public Object[] toArray() {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.toArray();
+ }
+
+ @Override
+ public Object[] toArray(Object[] array) {
+ if (!_directAccess && isDelayLoad()) {
+ load();
+ }
+ return super.toArray(array);
+ }
+
+ public boolean isDirectAccess() {
+ return _directAccess;
+ }
+
+ public void setDirectAccess(boolean direct) {
+ _directAccess = direct;
+ }
+
+ public BrokerFactory getBrokerFactory() {
+ return _brokerFactory;
+ }
+
+ @Override
+ public void load() {
+ ProxyCollections.loadCollection(this);
+ }
+
+ @Override
+ public Broker getBroker() {
+ if (_broker == null || _broker.isClosed()) {
+ if (_brokerFactory != null) {
+ _broker = _brokerFactory.newBroker();
+ }
+ }
+ return _broker;
+ }
+
+ @Override
+ public void closeBroker() {
+ if (_broker != null && !_broker.isClosed()) {
+ _broker.setAutoDetach(AutoDetach.DETACH_CLOSE);
+ _broker.close();
+ _broker = null;
+ }
+ }
+
+ @Override
+ public OpenJPAStateManager getOwnerStateManager() {
+ return _ownerSm;
+ }
+}
Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedArrayListProxy.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedCollectionChangeTrackerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedCollectionChangeTrackerImpl.java?rev=1306449&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedCollectionChangeTrackerImpl.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedCollectionChangeTrackerImpl.java Wed Mar 28 16:10:35 2012
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * A collection change tracker used by delay loaded collections.
+ *
+ * @nojavadoc
+ */
+public class DelayedCollectionChangeTrackerImpl
+ extends CollectionChangeTrackerImpl {
+
+ public DelayedCollectionChangeTrackerImpl(Collection coll, boolean dups,
+ boolean order,boolean autoOff) {
+ super(coll, dups, order, autoOff);
+ }
+
+ protected void add(Object elem) {
+ if (rem == null || !rem.remove(elem)) {
+ if (add == null) {
+ if (_dups || _order)
+ add = new ArrayList();
+ else
+ add = newSet();
+ }
+ add.add(elem);
+ } else {
+ if (change == null)
+ change = newSet();
+ change.add(elem);
+ }
+ }
+
+ protected void remove(Object elem) {
+ if (add == null || !add.remove(elem)) {
+ if (rem == null)
+ rem = newSet();
+ rem.add(elem);
+ }
+ }
+
+ protected void change(Object elem) {
+ throw new InternalException();
+ }
+}
Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedCollectionChangeTrackerImpl.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedProxy.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedProxy.java?rev=1306449&view=auto
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedProxy.java (added)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedProxy.java Wed Mar 28 16:10:35 2012
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openjpa.util;
+
+import org.apache.openjpa.kernel.Broker;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+
+public interface DelayedProxy {
+
+ void load();
+
+ boolean isDirectAccess();
+
+ void setDirectAccess(boolean direct);
+
+ Broker getBroker();
+
+ void closeBroker();
+
+ OpenJPAStateManager getOwnerStateManager();
+
+ OpenJPAStateManager getDelayedOwner();
+
+ int getDelayedField();
+}
Propchange: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/DelayedProxy.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyCollections.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyCollections.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyCollections.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyCollections.java Wed Mar 28 16:10:35 2012
@@ -18,12 +18,18 @@
*/
package org.apache.openjpa.util;
+import java.util.ArrayList;
import java.util.Collection;
-import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
+import org.apache.openjpa.kernel.Broker;
+import org.apache.openjpa.kernel.BrokerImpl;
+import org.apache.openjpa.kernel.DetachedValueStateManager;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.StateManagerImpl;
+
/**
* Utility methods used by collection proxies.
*
@@ -54,7 +60,10 @@ public class ProxyCollections
*/
public static void beforeAdd(ProxyCollection coll, Object value) {
assertAllowedType(value, coll.getElementType());
- dirty(coll, false);
+ // Must only dirty the collection outside of a delayed load
+ if (!isDirectAccess(coll)) {
+ dirty(coll, false);
+ }
}
/**
@@ -65,8 +74,11 @@ public class ProxyCollections
*/
public static boolean afterAdd(ProxyCollection coll, Object value,
boolean added) {
- if (added && coll.getChangeTracker() != null)
+ if (!isDirectAccess(coll) && added && coll.getChangeTracker() != null) {
+ setDirectAccess(coll,true);
((CollectionChangeTracker) coll.getChangeTracker()).added(value);
+ setDirectAccess(coll,false);
+ }
return added;
}
@@ -139,7 +151,7 @@ public class ProxyCollections
*/
public static boolean addAll(ProxyCollection coll, Collection values) {
boolean added = false;
- for (Iterator itr = values.iterator(); itr.hasNext();)
+ for (Iterator<?> itr = values.iterator(); itr.hasNext();)
added |= coll.add(itr.next());
return added;
}
@@ -149,7 +161,7 @@ public class ProxyCollections
*/
public static void beforeClear(ProxyCollection coll) {
dirty(coll, true);
- for (Iterator itr = coll.iterator(); itr.hasNext();)
+ for (Iterator<?> itr = coll.iterator(); itr.hasNext();)
removed(coll, itr.next(), false);
}
@@ -304,7 +316,10 @@ public class ProxyCollections
* Call before invoking {@link Collection#remove} on super.
*/
public static void beforeRemove(ProxyCollection coll, Object o) {
- dirty(coll, false);
+ // Must only dirty the collection outside of a delayed load
+ if (!isDirectAccess(coll)) {
+ dirty(coll, false);
+ }
}
/**
@@ -315,14 +330,40 @@ public class ProxyCollections
*/
public static boolean afterRemove(ProxyCollection coll, Object o,
boolean removed){
- if (!removed)
- return false;
- if (coll.getChangeTracker() != null)
+ boolean isDelayed = isDelayed(coll);
+ boolean direct = isDirectAccess(coll);
+ if (!isDelayed) {
+ if (!removed)
+ return false;
+ }
+ if (!direct && coll.getChangeTracker() != null) {
+ // switch on direct access to prevent the removed op from
+ // inadvertently loading the collection
+ setDirectAccess(coll, true);
((CollectionChangeTracker) coll.getChangeTracker()).removed(o);
- removed(coll, o, false);
+ setDirectAccess(coll, false);
+ }
+ if (!isDelayed) {
+ removed(coll, o, false);
+ }
return true;
}
+ private static boolean isDirectAccess(ProxyCollection coll) {
+ if (coll instanceof DelayedProxy) {
+ DelayedProxy dpxy = (DelayedProxy)coll;
+ return dpxy.isDirectAccess();
+ }
+ return false;
+ }
+
+ private static void setDirectAccess(ProxyCollection coll, boolean direct) {
+ if (coll instanceof DelayedProxy) {
+ DelayedProxy dpxy = (DelayedProxy)coll;
+ dpxy.setDirectAccess(direct);
+ }
+ }
+
/**
* Call before invoking {@link Vector#removeElement} on super.
*/
@@ -400,9 +441,9 @@ public class ProxyCollections
/**
* Override for {@link Collection#removeAll}.
*/
- public static boolean removeAll(ProxyCollection coll, Collection vals) {
+ public static boolean removeAll(ProxyCollection coll, Collection<?> vals) {
boolean removed = false;
- for (Iterator itr = vals.iterator(); itr.hasNext();)
+ for (Iterator<?> itr = vals.iterator(); itr.hasNext();)
removed |= coll.remove(itr.next());
return removed;
}
@@ -410,9 +451,9 @@ public class ProxyCollections
/**
* Override for {@link Collection#retainAll}.
*/
- public static boolean retainAll(ProxyCollection coll, Collection vals) {
+ public static boolean retainAll(ProxyCollection coll, Collection<?> vals) {
int size = coll.size();
- for (Iterator itr = coll.iterator(); itr.hasNext();)
+ for (Iterator<?> itr = coll.iterator(); itr.hasNext();)
if (!vals.contains(itr.next()))
itr.remove();
return coll.size() < size;
@@ -469,4 +510,110 @@ public class ProxyCollections
public static interface ProxyListIterator
extends ProxyIterator, ListIterator {
}
+
+ public static void loadCollection(ProxyCollection proxy) {
+ loadCollection(proxy, false);
+ }
+
+ public static void loadCollection(ProxyCollection proxy, boolean detaching) {
+ if (!isDelayed(proxy)) {
+ return;
+ }
+ DelayedProxy dProxy = (DelayedProxy)proxy;
+ if (dProxy.isDirectAccess()) {
+ return;
+ }
+ boolean state[] = new boolean[2];
+ try {
+ dProxy.setDirectAccess(true);
+ state = checkState(proxy);
+ boolean tracking = false;
+ ChangeTracker ct = proxy.getChangeTracker();
+ Collection<?> added = null;
+ Collection<?> removed = null;
+ if (ct != null && ct.isTracking() ) {
+ if (!ct.getAdded().isEmpty()) {
+ added = new ArrayList(ct.getAdded());
+ }
+ if (!ct.getRemoved().isEmpty()) {
+ removed = new ArrayList(ct.getRemoved());
+ }
+ tracking = true;
+ ct.stopTracking();
+ }
+ if (proxy.size() > 0) {
+ proxy.clear();
+ }
+ dProxy.getDelayedOwner().loadDelayedField(dProxy.getDelayedField());
+ if (!detaching && tracking && !ct.isTracking()) {
+ ct.startTracking();
+ }
+ // add new elements
+ if (added != null && added.size() > 0) {
+ dProxy.setDirectAccess(false);
+ proxy.addAll(added);
+ added.clear();
+ }
+ // purge removed elements
+ if (removed != null && removed.size() > 0) {
+ dProxy.setDirectAccess(false);
+ proxy.removeAll(removed);
+ removed.clear();
+ }
+ } finally {
+ dProxy.setDirectAccess(false);
+ if (state[0]) {
+ dProxy.closeBroker();
+ }
+ if (state[1]) {
+ clearStateManager(proxy);
+ }
+ }
+ }
+
+ public static boolean isDelayed(ProxyCollection proxy) {
+ if (proxy instanceof DelayedProxy) {
+ DelayedProxy dProxy = (DelayedProxy)proxy;
+ OpenJPAStateManager sm = dProxy.getDelayedOwner();
+ return (sm != null &&
+ sm.isDelayed(dProxy.getDelayedField()));
+ }
+ return false;
+ }
+
+ private static boolean[] checkState(ProxyCollection proxy) {
+ boolean[] state = new boolean[2];
+ DelayedProxy dProxy = (DelayedProxy)proxy;
+
+ OpenJPAStateManager sm = dProxy.getDelayedOwner();
+ if (sm != null) {
+ // If the broker assigned to this proxy is null, closed or no longer
+ // manages the pc, produce a new one
+ Broker broker = sm.getContext().getBroker();
+ if (broker == null || broker.isClosed()
+ || (!broker.isClosed() && !broker.isPersistent(sm.getPersistenceCapable()))) {
+ state[0] = true;
+ broker = dProxy.getBroker();
+ ((StateManagerImpl)sm).setBroker((BrokerImpl)broker);
+ }
+ if (sm.getPersistenceCapable().pcGetStateManager() == null) {
+ state[1] = true;
+ if (dProxy.getOwnerStateManager() != null) {
+ sm.getPersistenceCapable().pcReplaceStateManager(dProxy.getOwnerStateManager());
+ ((StateManagerImpl)dProxy.getOwnerStateManager()).setBroker((BrokerImpl)broker);
+ } else {
+ sm.getPersistenceCapable().pcReplaceStateManager(
+ new DetachedValueStateManager(sm.getPersistenceCapable(), sm.getContext()));
+ }
+ }
+ }
+ return state;
+ }
+
+ private static void clearStateManager(ProxyCollection proxy) {
+ OpenJPAStateManager sm = proxy.getOwner();
+ if (sm != null) {
+ sm.getPersistenceCapable().pcReplaceStateManager(null);
+ }
+ }
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManager.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManager.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManager.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManager.java Wed Mar 28 16:10:35 2012
@@ -113,4 +113,15 @@ public interface ProxyManager {
* @since 0.2.5
*/
public Proxy newCustomProxy (Object obj, boolean autoOff);
+
+ /**
+ * Returns whether this proxy manager is enabled for delayed collection
+ * loading. Delayed collection loading provides the ability to do simple,
+ * non-indexed add or remove operations on a lazy collection without
+ * loading the collection. The collection is loaded when necessary, such
+ * as iteration, indexed operations, isEmpty, or size.
+ *
+ * @since 2.2.1
+ */
+ public boolean getDelayCollectionLoading();
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java?rev=1306449&r1=1306448&r2=1306449&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java Wed Mar 28 16:10:35 2012
@@ -98,6 +98,7 @@ public class ProxyManagerImpl
private final Map _proxies = new NullSafeConcurrentHashMap();
private boolean _trackChanges = true;
private boolean _assertType = false;
+ private boolean _delayedCollectionLoading = false;
public ProxyManagerImpl() {
_unproxyable.add(TimeZone.class.getName());
@@ -138,7 +139,26 @@ public class ProxyManagerImpl
public void setAssertAllowedType(boolean assertType) {
_assertType = assertType;
}
-
+
+ /**
+ * Whether loading of collections should be delayed until an operation
+ * is performed that requires them to be loaded. This property only
+ * applies to proxies that implement java.util.Collection (ie. not arrays
+ * or maps). Defaults to false.
+ * @return
+ */
+ public boolean getDelayCollectionLoading() {
+ return _delayedCollectionLoading;
+ }
+
+ /**
+ * Whether loading of collections should be delayed until an operation
+ * is performed that requires them to be loaded. Defaults to false.
+ */
+ public void setDelayCollectionLoading(boolean delay) {
+ _delayedCollectionLoading = delay;
+ }
+
/**
* Return a mutable view of class names we know cannot be proxied
* correctly by this manager.
@@ -477,6 +497,9 @@ public class ProxyManagerImpl
*/
protected Class loadBuildTimeProxy(Class type, ClassLoader loader) {
try {
+ if (_delayedCollectionLoading && type.equals(java.util.ArrayList.class)) {
+ return org.apache.openjpa.util.DelayedArrayListProxy.class;
+ }
return Class.forName(getProxyClassName(type, false), true, loader);
} catch (Throwable t) {
return null;