You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by cu...@apache.org on 2010/03/30 05:43:20 UTC

svn commit: r928968 - in /openjpa/branches/2.0.x: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-persistence-jdbc/src...

Author: curtisr7
Date: Tue Mar 30 03:43:20 2010
New Revision: 928968

URL: http://svn.apache.org/viewvc?rev=928968&view=rev
Log:
OPENAJPA-1603: Decouple the QueryCache from the DataCache. Code contributed by Mike Dick and Rick Curtis.

Added:
    openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java   (with props)
    openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java   (with props)
Modified:
    openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java
    openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java
    openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java
    openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java
    openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java
    openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java

Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java (original)
+++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java Tue Mar 30 03:43:20 2010
@@ -30,12 +30,15 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import javax.sql.DataSource;
 
 import org.apache.commons.lang.StringUtils;
+import org.apache.openjpa.datacache.QueryCache;
+import org.apache.openjpa.datacache.QueryCacheStoreQuery;
 import org.apache.openjpa.enhance.PersistenceCapable;
 import org.apache.openjpa.event.OrphanedKeyAction;
 import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
@@ -295,6 +298,11 @@ public class JDBCStoreManager 
         return exists(mapping, sm.getObjectId(), context);
     }
 
+    public boolean isCached(List<Object> oids, BitSet edata) {
+        // JDBCStoreManager doesn't store oids in memory.
+        return false;
+    }
+    
     private boolean exists(ClassMapping mapping, Object oid, Object context) {
         // add where conditions on base class to avoid joins if subclass
         // doesn't use oid as identifier
@@ -455,8 +463,9 @@ public class JDBCStoreManager 
         // Check if the owner has eagerly loaded ToMany relations.
         for (int i = 0; i < fms.length; i++) {
             if (res.getEager(fms[i]) != null) {
-                if (!fms[i].getElement().isTypePC())
+                if (!fms[i].getElement().isTypePC()) {
                     continue;
+                }
                 Object coll =  owner.fetchObject(fms[i].getIndex());
                 if (coll instanceof Map)
                     coll = ((Map)coll).values();
@@ -471,24 +480,23 @@ public class JDBCStoreManager 
                     for (Iterator<?> itr = ((Collection<?>) coll).iterator();
                         itr.hasNext();) {
                         PersistenceCapable pc = (PersistenceCapable) itr.next();
-
-                        if (pc == null)
+                        if (pc == null) {
                             continue;
-
-                        OpenJPAStateManager sm = (OpenJPAStateManager) pc.
-                            pcGetStateManager();
-                        FieldMapping[] fmd = ((ClassMapping) sm.getMetaData()).
-                            getFieldMappings();
+                        }
+                        OpenJPAStateManager sm = (OpenJPAStateManager) pc.pcGetStateManager();
+                        ClassMapping cm =
+                            (ClassMapping) _conf.getMetaDataRepositoryInstance().getCachedMetaData(pc.getClass());
+                        FieldMapping[] fmd = cm.getFieldMappings();
                         for (int j = 0; j < fmd.length; j++) {
-                            Object oid = sm.getIntermediate(fmd[j].getIndex());
-                            // if oid was setIntermediate() previously
-                            // and it is the same as the owner,
-                            // then set the inverse relation
-                            if (oid != null &&
-                                oid.equals(owner.getObjectId())) {
-                                sm.storeObject(fmd[j].getIndex(),
-                                    owner.getPersistenceCapable());
-                                break;
+                            // don't check the oids for basic fields.
+                            if (fmd[j].isTypePC()) {
+                                Object oid = sm.getIntermediate(fmd[j].getIndex());
+                                // if oid was setIntermediate() previously and it is the same as the owner,generate
+                                // then set the inverse relation
+                                if (oid != null && oid.equals(owner.getObjectId())) {
+                                    sm.storeObject(fmd[j].getIndex(), owner.getPersistenceCapable());
+                                    break;
+                                }
                             }
                         }
                     }
@@ -911,16 +919,33 @@ public class JDBCStoreManager 
         return paged;
     }
 
-    public StoreQuery newQuery(String language) {
+    private StoreQuery newStoreQuery(String language) {
         ExpressionParser ep = QueryLanguages.parserForLanguage(language);
-        if (ep != null)
+        if (ep != null) { 
             return new JDBCStoreQuery(this, ep);
-        if (QueryLanguages.LANG_SQL.equals(language))
+        }
+        if (QueryLanguages.LANG_SQL.equals(language)) {
             return new SQLStoreQuery(this);
-        if (QueryLanguages.LANG_PREPARED_SQL.equals(language))
+        }
+        if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
             return new PreparedSQLStoreQuery(this);
+        }
         return null;
     }
+    
+    public StoreQuery newQuery(String language) {
+        StoreQuery sq = newStoreQuery(language); 
+        if (sq == null || QueryLanguages.parserForLanguage(language) == null) {
+            return sq;
+        }
+
+        QueryCache queryCache = _ctx.getConfiguration().getDataCacheManagerInstance().getSystemQueryCache();
+        if (queryCache == null) {
+            return sq;
+        }
+        
+        return new QueryCacheStoreQuery(sq, queryCache);
+    }
 
     public FetchConfiguration newFetchConfiguration() {
         return new JDBCFetchConfigurationImpl();

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java Tue Mar 30 03:43:20 2010
@@ -57,7 +57,11 @@ public class DataCacheManagerImpl
     
     public void initialize(OpenJPAConfiguration conf, ObjectValue dataCache, ObjectValue queryCache) {
         _conf = conf;
+        _queryCache = (QueryCache) queryCache.instantiate(QueryCache.class, conf);
+        if (_queryCache != null)
+            _queryCache.initialize(this);
         _cache = (DataCache) dataCache.instantiate(DataCache.class, conf);
+
         if (_cache == null)
             return;
          
@@ -69,9 +73,7 @@ public class DataCacheManagerImpl
         _policy = conf.getCacheDistributionPolicyInstance();
 
         _cache.initialize(this);
-        _queryCache = (QueryCache) queryCache.instantiate(QueryCache.class, conf);
-        if (_queryCache != null)
-            _queryCache.initialize(this);
+
     }
 
     public DataCache getSystemDataCache() {
@@ -155,6 +157,7 @@ public class DataCacheManagerImpl
         _includedTypes = includedTypes;
         _excludedTypes = excludedTypes;
     }
+    
     /**
      * Affirms the given class is eligible to be cached according to the cache mode
      * and the cache enable flag on the given metadata.

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java Tue Mar 30 03:43:20 2010
@@ -34,14 +34,11 @@ import org.apache.openjpa.kernel.DataCac
 import org.apache.openjpa.kernel.DataCacheStoreMode;
 import org.apache.openjpa.kernel.DelegatingStoreManager;
 import org.apache.openjpa.kernel.FetchConfiguration;
-import org.apache.openjpa.kernel.FindCallbacks;
 import org.apache.openjpa.kernel.LockLevels;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
 import org.apache.openjpa.kernel.PCState;
-import org.apache.openjpa.kernel.QueryLanguages;
 import org.apache.openjpa.kernel.StoreContext;
 import org.apache.openjpa.kernel.StoreManager;
-import org.apache.openjpa.kernel.StoreQuery;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.MetaDataRepository;
 import org.apache.openjpa.util.OpenJPAId;
@@ -228,22 +225,6 @@ public class DataCacheStoreManager
                 evictTypes(_ctx.getUpdatedTypes());
             }
 
-            // and notify the query cache.  notify in one batch to reduce synch
-            QueryCache queryCache = _ctx.getConfiguration().
-            getDataCacheManagerInstance().getSystemQueryCache();
-            if (queryCache != null) {
-                Collection<Class<?>> pers = _ctx.getPersistedTypes();
-                Collection<Class<?>> del = _ctx.getDeletedTypes();
-                Collection<Class<?>> up = _ctx.getUpdatedTypes();
-                int size = pers.size() + del.size() + up.size();
-                if (size > 0) {
-                    Collection<Class<?>> types = new ArrayList<Class<?>>(size);
-                    types.addAll(pers);
-                    types.addAll(del);
-                    types.addAll(up);
-                    queryCache.onTypesChanged(new TypesChangedEvent(this, types));
-                }
-            } 
         }
     }
 
@@ -292,12 +273,31 @@ public class DataCacheStoreManager
 
     public boolean exists(OpenJPAStateManager sm, Object edata) {
         DataCache cache = _mgr.selectCache(sm); 
-        if (cache != null && !isLocking(null)
-            && cache.contains(sm.getObjectId()))
+        if (cache != null && !isLocking(null) && cache.contains(sm.getObjectId()))
             return true;
         return super.exists(sm, edata);
     }
 
+    public boolean isCached(List<Object> oids, BitSet edata) {
+        // If using partitioned cache, we were and still are broke.
+        DataCache cache = _mgr.getSystemDataCache();
+        if (cache != null && !isLocking(null)) {
+            // BitSet size is not consistent.
+            for(int i = 0; i < oids.size(); i++) {
+                Object oid = oids.get(i);
+                // Only check the cache if we haven't found the current oid.
+                if (edata.get(i) == false && cache.contains(oid)) {
+                    edata.set(i);
+                }
+            }
+            if(edata.cardinality()==oids.size()){
+                return true;
+            }
+        }
+
+        return super.isCached(oids, edata);
+    }
+
     public boolean syncVersion(OpenJPAStateManager sm, Object edata) {
         DataCache cache = _mgr.selectCache(sm);
         if (cache == null || sm.isEmbedded())
@@ -660,22 +660,6 @@ public class DataCacheStoreManager
             .fireLocalStaleNotification(oid);
     }
 
-    public StoreQuery newQuery(String language) {
-        StoreQuery q = super.newQuery(language);
-
-        // if the query can't be parsed or it's using a non-parsed language
-        // (one for which there is no ExpressionParser), we can't cache it.
-        if (q == null || QueryLanguages.parserForLanguage(language) == null)
-            return q;
-
-        QueryCache queryCache = _ctx.getConfiguration().
-            getDataCacheManagerInstance().getSystemQueryCache();
-        if (queryCache == null)
-            return q;
-
-        return new QueryCacheStoreQuery(q, queryCache);
-    }
-
     /**
      * Create a new cacheable instance for the given state manager.
      */

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java Tue Mar 30 03:43:20 2010
@@ -33,6 +33,7 @@ import java.util.TreeMap;
 
 import org.apache.commons.collections.map.LinkedMap;
 import org.apache.openjpa.datacache.AbstractQueryCache.EvictPolicy;
+import org.apache.openjpa.kernel.DelegatingStoreManager;
 import org.apache.openjpa.kernel.FetchConfiguration;
 import org.apache.openjpa.kernel.LockLevels;
 import org.apache.openjpa.kernel.OpenJPAStateManager;
@@ -122,6 +123,7 @@ public class QueryCacheStoreQuery
 
         // get the cached data
         QueryResult res = _cache.get(qk);
+
         if (res == null)
             return null;        
         if (res.isEmpty())
@@ -153,24 +155,11 @@ public class QueryCacheStoreQuery
 
         int projs = getContext().getProjectionAliases().length;
         if (projs == 0) {
-            // make sure the data cache contains the oids for the query result;
-            // if it doesn't, then using the result could be slower than not
-            // using it because of the individual by-oid lookups
-            ClassMetaData meta = _repos.getMetaData(getContext().
-                getCandidateType(), _sctx.getClassLoader(), true);
-            if (meta.getDataCache() == null)
+            // We're only going to return the cached results if we have ALL results cached. This could be improved
+            // in the future to be a little more intelligent.
+            if (getContext().getStoreContext().isCached(res) == false) {
                 return null;
-
-            BitSet idxs = meta.getDataCache().containsAll(res);
-
-            // eventually we should optimize this to figure out how many objects
-            // the cache is missing and if only a few do a bulk fetch for them
-            int len = idxs.length();
-            if (len < res.size())
-                return null;
-            for (int i = 0; i < len; i++)
-                if (!idxs.get(i))
-                    return null;
+            }
         }
         return new CachedList(res, projs != 0, _sctx);
     }

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java Tue Mar 30 03:43:20 2010
@@ -200,14 +200,11 @@ public class QueryKey
             // since the class change framework deals with least-derived types,
             // record the least-derived access path types
             meta = metas[i];
-            if (meta.getDataCache() != null)
-                accessPathClassNames.add(meta.getDescribedType().getName());
-            while (meta.getPCSuperclass() != null)
-                meta = meta.getPCSuperclassMetaData();
-
-            // ensure that this metadata is cacheable
-            if (meta.getDataCache() == null)
-                return null;
+            accessPathClassNames.add(meta.getDescribedType().getName());
+            while (meta.getPCSuperclass() != null) {
+                meta = meta.getPCSuperclassMetaData(); 
+            }
+
             accessPathClassNames.add(meta.getDescribedType().getName());
         }
 

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java Tue Mar 30 03:43:20 2010
@@ -51,6 +51,8 @@ import org.apache.commons.lang.StringUti
 import org.apache.openjpa.conf.Compatibility;
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.datacache.DataCache;
+import org.apache.openjpa.datacache.QueryCache;
+import org.apache.openjpa.datacache.TypesChangedEvent;
 import org.apache.openjpa.ee.ManagedRuntime;
 import org.apache.openjpa.enhance.PCRegistry;
 import org.apache.openjpa.enhance.PersistenceCapable;
@@ -70,7 +72,6 @@ import org.apache.openjpa.lib.util.Refer
 import org.apache.openjpa.lib.util.ReferenceMap;
 import org.apache.openjpa.meta.ClassMetaData;
 import org.apache.openjpa.meta.FieldMetaData;
-import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.meta.MetaDataRepository;
 import org.apache.openjpa.meta.SequenceMetaData;
 import org.apache.openjpa.meta.ValueMetaData;
@@ -88,7 +89,6 @@ import org.apache.openjpa.util.ObjectId;
 import org.apache.openjpa.util.ObjectNotFoundException;
 import org.apache.openjpa.util.OpenJPAException;
 import org.apache.openjpa.util.OptimisticException;
-import org.apache.openjpa.util.Proxy;
 import org.apache.openjpa.util.RuntimeExceptionTranslator;
 import org.apache.openjpa.util.StoreException;
 import org.apache.openjpa.util.UnsupportedException;
@@ -1416,8 +1416,25 @@ public class BrokerImpl
                 releaseConn = _connRetainMode != CONN_RETAIN_ALWAYS;
                 if (rollback)
                     _store.rollback();
-                else
+                else {
+                    // and notify the query cache.  notify in one batch to reduce synch
+                    QueryCache queryCache = getConfiguration().
+                    getDataCacheManagerInstance().getSystemQueryCache();
+                    if (queryCache != null) {
+                        Collection<Class<?>> pers = getPersistedTypes();
+                        Collection<Class<?>> del = getDeletedTypes();
+                        Collection<Class<?>> up = getUpdatedTypes();
+                        int size = pers.size() + del.size() + up.size();
+                        if (size > 0) {
+                            Collection<Class<?>> types = new ArrayList<Class<?>>(size);
+                            types.addAll(pers);
+                            types.addAll(del);
+                            types.addAll(up);
+                            queryCache.onTypesChanged(new TypesChangedEvent(this, types));
+                        }
+                    } 
                     _store.commit();
+                }
             } else {
                 releaseConn = _connRetainMode == CONN_RETAIN_TRANS;
                 _store.rollbackOptimistic();
@@ -5039,4 +5056,19 @@ public class BrokerImpl
             return null;
         }
     }
