diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java index b658de189..82a10701a 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/AbstractDataCache.java @@ -21,7 +21,10 @@ package org.apache.openjpa.datacache; import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; +import java.util.List; +import java.util.Map; import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.event.RemoteCommitEvent; @@ -439,4 +442,14 @@ public abstract class AbstractDataCache log.warn(s_loc.get("exp-listener-ex"), e); } } + + /** + * Returns the objects for the given key List. + */ + public Map getAll(List keys) { + Map resultMap = new HashMap(keys.size()); + for(int i=0; i 0) - unloaded = addUnloaded(sm, fields, unloaded); - } else - unloaded = addUnloaded(sm, null, unloaded); + smList = (List) caches.get(cache); + if (smList == null) { + smList = new ArrayList(); + caches.put(cache, smList); + } + smList.add(sm); } else if (!cache.contains(sm.getObjectId())) unloaded = addUnloaded(sm, null, unloaded); } + + for (Iterator itr = caches.keySet().iterator(); itr.hasNext();) { + cache = (DataCache) itr.next(); + smList = (List) caches.get(cache); + List oidList = new ArrayList(smList.size()); + + for (itr=smList.iterator();itr.hasNext();) { + sm = (OpenJPAStateManager) itr.next(); + oidList.add((OpenJPAId) sm.getObjectId()); + } + + Map dataMap = cache.getAll(oidList); + + for (itr=smList.iterator();itr.hasNext();) { + sm = (OpenJPAStateManager) itr.next(); + data = (DataCachePCData) dataMap.get( + (OpenJPAId) sm.getObjectId()); + + if (sm.getManagedInstance() == null) { + if (data != null) { + //### the 'data.type' access here probably needs + //### to be addressed for bug 511 + sm.initialize(data.getType(), state); + data.load(sm, fetch, edata); + } else + unloaded = addUnloaded(sm, null, unloaded); + } else if (load != FORCE_LOAD_NONE + || sm.getPCState() == PCState.HOLLOW) { + data = cache.get(sm.getObjectId()); + if (data != null) { + // load unloaded fields + fields = sm.getUnloaded(fetch); + data.load(sm, fields, fetch, edata); + if (fields.length() > 0) + unloaded = addUnloaded(sm, fields, unloaded); + } else + unloaded = addUnloaded(sm, null, unloaded); + } + } + } if (unloaded == null) return Collections.EMPTY_LIST; diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java index 8a9275871..8db30d3a9 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DelegatingDataCache.java @@ -20,6 +20,8 @@ package org.apache.openjpa.datacache; import java.util.BitSet; import java.util.Collection; +import java.util.List; +import java.util.Map; import org.apache.commons.lang.ObjectUtils; import org.apache.openjpa.util.RuntimeExceptionTranslator; @@ -333,4 +335,14 @@ public class DelegatingDataCache throw translate(re); } } + + public Map getAll(List keys) { + if (_cache == null) + return null; + try { + return _cache.getAll(keys); + } catch (RuntimeException re) { + throw translate(re); + } + } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractPCData.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractPCData.java index 0c53840e4..6bf11e427 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractPCData.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractPCData.java @@ -75,9 +75,8 @@ public abstract class AbstractPCData case JavaTypes.COLLECTION: ProxyDataList c = (ProxyDataList) data; Collection c2 = (Collection) sm.newFieldProxy(fmd.getIndex()); - for (int i = 0; i < c.size(); i++) - c2.add(toNestedField(sm, fmd.getElement(), c.get(i), - fetch, context)); + c2 = toNestedFields(sm, fmd.getElement(), (Collection) data, + fetch, context); if (c2 instanceof Proxy) { ChangeTracker ct = ((Proxy) c2).getChangeTracker(); if (ct != null) @@ -87,17 +86,18 @@ public abstract class AbstractPCData case JavaTypes.MAP: Map m = (Map) data; Map m2 = (Map) sm.newFieldProxy(fmd.getIndex()); - Map.Entry e; - Object key; - Object value; - for (Iterator mi = m.entrySet().iterator(); mi.hasNext();) { - e = (Map.Entry) mi.next(); - key = toNestedField(sm, fmd.getKey(), e.getKey(), - fetch, context); - value = toNestedField(sm, fmd.getElement(), e.getValue(), - fetch, context); - m2.put(key, value); - } + Collection keys = new ArrayList (m.size()); + + for (Iterator mi = m.entrySet().iterator(); mi.hasNext();) + keys.add(mi.next()); + + Object[] keyArray = keys.toArray(); + Object[] values = toNestedFields(sm, fmd.getElement(), + keys, fetch, context).toArray(); + int idx = 0; + for (Iterator mi = m.entrySet().iterator(); mi.hasNext(); idx++) + m2.put(keyArray[idx], values[idx]); + return m2; case JavaTypes.ARRAY: int length = Array.getLength(data); @@ -151,6 +151,51 @@ public abstract class AbstractPCData } } + /** + * Transform the given data value to its field value. The data value + * may be a key, value, or element of a map or collection. + */ + protected Collection toNestedFields(OpenJPAStateManager sm, + ValueMetaData vmd, Collection data, FetchConfiguration fetch, + Object context) { + if (data == null) + return null; + + Collection ret = new ArrayList(data.size()); + switch (vmd.getDeclaredTypeCode()) { + case JavaTypes.DATE: + for (Iterator itr=data.iterator(); itr.hasNext();) + ret.add(((Date)itr.next()).clone()); + return ret; + case JavaTypes.LOCALE: + for (Iterator itr=data.iterator(); itr.hasNext();) + ret.add((Locale) itr.next()); + return ret; + case JavaTypes.PC: + if (vmd.isEmbedded()) + for (Iterator itr=data.iterator(); itr.hasNext();) + ret.add(toEmbeddedField(sm, vmd, itr.next(), fetch + , context)); + // no break + case JavaTypes.PC_UNTYPED: + Object[] r = toRelationFields(sm, data, fetch); + if (r != null) { + for (int i = 0; i < r.length; i++) + if (r[i] != null) + ret.add(r[i]); + else { + ret.add(sm.getContext().getConfiguration(). + getOrphanedKeyActionInstance(). + orphan(data, sm, vmd)); + } + return ret; + } + default: + return data; + } + } + + /** * Transform the given data into a relation field value. Default * implementation assumes the data is an oid. @@ -160,6 +205,15 @@ public abstract class AbstractPCData return sm.getContext().find(data, fetch, null, null, 0); } + /** + * Transform the given data into relation field values. Default + * implementation assumes the data is an oid. + */ + protected Object[] toRelationFields(OpenJPAStateManager sm, + Object data, FetchConfiguration fetch) { + return sm.getContext().findAll((Collection) data, fetch, null, null, 0); + } + /** * Transform the given data into an embedded PC field value. Default * implementation assumes the data is an {@link AbstractPCData}. diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java index 75aa0ea66..370c5789b 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java @@ -184,6 +184,7 @@ public class BrokerImpl private Set _updatedClss = null; private Set _deletedClss = null; private Set _pending = null; + private int findAllDepth = 0; // track instances that become transactional after the first savepoint // (the first uses the transactional cache) @@ -903,6 +904,8 @@ public class BrokerImpl */ protected Object[] findAll(Collection oids, FetchConfiguration fetch, BitSet exclude, Object edata, int flags, FindCallbacks call) { + findAllDepth ++; + // throw any exceptions for null oids up immediately if (oids == null) throw new NullPointerException("oids == null"); @@ -912,7 +915,9 @@ public class BrokerImpl // we have to use a map of oid->sm rather than a simple // array, so that we make sure not to create multiple sms for equivalent // oids if the user has duplicates in the given array - _loading = new HashMap((int) (oids.size() * 1.33 + 1)); + if (_loading == null) + _loading = new HashMap((int) (oids.size() * 1.33 + 1)); + if (call == null) call = this; if (fetch == null) @@ -1007,7 +1012,9 @@ public class BrokerImpl } catch (RuntimeException re) { throw new GeneralException(re); } finally { - _loading = null; + findAllDepth--; + if (findAllDepth == 0) + _loading = null; endOperation(); } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java index 5f4f68a2e..7b3233a7e 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/PCDataImpl.java @@ -136,6 +136,7 @@ public class PCDataImpl loadImplData(sm); FieldMetaData[] fmds = sm.getMetaData().getFields(); + ((StateManagerImpl)sm).setLoading(true); for (int i = 0; i < fmds.length; i++) { // load intermediate data for all unloaded fields and data for // fields in configured fetch groups