From 991cdcae7da3904a932bf9c5c453a6de0685e8c9 Mon Sep 17 00:00:00 2001
From: Michael Dick
Date: Fri, 28 Aug 2009 18:25:08 +0000
Subject: [PATCH] OPENJPA-1271: Enable CacheStoreMode and CacheRetrieveMode
properties to be set for an EntityManager.
git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@808981 13f79535-47bb-0310-9956-ffa450edef68
---
.../datacache/DataCacheStoreManager.java | 359 ++++++++--------
.../org/apache/openjpa/kernel/BrokerImpl.java | 43 ++
.../openjpa/kernel/DataCacheRetrieveMode.java | 33 ++
.../openjpa/kernel/DataCacheStoreMode.java | 42 ++
.../openjpa/kernel/DelegatingBroker.java | 35 ++
.../apache/openjpa/kernel/StoreContext.java | 57 +++
.../cache/jpa/AbstractCacheModeTestCase.java | 396 ++++++++++++++++++
.../cache/jpa/AbstractJPACacheTestCase.java | 155 -------
.../cache/jpa/TestCacheModeAll.java | 35 +-
.../jpa/TestCacheModeDisableSelective.java | 41 +-
.../jpa/TestCacheModeEnableSelective.java | 46 +-
.../cache/jpa/TestCacheModeNone.java | 39 +-
.../cache/jpa/model/CacheEntity.java | 2 +
.../cache/jpa/model/CacheableEntity.java | 10 +
.../jpa/model/NegatedCachableEntity.java | 10 +
.../jpa/model/NegatedUncacheableEntity.java | 10 +
.../cache/jpa/model/UncacheableEntity.java | 10 +
.../cache/jpa/model/UnspecifiedEntity.java | 10 +
.../cache/jpa/model/XmlCacheableEntity.java | 10 +
.../cache/jpa/model/XmlUncacheableEntity.java | 10 +
.../persistence/EntityManagerImpl.java | 45 +-
21 files changed, 1058 insertions(+), 340 deletions(-)
create mode 100644 openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DataCacheRetrieveMode.java
create mode 100644 openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DataCacheStoreMode.java
create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/AbstractCacheModeTestCase.java
delete mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/AbstractJPACacheTestCase.java
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
index 999129ec1..5c462d3de 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/DataCacheStoreManager.java
@@ -30,6 +30,8 @@ import java.util.Map;
import java.util.Map.Entry;
import org.apache.openjpa.enhance.PCDataGenerator;
+import org.apache.openjpa.kernel.DataCacheRetrieveMode;
+import org.apache.openjpa.kernel.DataCacheStoreMode;
import org.apache.openjpa.kernel.DelegatingStoreManager;
import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.LockLevels;
@@ -54,9 +56,9 @@ public class DataCacheStoreManager
extends DelegatingStoreManager {
// all the state managers changed in this transaction
- private Collection _inserts = null; // statemanagers
- private Map _updates = null; // statemanager -> fmd set
- private Collection _deletes = null; // statemanagers
+ private Collection _inserts = null;
+ private Map _updates = null;
+ private Collection _deletes = null;
// the owning context
private StoreContext _ctx = null;
@@ -130,127 +132,125 @@ public class DataCacheStoreManager
* Update all caches with the committed inserts, updates, and deletes.
*/
private void updateCaches() {
- // map each data cache to the modifications we need to perform
- Map modMap = null;
- Modifications mods;
- OpenJPAStateManager sm;
- DataCachePCData data;
- DataCache cache;
+ if(_ctx.getCacheStoreMode() != DataCacheStoreMode.BYPASS ) {
+ // map each data cache to the modifications we need to perform
+ Map modMap = null;
+ Modifications mods;
+ DataCachePCData data;
+ DataCache cache;
- // create pc datas for inserts
- if (_ctx.getPopulateDataCache() && _inserts != null) {
- for (Iterator itr = _inserts.iterator(); itr.hasNext();) {
- sm = (OpenJPAStateManager) itr.next();
- cache = sm.getMetaData().getDataCache();
- if (cache == null)
- continue;
+ // create pc datas for inserts
+ if (_ctx.getPopulateDataCache() && _inserts != null) {
+ for(OpenJPAStateManager sm : _inserts) {
+ cache = sm.getMetaData().getDataCache();
+ if (cache == null)
+ continue;
- if (modMap == null)
- modMap = new HashMap();
- mods = getModifications(modMap, cache);
- data = newPCData(sm);
- data.store(sm);
- mods.additions.add(new PCDataHolder(data, sm));
- }
- }
-
- // update pcdatas for updates
- Map.Entry entry;
- if (_updates != null) {
- BitSet fields;
- for (Iterator itr = _updates.entrySet().iterator();
- itr.hasNext();) {
- entry = (Map.Entry) itr.next();
- sm = (OpenJPAStateManager) entry.getKey();
- fields = (BitSet) entry.getValue();
-
- cache = sm.getMetaData().getDataCache();
- if (cache == null)
- continue;
-
- // it's ok not to clone the object that we get from the cache,
- // since we're inside the commit() method, so any modifications
- // to the underlying cache are valid. If the commit had not
- // already succeeded, then we'd want to clone the retrieved
- // object.
- if (modMap == null)
- modMap = new HashMap();
- data = cache.get(sm.getObjectId());
- mods = getModifications(modMap, cache);
-
- // data should always be non-null, since the object is
- // dirty, but maybe it got dropped from the cache in the
- // interim
- if (data == null) {
+ if (modMap == null)
+ modMap = new HashMap();
+ mods = getModifications(modMap, cache);
data = newPCData(sm);
data.store(sm);
- mods.newUpdates.add(new PCDataHolder(data, sm));
- } else {
- data.store(sm, fields);
- mods.existingUpdates.add(new PCDataHolder(data, sm));
+ mods.additions.add(new PCDataHolder(data, sm));
}
}
- }
- // remove pcdatas for deletes
- if (_deletes != null) {
- for (Iterator itr = _deletes.iterator(); itr.hasNext();) {
- sm = (OpenJPAStateManager) itr.next();
- cache = sm.getMetaData().getDataCache();
- if (cache == null)
- continue;
+ // update pcdatas for updates
+ if (_updates != null) {
+ BitSet fields;
+ OpenJPAStateManager sm;
+ for(Map.Entry entry : _updates.entrySet()) {
+ sm = entry.getKey();
+ fields = entry.getValue();
- if (modMap == null)
- modMap = new HashMap();
- mods = getModifications(modMap, cache);
- mods.deletes.add(sm.getObjectId());
- }
- }
+ cache = sm.getMetaData().getDataCache();
+ if (cache == null) {
+ continue;
+ }
- // notify the caches of the changes
- if (modMap != null) {
- for (Iterator itr = modMap.entrySet().iterator(); itr.hasNext();) {
- entry = (Map.Entry) itr.next();
- cache = (DataCache) entry.getKey();
- mods = (Modifications) entry.getValue();
+ // it's ok not to clone the object that we get from the cache,
+ // since we're inside the commit() method, so any modifications
+ // to the underlying cache are valid. If the commit had not
+ // already succeeded, then we'd want to clone the retrieved
+ // object.
+ if (modMap == null)
+ modMap = new HashMap();
+ data = cache.get(sm.getObjectId());
+ mods = getModifications(modMap, cache);
- // make sure we're not caching old versions
- cache.writeLock();
- try {
- transformToVersionSafePCDatas(cache, mods.additions);
- transformToVersionSafePCDatas(cache, mods.newUpdates);
- transformToVersionSafePCDatas(cache, mods.existingUpdates);
- cache.commit(mods.additions, mods.newUpdates,
- mods.existingUpdates, mods.deletes);
- } finally {
- cache.writeUnlock();
+ // data should always be non-null, since the object is
+ // dirty, but maybe it got dropped from the cache in the
+ // interim
+ if (data == null) {
+ data = newPCData(sm);
+ data.store(sm);
+ mods.newUpdates.add(new PCDataHolder(data, sm));
+ } else {
+ data.store(sm, fields);
+ mods.existingUpdates.add(new PCDataHolder(data, sm));
+ }
}
}
- }
- // if we were in largeTransaction mode, then we have recorded
- // the classes of updated/deleted objects and these now need to be
- // evicted
- if (_ctx.isTrackChangesByType()) {
- evictTypes(_ctx.getDeletedTypes());
- evictTypes(_ctx.getUpdatedTypes());
- }
+ // remove pcdatas for deletes
+ if (_deletes != null) {
+ for(OpenJPAStateManager sm : _deletes) {
+ cache = sm.getMetaData().getDataCache();
+ if (cache == null)
+ continue;
- // and notify the query cache. notify in one batch to reduce synch
- QueryCache queryCache = _ctx.getConfiguration().
+ if (modMap == null)
+ modMap = new HashMap();
+ mods = getModifications(modMap, cache);
+ mods.deletes.add(sm.getObjectId());
+ }
+ }
+
+ // notify the caches of the changes
+ if (modMap != null) {
+ for (Iterator itr = modMap.entrySet().iterator(); itr.hasNext();) {
+ Map.Entry entry = (Map.Entry) itr.next();
+ cache = (DataCache) entry.getKey();
+ mods = (Modifications) entry.getValue();
+
+ // make sure we're not caching old versions
+ cache.writeLock();
+ try {
+ transformToVersionSafePCDatas(cache, mods.additions);
+ transformToVersionSafePCDatas(cache, mods.newUpdates);
+ transformToVersionSafePCDatas(cache, mods.existingUpdates);
+ cache.commit(mods.additions, mods.newUpdates,
+ mods.existingUpdates, mods.deletes);
+ } finally {
+ cache.writeUnlock();
+ }
+ }
+ }
+
+ // if we were in largeTransaction mode, then we have recorded
+ // the classes of updated/deleted objects and these now need to be
+ // evicted
+ if (_ctx.isTrackChangesByType()) {
+ evictTypes(_ctx.getDeletedTypes());
+ 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 pers = _ctx.getPersistedTypes();
- Collection del = _ctx.getDeletedTypes();
- Collection up = _ctx.getUpdatedTypes();
- int size = pers.size() + del.size() + up.size();
- if (size > 0) {
- Collection types = new ArrayList(size);
- types.addAll(pers);
- types.addAll(del);
- types.addAll(up);
- queryCache.onTypesChanged(new TypesChangedEvent(this, types));
- }
+ if (queryCache != null) {
+ Collection pers = _ctx.getPersistedTypes();
+ Collection del = _ctx.getDeletedTypes();
+ Collection up = _ctx.getUpdatedTypes();
+ int size = pers.size() + del.size() + up.size();
+ if (size > 0) {
+ Collection types = new ArrayList(size);
+ types.addAll(pers);
+ types.addAll(del);
+ types.addAll(up);
+ queryCache.onTypesChanged(new TypesChangedEvent(this, types));
+ }
+ }
}
}
@@ -333,52 +333,74 @@ public class DataCacheStoreManager
return super.syncVersion(sm, edata);
}
- public boolean initialize(OpenJPAStateManager sm, PCState state,
- FetchConfiguration fetch, Object edata) {
+ public boolean initialize(OpenJPAStateManager sm, PCState state, FetchConfiguration fetch, Object edata) {
+ boolean rval;
DataCache cache = sm.getMetaData().getDataCache();
- if (cache == null || sm.isEmbedded())
- return super.initialize(sm, state, fetch, edata);
-
- DataCachePCData data = cache.get(sm.getObjectId());
- if (data != null && !isLocking(fetch)) {
- //### the 'data.type' access here probably needs to be
- //### addressed for bug 511
- sm.initialize(data.getType(), state);
- data.load(sm, fetch, edata);
- return true;
+ if (cache == null || sm.isEmbedded() || _ctx.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS
+ || _ctx.getCacheStoreMode() == DataCacheStoreMode.REFRESH) {
+ // save the return value and return later in case we need to update the cache)
+ rval = super.initialize(sm, state, fetch, edata);
}
- // initialize from store manager
- if (!super.initialize(sm, state, fetch, edata))
- return false;
- if (!_ctx.getPopulateDataCache())
- return true;
+ else {
+ DataCachePCData data = cache.get(sm.getObjectId());
+ if (data != null && !isLocking(fetch)) {
+ //### the 'data.type' access here probably needs to be
+ //### addressed for bug 511
+ sm.initialize(data.getType(), state);
+ data.load(sm, fetch, edata);
+ return true;
+ }
+ // initialize from store manager
+ if (!super.initialize(sm, state, fetch, edata)) {
+ return false;
+ }
+ rval = true; // same as rval = super.initialize(...)
+ }
+
+ // update the cache if configured appropriately.
+ if (_ctx.getCacheStoreMode() == DataCacheStoreMode.REFRESH && _ctx.getPopulateDataCache()) {
+ cacheStateManager(cache, sm);
+ }
+ return rval;
+ }
+
+ private void cacheStateManager(DataCache cache, OpenJPAStateManager sm) {
+ if(sm.isFlushed()) {
+ return;
+ }
// make sure that we're not trying to cache an old version
cache.writeLock();
try {
- data = cache.get(sm.getObjectId());
- if (data != null && compareVersion(sm, sm.getVersion(),
- data.getVersion()) == VERSION_EARLIER)
- return true;
+ DataCachePCData data = cache.get(sm.getObjectId());
+ if (data != null && compareVersion(sm, sm.getVersion(), data.getVersion()) == VERSION_EARLIER) {
+ return;
+ }
// cache newly loaded info. It is safe to cache data frorm
// initialize() because this method is only called upon
// initial load of the data.
- if (data == null)
+ boolean isNew = data == null;
+ if (isNew) {
data = newPCData(sm);
+ }
data.store(sm);
- cache.put(data);
+ if(isNew) {
+ cache.put(data);
+ }
+ else {
+ cache.update(data);
+ }
} finally {
cache.writeUnlock();
}
- return true;
}
public boolean load(OpenJPAStateManager sm, BitSet fields,
FetchConfiguration fetch, int lockLevel, Object edata) {
DataCache cache = sm.getMetaData().getDataCache();
- if (cache == null || sm.isEmbedded())
+ if (cache == null || sm.isEmbedded() || _ctx.getCacheRetrieveMode() == DataCacheRetrieveMode.BYPASS)
return super.load(sm, fields, fetch, lockLevel, edata);
DataCachePCData data = cache.get(sm.getObjectId());
@@ -392,33 +414,11 @@ public class DataCacheStoreManager
// so that if the store manager decides to modify it it won't affect us
if (!super.load(sm, (BitSet) fields.clone(), fetch, lockLevel, edata))
return false;
- if (!_ctx.getPopulateDataCache())
- return true;
- // Do not load changes into cache if the instance has been flushed
- if (sm.isFlushed())
- return true;
-
- // make sure that we're not trying to cache an old version
- cache.writeLock();
- try {
- data = cache.get(sm.getObjectId());
- if (data != null && compareVersion(sm, sm.getVersion(),
- data.getVersion()) == VERSION_EARLIER)
- return true;
-
- // cache newly loaded info
- boolean isNew = data == null;
- if (isNew)
- data = newPCData(sm);
- data.store(sm, fields);
- if (isNew)
- cache.put(data);
- else
- cache.update(data);
- } finally {
- cache.writeUnlock();
+ if (_ctx.getPopulateDataCache()) {
+ cacheStateManager(cache, sm);
}
return true;
+
}
public Collection loadAll(Collection sms, PCState state, int load,
@@ -430,7 +430,7 @@ public class DataCacheStoreManager
return super.loadAll(sms, state, load, fetch, edata);
}
- Map unloaded = null;
+ Map unloaded = null;
List smList = null;
Map caches = new HashMap();
OpenJPAStateManager sm;
@@ -509,12 +509,12 @@ public class DataCacheStoreManager
return failed;
// for each loaded instance, merge loaded state into cached data
- Map.Entry entry;
+
boolean isNew;
- for (Iterator itr = unloaded.entrySet().iterator(); itr.hasNext();) {
- entry = (Map.Entry) itr.next();
- sm = (OpenJPAStateManager) entry.getKey();
- fields = (BitSet) entry.getValue();
+
+ for(Map.Entry entry : unloaded.entrySet()) {
+ sm = entry.getKey();
+ fields = entry.getValue();
cache = sm.getMetaData().getDataCache();
if (cache == null || sm.isEmbedded() || (failed != null
@@ -550,10 +550,10 @@ public class DataCacheStoreManager
/**
* Helper method to add an unloaded instance to the given map.
*/
- private static Map addUnloaded(OpenJPAStateManager sm, BitSet fields,
- Map unloaded) {
+ private static Map addUnloaded(OpenJPAStateManager sm, BitSet fields,
+ Map unloaded) {
if (unloaded == null)
- unloaded = new HashMap();
+ unloaded = new HashMap();
unloaded.put(sm, fields);
return unloaded;
}
@@ -580,24 +580,29 @@ public class DataCacheStoreManager
sm = (OpenJPAStateManager) itr.next();
if (sm.getPCState() == PCState.PNEW && !sm.isFlushed()) {
- if (_inserts == null)
- _inserts = new ArrayList();
+ if (_inserts == null) {
+ _inserts = new ArrayList();
+ }
_inserts.add(sm);
// may have been re-persisted
- if (_deletes != null)
- _deletes.remove(sm);
+ if (_deletes != null) {
+ _deletes.remove(sm);
+ }
} else if (_inserts != null
&& (sm.getPCState() == PCState.PNEWDELETED
- || sm.getPCState() == PCState.PNEWFLUSHEDDELETED))
+ || sm.getPCState() == PCState.PNEWFLUSHEDDELETED)) {
_inserts.remove(sm);
+ }
else if (sm.getPCState() == PCState.PDIRTY) {
- if (_updates == null)
- _updates = new HashMap();
+ if (_updates == null) {
+ _updates = new HashMap();
+ }
_updates.put(sm, sm.getDirty());
} else if (sm.getPCState() == PCState.PDELETED) {
- if (_deletes == null)
- _deletes = new HashSet();
+ if (_deletes == null) {
+ _deletes = new HashSet();
+ }
_deletes.add(sm);
}
}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
index aec010f69..33989c7ac 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
@@ -38,6 +38,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Stack;
import java.util.TreeSet;
import java.util.concurrent.locks.ReentrantLock;
@@ -229,6 +230,12 @@ public class BrokerImpl
private boolean _cachePreparedQuery = true;
private boolean _cacheFinderQuery = true;
+ private DataCacheStoreMode _cacheStoreMode;
+ private DataCacheRetrieveMode _cacheRetrieveMode;
+
+ // Store and Retrieve mode may be suspended for a given operation. Stack may be overkill here.
+ private Stack _cacheStoreModeStack = new Stack();
+ private Stack _cacheRetrieveModeStack = new Stack();
// Map of properties whose values have been changed
// private Map _changedProperties =
@@ -4894,4 +4901,40 @@ public class BrokerImpl
unlock();
}
}
+
+ @Override
+ public DataCacheRetrieveMode getCacheRetrieveMode() {
+ return _cacheRetrieveMode;
+ }
+
+ @Override
+ public DataCacheStoreMode getCacheStoreMode() {
+ return _cacheStoreMode;
+ }
+
+ @Override
+ public void setCacheRetrieveMode(DataCacheRetrieveMode mode) {
+ _cacheRetrieveMode = mode;
+ }
+
+ @Override
+ public void setCacheStoreMode(DataCacheStoreMode mode) {
+ _cacheStoreMode = mode;
+ }
+
+ public void popCacheRetrieveMode() {
+ _cacheRetrieveMode = _cacheRetrieveModeStack.pop();
+ }
+
+ public void popCacheStoreMode() {
+ _cacheStoreMode = _cacheStoreModeStack.pop();
+ }
+
+ public void pushCacheRetrieveMode() {
+ _cacheRetrieveModeStack.push(_cacheRetrieveMode);
+ }
+
+ public void pushCacheStoreMode() {
+ _cacheStoreModeStack.push(_cacheStoreMode);
+ }
}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DataCacheRetrieveMode.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DataCacheRetrieveMode.java
new file mode 100644
index 000000000..0a4cea35c
--- /dev/null
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DataCacheRetrieveMode.java
@@ -0,0 +1,33 @@
+/*
+ * 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.kernel;
+
+/**
+ * DataCache Retrieve Modes.
+ */
+public enum DataCacheRetrieveMode {
+ /**
+ * Retrieve objects from the DataCache if a DataCache is enabled.
+ */
+ USE,
+ /**
+ * Ignore the DataCache and fetch data directly from the database.
+ */
+ BYPASS,
+}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DataCacheStoreMode.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DataCacheStoreMode.java
new file mode 100644
index 000000000..d12a13973
--- /dev/null
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DataCacheStoreMode.java
@@ -0,0 +1,42 @@
+/*
+ * 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.kernel;
+
+/**
+ * DataCache Store modes
+ */
+public enum DataCacheStoreMode {
+
+ /**
+ * Store updates, inserts and deletes in the DataCache. The DataCache will
+ * not be refreshed when data is read from the database.
+ */
+ USE,
+ /**
+ * Write updates, inserts and deletes directly to the database. The
+ * DataCache will not be aware of these changes and may need to be
+ * refreshed.
+ */
+ BYPASS,
+ /**
+ * Store updates, inserts and deletes in the DataCache. Entities which are
+ * read from the database will be refreshed in the DataCache.
+ */
+ REFRESH
+}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
index dfb7b43d3..5aa480d19 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingBroker.java
@@ -1411,4 +1411,39 @@ public class DelegatingBroker
_broker.setCachePreparedQuery(flag);
}
+ @Override
+ public DataCacheRetrieveMode getCacheRetrieveMode() {
+ return _broker.getCacheRetrieveMode();
+ }
+
+ @Override
+ public DataCacheStoreMode getCacheStoreMode() {
+ return _broker.getCacheStoreMode();
+ }
+
+ @Override
+ public void setCacheRetrieveMode(DataCacheRetrieveMode mode) {
+ _broker.setCacheRetrieveMode(mode);
+ }
+
+ @Override
+ public void setCacheStoreMode(DataCacheStoreMode mode) {
+ _broker.setCacheStoreMode(mode);
+ }
+
+ public void popCacheRetrieveMode() {
+ _broker.popCacheRetrieveMode();
+ }
+
+ public void popCacheStoreMode() {
+ _broker.popCacheStoreMode();
+ }
+
+ public void pushCacheRetrieveMode() {
+ _broker.pushCacheRetrieveMode();
+ }
+
+ public void pushCacheStoreMode() {
+ _broker.pushCacheStoreMode();
+ }
}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java
index 1d8d9d500..70863e4da 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreContext.java
@@ -458,4 +458,61 @@ public interface StoreContext {
* Releases the internal lock.
*/
public void unlock ();
+
+ /**
+ * Return the current DataCacheStoreMode for this context. The
+ * DataCacheStoreMode controls when entities are added / updated in the
+ * DataCache.
+ *
+ * @return DataCacheStore mode in use
+ * @since 2.0.0
+ */
+ public DataCacheStoreMode getCacheStoreMode();
+
+ /**
+ * Set DataCacheStoreMode
+ * @param mode The new DataCacheStoreMode
+ * @since 2.0.0
+ */
+ public void setCacheStoreMode(DataCacheStoreMode mode);
+
+ /**
+ * Return the current DataCacheRetrieveMode (controls whether objects will
+ * be loaded from the DataCache or direct from the database).
+ *
+ * @return DataCacheRetrieveMode in use.
+ * @since 2.0.0
+ */
+ public DataCacheRetrieveMode getCacheRetrieveMode();
+
+ /**
+ * Set DataCacheRetrieveMode
+ * @param mode new mode for obtaining data from the cache
+ * @since 2.0.0
+ */
+ public void setCacheRetrieveMode(DataCacheRetrieveMode mode);
+
+ /**
+ * Pop the DataCacheRetrieveMode stack
+ * @since 2.0.0
+ */
+ public void popCacheRetrieveMode();
+
+ /**
+ * Pop the DataCacheStoreMode stack.
+ * @since 2.0.0
+ */
+ public void popCacheStoreMode() ;
+
+ /**
+ * Push the current DataCacheRetrieveMode onto a saved stack.
+ * @since 2.0.0
+ */
+ public void pushCacheRetrieveMode() ;
+
+ /**
+ * Push the current DataCacheStoreMode onto a saved stack.
+ * @since 2.0.0
+ */
+ public void pushCacheStoreMode();
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/AbstractCacheModeTestCase.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/AbstractCacheModeTestCase.java
new file mode 100644
index 000000000..07c7b7ff6
--- /dev/null
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/AbstractCacheModeTestCase.java
@@ -0,0 +1,396 @@
+/*
+ * 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.cache.jpa;
+
+import java.util.List;
+
+import javax.persistence.Cache;
+import javax.persistence.CacheRetrieveMode;
+import javax.persistence.CacheStoreMode;
+import javax.persistence.EntityManager;
+
+import org.apache.openjpa.lib.jdbc.AbstractJDBCListener;
+import org.apache.openjpa.lib.jdbc.JDBCEvent;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.cache.jpa.model.CacheEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.CacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.NegatedCachableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.NegatedUncacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.UncacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.UnspecifiedEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.XmlCacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.XmlUncacheableEntity;
+
+public abstract class AbstractCacheModeTestCase extends AbstractCacheTestCase {
+ public abstract OpenJPAEntityManagerFactorySPI getEntityManagerFactory();
+
+ public abstract List getSql();
+
+ protected abstract Class>[] getExpectedNotInCache();
+
+ protected abstract Class>[] getExpectedInCache();
+
+ // =======================================================================
+ // Asserts
+ // =======================================================================
+ /**
+ * Assert whether the cache contains the expected results.
+ *
+ * @param cache
+ * The JPA Cache to verify
+ * @param expectCacheables
+ * Whether entities with @Cacheable(true) should be in the cache
+ * (almost always true)
+ * @param expectUncacheables
+ * Whether entities with @Cacheable(false) should be in the cache
+ * (almost always false)
+ * @param expectUnspecified
+ * Whether entities with no @Cacheable annotation should be in
+ * the cache (varies per config).
+ */
+ protected void assertCacheContents(Cache cache, boolean expectCacheables, boolean expectUncacheables,
+ boolean expectUnspecified) {
+ assertCacheables(cache, expectCacheables);
+ assertUncacheables(cache, expectUncacheables);
+ assertUnspecified(cache, expectUnspecified);
+ }
+
+ /**
+ * Assert whether the cacheable types are in the cache. This method exits on
+ * the first cache 'miss'.
+ *
+ * @param cache
+ * JPA Cache to verify
+ * @param expected
+ * If true the cacheable types should be in the cache, if false
+ * they should not be.
+ */
+ protected void assertCacheables(Cache cache, boolean expected) {
+ assertCached(cache, CacheableEntity.class, 1, expected);
+ assertCached(cache, NegatedUncacheableEntity.class, 1, expected);
+ assertCached(cache, XmlCacheableEntity.class, 1, expected);
+ }
+
+ /**
+ * Assert whether the uncacheable types are in the cache. This method exits
+ * on the first cache 'miss'.
+ *
+ * @param cache
+ * JPA Cache to verify
+ * @param expected
+ * If true the uncacheable types should be in the cache, if false
+ * they should not be.
+ */
+ protected void assertUncacheables(Cache cache, boolean expected) {
+ assertCached(cache, UncacheableEntity.class, 1, expected);
+ assertCached(cache, XmlUncacheableEntity.class, 1, expected);
+ assertCached(cache, NegatedCachableEntity.class, 1, expected);
+ }
+
+ /**
+ * Assert whether the unspecified types are in the cache. This method exits
+ * on the first cache 'miss'.
+ *
+ * @param cache
+ * JPA Cache to verify
+ * @param expected
+ * If true the unspecified types should be in the cache, if false
+ * they should not be.
+ */
+ protected void assertUnspecified(Cache cache, boolean expected) {
+ assertCached(cache, UnspecifiedEntity.class, 1, expected);
+ }
+
+ /**
+ * Assert that no sql is executed when running the supplied Action.
+ *
+ * @param act
+ * Action to execute.
+ */
+ public void assertNoSql(Action act) {
+ assertSqlInc(act, 0);
+ }
+
+ /**
+ * Assert that expectedSqls SQL statements are executed
+ * when running act
+ *
+ * @param act
+ * Action to run.
+ * @param expectedSqls
+ * Number of SQL statements that should be executed.
+ */
+ public void assertSqlInc(Action act, int expectedSqls) {
+ int before = getSql().size();
+ act.run();
+ assertEquals(before + expectedSqls, getSql().size());
+ }
+
+ // =======================================================================
+ // Utility classes
+ // =======================================================================
+ /**
+ * Basic 'runnable' interface used to run a set of commands, then analyze
+ * the number of SQL statements that result.
+ */
+ public interface Action {
+ public void run();
+ }
+
+ /**
+ * Simple JDBCListener which stores the executed sql in a List. The List is
+ * provided by the getSql() method so that subclasses may use separate
+ * lists.
+ *
+ * @author mikedd
+ *
+ */
+ public class Listener extends AbstractJDBCListener {
+ @Override
+ public void beforeExecuteStatement(JDBCEvent event) {
+ if (event.getSQL() != null && getSql() != null) {
+ getSql().add(event.getSQL());
+ }
+ }
+ }
+
+ // =======================================================================
+ // Test utilities
+ // =======================================================================
+ public boolean getCacheEnabled() {
+ return true;
+ }
+
+ // =======================================================================
+ // Common test methods.
+ // =======================================================================
+ /**
+ * Ensure that each call the em.find generates an SQL statement when
+ * CacheRetrieveMode.BYPASS is used.
+ */
+ public void testReadModeByass() {
+ assertSqlInc(new Action() {
+ public void run() {
+ EntityManager em = getEntityManagerFactory().createEntityManager();
+ em.setProperty(RETRIEVE_MODE_PROP, CacheRetrieveMode.BYPASS);
+ for (Class> cls : persistentTypes) {
+ em.find(cls, 1);
+ }
+ em.close();
+ }
+ }, persistentTypes.length);
+ }
+
+ /**
+ *
+ * Ensure that each entity in getExpectedInCache():
+ *
+ * - is in the cache
+ * - does not go to the database for a find operation
+ * - is not null
+ *
+ *
+ *
+ * and
+ *
+ *
+ * Ensure that each entity in getExpectedNotInCache() :
+ *
+ * - is not in the cache
+ * - results in a single SQL statement when em.find() is called
+ * - is not null
+ *
+ *
+ *
+ */
+ public void testRetrieveModeUse() {
+ assertNoSql(new Action() {
+ public void run() {
+ EntityManager em = getEntityManagerFactory().createEntityManager();
+ em.setProperty(RETRIEVE_MODE_PROP, CacheRetrieveMode.USE);
+ for (Class> cls : getExpectedInCache()) {
+ assertCached(getEntityManagerFactory().getCache(), cls, 1, true);
+ assertNotNull(em.find(cls, 1));
+ }
+ em.close();
+ }
+ });
+ assertSqlInc(new Action() {
+ public void run() {
+ EntityManager em = getEntityManagerFactory().createEntityManager();
+ em.setProperty(RETRIEVE_MODE_PROP, CacheRetrieveMode.USE);
+ for (Class> cls : getExpectedNotInCache()) {
+ assertCached(getEntityManagerFactory().getCache(), cls, 1, false);
+ assertNotNull(em.find(cls, 1));
+ }
+ em.close();
+ }
+ }, getExpectedNotInCache().length);
+ }
+
+ public void updateAndFind(Class extends CacheEntity> classToUpdate, int idToUpdate,
+ Class extends CacheEntity> classToFind, int idToFind,
+ CacheStoreMode storeMode, CacheRetrieveMode retrieveMode) {
+ EntityManager em = getEntityManagerFactory().createEntityManager();
+
+ if (storeMode != null) {
+ em.setProperty(STORE_MODE_PROP, storeMode);
+ }
+ if (retrieveMode != null) {
+ em.setProperty(RETRIEVE_MODE_PROP, retrieveMode);
+ }
+
+ em.getTransaction().begin();
+ CacheEntity ce1 = em.find(classToUpdate, idToUpdate);
+ CacheEntity ce2 = em.find(classToFind, idToFind);
+ assertNotNull(ce1);
+ assertNotNull(ce2);
+ ce1.setName(ce1.getName() + "UPD");
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ /**
+ *
+ * Test logic to validate different CacheStoreModes. It should behave
+ * identically for all shared-cache-modes except NONE which never caches
+ * anything.
+ *
+ *
+ * This method only tests setting the store mode on the EntityManager
+ * itself.
+ *
+ *
+ * The first transaction updates CacheableEntity::1 with CacheStoreMode
+ * tran1StoreMode, calls find for CacheableEntity::1 and
+ * XmlCacheableEntity::1. This will never trigger a cache refresh since the
+ * data is up to date - but it could trigger additional SQL
+ *
+ *
+ * The second transaction updates XmlCacheableEntity::1 with CacheStoreMode
+ * tran2StoreMode, calls find for CacheableEntity::1 and
+ * XmlCacheableEntity::1. In this case if tran2StoreMode ==
+ * CacheStoreMode.REFRESH we may update the cache with the state of
+ * CacheableEntity::1.
+ *
+ *
+ * @param tran1StoreMode
+ * CacheStoreMode to use in transaction 1.
+ * @param tran2StoreMode
+ * cacheStoreMode to use in transaction 2.
+ * @param cacheUpdatedForTran1
+ * Whether the cache will contain an updated version of
+ * CacheableEntity::1
+ * @param cacheUpdatedForTran2
+ * Whether the cache will contain an updated version of
+ * XmlCacheableEntity::1
+ * @param version
+ * Expected starting version of for both entities
+ */
+ public void entityManagerStoreModeTest(CacheStoreMode tran1StoreMode, CacheStoreMode tran2StoreMode,
+ boolean cacheUpdatedForTran1, boolean cacheUpdatedForTran2, int version) {
+ updateAndFind(CacheableEntity.class, 1, XmlCacheableEntity.class, 1, tran1StoreMode, null);
+ updateAndFind(XmlCacheableEntity.class, 1, CacheableEntity.class, 1, tran2StoreMode, null);
+
+ // get entities from the cache and ensure their versions are as
+ // expected.
+ EntityManager em = getEntityManagerFactory().createEntityManager();
+ em = getEntityManagerFactory().createEntityManager();
+ CacheableEntity ceFromEM = em.find(CacheableEntity.class, 1);
+ XmlCacheableEntity xceFromEM = em.find(XmlCacheableEntity.class, 1);
+ em.close();
+ assertEquals(cacheUpdatedForTran1 ? version + 1 : version, ceFromEM.getVersion());
+ assertEquals(cacheUpdatedForTran2 ? version + 1 : version, xceFromEM.getVersion());
+
+ // get the data from the database. Version should always have been
+ // updated in this case.
+ em = getEntityManagerFactory().createEntityManager();
+ em.setProperty(RETRIEVE_MODE_PROP, CacheRetrieveMode.BYPASS);
+ CacheableEntity ceFromDB =
+ (CacheableEntity) em.createNativeQuery("Select * from CacheableEntity where id = 1", CacheableEntity.class)
+ .getSingleResult();
+
+ XmlCacheableEntity xceFromDB =
+ (XmlCacheableEntity) em.createNativeQuery("Select * from XmlCacheableEntity where id = 1",
+ XmlCacheableEntity.class).getSingleResult();
+
+ assertEquals(version + 1, ceFromDB.getVersion());
+ assertEquals(version + 1, xceFromDB.getVersion());
+ em.close();
+ }
+
+ /**
+ * Execute the defaultStoreModeTest with
+ */
+ public void testStoreModeUseBypass() throws Exception {
+ if (getCacheEnabled()) {
+ entityManagerStoreModeTest(CacheStoreMode.USE, CacheStoreMode.BYPASS, true, false, 1);
+ }
+ }
+
+ public void testStoreModeUseUse() {
+ if (getCacheEnabled()) {
+ entityManagerStoreModeTest(CacheStoreMode.USE, CacheStoreMode.USE, true, true, 1);
+ }
+ }
+
+ public void testStoreModeUseRefresh() {
+ if (getCacheEnabled()) {
+ entityManagerStoreModeTest(CacheStoreMode.USE, CacheStoreMode.REFRESH, true, true, 1);
+ }
+ }
+
+ public void entityManagerStoreModeTest() {
+ if (getCacheEnabled()) {
+ entityManagerStoreModeTest(CacheStoreMode.BYPASS, CacheStoreMode.BYPASS, false, false, 1);
+ }
+ }
+
+ public void testStoreModeBypassUse() {
+ if (getCacheEnabled()) {
+ entityManagerStoreModeTest(CacheStoreMode.BYPASS, CacheStoreMode.USE, false, true, 1);
+ }
+ }
+
+ public void testStoreModeBypassRefresh() {
+ if (getCacheEnabled()) {
+ // REFRESH picks up the changes from the database, even though the
+ // first update was done with BYPASS
+ entityManagerStoreModeTest(CacheStoreMode.BYPASS, CacheStoreMode.REFRESH, true, true, 1);
+ }
+ }
+
+ public void testStoreModeRefreshUse() {
+ if (getCacheEnabled()) {
+ entityManagerStoreModeTest(CacheStoreMode.REFRESH, CacheStoreMode.USE, true, true, 1);
+ }
+ }
+
+ public void testStoreModeRefreshBypass() {
+ if (getCacheEnabled()) {
+ entityManagerStoreModeTest(CacheStoreMode.REFRESH, CacheStoreMode.BYPASS, true, false, 1);
+ }
+ }
+
+ public void testStoreModeRefreshRefresh() {
+ if (getCacheEnabled()) {
+ entityManagerStoreModeTest(CacheStoreMode.REFRESH, CacheStoreMode.REFRESH, true, true, 1);
+ }
+ }
+}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/AbstractJPACacheTestCase.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/AbstractJPACacheTestCase.java
deleted file mode 100644
index b7aecf88e..000000000
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/AbstractJPACacheTestCase.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * 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.cache.jpa;
-
-import java.lang.reflect.Modifier;
-
-import javax.persistence.Cache;
-import javax.persistence.EntityManager;
-
-import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
-import org.apache.openjpa.persistence.OpenJPAPersistence;
-import org.apache.openjpa.persistence.cache.jpa.model.CacheEntity;
-import org.apache.openjpa.persistence.cache.jpa.model.CacheableEntity;
-import org.apache.openjpa.persistence.cache.jpa.model.NegatedCachableEntity;
-import org.apache.openjpa.persistence.cache.jpa.model.NegatedUncacheableEntity;
-import org.apache.openjpa.persistence.cache.jpa.model.UncacheableEntity;
-import org.apache.openjpa.persistence.cache.jpa.model.UnspecifiedEntity;
-import org.apache.openjpa.persistence.cache.jpa.model.XmlCacheableEntity;
-import org.apache.openjpa.persistence.cache.jpa.model.XmlUncacheableEntity;
-import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
-
-public abstract class AbstractJPACacheTestCase extends AbstractPersistenceTestCase {
- public abstract OpenJPAEntityManagerFactorySPI getEntityManagerFactory();
-
- private static Class>[] persistentTypes =
- { CacheableEntity.class, UncacheableEntity.class, UnspecifiedEntity.class,
- NegatedCachableEntity.class, NegatedUncacheableEntity.class, XmlCacheableEntity.class,
- XmlUncacheableEntity.class };
-
- public void populate() throws IllegalAccessException, InstantiationException {
- EntityManager em = getEntityManagerFactory().createEntityManager();
- em.getTransaction().begin();
- for (Class> clss : persistentTypes) {
- if (!Modifier.isAbstract(clss.getModifiers())) {
- CacheEntity ce = (CacheEntity) clss.newInstance();
- ce.setId(1);
- em.persist(ce);
- }
- }
- em.getTransaction().commit();
- em.close();
- }
-
- public OpenJPAEntityManagerFactorySPI createEntityManagerFactory(String puName) {
- OpenJPAEntityManagerFactorySPI emf =
- (OpenJPAEntityManagerFactorySPI) OpenJPAPersistence.createEntityManagerFactory(puName,
- "META-INF/caching-persistence.xml", getPropertiesMap("openjpa.DataCache", "true",
- "openjpa.RemoteCommitProvider", "sjvm", persistentTypes));
- return emf;
- }
-
- @Override
- public void setUp() throws Exception {
- super.setUp();
- // populate once per test method in case we add more methods
- cleanDatabase();
- populate();
- }
-
- public void cleanDatabase() throws Exception {
- EntityManager em = getEntityManagerFactory().createEntityManager();
- em.getTransaction().begin();
- for (Class> clss : persistentTypes) {
- if (!Modifier.isAbstract(clss.getModifiers())) {
- em.createQuery("Delete from " + clss.getSimpleName()).executeUpdate();
- }
- }
- em.getTransaction().commit();
- em.close();
- }
-
- /**
- * Assert whether the cache contains the expected results.
- *
- * @param cache
- * The JPA Cache to verify
- * @param expectCacheables
- * Whether entities with @Cacheable(true) should be in the cache
- * (almost always true)
- * @param expectUncacheables
- * Whether entities with @Cacheable(false) should be in the cache
- * (almost always false)
- * @param expectUnspecified
- * Whether entities with no @Cacheable annotation should be in
- * the cache (varies per config).
- */
- protected void assertCacheContents(Cache cache, boolean expectCacheables, boolean expectUncacheables,
- boolean expectUnspecified) {
- assertCacheables(cache, expectCacheables);
- assertUncacheables(cache, expectUncacheables);
- assertUnspecified(cache, expectUnspecified);
- }
-
- /**
- * Assert whether the cacheable types are in the cache. This method exits on
- * the first cache 'miss'.
- *
- * @param cache
- * JPA Cache to verify
- * @param expected
- * If true the cacheable types should be in the cache, if false
- * they should not be.
- */
- protected void assertCacheables(Cache cache, boolean expected) {
- assertCached(cache, CacheableEntity.class, 1, expected);
- assertCached(cache, NegatedUncacheableEntity.class, 1, expected);
- assertCached(cache, XmlCacheableEntity.class, 1, expected);
- }
-
- /**
- * Assert whether the uncacheable types are in the cache. This method exits
- * on the first cache 'miss'.
- *
- * @param cache
- * JPA Cache to verify
- * @param expected
- * If true the uncacheable types should be in the cache, if false
- * they should not be.
- */
- protected void assertUncacheables(Cache cache, boolean expected) {
- assertCached(cache, UncacheableEntity.class, 1, expected);
- assertCached(cache, XmlUncacheableEntity.class, 1, expected);
- assertCached(cache, NegatedCachableEntity.class, 1, expected);
- }
-
- /**
- * Assert whether the unspecified types are in the cache. This method exits
- * on the first cache 'miss'.
- *
- * @param cache
- * JPA Cache to verify
- * @param expected
- * If true the unspecified types should be in the cache, if false
- * they should not be.
- */
- protected void assertUnspecified(Cache cache, boolean expected) {
- assertCached(cache, UnspecifiedEntity.class, 1, expected);
- }
-}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeAll.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeAll.java
index dd54c7786..ff97cb880 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeAll.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeAll.java
@@ -18,14 +18,24 @@
*/
package org.apache.openjpa.persistence.cache.jpa;
-import javax.persistence.Cache;
+import java.util.ArrayList;
+import java.util.List;
+import javax.persistence.Cache;
+import javax.persistence.CacheStoreMode;
+
+import org.apache.openjpa.lib.jdbc.JDBCListener;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
-public class TestCacheModeAll extends AbstractJPACacheTestCase {
+public class TestCacheModeAll extends AbstractCacheModeTestCase {
private static OpenJPAEntityManagerFactorySPI emf = null;
private static Cache cache = null;
+ private static List sql = new ArrayList();
+ private static JDBCListener listener;
+
+ private static Class>[] expectedInCache = persistentTypes;
+ private static Class>[] expectedNotInCache = {};
@Override
public OpenJPAEntityManagerFactorySPI getEntityManagerFactory() {
@@ -38,6 +48,17 @@ public class TestCacheModeAll extends AbstractJPACacheTestCase {
return emf;
}
+ public JDBCListener getListener() {
+ if (listener == null) {
+ listener = new Listener();
+ }
+ return listener;
+ }
+
+ public List getSql() {
+ return sql;
+ }
+
public void testCacheables() {
assertCacheables(cache, true);
}
@@ -49,4 +70,14 @@ public class TestCacheModeAll extends AbstractJPACacheTestCase {
public void testUnspecified() {
assertUnspecified(cache, true);
}
+
+ @Override
+ protected Class>[] getExpectedInCache() {
+ return expectedInCache;
+ }
+
+ @Override
+ protected Class>[] getExpectedNotInCache() {
+ return expectedNotInCache;
+ }
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeDisableSelective.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeDisableSelective.java
index 552603567..015c99bae 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeDisableSelective.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeDisableSelective.java
@@ -18,14 +18,32 @@
*/
package org.apache.openjpa.persistence.cache.jpa;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.persistence.Cache;
+import javax.persistence.CacheStoreMode;
+import org.apache.openjpa.lib.jdbc.JDBCListener;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.cache.jpa.model.CacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.NegatedUncacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.UncacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.UnspecifiedEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.XmlCacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.XmlUncacheableEntity;
-public class TestCacheModeDisableSelective extends AbstractJPACacheTestCase {
+public class TestCacheModeDisableSelective extends AbstractCacheModeTestCase {
private static OpenJPAEntityManagerFactorySPI emf = null;
private static Cache cache = null;
+ private static List sql = new ArrayList();
+ private static JDBCListener listener;
+
+ private static Class>[] expectedInCache =
+ { CacheableEntity.class, XmlCacheableEntity.class, NegatedUncacheableEntity.class, UnspecifiedEntity.class, };
+ private static Class>[] expectedNotInCache =
+ { UncacheableEntity.class, XmlUncacheableEntity.class, };
@Override
public OpenJPAEntityManagerFactorySPI getEntityManagerFactory() {
@@ -38,6 +56,17 @@ public class TestCacheModeDisableSelective extends AbstractJPACacheTestCase {
return emf;
}
+ public JDBCListener getListener() {
+ if (listener == null) {
+ listener = new Listener();
+ }
+ return listener;
+ }
+
+ public List getSql() {
+ return sql;
+ }
+
public void testCacheables() {
assertCacheables(cache, true);
}
@@ -49,4 +78,14 @@ public class TestCacheModeDisableSelective extends AbstractJPACacheTestCase {
public void testUnspecified() {
assertUnspecified(cache, true);
}
+
+ @Override
+ protected Class>[] getExpectedInCache() {
+ return expectedInCache;
+ }
+
+ @Override
+ protected Class>[] getExpectedNotInCache() {
+ return expectedNotInCache;
+ }
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeEnableSelective.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeEnableSelective.java
index 1ff9bdcc5..2ed9effe5 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeEnableSelective.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeEnableSelective.java
@@ -18,14 +18,31 @@
*/
package org.apache.openjpa.persistence.cache.jpa;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.persistence.Cache;
+import org.apache.openjpa.lib.jdbc.JDBCListener;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.cache.jpa.model.CacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.NegatedUncacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.UncacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.UnspecifiedEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.XmlCacheableEntity;
+import org.apache.openjpa.persistence.cache.jpa.model.XmlUncacheableEntity;
-public class TestCacheModeEnableSelective extends AbstractJPACacheTestCase {
+public class TestCacheModeEnableSelective extends AbstractCacheModeTestCase {
private static OpenJPAEntityManagerFactorySPI emf = null;
private static Cache cache = null;
+ private static List sql = new ArrayList();
+ private static JDBCListener listener;
+
+ private static Class>[] expectedInCache =
+ { CacheableEntity.class, XmlCacheableEntity.class, NegatedUncacheableEntity.class, };
+ private static Class>[] expectedNotInCache =
+ { UncacheableEntity.class, XmlUncacheableEntity.class, UnspecifiedEntity.class, };
@Override
public OpenJPAEntityManagerFactorySPI getEntityManagerFactory() {
@@ -38,6 +55,31 @@ public class TestCacheModeEnableSelective extends AbstractJPACacheTestCase {
return emf;
}
+ public JDBCListener getListener() {
+ if (listener == null) {
+ listener = new Listener();
+ }
+ return listener;
+ }
+
+ public List getSql() {
+ return sql;
+ }
+
+ @Override
+ protected Class>[] getExpectedInCache() {
+ return expectedInCache;
+ }
+
+ @Override
+ protected Class>[] getExpectedNotInCache() {
+ return expectedNotInCache;
+ }
+
+ // =======================================================================
+ // Tests
+ // =======================================================================
+
public void testCacheables() {
assertCacheables(cache, true);
}
@@ -49,5 +91,5 @@ public class TestCacheModeEnableSelective extends AbstractJPACacheTestCase {
public void testUnspecified() {
assertUnspecified(cache, false);
}
-
+
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeNone.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeNone.java
index 55ca94af1..7aee383c4 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeNone.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/TestCacheModeNone.java
@@ -18,14 +18,24 @@
*/
package org.apache.openjpa.persistence.cache.jpa;
+import java.util.ArrayList;
+import java.util.List;
+
import javax.persistence.Cache;
+import org.apache.openjpa.lib.jdbc.JDBCListener;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.StoreCache;
-public class TestCacheModeNone extends AbstractJPACacheTestCase {
+public class TestCacheModeNone extends AbstractCacheModeTestCase {
private static OpenJPAEntityManagerFactorySPI emf = null;
private static Cache cache = null;
+ private static List sql = new ArrayList();
+ private static JDBCListener listener;
+
+ private static Class>[] expectedInCache = {};
+ private static Class>[] expectedNotInCache = persistentTypes;
@Override
public OpenJPAEntityManagerFactorySPI getEntityManagerFactory() {
@@ -38,6 +48,22 @@ public class TestCacheModeNone extends AbstractJPACacheTestCase {
return emf;
}
+ public JDBCListener getListener() {
+ if (listener == null) {
+ listener = new Listener();
+ }
+ return listener;
+ }
+
+ public List getSql() {
+ return sql;
+ }
+
+ @Override
+ public boolean getCacheEnabled() {
+ return false;
+ }
+
public void testCacheables() {
assertCacheables(cache, false);
}
@@ -49,4 +75,15 @@ public class TestCacheModeNone extends AbstractJPACacheTestCase {
public void testUnspecified() {
assertUnspecified(cache, false);
}
+
+ @Override
+ protected Class>[] getExpectedInCache() {
+ return expectedInCache;
+ }
+
+ @Override
+ protected Class>[] getExpectedNotInCache() {
+ return expectedNotInCache;
+ }
+
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/CacheEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/CacheEntity.java
index cfeaffe7e..5c68b856a 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/CacheEntity.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/CacheEntity.java
@@ -21,4 +21,6 @@ package org.apache.openjpa.persistence.cache.jpa.model;
public interface CacheEntity {
public void setId(int id);
+ public void setName(String name);
+ public String getName();
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/CacheableEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/CacheableEntity.java
index 9c826e485..507e74464 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/CacheableEntity.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/CacheableEntity.java
@@ -31,6 +31,8 @@ public class CacheableEntity implements CacheEntity {
@Version
private int version;
+
+ private String name;
public int getId() {
return id;
@@ -47,4 +49,12 @@ public class CacheableEntity implements CacheEntity {
public void setVersion(int version) {
this.version = version;
}
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/NegatedCachableEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/NegatedCachableEntity.java
index 9a95cab09..41d005005 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/NegatedCachableEntity.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/NegatedCachableEntity.java
@@ -33,6 +33,16 @@ public class NegatedCachableEntity implements CacheEntity {
@Version
private int version;
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
public int getId() {
return id;
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/NegatedUncacheableEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/NegatedUncacheableEntity.java
index 8ce5df03a..954750583 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/NegatedUncacheableEntity.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/NegatedUncacheableEntity.java
@@ -34,6 +34,16 @@ public class NegatedUncacheableEntity implements CacheEntity {
@Version
private int version;
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
public int getId() {
return id;
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/UncacheableEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/UncacheableEntity.java
index 82cdce726..8d9bdd929 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/UncacheableEntity.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/UncacheableEntity.java
@@ -31,6 +31,16 @@ public class UncacheableEntity implements CacheEntity {
@Version
private int version;
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
public int getId() {
return id;
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/UnspecifiedEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/UnspecifiedEntity.java
index 7ada8e19e..3d4e796bc 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/UnspecifiedEntity.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/UnspecifiedEntity.java
@@ -29,6 +29,16 @@ public class UnspecifiedEntity implements CacheEntity {
@Version
private int version;
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
public int getId() {
return id;
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/XmlCacheableEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/XmlCacheableEntity.java
index 1134ca1f2..c8db48df3 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/XmlCacheableEntity.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/XmlCacheableEntity.java
@@ -32,6 +32,8 @@ public class XmlCacheableEntity implements CacheEntity {
@Version
private int version;
+
+ private String name;
public int getId() {
return id;
@@ -48,4 +50,12 @@ public class XmlCacheableEntity implements CacheEntity {
public void setVersion(int version) {
this.version = version;
}
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
}
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/XmlUncacheableEntity.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/XmlUncacheableEntity.java
index 34cc5a504..c8d1da6a0 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/XmlUncacheableEntity.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/cache/jpa/model/XmlUncacheableEntity.java
@@ -33,6 +33,16 @@ public class XmlUncacheableEntity implements CacheEntity {
@Version
private int version;
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
public int getId() {
return id;
}
diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
index a68ac2ea0..ff21202e6 100644
--- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
+++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/EntityManagerImpl.java
@@ -38,6 +38,8 @@ import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
+import javax.persistence.CacheRetrieveMode;
+import javax.persistence.CacheStoreMode;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
@@ -57,6 +59,8 @@ import org.apache.openjpa.enhance.PCRegistry;
import org.apache.openjpa.enhance.Reflection;
import org.apache.openjpa.kernel.AbstractBrokerFactory;
import org.apache.openjpa.kernel.Broker;
+import org.apache.openjpa.kernel.DataCacheRetrieveMode;
+import org.apache.openjpa.kernel.DataCacheStoreMode;
import org.apache.openjpa.kernel.DelegatingBroker;
import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.FindCallbacks;
@@ -105,6 +109,9 @@ public class EntityManagerImpl
private Map _plans = new IdentityHashMap(1);
private RuntimeExceptionTranslator _ret = PersistenceExceptions.getRollbackTranslator(this);
+
+ protected final String RETRIEVE_MODE_PROP = "javax.persistence.cache.retrieveMode";
+ protected final String STORE_MODE_PROP = "javax.persistence.cache.storeMode";
public EntityManagerImpl() {
// for Externalizable
@@ -482,9 +489,9 @@ public class EntityManagerImpl
public T find(Class cls, Object oid, LockModeType mode,
Map properties) {
assertNotCloseInvoked();
- if (mode != null && mode != LockModeType.NONE)
+ if (mode != null && mode != LockModeType.NONE) {
_broker.assertActiveTransaction();
-
+ }
processLockProperties(pushFetchPlan(), mode, properties);
try {
oid = _broker.newObjectId(cls, oid);
@@ -1638,4 +1645,38 @@ public class EntityManagerImpl
int dot = s.lastIndexOf('.');
return dot == -1 ? s : s.substring(dot+1);
}
+
+ public void setRetrieveMode(CacheRetrieveMode retrieveMode) {
+ _broker.setCacheRetrieveMode(toDataCacheRetrieveMode(retrieveMode));
+ }
+
+ public CacheRetrieveMode getRetrieveMode() {
+ return fromDataCacheRetrieveMode(_broker.getCacheRetrieveMode());
+ }
+
+ public void setStoreMode(CacheStoreMode storeMode) {
+ _broker.setCacheStoreMode(toDataCacheStoreMode(storeMode));
+ }
+
+ public CacheStoreMode getStoreMode() {
+ return fromDataCacheStoreMode(_broker.getCacheStoreMode());
+ }
+
+ private final DataCacheRetrieveMode toDataCacheRetrieveMode(CacheRetrieveMode mode ) {
+ // relies on the CacheRetrieveMode enums being nearly identical
+ return DataCacheRetrieveMode.valueOf(mode.toString());
+ }
+
+ private final DataCacheStoreMode toDataCacheStoreMode(CacheStoreMode mode ) {
+ // relies on the CacheStoreMode enums being nearly identical
+ return DataCacheStoreMode.valueOf(mode.toString());
+ }
+
+ private final CacheRetrieveMode fromDataCacheRetrieveMode(DataCacheRetrieveMode mode) {
+ return CacheRetrieveMode.valueOf(mode.toString());
+ }
+
+ private final CacheStoreMode fromDataCacheStoreMode(DataCacheStoreMode mode) {
+ return CacheStoreMode.valueOf(mode.toString());
+ }
}