+    
+    public boolean isCached(List<Object> oids) {
+        BitSet loaded = new BitSet(oids.size());
+        //check L1 cache first
+        for (int i = 0; i < oids.size(); i++) {
+            Object oid = oids.get(i);
+            if (_cache.getById(oid, false) != null) {
+                loaded.set(i);
+            }
+        }
+        if(loaded.cardinality()==oids.size()){
+            return true;
+        }
+        return _store.isCached(oids, loaded);
+    };
 }

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java Tue Mar 30 03:43:20 2010
@@ -21,6 +21,7 @@ package org.apache.openjpa.kernel;
 import java.util.BitSet;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -1463,4 +1464,8 @@ public class DelegatingBroker
     public Object getConnectionFactory2() {
         return _broker.getConnectionFactory2();
     }
+    
+    public boolean isCached(List<Object> oid) {
+        return _broker.isCached(oid);
+    }
 }

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java Tue Mar 30 03:43:20 2010
@@ -20,6 +20,7 @@ package org.apache.openjpa.kernel;
 
 import java.util.BitSet;
 import java.util.Collection;
+import java.util.List;
 
 import org.apache.openjpa.lib.rop.ResultObjectProvider;
 import org.apache.openjpa.meta.ClassMetaData;
@@ -199,4 +200,9 @@ public abstract class DelegatingStoreMan
     public boolean cancelAll() {
         return _store.cancelAll();
 	}
+	
+    public boolean isCached(List<Object> oids, BitSet edata) {
+        return _store.isCached(oids, edata);
+    }
+    
 }

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java Tue Mar 30 03:43:20 2010
@@ -21,9 +21,11 @@ package org.apache.openjpa.kernel;
 import java.util.BitSet;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.List;
 
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.meta.ValueMetaData;
+import org.apache.openjpa.util.UserException;
 
 /**
  * Represents a set of managed objects and their environment.
@@ -111,8 +113,8 @@ public interface StoreContext {
     public String getConnectionPassword();
 
     /**
-     * Return the cached instance for the given oid/object, or null if not
-     * cached.
+     * Return the instance for the given oid/object , or null if not
+     * found in the L1 cache. 
      *
      * @param oid the object's id
      * @return the cached object, or null if not cached
@@ -490,4 +492,12 @@ public interface StoreContext {
      * @return the NonJTA connection factory or null if connectionFactoryName is blank.
      */
     public Object getConnectionFactory2();
