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
This commit is contained in:
Michael Dick 2009-08-28 18:25:08 +00:00
parent 78e93abb51
commit 991cdcae7d
21 changed files with 1058 additions and 340 deletions

View File

@ -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<OpenJPAStateManager> _inserts = null;
private Map<OpenJPAStateManager, BitSet> _updates = null;
private Collection<OpenJPAStateManager> _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<OpenJPAStateManager, BitSet> 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<OpenJPAStateManager, BitSet> 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<OpenJPAStateManager, BitSet> 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<OpenJPAStateManager, BitSet> addUnloaded(OpenJPAStateManager sm, BitSet fields,
Map<OpenJPAStateManager, BitSet> unloaded) {
if (unloaded == null)
unloaded = new HashMap();
unloaded = new HashMap<OpenJPAStateManager, BitSet>();
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<OpenJPAStateManager>();
}
_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<OpenJPAStateManager, BitSet>();
}
_updates.put(sm, sm.getDirty());
} else if (sm.getPCState() == PCState.PDELETED) {
if (_deletes == null)
_deletes = new HashSet();
if (_deletes == null) {
_deletes = new HashSet<OpenJPAStateManager>();
}
_deletes.add(sm);
}
}

View File

@ -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<DataCacheStoreMode> _cacheStoreModeStack = new Stack<DataCacheStoreMode>();
private Stack<DataCacheRetrieveMode> _cacheRetrieveModeStack = new Stack<DataCacheRetrieveMode>();
// Map of properties whose values have been changed
// private Map<String, String> _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);
}
}

View File

@ -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,
}

View File

@ -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
}

View File

@ -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();
}
}

View File

@ -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();
}

View File

@ -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<String> 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 <literal>expectedSqls</literal> SQL statements are executed
* when running <literal>act</literal>
*
* @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);
}
/**
* <p>
* Ensure that each entity in getExpectedInCache():
* <ul>
* <li>is in the cache</li>
* <li>does not go to the database for a find operation</li>
* <li>is not null</li>
* </ul>
* </p>
* <p>
* and
* </p>
* <p>
* Ensure that each entity in getExpectedNotInCache() :
* <ul>
* <li>is not in the cache</li>
* <li>results in a single SQL statement when em.find() is called</li>
* <li>is not null</li>
* </ul>
* </p>
*
*/
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();
}
/**
* <p>
* Test logic to validate different CacheStoreModes. It should behave
* identically for all shared-cache-modes except NONE which never caches
* anything.
* </p>
* <p>
* This method only tests setting the store mode on the EntityManager
* itself.
* </p>
* <p>
* 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
* </p>
* <p>
* 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.
* </p>
*
* @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);
}
}
}

View File

@ -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);
}
}

View File

@ -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<String> sql = new ArrayList<String>();
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<String> 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;
}
}

View File

@ -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<String> sql = new ArrayList<String>();
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<String> 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;
}
}

View File

@ -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<String> sql = new ArrayList<String>();
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<String> 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);
}
}

View File

@ -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<String> sql = new ArrayList<String>();
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<String> 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;
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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<FetchConfiguration,FetchPlan> _plans = new IdentityHashMap<FetchConfiguration,FetchPlan>(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> T find(Class<T> cls, Object oid, LockModeType mode,
Map<String, Object> 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());
}
}