blob: 4dd2a256f453e8ee522be422c016dc978bcb7c60 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 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 v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// 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.descriptors.CacheIndex;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.sessions.DataRecord;
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, DataRecord 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.
*/
@Override
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, DataRecord 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
*/
@Override
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.
*/
@Override
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, DataRecord 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);
}
}
}