+    
+    /**
+     * Indicate whether the oid can be found in the StoreContext's L1 cache or in the StoreManager cache.
+     * @param oid List of ObjectIds for PersistenceCapables which may be found in memory.
+     * @return true if the oid is available in memory (cached) otherwise false.
+     * @since 2.0.0. 
+     */
+    public boolean isCached(List<Object> oid);
 }

Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java (original)
+++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java Tue Mar 30 03:43:20 2010
@@ -20,6 +20,7 @@ package org.apache.openjpa.kernel;
 
 import java.util.BitSet;
 import java.util.Collection;
+import java.util.List;
 
 import org.apache.openjpa.lib.rop.ResultObjectProvider;
 import org.apache.openjpa.lib.util.Closeable;
@@ -99,6 +100,13 @@ public interface StoreManager
      * if it does not.
      */
     public boolean exists(OpenJPAStateManager sm, Object edata);
+    
+    /**
+     * Verify that the given instance exists in the data store in memory; return false
+     * if it does not. When an object is found in memory the corresponding element of 
+     * the BitSet is set to 1. 
+     */
+    public boolean isCached(List<Object> oids, BitSet edata);
 
     /**
      * Update the version information in the given state manager to the

Modified: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java (original)
+++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java Tue Mar 30 03:43:20 2010
@@ -781,7 +781,8 @@ public abstract class CacheTest extends 
             Collection c = (Collection) q.execute();
             iterate(c);
 
-            assertInCache(q, Boolean.FALSE);
+            // Query results are no longer dependent on cacheability of an entity.
+            assertInCache(q, Boolean.TRUE);
         }
         finally {
             close(broker);
@@ -801,7 +802,8 @@ public abstract class CacheTest extends 
             Collection c = (Collection) q.execute();
             iterate(c);
 
-            assertInCache(q, Boolean.FALSE);
+         // Query results are no longer dependent on cacheability of an entity.
+            assertInCache(q, Boolean.TRUE);
         }
         finally {
             close(broker);

Modified: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java (original)
+++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java Tue Mar 30 03:43:20 2010
@@ -23,112 +23,104 @@ import java.util.List;
 import javax.persistence.EntityManager;
 import javax.persistence.NamedQuery;
 
-import org.apache.openjpa.persistence.common.utils.AbstractTestCase;
 import org.apache.openjpa.persistence.querycache.common.apps.Entity1;
 import org.apache.openjpa.persistence.querycache.common.apps.Entity2;
+import org.apache.openjpa.persistence.test.SQLListenerTestCase;
 
 @NamedQuery(name = "setParam1",
-    query = "SELECT o FROM Entity1 o WHERE o.pk LIKE :pk")
-public class TestQueryCache extends AbstractTestCase {
+    query = "SELECT o FROM Entity1 o WHERE o.pk = :pk")
+public class TestQueryCache extends SQLListenerTestCase {
 
     EntityManager em;
 
-    public TestQueryCache(String name) {
-        super(name, "");
-        System.setProperty("cactus.contextURL",
-            "http://localhost:9000/cachecactus");
-        em = currentEntityManager();
-    }
-
-    /*public static Test suite()
-    {
-        ServletTestSuite suite = new ServletTestSuite();
-        suite.addTestSuite(TestQueryCache.class);
-        return suite;
-    }*/
     public void setUp() {
-        System.setProperty("cactus.contextURL",
-            "http://localhost:9000/cactuswebapp");
-
-        //deleteAll(Entity2.class);
-        deleteAll(Entity1.class);
-
-        int instNum = 10;
-
-        startTx(em);
-
+        super.setUp(
+            DROP_TABLES,
+            "openjpa.QueryCache", "true", 
+            "openjpa.RemoteCommitProvider","sjvm",
+            Entity1.class,Entity2.class
+        // ,"openjpa.Log","SQL=trace"
+            );
+        em = emf.createEntityManager();
+        
+        em.getTransaction().begin();
         //create and persist multiple entity1 instances
-        for (int i = 0; i < instNum; i++) {
+        for (int i = 0; i < 10; i++) {
             Entity1 ent = new Entity1(i, "string" + i, i + 2);
             Entity2 ent2 = new Entity2(i * 2, "ent2" + i, i);
             ent.setEntity2Field(ent2);
             em.persist(ent);
         }
-
-        endTx(em);
-        endEm(em);
+        em.getTransaction().commit();
     }
 
+    public void testCachedQuery(){
+        em.createQuery("Select object(o) from Entity1 o").getResultList().get(0);        
+        resetSQL();
+        em.createQuery("Select object(o) from Entity1 o").getResultList().get(0);
+        em.createQuery("Select object(o) from Entity1 o").getResultList().get(0);
+        
+        assertEquals(0, getSQLCount());
+        
+    }
     public void testResultList() {
-        em = currentEntityManager();
         List list = em.createQuery("Select object(o) from Entity1 o")
             .getResultList();
 
         assertEquals(10, list.size());
 
-        endEm(em);
     }
 
     public void testGetSingleList() {
-        em = currentEntityManager();
+
         String curr = 2 + "";
 
         Entity1 ret = (Entity1) em
-            .createQuery("SELECT o FROM Entity1 o WHERE o.pk LIKE :pk")
-            .setParameter("pk", curr)
+            .createQuery("SELECT o FROM Entity1 o WHERE o.pk = :pk")
+            .setParameter("pk", Long.valueOf(curr))
             .getSingleResult();
 
         assertNotNull(ret);
         assertEquals("string2", ret.getStringField());
         assertEquals(4, ret.getIntField());
 
-        endEm(em);
+
     }
 
     public void testExecuteUpdate() {
         String curr = 2 + "";
         String curr2 = 22 + "";
 
-        em = currentEntityManager();
+
         startTx(em);
 
         Entity1 entity1 = (Entity1) em
-            .createQuery("SELECT o FROM Entity1 o WHERE o.pk LIKE :pk")
-            .setParameter("pk", curr)
+            .createQuery("SELECT o FROM Entity1 o WHERE o.pk = :pk")
+            .setParameter("pk", Long.valueOf(curr))
             .getSingleResult();
 
-        int ret = em.createQuery("Delete FROM Entity1 o WHERE o.pk LIKE :pk")
-            .setParameter("pk", curr)
+        int ret = em.createQuery("Delete FROM Entity1 o WHERE o.pk = :pk")
+            .setParameter("pk", Long.valueOf(curr))
             .executeUpdate();
         assertEquals(ret, 1);
 
         // cascade remove doesn't remove the entity2
-        int retTmp = em.createQuery("Delete FROM Entity2 o WHERE o.pk LIKE :pk")
+        int retTmp = em.createQuery("Delete FROM Entity2 o WHERE o.pk = :pk")
             .setParameter("pk", entity1.getEntity2Field().getPk())
             .executeUpdate();
 
-        int ret2 = em.createQuery("Delete FROM Entity1 o WHERE o.pk LIKE :pk")
-            .setParameter("pk", curr2)
+        int ret2 = em.createQuery("Delete FROM Entity1 o WHERE o.pk = :pk")
+            .setParameter("pk", Long.valueOf(curr2))
             .executeUpdate();
 
         assertEquals(ret2, 0);
 
         endTx(em);
-        endEm(em);
+
     }
 
     public void testSetMaxResults() {
-        em = currentEntityManager();
+
 
         List l = em.createQuery("Select object(o) from Entity1 o")
             .setMaxResults(5)
@@ -137,11 +129,11 @@ public class TestQueryCache extends Abst
         assertNotNull(l);
         assertEquals(5, l.size());
 
-        endEm(em);
+
     }
 
     public void testSetFirstResults() {
-        em = currentEntityManager();
+
 
         List l = em.createQuery("Select object(o) from Entity1 o")
             .setFirstResult(3)
@@ -153,37 +145,23 @@ public class TestQueryCache extends Abst
         assertEquals("string3", ent.getStringField());
         assertEquals(5, ent.getIntField());
 
-        endEm(em);
-    }
-
-    // Tests Binding an argument to a named parameter.
-    // pk, the named parameter --Not working yet--
-    public void xxxtestSetParameter1() {
-
-        em = currentEntityManager();
-        String curr = 2 + "";
-
-        List ret = em.createQuery("SELECT o FROM Entity1 o WHERE o.pk LIKE :pk")
-            .setParameter("pk", curr)
-            .getResultList();
-
-        assertNotNull(ret);
-        assertEquals(1, ret.size());
 
-        ret = em.createNamedQuery("setParam1")
-            .setParameter("pk", curr)
-            .getResultList();
-
-        assertNotNull(ret);
-        assertEquals(1, ret.size());
+    }
 
-        endTx(em);
+    protected void startTx(EntityManager em) {
+        em.getTransaction().begin();
     }
-    
-    @Override
-    public String getPersistenceUnitName() { 
-        return "QueryCache";
+
+    protected boolean isActiveTx(EntityManager em) {
+        return em.getTransaction().isActive();
     }
 
-    //rest of the interface is tested by the CTS
+    protected void endTx(EntityManager em) {
+        if (em.getTransaction().isActive()) {
+            if (em.getTransaction().getRollbackOnly())
+                em.getTransaction().rollback();
+            else
+                em.getTransaction().commit();
+        }
+    }
 }

Added: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java?rev=928968&view=auto
==============================================================================
--- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java (added)
+++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java Tue Mar 30 03:43:20 2010
@@ -0,0 +1,67 @@
+/*
+ * 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.persistence.relations;
+
+import java.util.Collection;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+
+@Entity
+public class PPerson {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private int id;
+
+    private String name;
+
+    @ManyToMany(fetch=FetchType.EAGER, mappedBy="people")
+    private Collection<PPhone> phones;
+
+    public int getId() {
+        return id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Collection<PPhone> getPhones() {
+        return phones;
+    }
+
+    public void setPhones(Collection<PPhone> phones) {
+        this.phones = phones;
+    }
+
+    @Override
+    public String toString() {
+        return "Person [id=" + id + ", number=" + name + "]";
+    }
+    
+    
+}

Propchange: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java?rev=928968&view=auto
==============================================================================
--- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java (added)
+++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java Tue Mar 30 03:43:20 2010
@@ -0,0 +1,65 @@
+/*
+ * 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.persistence.relations;
+
+import java.util.Collection;
+
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+
+@Entity
+public class PPhone {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private int id;
+
+    private String number;
+
+    @ManyToMany(fetch=FetchType.EAGER)
+    private Collection<PPerson> people;
+
+    public int getId() {
+        return id;
+    }
+    
+    public String getNumber() {
+        return number;
+    }
+
+    public void setNumber(String number) {
+        this.number = number;
+    }
+
+    public Collection<PPerson> getPeople() {
+        return people;
+    }
+
+    public void setPeople(Collection<PPerson> people) {
+        this.people = people;
+    }
+
+    @Override
+    public String toString() {
+        return "Phone [id=" + id + ", number=" + number + "]";
+    }
+}

Propchange: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java (original)
+++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java Tue Mar 30 03:43:20 2010
@@ -18,6 +18,7 @@
  */
 package org.apache.openjpa.persistence.relations;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
@@ -41,13 +42,18 @@ public class TestInverseEagerSQL
 
     public int numCustomers = 1;
     public int numOrdersPerCustomer = 4;
+    
+    public int _nPeople = 3; 
+    public int _nPhones = 3;
 
     public void setUp() {
         setUp(Customer.class, Customer.CustomerKey.class, Order.class, 
             EntityAInverseEager.class, EntityA1InverseEager.class,
             EntityA2InverseEager.class, EntityBInverseEager.class,
             EntityCInverseEager.class, EntityDInverseEager.class,
-            Publisher.class, Magazine.class, DROP_TABLES);
+            Publisher.class, Magazine.class, 
+            PPerson.class, PPhone.class, 
+            DROP_TABLES);
 
         // Not all databases support GenerationType.IDENTITY column(s)
         if (!((JDBCConfiguration) emf.getConfiguration()).
@@ -132,6 +138,21 @@ public class TestInverseEagerSQL
             magazine.setName("magagine"+i+"_"+p2.getName());
             em.persist(magazine);
         }
+        
+        PPerson person;
+        PPhone phone;
+        for(int i =0; i < _nPeople; i++) { 
+            person = new PPerson();
+            person.setPhones(new ArrayList<PPhone>());
+            em.persist(person);
+            for(int j = 0; j < _nPhones; j++) { 
+                phone = new PPhone(); 
+                phone.setPeople(new ArrayList<PPerson>());
+                phone.getPeople().add(person);
+                person.getPhones().add(phone);
+                em.persist(phone);
+            }
+        }
 
         em.flush();
         em.getTransaction().commit();
@@ -255,8 +276,8 @@ public class TestInverseEagerSQL
         // Not all databases support GenerationType.IDENTITY column(s)
         if (!((JDBCConfiguration) emf.getConfiguration()).
             getDBDictionaryInstance().supportsAutoAssign) {
-			return;
-		}
+            return;
+        }
         sql.clear();
 
         OpenJPAEntityManager em = emf.createEntityManager();
