/******************************************************************************* | |
* Copyright (c) 1998, 2013 Oracle and/or its affiliates. All rights reserved. | |
* This program and the accompanying materials are made available under the | |
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Oracle - initial API and implementation from Oracle TopLink | |
******************************************************************************/ | |
package org.eclipse.persistence.internal.sessions; | |
import java.util.*; | |
import org.eclipse.persistence.internal.identitymaps.*; | |
import org.eclipse.persistence.queries.*; | |
import org.eclipse.persistence.expressions.*; | |
import org.eclipse.persistence.exceptions.*; | |
import org.eclipse.persistence.internal.sessions.AbstractSession; | |
import org.eclipse.persistence.descriptors.CacheIndex; | |
import org.eclipse.persistence.descriptors.ClassDescriptor; | |
import org.eclipse.persistence.sessions.Record; | |
import org.eclipse.persistence.logging.SessionLog; | |
import org.eclipse.persistence.internal.descriptors.ObjectBuilder; | |
import org.eclipse.persistence.internal.descriptors.PersistenceEntity; | |
import org.eclipse.persistence.internal.helper.WriteLockManager; | |
/** | |
* INTERNAL: | |
* Internal subclass that provides access to identity maps through the session. | |
* Implements the IdentityMapAccessor interface which provides all publicly available | |
* identity map functionality to users. | |
* This is the main class that should be used to access identity maps. In general, any | |
* function that accesses the identity map manager should go through this class | |
* Any session specific functionality appears in subclasses | |
*/ | |
public class IsolatedClientSessionIdentityMapAccessor extends org.eclipse.persistence.internal.sessions.IdentityMapAccessor { | |
protected Map objectsLockedForClone; | |
/** | |
* INTERNAL: | |
* An IdentityMapAccessor sits between the session and the identityMapManager | |
* It needs references in both directions | |
*/ | |
public IsolatedClientSessionIdentityMapAccessor(AbstractSession session) { | |
super(session); | |
} | |
/** | |
* INTERNAL: | |
* Deferred lock the identity map for the object, this is used for avoiding deadlock | |
* The return cacheKey should be used to release the deferred lock | |
*/ | |
@Override | |
public CacheKey acquireDeferredLock(Object primaryKey, Class javaClass, ClassDescriptor descriptor, boolean isCacheCheckComplete) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().acquireDeferredLock(primaryKey, javaClass, descriptor, isCacheCheckComplete); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().acquireDeferredLock(primaryKey, javaClass, descriptor, isCacheCheckComplete); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Provides access for setting a concurrency lock on an object in the IdentityMap. | |
* called with true from the merge process, if true then the refresh will not refresh the object. | |
*/ | |
@Override | |
public CacheKey acquireLock(Object primaryKey, Class domainClass, boolean forMerge, ClassDescriptor descriptor, boolean isCacheCheckComplete) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().acquireLock(primaryKey, domainClass, forMerge, descriptor, isCacheCheckComplete); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().acquireLock(primaryKey, domainClass, forMerge, descriptor, isCacheCheckComplete); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Provides access for setting a concurrency lock on an object in the IdentityMap. | |
* called with true from the merge process, if true then the refresh will not refresh the object. | |
*/ | |
@Override | |
public CacheKey acquireLockNoWait(Object primaryKey, Class domainClass, boolean forMerge, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().acquireLockNoWait(primaryKey, domainClass, forMerge, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().acquireLockNoWait(primaryKey, domainClass, forMerge, descriptor); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Provides access for setting a concurrency lock on an object in the IdentityMap. | |
* called with true from the merge process, if true then the refresh will not refresh the object. | |
*/ | |
@Override | |
public CacheKey acquireLockWithWait(Object primaryKey, Class domainClass, boolean forMerge, ClassDescriptor descriptor, int wait) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().acquireLockWithWait(primaryKey, domainClass, forMerge, descriptor, wait); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().acquireLockWithWait(primaryKey, domainClass, forMerge, descriptor, wait); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Find the cachekey for the provided primary key and place a readlock on it. | |
* This will allow multiple users to read the same object but prevent writes to | |
* the object while the read lock is held. | |
*/ | |
@Override | |
public CacheKey acquireReadLockOnCacheKey(Object primaryKey, Class domainClass, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().acquireReadLockOnCacheKey(primaryKey, domainClass, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().acquireReadLockOnCacheKey(primaryKey, domainClass, descriptor); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Find the cachekey for the provided primary key and place a readlock on it. | |
* This will allow multiple users to read the same object but prevent writes to | |
* the object while the read lock is held. | |
* If no readlock can be acquired then do not wait but return null. | |
*/ | |
@Override | |
public CacheKey acquireReadLockOnCacheKeyNoWait(Object primaryKey, Class domainClass, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().acquireReadLockOnCacheKeyNoWait(primaryKey, domainClass, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().acquireReadLockOnCacheKeyNoWait(primaryKey, domainClass, descriptor); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Lock the entire cache if the cache isolation requires. | |
* By default concurrent reads and writes are allowed. | |
* By write, unit of work merge is meant. | |
*/ | |
@Override | |
public boolean acquireWriteLock() { | |
getIdentityMapManager().acquireWriteLock(); | |
// must lock the parents cache as well. | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().acquireWriteLock(); | |
} | |
/** | |
* ADVANCED: | |
* Return if their is an object for the primary key. | |
*/ | |
@Override | |
public boolean containsObjectInIdentityMap(Object primaryKey, Class theClass, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
if (this.identityMapManager == null) { | |
return false; | |
} | |
return getIdentityMapManager().containsKey(primaryKey, theClass, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().containsObjectInIdentityMap(primaryKey, theClass, descriptor); | |
} | |
} | |
/** | |
* INTERNAL: | |
* This method is used to get a list of those classes with IdentityMaps in the Session. | |
*/ | |
@Override | |
public Vector getClassesRegistered() { | |
Vector results = getIdentityMapManager().getClassesRegistered(); | |
results.addAll(((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getClassesRegistered()); | |
return results; | |
} | |
/** | |
* ADVANCED: | |
* Query the cache in-memory. | |
* If the expression is too complex an exception will be thrown. | |
* Only return objects that are invalid in the cache if specified. | |
*/ | |
@Override | |
public Vector getAllFromIdentityMap(Expression selectionCriteria, Class theClass, Record translationRow, int valueHolderPolicy, boolean shouldReturnInvalidatedObjects) throws QueryException { | |
if (!session.getDescriptor(theClass).getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().getAllFromIdentityMap(selectionCriteria, theClass, translationRow, valueHolderPolicy, shouldReturnInvalidatedObjects); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getAllFromIdentityMap(selectionCriteria, theClass, translationRow, valueHolderPolicy, shouldReturnInvalidatedObjects); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Retrieve the cache key for the given identity information. | |
* @param primaryKey the primary key of the cache key to be retrieved. | |
* @param myClass the class of the cache key to be retrieved. | |
*/ | |
@Override | |
public CacheKey getCacheKeyForObject(Object primaryKey, Class myClass, ClassDescriptor descriptor, boolean forMerge) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
if (this.identityMapManager == null) { | |
return null; | |
} | |
return getIdentityMapManager().getCacheKeyForObject(primaryKey, myClass, descriptor, forMerge); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getCacheKeyForObject(primaryKey, myClass, descriptor, forMerge); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Retrieve the cache key for the given identity information. | |
* @param primaryKey the primary key of the cache key to be retrieved. | |
* @param myClass the class of the cache key to be retrieved. | |
*/ | |
@Override | |
public CacheKey getCacheKeyForObjectForLock(Object primaryKey, Class myClass, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
if (this.identityMapManager == null) { | |
return null; | |
} | |
return getIdentityMapManager().getCacheKeyForObjectForLock(primaryKey, myClass, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getCacheKeyForObjectForLock(primaryKey, myClass, descriptor); | |
} | |
} | |
/** | |
* ADVANCED: | |
* Return the object from the identity with the primary and class. | |
*/ | |
@Override | |
public Object getFromIdentityMap(Object primaryKey, Object object, Class theClass, boolean shouldReturnInvalidatedObjects, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()){ | |
Object cachedObject = null; | |
if (this.identityMapManager != null){ | |
cachedObject = getIdentityMapManager().getFromIdentityMap(primaryKey, theClass, shouldReturnInvalidatedObjects, descriptor); | |
} | |
if (descriptor.getCachePolicy().isIsolated()) { | |
return cachedObject; | |
}else{ | |
return getAndCloneCacheKeyFromParent(primaryKey, object, theClass, shouldReturnInvalidatedObjects, descriptor); | |
} | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getFromIdentityMap(primaryKey, object, theClass, shouldReturnInvalidatedObjects, descriptor); | |
} | |
} | |
protected Object getAndCloneCacheKeyFromParent(Object primaryKey, Object objectToClone, Class theClass, boolean shouldReturnInvalidatedObjects, ClassDescriptor descriptor) { | |
CacheKey cacheKey = null; | |
if (objectToClone != null && objectToClone instanceof PersistenceEntity){ | |
cacheKey = ((PersistenceEntity)objectToClone)._persistence_getCacheKey(); | |
} | |
if (cacheKey == null || cacheKey.isIsolated() || cacheKey.getOwningMap() == null){ | |
org.eclipse.persistence.internal.sessions.IdentityMapAccessor parentIdentityMapAccessor = session.getParent().getIdentityMapAccessorInstance(); | |
cacheKey = parentIdentityMapAccessor.getCacheKeyForObject(primaryKey, theClass, descriptor, false); | |
} | |
Object objectFromCache = null; | |
// this check could be simplified to one line but would create a window | |
// in which GC could remove the object and we would end up with a null pointer | |
// as well we must inspect the cacheKey without locking on it. | |
if ((cacheKey != null) && (shouldReturnInvalidatedObjects || !descriptor.getCacheInvalidationPolicy().isInvalidated(cacheKey))) { | |
synchronized (cacheKey) { | |
//if the object in the cachekey is null but the key is acquired then | |
//someone must be rebuilding it or creating a new one. Sleep until | |
// it's finished. A plain wait here would be more efficient but we may not | |
// get notified for quite some time (ie deadlock) if the other thread | |
//is building the object. Must wait and not sleep in order for the monitor to be released | |
objectFromCache = cacheKey.getObject(); | |
try { | |
while (cacheKey.isAcquired() && (objectFromCache == null)) { | |
cacheKey.wait(5); | |
} | |
} catch (InterruptedException ex) { | |
} | |
if (objectFromCache == null) { | |
return null; | |
} | |
} | |
} else { | |
return null; | |
} | |
ClassDescriptor concreteDescriptor = descriptor; | |
// Ensure correct subclass descriptor. | |
if (objectFromCache.getClass() != descriptor.getJavaClass()) { | |
concreteDescriptor = session.getDescriptor(objectFromCache); | |
} | |
ObjectBuilder builder = concreteDescriptor.getObjectBuilder(); | |
Object workingClone = null; | |
// The cache/objects being registered must first be locked to ensure | |
// that a merge or refresh does not occur on the object while being cloned to | |
// avoid cloning a partially merged/refreshed object. | |
// If a cache isolation level is used, then lock the entire cache. | |
// otherwise lock the object and it related objects (not using indirection) as a unit. | |
// If just a simple object (all indirection) a simple read-lock can be used. | |
// PERF: Cache if check to write is required. | |
org.eclipse.persistence.internal.sessions.IdentityMapAccessor parentIdentityMapAccessor = session.getParent().getIdentityMapAccessorInstance(); | |
boolean identityMapLocked = parentIdentityMapAccessor.acquireWriteLock(); | |
boolean rootOfCloneRecursion = false; | |
if (identityMapLocked) { | |
session.checkAndRefreshInvalidObject(objectFromCache, cacheKey, descriptor); | |
} else { | |
// Check if we have locked all required objects already. | |
if (this.objectsLockedForClone == null) { | |
// PERF: If a simple object just acquire a simple read-lock. | |
if (concreteDescriptor.shouldAcquireCascadedLocks()) { | |
this.objectsLockedForClone = parentIdentityMapAccessor.getWriteLockManager().acquireLocksForClone(objectFromCache, concreteDescriptor, cacheKey, session); | |
} else { | |
session.checkAndRefreshInvalidObject(objectFromCache, cacheKey, descriptor); | |
cacheKey.acquireReadLock(); | |
} | |
rootOfCloneRecursion = true; | |
} | |
} | |
try { | |
// bug:6167576 Must acquire the lock before cloning. | |
workingClone = builder.instantiateWorkingCopyClone(objectFromCache, session); | |
// PERF: Cache the primary key if implements PersistenceEntity. | |
if (workingClone instanceof PersistenceEntity) { | |
((PersistenceEntity)workingClone)._persistence_setId(cacheKey.getKey()); | |
} | |
CacheKey localCacheKey = acquireLock(primaryKey, theClass, descriptor, false); | |
try{ | |
localCacheKey.setObject(workingClone); | |
localCacheKey.setReadTime(cacheKey.getReadTime()); | |
localCacheKey.setWriteLockValue(cacheKey.getWriteLockValue()); | |
builder.populateAttributesForClone(objectFromCache, cacheKey, workingClone, null, session); | |
}finally{ | |
localCacheKey.release(); | |
} | |
//also clone the fetch group reference if applied | |
if (concreteDescriptor.hasFetchGroupManager()) { | |
concreteDescriptor.getFetchGroupManager().copyFetchGroupInto(objectFromCache, workingClone, session); | |
} | |
} finally { | |
// If the entire cache was locked, release the cache lock, | |
// otherwise either release the cache-key for a simple lock, | |
// otherwise release the entire set of locks for related objects if this was the root. | |
if (identityMapLocked) { | |
parentIdentityMapAccessor.releaseWriteLock(); | |
} else { | |
if (rootOfCloneRecursion) { | |
if (this.objectsLockedForClone == null) { | |
cacheKey.releaseReadLock(); | |
} else { | |
for (Iterator iterator = this.objectsLockedForClone.values().iterator(); iterator.hasNext();) { | |
((CacheKey)iterator.next()).releaseReadLock(); | |
} | |
this.objectsLockedForClone = null; | |
} | |
session.executeDeferredEvents(); | |
} | |
} | |
} | |
concreteDescriptor.getObjectBuilder().instantiateEagerMappings(workingClone, session); | |
return workingClone; | |
} | |
/** | |
* INTERNAL: | |
* Return the object from the local identity map with the primary and class. | |
* This avoids checking the parent cache for the unit of work. | |
*/ | |
public Object getFromLocalIdentityMap(Object primaryKey, Class theClass, boolean shouldReturnInvalidatedObjects, ClassDescriptor descriptor) { | |
return getFromIdentityMap(primaryKey, null, theClass, shouldReturnInvalidatedObjects, descriptor); | |
} | |
/** | |
* INTERNAL: | |
* Query the cache in-memory. | |
* If the object is not found null is returned. | |
* If the expression is too complex an exception will be thrown. | |
*/ | |
@Override | |
public Object getFromIdentityMap(Expression selectionCriteria, Class theClass, Record translationRow, int valueHolderPolicy, boolean conforming, boolean shouldReturnInvalidatedObjects, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().getFromIdentityMap(selectionCriteria, theClass, translationRow, valueHolderPolicy, conforming, shouldReturnInvalidatedObjects, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getFromIdentityMap(selectionCriteria, theClass, translationRow, valueHolderPolicy, conforming, shouldReturnInvalidatedObjects, descriptor); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Return the object from the identity with the primary and class. | |
* Only return invalidated objects if requested | |
*/ | |
@Override | |
public Object getFromIdentityMapWithDeferredLock(Object primaryKey, Class theClass, boolean shouldReturnInvalidatedObjects, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
if (this.identityMapManager == null) { | |
return null; | |
} | |
return getIdentityMapManager().getFromIdentityMapWithDeferredLock(primaryKey, theClass, shouldReturnInvalidatedObjects, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getFromIdentityMapWithDeferredLock(primaryKey, theClass, shouldReturnInvalidatedObjects, descriptor); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Get the IdentityMapManager for this IdentityMapAccessor | |
* This method should be used for all IdentityMapManager access since it may | |
* be overridden in sub classes. | |
*/ | |
@Override | |
public IdentityMapManager getIdentityMapManager() { | |
// PERF: Lazy init manager as normally isolated object are only read in the unit of work. | |
if (this.identityMapManager == null) { | |
this.identityMapManager = new IdentityMapManager(this.session); | |
} | |
return this.identityMapManager; | |
} | |
/** | |
* INTERNAL: | |
* Get the identity map for the given class from the IdentityMapManager | |
*/ | |
@Override | |
public IdentityMap getIdentityMap(ClassDescriptor descriptor, boolean returnNullIfMissing) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().getIdentityMap(descriptor, returnNullIfMissing); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getIdentityMap(descriptor, returnNullIfMissing); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Get the cached results associated with a query. Results are cached by the | |
* values of the parameters to the query so different parameters will have | |
* different cached results. | |
*/ | |
@Override | |
public Object getQueryResult(ReadQuery query, List parameters, boolean checkExpiry) { | |
if (((IsolatedClientSession)session).isIsolatedQuery(query)) { | |
return getIdentityMapManager().getQueryResult(query, parameters, checkExpiry); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getQueryResult(query, parameters, checkExpiry); | |
} | |
} | |
/** | |
* INTERNAL: | |
* get the session associated with this IdentityMapAccessor | |
*/ | |
@Override | |
public AbstractSession getSession() { | |
return session; | |
} | |
/** | |
* INTERNAL: | |
* Get the wrapper object from the cache key associated with the given primary key, | |
* this is used for EJB. | |
*/ | |
@Override | |
public Object getWrapper(Object primaryKey, Class theClass) { | |
if (!session.getDescriptor(theClass).getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().getWrapper(primaryKey, theClass); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getWrapper(primaryKey, theClass); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Returns the single write Lock manager for this session | |
*/ | |
public WriteLockManager getWriteLockManager() { | |
// As there should only be one write lock manager per server session | |
// get the one from the parent. | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getWriteLockManager(); | |
} | |
/** | |
* ADVANCED: | |
* Extract the write lock value from the identity map. | |
*/ | |
@Override | |
public Object getWriteLockValue(Object primaryKey, Class theClass, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().getWriteLockValue(primaryKey, theClass, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getWriteLockValue(primaryKey, theClass, descriptor); | |
} | |
} | |
/** | |
* PUBLIC: | |
* Reset the entire object cache. | |
* <p> NOTE: be careful using this method. This method blows away both this session's and its parents caches, | |
* this includes the server cache or any other cache. This throws away any objects that have been read in. | |
* Extream caution should be used before doing this because object identity will no longer | |
* be maintained for any objects currently read in. This should only be called | |
* if the application knows that it no longer has references to object held in the cache. | |
*/ | |
@Override | |
public void initializeAllIdentityMaps() { | |
super.initializeAllIdentityMaps(); | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().initializeAllIdentityMaps(); | |
} | |
/** | |
* PUBLIC: | |
* Reset the identity map for only the instances of the class. | |
* For inheritance the user must make sure that they only use the root class. | |
* Caution must be used in doing this to ensure that the objects within the identity map | |
* are not referenced from other objects of other classes or from the application. | |
*/ | |
@Override | |
public void initializeIdentityMap(Class theClass) { | |
getSession().log(SessionLog.FINER, SessionLog.CACHE, "initialize_identitymap", theClass); | |
if (!session.getDescriptor(theClass).getCachePolicy().isSharedIsolation()) { | |
getIdentityMapManager().initializeIdentityMap(theClass); | |
} else { | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().initializeIdentityMap(theClass); | |
} | |
} | |
/** | |
* Invalidate/remove any results for the class from the query cache. | |
* This is used to invalidate the query cache on any change. | |
*/ | |
@Override | |
public void invalidateQueryCache(Class classThatChanged) { | |
if (!session.getDescriptor(classThatChanged).getCachePolicy().isSharedIsolation()) { | |
getIdentityMapManager().invalidateQueryCache(classThatChanged); | |
} else { | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().invalidateQueryCache(classThatChanged); | |
} | |
} | |
/** | |
* PUBLIC: | |
* Reset the entire local object cache. | |
* This throws away any objects that have been read in. | |
* Extreme caution should be used before doing this because object identity will no longer | |
* be maintained for any objects currently read in. This should only be called | |
* if the application knows that it no longer has references to object held in the cache. | |
*/ | |
@Override | |
public void initializeIdentityMaps() { | |
getSession().log(SessionLog.FINER, SessionLog.CACHE, "initialize_identitymaps"); | |
getIdentityMapManager().initializeIdentityMaps(); | |
getSession().getCommitManager().reinitialize(); | |
} | |
/** | |
* INTERNAL: | |
* Set the results for a query. | |
* Query results are cached based on the parameter values provided to the query | |
* different parameter values access different caches. | |
*/ | |
@Override | |
public void putQueryResult(ReadQuery query, List parameters, Object results) { | |
if (((IsolatedClientSession)session).isIsolatedQuery(query)) { | |
getIdentityMapManager().putQueryResult(query, parameters, results); | |
} else { | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().putQueryResult(query, parameters, results); | |
} | |
} | |
/** | |
* Index the cache key by the index values. | |
*/ | |
@Override | |
public void putCacheKeyByIndex(CacheIndex index, CacheId indexValues, CacheKey cacheKey, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
getIdentityMapManager().putCacheKeyByIndex(index, indexValues, cacheKey, descriptor); | |
} else { | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().putCacheKeyByIndex(index, indexValues, cacheKey, descriptor); | |
} | |
} | |
/** | |
* Return the cache key for the cache index or null if not found. | |
*/ | |
@Override | |
public CacheKey getCacheKeyByIndex(CacheIndex index, CacheId indexValues, boolean shouldCheckExpiry, ClassDescriptor descriptor) { | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().getCacheKeyByIndex(index, indexValues, shouldCheckExpiry, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().getCacheKeyByIndex(index, indexValues, shouldCheckExpiry, descriptor); | |
} | |
} | |
/** | |
* PUBLIC: | |
* Used to print all the objects in the identity map of the passed in class. | |
* The output of this method will be logged to this session's SessionLog at SEVERE level. | |
*/ | |
@Override | |
public void printIdentityMap(Class businessClass) { | |
if (getSession().shouldLog(SessionLog.SEVERE, SessionLog.CACHE)) { | |
if (!session.getDescriptor(businessClass).getCachePolicy().isSharedIsolation()) { | |
getIdentityMapManager().printIdentityMap(businessClass); | |
} else { | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().printIdentityMap(businessClass); | |
} | |
} | |
} | |
/** | |
* PUBLIC: | |
* Used to print all the objects in every identity map in this session. | |
* The output of this method will be logged to this session's SessionLog at SEVERE level. | |
*/ | |
@Override | |
public void printIdentityMaps() { | |
if (getSession().shouldLog(SessionLog.SEVERE, SessionLog.CACHE)) { | |
getIdentityMapManager().printIdentityMaps(); | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().printIdentityMaps(); | |
} | |
} | |
/** | |
* PUBLIC: | |
* Used to print all the locks in every identity map in this session. | |
* The output of this method will be logged to this session's SessionLog at FINEST level. | |
*/ | |
@Override | |
public void printIdentityMapLocks() { | |
if (getSession().shouldLog(SessionLog.FINEST, SessionLog.CACHE)) { | |
getIdentityMapManager().printLocks(); | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().printIdentityMapLocks(); | |
} | |
} | |
/** | |
* ADVANCED: | |
* Register the object with the identity map. | |
* The object must always be registered with its version number if optimistic locking is used. | |
* The readTime may also be included in the cache key as it is constructed. | |
*/ | |
public CacheKey internalPutInIdentityMap(Object domainObject, Object key, Object writeLockValue, long readTime, ClassDescriptor descriptor) { | |
//no need to unwrap as the put will unwrap later anyway | |
if (!descriptor.getCachePolicy().isSharedIsolation()) { | |
return getIdentityMapManager().putInIdentityMap(domainObject, key, writeLockValue, readTime, descriptor); | |
} else { | |
return ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().internalPutInIdentityMap(domainObject, key, writeLockValue, readTime, descriptor); | |
} | |
} | |
/** | |
* ADVANCED: | |
* Queries the cache in-memory with the passed in criteria and invalidates matching Objects. | |
* If the expression is too complex either all or none object of theClass invalidated (depending on shouldInvalidateOnException value). | |
* @param selectionCriteria Expression selecting the Objects to be returned | |
* @param theClass Class to be considered | |
* @param translationRow Record | |
* @param shouldInvalidateOnException boolean indicates weather to invalidate the object if conform threw exception. | |
*/ | |
@Override | |
public void invalidateObjects(Expression selectionCriteria, Class theClass, Record translationRow, boolean shouldInvalidateOnException) { | |
if (!session.getDescriptor(theClass).getCachePolicy().isSharedIsolation()) { | |
getIdentityMapManager().invalidateObjects(selectionCriteria, theClass, translationRow, shouldInvalidateOnException); | |
} else { | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().invalidateObjects(selectionCriteria, theClass, translationRow, shouldInvalidateOnException); | |
} | |
} | |
/** | |
* INTERNAL: | |
* Lock the entire cache if the cache isolation requires. | |
* By default concurrent reads and writes are allowed. | |
* By write, unit of work merge is meant. | |
*/ | |
@Override | |
public void releaseWriteLock() { | |
//release in the opposite order of the acquire | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().releaseWriteLock(); | |
getIdentityMapManager().releaseWriteLock(); | |
} | |
/** | |
* ADVANCED: | |
* Remove the object from the object cache. | |
*/ | |
@Override | |
public Object removeFromIdentityMap(Object key, Class theClass, ClassDescriptor descriptor, Object object) { | |
Object removedObject = null; | |
if (descriptor.isIsolated() || descriptor.isProtectedIsolation()) { | |
removedObject = getIdentityMapManager().removeFromIdentityMap(key, theClass, descriptor, object); | |
} | |
if (!descriptor.isIsolated()){ | |
removedObject = ((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().removeFromIdentityMap(key, theClass, descriptor, object); | |
} | |
return removedObject; | |
} | |
/** | |
* INTERNAL: | |
* Set the IdentityMapManager for this IdentityMapAccessor | |
*/ | |
@Override | |
public void setIdentityMapManager(IdentityMapManager identityMapManager) { | |
this.identityMapManager = identityMapManager; | |
} | |
/** | |
* INTERNAL: | |
* Update the wrapper object the cache key associated with the given primary key, | |
* this is used for EJB. | |
*/ | |
@Override | |
public void setWrapper(Object primaryKey, Class theClass, Object wrapper) { | |
if (!getSession().getDescriptor(theClass).getCachePolicy().isSharedIsolation()) { | |
getIdentityMapManager().setWrapper(primaryKey, theClass, wrapper); | |
} else { | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().setWrapper(primaryKey, theClass, wrapper); | |
} | |
} | |
/** | |
* ADVANCED: | |
* Update the write lock value in the identity map. | |
*/ | |
@Override | |
public void updateWriteLockValue(Object primaryKey, Class theClass, Object writeLockValue) { | |
if (!getSession().getDescriptor(theClass).getCachePolicy().isSharedIsolation()) { | |
getIdentityMapManager().setWriteLockValue(primaryKey, theClass, writeLockValue); | |
} else { | |
((IsolatedClientSession)session).getParent().getIdentityMapAccessorInstance().updateWriteLockValue(primaryKey, theClass, writeLockValue); | |
} | |
} | |
} |