@@ -282,6 +303,36 @@ public class TestInverseEagerSQL
         assertEquals(0, sql.size());
         em.close();
     }
+    
+    public void testManyToManyEagerEagerInverseLazyQuery() {
+        // Not all databases support GenerationType.IDENTITY column(s)
+        if (!((JDBCConfiguration) emf.getConfiguration()).
+            getDBDictionaryInstance().supportsAutoAssign) {
+            return;
+        }
+        sql.clear();
+
+        OpenJPAEntityManager em = emf.createEntityManager();
+        String query = "select p FROM PPerson p";
+        Query q = em.createQuery(query);
+        List list = q.getResultList();
+        assertEquals(_nPeople, list.size());
+        assertEquals(7, sql.size());
+
+        sql.clear();
+        em.clear();
+        for (int i = 0; i < list.size(); i++) {
+            PPerson p = (PPerson) list.get(i);
+            Collection<PPhone> phones = p.getPhones();
+            assertEquals(_nPhones, phones.size());
+            for(PPhone phone : p.getPhones()) {
+                assertNotNull(phone.getPeople());
+                assertTrue(phone.getPeople().contains(p));
+            }
+        }
+        assertEquals(0, sql.size());
+        em.close();
+    }
 
     public void testTargetOrphanRemoval() {
         // Not all databases support GenerationType.IDENTITY column(s)

Modified: openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java
URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
==============================================================================
--- openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java (original)
+++ openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java Tue Mar 30 03:43:20 2010
@@ -283,4 +283,8 @@ public class XMLStoreManager
         }
         return new ListResultObjectProvider(pcs);
     }
+    public boolean isCached(List<Object> oids, BitSet edata) {
+        // XMLStoreManager does not cache oids. 
+        return false;
+    }
 }



Re: svn commit: r928968 - in /openjpa/branches/2.0.x: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ openjpa-kernel/src/main/java/org/apache/openjpa/datacache/ openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ openjpa-persistence-jdbc/src...

Posted by Donald Woods <dw...@apache.org>.
Rick, don't forget to merge these changes into trunk.
For future work, please use trunk before checking into 2.0.x.


-Donald


On 3/29/10 11:43 PM, curtisr7@apache.org wrote:
> Author: curtisr7
> Date: Tue Mar 30 03:43:20 2010
> New Revision: 928968
> 
> URL: http://svn.apache.org/viewvc?rev=928968&view=rev
> Log:
> OPENAJPA-1603: Decouple the QueryCache from the DataCache. Code contributed by Mike Dick and Rick Curtis.
> 
> Added:
>     openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java   (with props)
>     openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java   (with props)
> Modified:
>     openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java
>     openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java
>     openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java
>     openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java
>     openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java
>     openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java
> 
> Modified: openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java (original)
> +++ openjpa/branches/2.0.x/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreManager.java Tue Mar 30 03:43:20 2010
> @@ -30,12 +30,15 @@ import java.util.Collection;
>  import java.util.Collections;
>  import java.util.HashSet;
>  import java.util.Iterator;
> +import java.util.List;
>  import java.util.Map;
>  import java.util.Set;
>  
>  import javax.sql.DataSource;
>  
>  import org.apache.commons.lang.StringUtils;
> +import org.apache.openjpa.datacache.QueryCache;
> +import org.apache.openjpa.datacache.QueryCacheStoreQuery;
>  import org.apache.openjpa.enhance.PersistenceCapable;
>  import org.apache.openjpa.event.OrphanedKeyAction;
>  import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
> @@ -295,6 +298,11 @@ public class JDBCStoreManager 
>          return exists(mapping, sm.getObjectId(), context);
>      }
>  
> +    public boolean isCached(List<Object> oids, BitSet edata) {
> +        // JDBCStoreManager doesn't store oids in memory.
> +        return false;
> +    }
> +    
>      private boolean exists(ClassMapping mapping, Object oid, Object context) {
>          // add where conditions on base class to avoid joins if subclass
>          // doesn't use oid as identifier
> @@ -455,8 +463,9 @@ public class JDBCStoreManager 
>          // Check if the owner has eagerly loaded ToMany relations.
>          for (int i = 0; i < fms.length; i++) {
>              if (res.getEager(fms[i]) != null) {
> -                if (!fms[i].getElement().isTypePC())
> +                if (!fms[i].getElement().isTypePC()) {
>                      continue;
> +                }
>                  Object coll =  owner.fetchObject(fms[i].getIndex());
>                  if (coll instanceof Map)
>                      coll = ((Map)coll).values();
> @@ -471,24 +480,23 @@ public class JDBCStoreManager 
>                      for (Iterator<?> itr = ((Collection<?>) coll).iterator();
>                          itr.hasNext();) {
>                          PersistenceCapable pc = (PersistenceCapable) itr.next();
> -
> -                        if (pc == null)
> +                        if (pc == null) {
>                              continue;
> -
> -                        OpenJPAStateManager sm = (OpenJPAStateManager) pc.
> -                            pcGetStateManager();
> -                        FieldMapping[] fmd = ((ClassMapping) sm.getMetaData()).
> -                            getFieldMappings();
> +                        }
> +                        OpenJPAStateManager sm = (OpenJPAStateManager) pc.pcGetStateManager();
> +                        ClassMapping cm =
> +                            (ClassMapping) _conf.getMetaDataRepositoryInstance().getCachedMetaData(pc.getClass());
> +                        FieldMapping[] fmd = cm.getFieldMappings();
>                          for (int j = 0; j < fmd.length; j++) {
> -                            Object oid = sm.getIntermediate(fmd[j].getIndex());
> -                            // if oid was setIntermediate() previously
> -                            // and it is the same as the owner,
> -                            // then set the inverse relation
> -                            if (oid != null &&
> -                                oid.equals(owner.getObjectId())) {
> -                                sm.storeObject(fmd[j].getIndex(),
> -                                    owner.getPersistenceCapable());
> -                                break;
> +                            // don't check the oids for basic fields.
> +                            if (fmd[j].isTypePC()) {
> +                                Object oid = sm.getIntermediate(fmd[j].getIndex());
> +                                // if oid was setIntermediate() previously and it is the same as the owner,generate
> +                                // then set the inverse relation
> +                                if (oid != null && oid.equals(owner.getObjectId())) {
> +                                    sm.storeObject(fmd[j].getIndex(), owner.getPersistenceCapable());
> +                                    break;
> +                                }
>                              }
>                          }
>                      }
> @@ -911,16 +919,33 @@ public class JDBCStoreManager 
>          return paged;
>      }
>  
> -    public StoreQuery newQuery(String language) {
> +    private StoreQuery newStoreQuery(String language) {
>          ExpressionParser ep = QueryLanguages.parserForLanguage(language);
> -        if (ep != null)
> +        if (ep != null) { 
>              return new JDBCStoreQuery(this, ep);
> -        if (QueryLanguages.LANG_SQL.equals(language))
> +        }
> +        if (QueryLanguages.LANG_SQL.equals(language)) {
>              return new SQLStoreQuery(this);
> -        if (QueryLanguages.LANG_PREPARED_SQL.equals(language))
> +        }
> +        if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
>              return new PreparedSQLStoreQuery(this);
> +        }
>          return null;
>      }
> +    
> +    public StoreQuery newQuery(String language) {
> +        StoreQuery sq = newStoreQuery(language); 
> +        if (sq == null || QueryLanguages.parserForLanguage(language) == null) {
> +            return sq;
> +        }
> +
> +        QueryCache queryCache = _ctx.getConfiguration().getDataCacheManagerInstance().getSystemQueryCache();
> +        if (queryCache == null) {
> +            return sq;
> +        }
> +        
> +        return new QueryCacheStoreQuery(sq, queryCache);
> +    }
>  
>      public FetchConfiguration newFetchConfiguration() {
>          return new JDBCFetchConfigurationImpl();
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheManagerImpl.java Tue Mar 30 03:43:20 2010
> @@ -57,7 +57,11 @@ public class DataCacheManagerImpl
>      
>      public void initialize(OpenJPAConfiguration conf, ObjectValue dataCache, ObjectValue queryCache) {
>          _conf = conf;
> +        _queryCache = (QueryCache) queryCache.instantiate(QueryCache.class, conf);
> +        if (_queryCache != null)
> +            _queryCache.initialize(this);
>          _cache = (DataCache) dataCache.instantiate(DataCache.class, conf);
> +
>          if (_cache == null)
>              return;
>           
> @@ -69,9 +73,7 @@ public class DataCacheManagerImpl
>          _policy = conf.getCacheDistributionPolicyInstance();
>  
>          _cache.initialize(this);
> -        _queryCache = (QueryCache) queryCache.instantiate(QueryCache.class, conf);
> -        if (_queryCache != null)
> -            _queryCache.initialize(this);
> +
>      }
>  
>      public DataCache getSystemDataCache() {
> @@ -155,6 +157,7 @@ public class DataCacheManagerImpl
>          _includedTypes = includedTypes;
>          _excludedTypes = excludedTypes;
>      }
> +    
>      /**
>       * Affirms the given class is eligible to be cached according to the cache mode
>       * and the cache enable flag on the given metadata.
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java Tue Mar 30 03:43:20 2010
> @@ -34,14 +34,11 @@ import org.apache.openjpa.kernel.DataCac
>  import org.apache.openjpa.kernel.DataCacheStoreMode;
>  import org.apache.openjpa.kernel.DelegatingStoreManager;
>  import org.apache.openjpa.kernel.FetchConfiguration;
> -import org.apache.openjpa.kernel.FindCallbacks;
>  import org.apache.openjpa.kernel.LockLevels;
>  import org.apache.openjpa.kernel.OpenJPAStateManager;
>  import org.apache.openjpa.kernel.PCState;
> -import org.apache.openjpa.kernel.QueryLanguages;
>  import org.apache.openjpa.kernel.StoreContext;
>  import org.apache.openjpa.kernel.StoreManager;
> -import org.apache.openjpa.kernel.StoreQuery;
>  import org.apache.openjpa.meta.ClassMetaData;
>  import org.apache.openjpa.meta.MetaDataRepository;
>  import org.apache.openjpa.util.OpenJPAId;
> @@ -228,22 +225,6 @@ public class DataCacheStoreManager
>                  evictTypes(_ctx.getUpdatedTypes());
>              }
>  
> -            // and notify the query cache.  notify in one batch to reduce synch
> -            QueryCache queryCache = _ctx.getConfiguration().
> -            getDataCacheManagerInstance().getSystemQueryCache();
> -            if (queryCache != null) {
> -                Collection<Class<?>> pers = _ctx.getPersistedTypes();
> -                Collection<Class<?>> del = _ctx.getDeletedTypes();
> -                Collection<Class<?>> up = _ctx.getUpdatedTypes();
> -                int size = pers.size() + del.size() + up.size();
> -                if (size > 0) {
> -                    Collection<Class<?>> types = new ArrayList<Class<?>>(size);
> -                    types.addAll(pers);
> -                    types.addAll(del);
> -                    types.addAll(up);
> -                    queryCache.onTypesChanged(new TypesChangedEvent(this, types));
> -                }
> -            } 
>          }
>      }
>  
> @@ -292,12 +273,31 @@ public class DataCacheStoreManager
>  
>      public boolean exists(OpenJPAStateManager sm, Object edata) {
>          DataCache cache = _mgr.selectCache(sm); 
> -        if (cache != null && !isLocking(null)
> -            && cache.contains(sm.getObjectId()))
> +        if (cache != null && !isLocking(null) && cache.contains(sm.getObjectId()))
>              return true;
>          return super.exists(sm, edata);
>      }
>  
> +    public boolean isCached(List<Object> oids, BitSet edata) {
> +        // If using partitioned cache, we were and still are broke.
> +        DataCache cache = _mgr.getSystemDataCache();
> +        if (cache != null && !isLocking(null)) {
> +            // BitSet size is not consistent.
> +            for(int i = 0; i < oids.size(); i++) {
> +                Object oid = oids.get(i);
> +                // Only check the cache if we haven't found the current oid.
> +                if (edata.get(i) == false && cache.contains(oid)) {
> +                    edata.set(i);
> +                }
> +            }
> +            if(edata.cardinality()==oids.size()){
> +                return true;
> +            }
> +        }
> +
> +        return super.isCached(oids, edata);
> +    }
> +
>      public boolean syncVersion(OpenJPAStateManager sm, Object edata) {
>          DataCache cache = _mgr.selectCache(sm);
>          if (cache == null || sm.isEmbedded())
> @@ -660,22 +660,6 @@ public class DataCacheStoreManager
>              .fireLocalStaleNotification(oid);
>      }
>  
> -    public StoreQuery newQuery(String language) {
> -        StoreQuery q = super.newQuery(language);
> -
> -        // if the query can't be parsed or it's using a non-parsed language
> -        // (one for which there is no ExpressionParser), we can't cache it.
> -        if (q == null || QueryLanguages.parserForLanguage(language) == null)
> -            return q;
> -
> -        QueryCache queryCache = _ctx.getConfiguration().
> -            getDataCacheManagerInstance().getSystemQueryCache();
> -        if (queryCache == null)
> -            return q;
> -
> -        return new QueryCacheStoreQuery(q, queryCache);
> -    }
> -
>      /**
>       * Create a new cacheable instance for the given state manager.
>       */
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java Tue Mar 30 03:43:20 2010
> @@ -33,6 +33,7 @@ import java.util.TreeMap;
>  
>  import org.apache.commons.collections.map.LinkedMap;
>  import org.apache.openjpa.datacache.AbstractQueryCache.EvictPolicy;
> +import org.apache.openjpa.kernel.DelegatingStoreManager;
>  import org.apache.openjpa.kernel.FetchConfiguration;
>  import org.apache.openjpa.kernel.LockLevels;
>  import org.apache.openjpa.kernel.OpenJPAStateManager;
> @@ -122,6 +123,7 @@ public class QueryCacheStoreQuery
>  
>          // get the cached data
>          QueryResult res = _cache.get(qk);
> +
>          if (res == null)
>              return null;        
>          if (res.isEmpty())
> @@ -153,24 +155,11 @@ public class QueryCacheStoreQuery
>  
>          int projs = getContext().getProjectionAliases().length;
>          if (projs == 0) {
> -            // make sure the data cache contains the oids for the query result;
> -            // if it doesn't, then using the result could be slower than not
> -            // using it because of the individual by-oid lookups
> -            ClassMetaData meta = _repos.getMetaData(getContext().
> -                getCandidateType(), _sctx.getClassLoader(), true);
> -            if (meta.getDataCache() == null)
> +            // We're only going to return the cached results if we have ALL results cached. This could be improved
> +            // in the future to be a little more intelligent.
> +            if (getContext().getStoreContext().isCached(res) == false) {
>                  return null;
> -
> -            BitSet idxs = meta.getDataCache().containsAll(res);
> -
> -            // eventually we should optimize this to figure out how many objects
> -            // the cache is missing and if only a few do a bulk fetch for them
> -            int len = idxs.length();
> -            if (len < res.size())
> -                return null;
> -            for (int i = 0; i < len; i++)
> -                if (!idxs.get(i))
> -                    return null;
> +            }
>          }
>          return new CachedList(res, projs != 0, _sctx);
>      }
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryKey.java Tue Mar 30 03:43:20 2010
> @@ -200,14 +200,11 @@ public class QueryKey
>              // since the class change framework deals with least-derived types,
>              // record the least-derived access path types
>              meta = metas[i];
> -            if (meta.getDataCache() != null)
> -                accessPathClassNames.add(meta.getDescribedType().getName());
> -            while (meta.getPCSuperclass() != null)
> -                meta = meta.getPCSuperclassMetaData();
> -
> -            // ensure that this metadata is cacheable
> -            if (meta.getDataCache() == null)
> -                return null;
> +            accessPathClassNames.add(meta.getDescribedType().getName());
> +            while (meta.getPCSuperclass() != null) {
> +                meta = meta.getPCSuperclassMetaData(); 
> +            }
> +
>              accessPathClassNames.add(meta.getDescribedType().getName());
>          }
>  
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java Tue Mar 30 03:43:20 2010
> @@ -51,6 +51,8 @@ import org.apache.commons.lang.StringUti
>  import org.apache.openjpa.conf.Compatibility;
>  import org.apache.openjpa.conf.OpenJPAConfiguration;
>  import org.apache.openjpa.datacache.DataCache;
> +import org.apache.openjpa.datacache.QueryCache;
> +import org.apache.openjpa.datacache.TypesChangedEvent;
>  import org.apache.openjpa.ee.ManagedRuntime;
>  import org.apache.openjpa.enhance.PCRegistry;
>  import org.apache.openjpa.enhance.PersistenceCapable;
> @@ -70,7 +72,6 @@ import org.apache.openjpa.lib.util.Refer
>  import org.apache.openjpa.lib.util.ReferenceMap;
>  import org.apache.openjpa.meta.ClassMetaData;
>  import org.apache.openjpa.meta.FieldMetaData;
> -import org.apache.openjpa.meta.JavaTypes;
>  import org.apache.openjpa.meta.MetaDataRepository;
>  import org.apache.openjpa.meta.SequenceMetaData;
>  import org.apache.openjpa.meta.ValueMetaData;
> @@ -88,7 +89,6 @@ import org.apache.openjpa.util.ObjectId;
>  import org.apache.openjpa.util.ObjectNotFoundException;
>  import org.apache.openjpa.util.OpenJPAException;
>  import org.apache.openjpa.util.OptimisticException;
> -import org.apache.openjpa.util.Proxy;
>  import org.apache.openjpa.util.RuntimeExceptionTranslator;
>  import org.apache.openjpa.util.StoreException;
>  import org.apache.openjpa.util.UnsupportedException;
> @@ -1416,8 +1416,25 @@ public class BrokerImpl
>                  releaseConn = _connRetainMode != CONN_RETAIN_ALWAYS;
>                  if (rollback)
>                      _store.rollback();
> -                else
> +                else {
> +                    // and notify the query cache.  notify in one batch to reduce synch
> +                    QueryCache queryCache = getConfiguration().
> +                    getDataCacheManagerInstance().getSystemQueryCache();
> +                    if (queryCache != null) {
> +                        Collection<Class<?>> pers = getPersistedTypes();
> +                        Collection<Class<?>> del = getDeletedTypes();
> +                        Collection<Class<?>> up = getUpdatedTypes();
> +                        int size = pers.size() + del.size() + up.size();
> +                        if (size > 0) {
> +                            Collection<Class<?>> types = new ArrayList<Class<?>>(size);
> +                            types.addAll(pers);
> +                            types.addAll(del);
> +                            types.addAll(up);
> +                            queryCache.onTypesChanged(new TypesChangedEvent(this, types));
> +                        }
> +                    } 
>                      _store.commit();
> +                }
>              } else {
>                  releaseConn = _connRetainMode == CONN_RETAIN_TRANS;
>                  _store.rollbackOptimistic();
> @@ -5039,4 +5056,19 @@ public class BrokerImpl
>              return null;
>          }
>      }
> +    
> +    public boolean isCached(List<Object> oids) {
> +        BitSet loaded = new BitSet(oids.size());
> +        //check L1 cache first
> +        for (int i = 0; i < oids.size(); i++) {
> +            Object oid = oids.get(i);
> +            if (_cache.getById(oid, false) != null) {
> +                loaded.set(i);
> +            }
> +        }
> +        if(loaded.cardinality()==oids.size()){
> +            return true;
> +        }
> +        return _store.isCached(oids, loaded);
> +    };
>  }
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java Tue Mar 30 03:43:20 2010
> @@ -21,6 +21,7 @@ package org.apache.openjpa.kernel;
>  import java.util.BitSet;
>  import java.util.Collection;
>  import java.util.Iterator;
> +import java.util.List;
>  import java.util.Map;
>  import java.util.Set;
>  
> @@ -1463,4 +1464,8 @@ public class DelegatingBroker
>      public Object getConnectionFactory2() {
>          return _broker.getConnectionFactory2();
>      }
> +    
> +    public boolean isCached(List<Object> oid) {
> +        return _broker.isCached(oid);
> +    }
>  }
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingStoreManager.java Tue Mar 30 03:43:20 2010
> @@ -20,6 +20,7 @@ package org.apache.openjpa.kernel;
>  
>  import java.util.BitSet;
>  import java.util.Collection;
> +import java.util.List;
>  
>  import org.apache.openjpa.lib.rop.ResultObjectProvider;
>  import org.apache.openjpa.meta.ClassMetaData;
> @@ -199,4 +200,9 @@ public abstract class DelegatingStoreMan
>      public boolean cancelAll() {
>          return _store.cancelAll();
>  	}
> +	
> +    public boolean isCached(List<Object> oids, BitSet edata) {
> +        return _store.isCached(oids, edata);
> +    }
> +    
>  }
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java Tue Mar 30 03:43:20 2010
> @@ -21,9 +21,11 @@ package org.apache.openjpa.kernel;
>  import java.util.BitSet;
>  import java.util.Collection;
>  import java.util.Iterator;
> +import java.util.List;
>  
>  import org.apache.openjpa.conf.OpenJPAConfiguration;
>  import org.apache.openjpa.meta.ValueMetaData;
> +import org.apache.openjpa.util.UserException;
>  
>  /**
>   * Represents a set of managed objects and their environment.
> @@ -111,8 +113,8 @@ public interface StoreContext {
>      public String getConnectionPassword();
>  
>      /**
> -     * Return the cached instance for the given oid/object, or null if not
> -     * cached.
> +     * Return the instance for the given oid/object , or null if not
> +     * found in the L1 cache. 
>       *
>       * @param oid the object's id
>       * @return the cached object, or null if not cached
> @@ -490,4 +492,12 @@ public interface StoreContext {
>       * @return the NonJTA connection factory or null if connectionFactoryName is blank.
>       */
>      public Object getConnectionFactory2();
> +    
> +    /**
> +     * Indicate whether the oid can be found in the StoreContext's L1 cache or in the StoreManager cache.
> +     * @param oid List of ObjectIds for PersistenceCapables which may be found in memory.
> +     * @return true if the oid is available in memory (cached) otherwise false.
> +     * @since 2.0.0. 
> +     */
> +    public boolean isCached(List<Object> oid);
>  }
> 
> Modified: openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java (original)
> +++ openjpa/branches/2.0.x/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreManager.java Tue Mar 30 03:43:20 2010
> @@ -20,6 +20,7 @@ package org.apache.openjpa.kernel;
>  
>  import java.util.BitSet;
>  import java.util.Collection;
> +import java.util.List;
>  
>  import org.apache.openjpa.lib.rop.ResultObjectProvider;
>  import org.apache.openjpa.lib.util.Closeable;
> @@ -99,6 +100,13 @@ public interface StoreManager
>       * if it does not.
>       */
>      public boolean exists(OpenJPAStateManager sm, Object edata);
> +    
> +    /**
> +     * Verify that the given instance exists in the data store in memory; return false
> +     * if it does not. When an object is found in memory the corresponding element of 
> +     * the BitSet is set to 1. 
> +     */
> +    public boolean isCached(List<Object> oids, BitSet edata);
>  
>      /**
>       * Update the version information in the given state manager to the
> 
> Modified: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java (original)
> +++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/datacache/CacheTest.java Tue Mar 30 03:43:20 2010
> @@ -781,7 +781,8 @@ public abstract class CacheTest extends 
>              Collection c = (Collection) q.execute();
>              iterate(c);
>  
> -            assertInCache(q, Boolean.FALSE);
> +            // Query results are no longer dependent on cacheability of an entity.
> +            assertInCache(q, Boolean.TRUE);
>          }
>          finally {
>              close(broker);
> @@ -801,7 +802,8 @@ public abstract class CacheTest extends 
>              Collection c = (Collection) q.execute();
>              iterate(c);
>  
> -            assertInCache(q, Boolean.FALSE);
> +         // Query results are no longer dependent on cacheability of an entity.
> +            assertInCache(q, Boolean.TRUE);
>          }
>          finally {
>              close(broker);
> 
> Modified: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java (original)
> +++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/querycache/TestQueryCache.java Tue Mar 30 03:43:20 2010
> @@ -23,112 +23,104 @@ import java.util.List;
>  import javax.persistence.EntityManager;
>  import javax.persistence.NamedQuery;
>  
> -import org.apache.openjpa.persistence.common.utils.AbstractTestCase;
>  import org.apache.openjpa.persistence.querycache.common.apps.Entity1;
>  import org.apache.openjpa.persistence.querycache.common.apps.Entity2;
> +import org.apache.openjpa.persistence.test.SQLListenerTestCase;
>  
>  @NamedQuery(name = "setParam1",
> -    query = "SELECT o FROM Entity1 o WHERE o.pk LIKE :pk")
> -public class TestQueryCache extends AbstractTestCase {
> +    query = "SELECT o FROM Entity1 o WHERE o.pk = :pk")
> +public class TestQueryCache extends SQLListenerTestCase {
>  
>      EntityManager em;
>  
> -    public TestQueryCache(String name) {
> -        super(name, "");
> -        System.setProperty("cactus.contextURL",
> -            "http://localhost:9000/cachecactus");
> -        em = currentEntityManager();
> -    }
> -
> -    /*public static Test suite()
> -    {
> -        ServletTestSuite suite = new ServletTestSuite();
> -        suite.addTestSuite(TestQueryCache.class);
> -        return suite;
> -    }*/
>      public void setUp() {
> -        System.setProperty("cactus.contextURL",
> -            "http://localhost:9000/cactuswebapp");
> -
> -        //deleteAll(Entity2.class);
> -        deleteAll(Entity1.class);
> -
> -        int instNum = 10;
> -
> -        startTx(em);
> -
> +        super.setUp(
> +            DROP_TABLES,
> +            "openjpa.QueryCache", "true", 
> +            "openjpa.RemoteCommitProvider","sjvm",
> +            Entity1.class,Entity2.class
> +        // ,"openjpa.Log","SQL=trace"
> +            );
> +        em = emf.createEntityManager();
> +        
> +        em.getTransaction().begin();
>          //create and persist multiple entity1 instances
> -        for (int i = 0; i < instNum; i++) {
> +        for (int i = 0; i < 10; i++) {
>              Entity1 ent = new Entity1(i, "string" + i, i + 2);
>              Entity2 ent2 = new Entity2(i * 2, "ent2" + i, i);
>              ent.setEntity2Field(ent2);
>              em.persist(ent);
>          }
> -
> -        endTx(em);
> -        endEm(em);
> +        em.getTransaction().commit();
>      }
>  
> +    public void testCachedQuery(){
> +        em.createQuery("Select object(o) from Entity1 o").getResultList().get(0);        
> +        resetSQL();
> +        em.createQuery("Select object(o) from Entity1 o").getResultList().get(0);
> +        em.createQuery("Select object(o) from Entity1 o").getResultList().get(0);
> +        
> +        assertEquals(0, getSQLCount());
> +        
> +    }
>      public void testResultList() {
> -        em = currentEntityManager();
>          List list = em.createQuery("Select object(o) from Entity1 o")
>              .getResultList();
>  
>          assertEquals(10, list.size());
>  
> -        endEm(em);
>      }
>  
>      public void testGetSingleList() {
> -        em = currentEntityManager();
> +
>          String curr = 2 + "";
>  
>          Entity1 ret = (Entity1) em
> -            .createQuery("SELECT o FROM Entity1 o WHERE o.pk LIKE :pk")
> -            .setParameter("pk", curr)
> +            .createQuery("SELECT o FROM Entity1 o WHERE o.pk = :pk")
> +            .setParameter("pk", Long.valueOf(curr))
>              .getSingleResult();
>  
>          assertNotNull(ret);
>          assertEquals("string2", ret.getStringField());
>          assertEquals(4, ret.getIntField());
>  
> -        endEm(em);
> +
>      }
>  
>      public void testExecuteUpdate() {
>          String curr = 2 + "";
>          String curr2 = 22 + "";
>  
> -        em = currentEntityManager();
> +
>          startTx(em);
>  
>          Entity1 entity1 = (Entity1) em
> -            .createQuery("SELECT o FROM Entity1 o WHERE o.pk LIKE :pk")
> -            .setParameter("pk", curr)
> +            .createQuery("SELECT o FROM Entity1 o WHERE o.pk = :pk")
> +            .setParameter("pk", Long.valueOf(curr))
>              .getSingleResult();
>  
> -        int ret = em.createQuery("Delete FROM Entity1 o WHERE o.pk LIKE :pk")
> -            .setParameter("pk", curr)
> +        int ret = em.createQuery("Delete FROM Entity1 o WHERE o.pk = :pk")
> +            .setParameter("pk", Long.valueOf(curr))
>              .executeUpdate();
>          assertEquals(ret, 1);
>  
>          // cascade remove doesn't remove the entity2
> -        int retTmp = em.createQuery("Delete FROM Entity2 o WHERE o.pk LIKE :pk")
> +        int retTmp = em.createQuery("Delete FROM Entity2 o WHERE o.pk = :pk")
>              .setParameter("pk", entity1.getEntity2Field().getPk())
>              .executeUpdate();
>  
> -        int ret2 = em.createQuery("Delete FROM Entity1 o WHERE o.pk LIKE :pk")
> -            .setParameter("pk", curr2)
> +        int ret2 = em.createQuery("Delete FROM Entity1 o WHERE o.pk = :pk")
> +            .setParameter("pk", Long.valueOf(curr2))
>              .executeUpdate();
>  
>          assertEquals(ret2, 0);
>  
>          endTx(em);
> -        endEm(em);
> +
>      }
>  
>      public void testSetMaxResults() {
> -        em = currentEntityManager();
> +
>  
>          List l = em.createQuery("Select object(o) from Entity1 o")
>              .setMaxResults(5)
> @@ -137,11 +129,11 @@ public class TestQueryCache extends Abst
>          assertNotNull(l);
>          assertEquals(5, l.size());
>  
> -        endEm(em);
> +
>      }
>  
>      public void testSetFirstResults() {
> -        em = currentEntityManager();
> +
>  
>          List l = em.createQuery("Select object(o) from Entity1 o")
>              .setFirstResult(3)
> @@ -153,37 +145,23 @@ public class TestQueryCache extends Abst
>          assertEquals("string3", ent.getStringField());
>          assertEquals(5, ent.getIntField());
>  
> -        endEm(em);
> -    }
> -
> -    // Tests Binding an argument to a named parameter.
> -    // pk, the named parameter --Not working yet--
> -    public void xxxtestSetParameter1() {
> -
> -        em = currentEntityManager();
> -        String curr = 2 + "";
> -
> -        List ret = em.createQuery("SELECT o FROM Entity1 o WHERE o.pk LIKE :pk")
> -            .setParameter("pk", curr)
> -            .getResultList();
> -
> -        assertNotNull(ret);
> -        assertEquals(1, ret.size());
>  
> -        ret = em.createNamedQuery("setParam1")
> -            .setParameter("pk", curr)
> -            .getResultList();
> -
> -        assertNotNull(ret);
> -        assertEquals(1, ret.size());
> +    }
>  
> -        endTx(em);
> +    protected void startTx(EntityManager em) {
> +        em.getTransaction().begin();
>      }
> -    
> -    @Override
> -    public String getPersistenceUnitName() { 
> -        return "QueryCache";
> +
> +    protected boolean isActiveTx(EntityManager em) {
> +        return em.getTransaction().isActive();
>      }
>  
> -    //rest of the interface is tested by the CTS
> +    protected void endTx(EntityManager em) {
> +        if (em.getTransaction().isActive()) {
> +            if (em.getTransaction().getRollbackOnly())
> +                em.getTransaction().rollback();
> +            else
> +                em.getTransaction().commit();
> +        }
> +    }
>  }
> 
> Added: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java?rev=928968&view=auto
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java (added)
> +++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java Tue Mar 30 03:43:20 2010
> @@ -0,0 +1,67 @@
> +/*
> + * 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.persistence.relations;
> +
> +import java.util.Collection;
> +
> +import javax.persistence.Entity;
> +import javax.persistence.FetchType;
> +import javax.persistence.GeneratedValue;
> +import javax.persistence.GenerationType;
> +import javax.persistence.Id;
> +import javax.persistence.ManyToMany;
> +
> +@Entity
> +public class PPerson {
> +    @Id
> +    @GeneratedValue(strategy = GenerationType.IDENTITY)
> +    private int id;
> +
> +    private String name;
> +
> +    @ManyToMany(fetch=FetchType.EAGER, mappedBy="people")
> +    private Collection<PPhone> phones;
> +
> +    public int getId() {
> +        return id;
> +    }
> +
> +    public String getName() {
> +        return name;
> +    }
> +
> +    public void setName(String name) {
> +        this.name = name;
> +    }
> +
> +    public Collection<PPhone> getPhones() {
> +        return phones;
> +    }
> +
> +    public void setPhones(Collection<PPhone> phones) {
> +        this.phones = phones;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return "Person [id=" + id + ", number=" + name + "]";
> +    }
> +    
> +    
> +}
> 
> Propchange: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPerson.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Added: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java?rev=928968&view=auto
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java (added)
> +++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java Tue Mar 30 03:43:20 2010
> @@ -0,0 +1,65 @@
> +/*
> + * 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.persistence.relations;
> +
> +import java.util.Collection;
> +
> +import javax.persistence.Entity;
> +import javax.persistence.FetchType;
> +import javax.persistence.GeneratedValue;
> +import javax.persistence.GenerationType;
> +import javax.persistence.Id;
> +import javax.persistence.ManyToMany;
> +
> +@Entity
> +public class PPhone {
> +    @Id
> +    @GeneratedValue(strategy = GenerationType.IDENTITY)
> +    private int id;
> +
> +    private String number;
> +
> +    @ManyToMany(fetch=FetchType.EAGER)
> +    private Collection<PPerson> people;
> +
> +    public int getId() {
> +        return id;
> +    }
> +    
> +    public String getNumber() {
> +        return number;
> +    }
> +
> +    public void setNumber(String number) {
> +        this.number = number;
> +    }
> +
> +    public Collection<PPerson> getPeople() {
> +        return people;
> +    }
> +
> +    public void setPeople(Collection<PPerson> people) {
> +        this.people = people;
> +    }
> +
> +    @Override
> +    public String toString() {
> +        return "Phone [id=" + id + ", number=" + number + "]";
> +    }
> +}
> 
> Propchange: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/PPhone.java
> ------------------------------------------------------------------------------
>     svn:eol-style = native
> 
> Modified: openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java (original)
> +++ openjpa/branches/2.0.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestInverseEagerSQL.java Tue Mar 30 03:43:20 2010
> @@ -18,6 +18,7 @@
>   */
>  package org.apache.openjpa.persistence.relations;
>  
> +import java.util.ArrayList;
>  import java.util.Collection;
>  import java.util.Iterator;
>  import java.util.List;
> @@ -41,13 +42,18 @@ public class TestInverseEagerSQL
>  
>      public int numCustomers = 1;
>      public int numOrdersPerCustomer = 4;
> +    
> +    public int _nPeople = 3; 
> +    public int _nPhones = 3;
>  
>      public void setUp() {
>          setUp(Customer.class, Customer.CustomerKey.class, Order.class, 
>              EntityAInverseEager.class, EntityA1InverseEager.class,
>              EntityA2InverseEager.class, EntityBInverseEager.class,
>              EntityCInverseEager.class, EntityDInverseEager.class,
> -            Publisher.class, Magazine.class, DROP_TABLES);
> +            Publisher.class, Magazine.class, 
> +            PPerson.class, PPhone.class, 
> +            DROP_TABLES);
>  
>          // Not all databases support GenerationType.IDENTITY column(s)
>          if (!((JDBCConfiguration) emf.getConfiguration()).
> @@ -132,6 +138,21 @@ public class TestInverseEagerSQL
>              magazine.setName("magagine"+i+"_"+p2.getName());
>              em.persist(magazine);
>          }
> +        
> +        PPerson person;
> +        PPhone phone;
> +        for(int i =0; i < _nPeople; i++) { 
> +            person = new PPerson();
> +            person.setPhones(new ArrayList<PPhone>());
> +            em.persist(person);
> +            for(int j = 0; j < _nPhones; j++) { 
> +                phone = new PPhone(); 
> +                phone.setPeople(new ArrayList<PPerson>());
> +                phone.getPeople().add(person);
> +                person.getPhones().add(phone);
> +                em.persist(phone);
> +            }
> +        }
>  
>          em.flush();
>          em.getTransaction().commit();
> @@ -255,8 +276,8 @@ public class TestInverseEagerSQL
>          // Not all databases support GenerationType.IDENTITY column(s)
>          if (!((JDBCConfiguration) emf.getConfiguration()).
>              getDBDictionaryInstance().supportsAutoAssign) {
> -			return;
> -		}
> +            return;
> +        }
>          sql.clear();
>  
>          OpenJPAEntityManager em = emf.createEntityManager();
> @@ -282,6 +303,36 @@ public class TestInverseEagerSQL
>          assertEquals(0, sql.size());
>          em.close();
>      }
> +    
> +    public void testManyToManyEagerEagerInverseLazyQuery() {
> +        // Not all databases support GenerationType.IDENTITY column(s)
> +        if (!((JDBCConfiguration) emf.getConfiguration()).
> +            getDBDictionaryInstance().supportsAutoAssign) {
> +            return;
> +        }
> +        sql.clear();
> +
> +        OpenJPAEntityManager em = emf.createEntityManager();
> +        String query = "select p FROM PPerson p";
> +        Query q = em.createQuery(query);
> +        List list = q.getResultList();
> +        assertEquals(_nPeople, list.size());
> +        assertEquals(7, sql.size());
> +
> +        sql.clear();
> +        em.clear();
> +        for (int i = 0; i < list.size(); i++) {
> +            PPerson p = (PPerson) list.get(i);
> +            Collection<PPhone> phones = p.getPhones();
> +            assertEquals(_nPhones, phones.size());
> +            for(PPhone phone : p.getPhones()) {
> +                assertNotNull(phone.getPeople());
> +                assertTrue(phone.getPeople().contains(p));
> +            }
> +        }
> +        assertEquals(0, sql.size());
> +        em.close();
> +    }
>  
>      public void testTargetOrphanRemoval() {
>          // Not all databases support GenerationType.IDENTITY column(s)
> 
> Modified: openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java
> URL: http://svn.apache.org/viewvc/openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java?rev=928968&r1=928967&r2=928968&view=diff
> ==============================================================================
> --- openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java (original)
> +++ openjpa/branches/2.0.x/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStoreManager.java Tue Mar 30 03:43:20 2010
> @@ -283,4 +283,8 @@ public class XMLStoreManager
>          }
>          return new ListResultObjectProvider(pcs);
>      }
> +    public boolean isCached(List<Object> oids, BitSet edata) {
> +        // XMLStoreManager does not cache oids. 
> +        return false;
> +    }
>  }
> 
> 
>