FileDocCategorySizeDatePackage
IdentityMapManager.javaAPI DocGlassfish v2 API49629Tue May 22 16:54:36 BST 2007oracle.toplink.essentials.internal.identitymaps

IdentityMapManager

public class IdentityMapManager extends Object implements Serializable, Cloneable

Purpose: Maintain identity maps for domain classes mapped with TopLink.

Responsibilities:

  • Build new identity maps lazily using info from the descriptor
  • Insert objects into appropriate identity map
  • Get object from appropriate identity map using object or primary key with class
  • Get and Set write lock values for cached objects
since
TOPLink/Java 1.0

Fields Summary
protected Hashtable
identityMaps
A table of identity maps with the key being the domain Class.
protected Map
queryResults
A table of identity maps with the key being the query
protected AbstractSession
session
A reference to the session owning this manager.
protected transient ConcurrencyManager
cacheMutex
Ensure mutual exclusion depending on the cache isolation.
protected IdentityMap
lastAccessedIdentityMap
Optimize the object retrival from the identity map.
protected Class
lastAccessedIdentityMapClass
protected transient WriteLockManager
writeLockManager
Used to store the write lock manager used for merging.
protected Boolean
isCacheAccessPreCheckRequired
PERF: Used to avoid readLock and profiler checks to improve performance.
Constructors Summary
public IdentityMapManager(AbstractSession session)


       
        this.session = session;
        this.cacheMutex = new ConcurrencyManager();
        this.identityMaps = new Hashtable();
        this.queryResults = JavaPlatform.getQueryCacheMap();
    
Methods Summary
public oracle.toplink.essentials.internal.identitymaps.CacheKeyacquireDeferredLock(java.util.Vector primaryKey, java.lang.Class domainClass, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
Provides access for setting a deferred lock on an object in the IdentityMap.

        CacheKey cacheKey = null;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                cacheKey = getIdentityMap(descriptor).acquireDeferredLock(primaryKey);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            cacheKey = getIdentityMap(descriptor).acquireDeferredLock(primaryKey);
        }

        return cacheKey;
    
public oracle.toplink.essentials.internal.identitymaps.CacheKeyacquireLock(java.util.Vector primaryKey, java.lang.Class domainClass, boolean forMerge, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
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

see
IdentityMap#aquire

        CacheKey cacheKey = null;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                cacheKey = getIdentityMap(descriptor).acquireLock(primaryKey, forMerge);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            cacheKey = getIdentityMap(descriptor).acquireLock(primaryKey, forMerge);
        }

        return cacheKey;
    
public oracle.toplink.essentials.internal.identitymaps.CacheKeyacquireLockNoWait(java.util.Vector primaryKey, java.lang.Class domainClass, boolean forMerge, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
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

see
IdentityMap#aquire

        CacheKey cacheKey = null;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                cacheKey = getIdentityMap(descriptor).acquireLockNoWait(primaryKey, forMerge);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            cacheKey = getIdentityMap(descriptor).acquireLockNoWait(primaryKey, forMerge);
        }

        return cacheKey;
    
public voidacquireReadLock()
Provides access for setting a concurrency lock on an IdentityMap.

see
IdentityMap#aquire

        getSession().startOperationProfile(SessionProfiler.CACHE);

        if (getSession().getDatasourceLogin().shouldSynchronizedReadOnWrite()) {
            getCacheMutex().acquireReadLock();
        }

        getSession().endOperationProfile(SessionProfiler.CACHE);
    
public oracle.toplink.essentials.internal.identitymaps.CacheKeyacquireReadLockOnCacheKey(java.util.Vector primaryKey, java.lang.Class domainClass, oracle.toplink.essentials.descriptors.ClassDescriptor 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.

        CacheKey cacheKey = null;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                cacheKey = getIdentityMap(descriptor).acquireReadLockOnCacheKey(primaryKey);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            cacheKey = getIdentityMap(descriptor).acquireReadLockOnCacheKey(primaryKey);
        }

        return cacheKey;
    
public oracle.toplink.essentials.internal.identitymaps.CacheKeyacquireReadLockOnCacheKeyNoWait(java.util.Vector primaryKey, java.lang.Class domainClass, oracle.toplink.essentials.descriptors.ClassDescriptor 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.

        CacheKey cacheKey = null;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                cacheKey = getIdentityMap(descriptor).acquireReadLockOnCacheKeyNoWait(primaryKey);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            cacheKey = getIdentityMap(descriptor).acquireReadLockOnCacheKeyNoWait(primaryKey);
        }

        return cacheKey;
    
public booleanacquireWriteLock()
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.

        if (getSession().getDatasourceLogin().shouldSynchronizedReadOnWrite() || getSession().getDatasourceLogin().shouldSynchronizeWrites()) {
            getCacheMutex().acquire();
            return true;
        }
        return false;
    
public oracle.toplink.essentials.internal.identitymaps.IdentityMapbuildNewIdentityMap(oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
INTERNAL: (Public to allow testing to access) Return a new empty identity map to cache instances of the class.

        if (getSession().isUnitOfWork()) {
            return new FullIdentityMap(100);
        }

        try {
            Constructor constructor = null;
            if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
                try {
                    constructor = (Constructor)AccessController.doPrivileged(new PrivilegedGetConstructorFor(descriptor.getIdentityMapClass(), new Class[] { ClassConstants.PINT }, false));
                    return (IdentityMap)AccessController.doPrivileged(new PrivilegedInvokeConstructor(constructor, new Object[] { new Integer(descriptor.getIdentityMapSize())}));
                } catch (PrivilegedActionException exception) {
                    throw DescriptorException.invalidIdentityMap(descriptor, exception.getException());
                }
            } else {
                constructor = PrivilegedAccessHelper.getConstructorFor(descriptor.getIdentityMapClass(), new Class[] { ClassConstants.PINT }, false);
                return (IdentityMap)PrivilegedAccessHelper.invokeConstructor(constructor, new Object[] { new Integer(descriptor.getIdentityMapSize())});

            }
        } catch (Exception exception) {
            throw DescriptorException.invalidIdentityMap(descriptor, exception);
        }
    
private java.lang.ObjectcheckForInheritance(java.lang.Object domainObject, java.lang.Class superClass)
This method is used to resolve the inheritance issues arisen when conforming from the identity map 1. Avoid reading the unintended subclass during in-memory queyr(e.g. when querying on large project, do not want to check small project, both are inheritanced from the project, and stored in the same identity map). 2. EJB container-generated classes broke the inheritance hirearchy. Need to use associated descriptor to track the relationship. CR4005-2612426, King-Sept-18-2002

        if ((domainObject != null) && ((domainObject.getClass() != superClass) && (!superClass.isInstance(domainObject)))) {
            //before returning null, check if we are using EJB inheritance.
            ClassDescriptor descriptor = getSession().getDescriptor(superClass);

            if (descriptor.hasInheritance() && descriptor.getInheritancePolicy().getUseDescriptorsToValidateInheritedObjects()) {
                //EJB inheritance on the descriptors, not the container-generated classes/objects. We need to check the
                //identity map for the bean instance through the descriptor.
                if (descriptor.getInheritancePolicy().getSubclassDescriptor(domainObject.getClass()) == null) {
                    return null;
                }

                //else
                return domainObject;
            }

            //else
            return null;
        }

        //else
        return domainObject;
    
public voidclearCacheAccessPreCheck()
Clear the cache access pre-check flag, used from session when profiler .

        this.isCacheAccessPreCheckRequired = null;
    
public voidclearLastAccessedIdentityMap()
INTERNAL: Clear the the lastAccessedIdentityMap and the lastAccessedIdentityMapClass

        lastAccessedIdentityMap = null;
        lastAccessedIdentityMapClass = null;
    
public voidclearQueryCache()
Clear all the query caches

        this.queryResults = JavaPlatform.getQueryCacheMap();
    
public voidclearQueryCache(oracle.toplink.essentials.queryframework.ReadQuery query)
Remove the cache key related to a query. Note this method is not synchronized and care should be taken to ensure there are no other threads accessing the cache key. This is used to clean up cached clones of queries

        if (query != null) {
            queryResults.remove(query);
        }
    
public java.lang.Objectclone()
INTERNAL: Clones itself, used for uow commit and resume on failure.

        IdentityMapManager manager = null;

        try {
            manager = (IdentityMapManager)super.clone();
            manager.setIdentityMaps(new Hashtable());
            for (Enumeration identityMapEnum = getIdentityMaps().keys();
                     identityMapEnum.hasMoreElements();) {
                Class theClass = (Class)identityMapEnum.nextElement();
                manager.getIdentityMaps().put(theClass, ((IdentityMap)getIdentityMaps().get(theClass)).clone());
            }
        } catch (Exception e) {
            ;
        }

        return manager;
    
public booleancontainsKey(java.util.Vector key, java.lang.Class theClass, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)

        // Check for null, contains causes null pointer.
        for (int index = 0; index < key.size(); index++) {
            if (key.elementAt(index) == null) {
                return false;
            }
        }

        IdentityMap map = getIdentityMap(descriptor);
        boolean contains;

        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                contains = map.containsKey(key);
            } finally {
                releaseReadLock();
                getSession().endOperationProfile(SessionProfiler.CACHE);
            }
        } else {
            contains = map.containsKey(key);
        }

        return contains;
    
public java.util.VectorgetAllFromIdentityMap(oracle.toplink.essentials.expressions.Expression selectionCriteria, java.lang.Class theClass, oracle.toplink.essentials.sessions.Record translationRow, oracle.toplink.essentials.queryframework.InMemoryQueryIndirectionPolicy valueHolderPolicy, boolean shouldReturnInvalidatedObjects)
Query the cache in-memory.

        ClassDescriptor descriptor = getSession().getDescriptor(theClass);
        getSession().startOperationProfile(SessionProfiler.CACHE);
        Vector objects = null;
        try {
            Expression selectionCriteriaClone = selectionCriteria;

            // Only clone if required.
            if ((selectionCriteria != null) && (selectionCriteriaClone.getBuilder().getSession() == null)) {
                selectionCriteriaClone = (Expression)selectionCriteria.clone();
                selectionCriteriaClone.getBuilder().setSession(getSession().getRootSession(null));
                selectionCriteriaClone.getBuilder().setQueryClass(theClass);
            }
            objects = new Vector();
            IdentityMap map = getIdentityMap(descriptor);

            // cache the current time to avoid calculating it every time through the loop
            long currentTimeInMillis = System.currentTimeMillis();
            for (Enumeration cacheEnum = map.keys(); cacheEnum.hasMoreElements();) {
                CacheKey key = (CacheKey)cacheEnum.nextElement();
                if ((key.getObject() == null) || (!shouldReturnInvalidatedObjects && getSession().getDescriptor(theClass).getCacheInvalidationPolicy().isInvalidated(key, currentTimeInMillis))) {
                    continue;
                }
                Object object = key.getObject();

                // Bug # 3216337 - key.getObject() should check for null; object may be GC'd (MWN)
                if (object == null) {
                    continue;
                }

                // Must check for inheritance.
                if ((object.getClass() == theClass) || (theClass.isInstance(object))) {
                    if (selectionCriteriaClone == null) {
                        objects.addElement(object);
                        getSession().incrementProfile(SessionProfiler.CacheHits);
                    } else {
                        try {
                            if (selectionCriteriaClone.doesConform(object, getSession(), (AbstractRecord)translationRow, valueHolderPolicy)) {
                                objects.addElement(object);
                                getSession().incrementProfile(SessionProfiler.CacheHits);
                            }
                        } catch (QueryException queryException) {
                            if (queryException.getErrorCode() == QueryException.MUST_INSTANTIATE_VALUEHOLDERS) {
                                if (valueHolderPolicy.shouldIgnoreIndirectionExceptionReturnConformed()) {
                                    objects.addElement(object);
                                    getSession().incrementProfile(SessionProfiler.CacheHits);
                                } else if (valueHolderPolicy.shouldThrowIndirectionException()) {
                                    throw queryException;
                                }
                            } else {
                                throw queryException;
                            }
                        }
                    }
                }
            }
        } finally {
            getSession().endOperationProfile(SessionProfiler.CACHE);
        }
        return objects;
    
public oracle.toplink.essentials.internal.identitymaps.CacheKeygetCacheKeyForObject(java.util.Vector primaryKey, java.lang.Class myClass, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
INTERNAL: Retrieve the cache key for the given identity information

param
Vector the primary key of the cache key to be retrieved
param
Class the class of the cache key to be retrieved
return
CacheKey

        IdentityMap map = getIdentityMap(descriptor);
        CacheKey cacheKey = null;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                cacheKey = map.getCacheKey(primaryKey);
            } finally {
                releaseReadLock();
                getSession().endOperationProfile(SessionProfiler.CACHE);
            }
        } else {
            cacheKey = map.getCacheKey(primaryKey);
        }
        return cacheKey;
    
public oracle.toplink.essentials.internal.helper.ConcurrencyManagergetCacheMutex()
Return the cache mutex. This allows for the entire cache to be locked. This is done for transaction isolations on merges, although never locked by default.

        return cacheMutex;
    
public java.util.VectorgetClassesRegistered()
INTERNAL: This method is used to get a list of those classes with IdentityMaps in the Session.

        Enumeration classes = getIdentityMaps().keys();
        Vector results = new Vector(getIdentityMaps().size());
        while (classes.hasMoreElements()) {
            results.add(((Class)classes.nextElement()).getName());
        }
        return results;
    
public java.lang.ObjectgetFromIdentityMap(java.lang.Object object)
Get the object from the identity map which has the same identity information as the given object.

        ClassDescriptor descriptor = getSession().getDescriptor(object);
        Vector primaryKey = descriptor.getObjectBuilder().extractPrimaryKeyFromObject(object, getSession());
        return getFromIdentityMap(primaryKey, object.getClass(), descriptor);
    
public java.lang.ObjectgetFromIdentityMap(java.util.Vector key, java.lang.Class theClass, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
Get the object from the identity map which has the given primary key and class

        return getFromIdentityMap(key, theClass, true, descriptor);
    
public java.lang.ObjectgetFromIdentityMap(java.util.Vector key, java.lang.Class theClass, boolean shouldReturnInvalidatedObjects, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
Get the object from the identity map which has the given primary key and class Only return the object if it has not Invalidated

        if (key == null) {
            return null;
        }

        // Check for null, contains causes null pointer.
        for (int index = 0; index < key.size(); index++) {
            if (key.elementAt(index) == null) {
                return null;
            }
        }

        CacheKey cacheKey;
        IdentityMap map = getIdentityMap(descriptor);
        Object domainObject = null;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                cacheKey = map.getCacheKey(key);
            } finally {
                releaseReadLock();
            }
        } else {
            cacheKey = map.getCacheKey(key);
        }

        if ((cacheKey != null) && (shouldReturnInvalidatedObjects || !getSession().getDescriptor(theClass).getCacheInvalidationPolicy().isInvalidated(cacheKey, System.currentTimeMillis()))) {
            //bug 4772232- acquire readlock on cachekey then release to ensure object is fully built before being returned
            try {
                cacheKey.acquireReadLock();
            } finally {
                cacheKey.releaseReadLock();
            }
            //bug 4772232- acquire readlock on cachekey then release to ensure object is fully built before being returned
            try {
                cacheKey.acquireReadLock();
                domainObject = cacheKey.getObject();
            } finally {
                cacheKey.releaseReadLock();
            }
            //reslove the inheritance issues
            domainObject = checkForInheritance(domainObject, theClass);
        }

        if (isCacheAccessPreCheckRequired()) {
            getSession().endOperationProfile(SessionProfiler.CACHE);
            if (domainObject == null) {
                getSession().incrementProfile(SessionProfiler.CacheMisses);
            } else {
                getSession().incrementProfile(SessionProfiler.CacheHits);
            }
        }

        return domainObject;
    
public java.lang.ObjectgetFromIdentityMap(oracle.toplink.essentials.expressions.Expression selectionCriteria, java.lang.Class theClass, oracle.toplink.essentials.sessions.Record translationRow, oracle.toplink.essentials.queryframework.InMemoryQueryIndirectionPolicy valueHolderPolicy, boolean conforming, boolean shouldReturnInvalidatedObjects, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)

        UnitOfWorkImpl unitOfWork = (conforming) ? (UnitOfWorkImpl)getSession() : null;
        getSession().startOperationProfile(SessionProfiler.CACHE);
        try {
            Expression selectionCriteriaClone = selectionCriteria;

            // Only clone if required.
            if ((selectionCriteria != null) && (selectionCriteriaClone.getBuilder().getSession() == null)) {
                selectionCriteriaClone = (Expression)selectionCriteria.clone();
                selectionCriteriaClone.getBuilder().setSession(getSession().getRootSession(null));
                selectionCriteriaClone.getBuilder().setQueryClass(theClass);
            }
            IdentityMap map = getIdentityMap(descriptor);

            // cache the current time to avoid calculating it every time through the loop
            long currentTimeInMillis = System.currentTimeMillis();
            for (Enumeration cacheEnum = map.keys(); cacheEnum.hasMoreElements();) {
                CacheKey key = (CacheKey)cacheEnum.nextElement();
                if (!shouldReturnInvalidatedObjects && descriptor.getCacheInvalidationPolicy().isInvalidated(key, currentTimeInMillis)) {
                    continue;
                }
                Object object = key.getObject();

                // Bug # 3216337 - key.getObject() should check for null; object may be GC'd (MWN)
                if (object == null) {
                    continue;
                }

                // Must check for inheritance.
                if ((object.getClass() == theClass) || (theClass.isInstance(object))) {
                    if (selectionCriteriaClone == null) {
                        // bug 2782991: if first found was deleted nothing returned. 
                        if (!(conforming && unitOfWork.isObjectDeleted(object))) {
                            getSession().incrementProfile(SessionProfiler.CacheHits);
                            return object;
                        }
                    }

                    //CR 3677 integration of a ValueHolderPolicy
                    try {
                        if (selectionCriteriaClone.doesConform(object, getSession(), (AbstractRecord)translationRow, valueHolderPolicy)) {
                            // bug 2782991: if first found was deleted nothing returned. 
                            if (!(conforming && unitOfWork.isObjectDeleted(object))) {
                                getSession().incrementProfile(SessionProfiler.CacheHits);
                                return object;
                            }
                        }
                    } catch (QueryException queryException) {
                        if (queryException.getErrorCode() == QueryException.MUST_INSTANTIATE_VALUEHOLDERS) {
                            if (valueHolderPolicy.shouldIgnoreIndirectionExceptionReturnConformed()) {
                                // bug 2782991: if first found was deleted nothing returned. 
                                if (!(conforming && unitOfWork.isObjectDeleted(object))) {
                                    getSession().incrementProfile(SessionProfiler.CacheHits);
                                    return object;
                                }
                            } else if (valueHolderPolicy.shouldIgnoreIndirectionExceptionReturnNotConformed()) {
                                // For bug 2667870 just skip this item, but do not abort.
                            } else {
                                throw queryException;
                            }
                        } else {
                            throw queryException;
                        }
                    }
                }
            }
        } finally {
            getSession().endOperationProfile(SessionProfiler.CACHE);
        }
        return null;
    
public java.lang.ObjectgetFromIdentityMapWithDeferredLock(java.util.Vector key, java.lang.Class theClass, boolean shouldReturnInvalidatedObjects, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
Get the object from the cache with the given primary key and class do not return the object if it was invalidated

        if (key == null) {
            getSession().incrementProfile(SessionProfiler.CacheMisses);
            return null;
        }

        // Check for null, contains causes null pointer.
        for (int index = 0; index < key.size(); index++) {
            if (key.elementAt(index) == null) {
                getSession().incrementProfile(SessionProfiler.CacheMisses);
                return null;
            }
        }

        IdentityMap map = getIdentityMap(descriptor);
        CacheKey cacheKey;
        Object domainObject = null;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                cacheKey = map.getCacheKey(key);
            } finally {
                releaseReadLock();
            }
        } else {
            cacheKey = map.getCacheKey(key);
        }

        if ((cacheKey != null) && (shouldReturnInvalidatedObjects || !descriptor.getCacheInvalidationPolicy().isInvalidated(cacheKey, System.currentTimeMillis()))) {
            cacheKey.acquireDeferredLock();
            domainObject = cacheKey.getObject();
            cacheKey.releaseDeferredLock();
        }

        //reslove the inheritance issues
        domainObject = checkForInheritance(domainObject, theClass);

        if (isCacheAccessPreCheckRequired()) {
            getSession().endOperationProfile(SessionProfiler.CACHE);
            if (domainObject == null) {
                getSession().incrementProfile(SessionProfiler.CacheMisses);
            } else {
                getSession().incrementProfile(SessionProfiler.CacheHits);
            }
        }

        return domainObject;
    
public oracle.toplink.essentials.internal.identitymaps.IdentityMapgetIdentityMap(oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
INTERNAL: (public to allow test cases to check) Return the identity map for the class, if missing create a new one.

        IdentityMap identityMap;

        // Enusre that an im is only used for the root descriptor for inheritence.
        // This is required to obtain proper cache hits.
        if (descriptor.hasInheritance()) {
            descriptor = descriptor.getInheritancePolicy().getRootParentDescriptor();
        }
        Class descriptorClass = descriptor.getJavaClass();

        // PERF: Synchronize around caching of last accessed map and lookup/build,
        // note that get is synchronized anyway so this is not adding any additional synching.
        synchronized (this) {
            // Optimazition for object retrival.
            IdentityMap tempMap = this.lastAccessedIdentityMap;
            if ((tempMap != null) && (this.lastAccessedIdentityMapClass == descriptorClass)) {
                return tempMap;
            }

            // PERF: Only synch around creation.
            identityMap = (IdentityMap)getIdentityMaps().get(descriptorClass);
            if (identityMap == null) {
                identityMap = buildNewIdentityMap(descriptor);
                getIdentityMaps().put(descriptorClass, identityMap);
            }
            this.lastAccessedIdentityMap = identityMap;
            this.lastAccessedIdentityMapClass = descriptorClass;
        }
        return identityMap;
    
public java.util.EnumerationgetIdentityMapClasses()
INTERNAL:

return
an enumeration of the classes in the identity map.

        return identityMaps.keys();
    
protected java.util.HashtablegetIdentityMaps()

        return identityMaps;
    
protected java.util.VectorgetKey(java.lang.Object domainObject)

        return getSession().keyFromObject(domainObject);
    
protected oracle.toplink.essentials.internal.sessions.AbstractSessiongetSession()

        return session;
    
public java.lang.ObjectgetWrapper(java.util.Vector primaryKey, java.lang.Class theClass)
Get the wrapper object from the cache key associated with the given primary key, this is used for EJB.

        ClassDescriptor descriptor = getSession().getDescriptor(theClass);
        IdentityMap map = getIdentityMap(descriptor);
        Object wrapper;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                wrapper = map.getWrapper(primaryKey);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            wrapper = map.getWrapper(primaryKey);
        }
        return wrapper;
    
public oracle.toplink.essentials.internal.helper.WriteLockManagergetWriteLockManager()
INTERNAL: Returns the single write Lock manager for this session

        // With Isolated Sessions not all Identity maps need a WriteLockManager so
        //lazy initialize
        synchronized (this) {
            if (this.writeLockManager == null) {
                this.writeLockManager = new WriteLockManager();
            }
        }
        return this.writeLockManager;
    
public java.lang.ObjectgetWriteLockValue(java.util.Vector primaryKey, java.lang.Class domainClass, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
Retrieve the write lock value of the cache key associated with the given primary key,

        IdentityMap map = getIdentityMap(descriptor);
        Object value;
        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            acquireReadLock();
            try {
                value = map.getWriteLockValue(primaryKey);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            value = map.getWriteLockValue(primaryKey);
        }
        return value;
    
public voidinitializeIdentityMap(java.lang.Class theClass)
Reset the identity map for only the instances of the class. For inheritence the user must make sure that they only use the root class.

        ClassDescriptor descriptor = getSession().getDescriptor(theClass);

        if (descriptor == null) {
            throw ValidationException.missingDescriptor(String.valueOf(theClass));
        }
        if (descriptor.isChildDescriptor()) {
            throw ValidationException.childDescriptorsDoNotHaveIdentityMap();
        }

        // Bug 3736313 - look up identity map by descriptor's java class
        Class javaClass = descriptor.getJavaClass();

        // bug 3745484 - clear the cached identity map if we are clearing the associated identity map
        if (javaClass == lastAccessedIdentityMapClass) {
            clearLastAccessedIdentityMap();
        }
        IdentityMap identityMap = buildNewIdentityMap(descriptor);
        getIdentityMaps().put(javaClass, identityMap);
    
public voidinitializeIdentityMaps()

        clearLastAccessedIdentityMap();
        setIdentityMaps(new Hashtable());
        clearQueryCache();
    
protected booleanisCacheAccessPreCheckRequired()
PERF: Used to micro optimize cache access. Avoid the readLock and profile checks if not required.

        if (this.isCacheAccessPreCheckRequired == null) {
            if ((getSession().getProfiler() != null) || getSession().getDatasourceLogin().shouldSynchronizedReadOnWrite()) {
                this.isCacheAccessPreCheckRequired = Boolean.TRUE;
            } else {
                this.isCacheAccessPreCheckRequired = Boolean.FALSE;
            }
        }
        return this.isCacheAccessPreCheckRequired.booleanValue();
    
public voidprintIdentityMap(java.lang.Class businessClass)
INTERNAL: 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.

        String cr = Helper.cr();
        ClassDescriptor descriptor = getSession().getDescriptor(businessClass);
        int cacheCounter = 0;
        StringWriter writer = new StringWriter();
        if (descriptor.isAggregateDescriptor()) {
            return;//do nothing if descriptor is aggregate
        }

        IdentityMap map = getIdentityMap(descriptor);
        writer.write(LoggingLocalization.buildMessage("identitymap_for", new Object[] { cr, Helper.getShortClassName(map.getClass()), Helper.getShortClassName(businessClass) }));
        if (descriptor.hasInheritance()) {
            if (descriptor.getInheritancePolicy().isRootParentDescriptor()) {
                writer.write(LoggingLocalization.buildMessage("includes"));
                Vector childDescriptors;
                childDescriptors = descriptor.getInheritancePolicy().getChildDescriptors();
                if ((childDescriptors != null) && (childDescriptors.size() != 0)) {//Bug#2675242
                    Enumeration enum2 = childDescriptors.elements();
                    writer.write(Helper.getShortClassName((Class)((ClassDescriptor)enum2.nextElement()).getJavaClass()));
                    while (enum2.hasMoreElements()) {
                        writer.write(", " + Helper.getShortClassName((Class)((ClassDescriptor)enum2.nextElement()).getJavaClass()));
                    }
                }
                writer.write(")");
            }
        }

        for (Enumeration enumtr = map.keys(); enumtr.hasMoreElements();) {
            oracle.toplink.essentials.internal.identitymaps.CacheKey cacheKey = (oracle.toplink.essentials.internal.identitymaps.CacheKey)enumtr.nextElement();
            Object object = cacheKey.getObject();
            if (businessClass.isInstance(object)) {
                cacheCounter++;
                if (object == null) {
                    writer.write(LoggingLocalization.buildMessage("key_object_null", new Object[] { cr, cacheKey.getKey(), "\t" }));
                } else {
                    writer.write(LoggingLocalization.buildMessage("key_identity_hash_code_object", new Object[] { cr, cacheKey.getKey(), "\t", String.valueOf(System.identityHashCode(object)), object }));
                }
            }
        }
        writer.write(LoggingLocalization.buildMessage("elements", new Object[] { cr, String.valueOf(cacheCounter) }));
        getSession().log(SessionLog.SEVERE, SessionLog.CACHE, writer.toString(), null, null, false);
    
public voidprintIdentityMaps()
INTERNAL: 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.

        for (Iterator iterator = getSession().getDescriptors().keySet().iterator();
                 iterator.hasNext();) {
            Class businessClass = (Class)iterator.next();
            ClassDescriptor descriptor = getSession().getDescriptor(businessClass);
            if (descriptor.hasInheritance()) {
                if (descriptor.getInheritancePolicy().isRootParentDescriptor()) {
                    printIdentityMap(businessClass);
                }
            } else {
                printIdentityMap(businessClass);
            }
        }
    
public voidprintLocks()
INTERNAL: 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.

        StringWriter writer = new StringWriter();
        HashMap threadCollection = new HashMap();
        writer.write(TraceLocalization.buildMessage("lock_writer_header", (Object[])null) + Helper.cr());
        Iterator idenityMapsIterator = this.session.getIdentityMapAccessorInstance().getIdentityMapManager().getIdentityMaps().values().iterator();
        while (idenityMapsIterator.hasNext()) {
            IdentityMap idenityMap = (IdentityMap)idenityMapsIterator.next();
            idenityMap.collectLocks(threadCollection);
        }
        Object[] parameters = new Object[1];
        for (Iterator threads = threadCollection.keySet().iterator(); threads.hasNext();) {
            Thread activeThread = (Thread)threads.next();
            parameters[0] = activeThread.getName();
            writer.write(TraceLocalization.buildMessage("active_thread", parameters) + Helper.cr());
            for (Iterator cacheKeys = ((HashSet)threadCollection.get(activeThread)).iterator();
                     cacheKeys.hasNext();) {
                CacheKey cacheKey = (CacheKey)cacheKeys.next();
                parameters[0] = cacheKey.getObject();
                writer.write(TraceLocalization.buildMessage("locked_object", parameters) + Helper.cr());
                parameters[0] = new Integer(cacheKey.getMutex().getDepth());
                writer.write(TraceLocalization.buildMessage("depth", parameters) + Helper.cr());
            }
            DeferredLockManager deferredLockManager = ConcurrencyManager.getDeferredLockManager(activeThread);
            if (deferredLockManager != null) {
                for (Iterator deferredLocks = deferredLockManager.getDeferredLocks().iterator();
                         deferredLocks.hasNext();) {
                    ConcurrencyManager lock = (ConcurrencyManager)deferredLocks.next();
                    parameters[0] = lock.getOwnerCacheKey().getObject();
                    writer.write(TraceLocalization.buildMessage("deferred_locks", parameters) + Helper.cr());
                }
            }
        }
        writer.write(Helper.cr() + TraceLocalization.buildMessage("lock_writer_footer", (Object[])null) + Helper.cr());
        getSession().log(SessionLog.FINEST, SessionLog.CACHE, writer.toString(), null, null, false);
    
public voidprintLocks(java.lang.Class theClass)
INTERNAL: Used to print all the Locks in the specified identity map in this session. The output of this method will be logged to this session's SessionLog at FINEST level.

        ClassDescriptor descriptor = getSession().getDescriptor(theClass);
        StringWriter writer = new StringWriter();
        HashMap threadCollection = new HashMap();
        writer.write(TraceLocalization.buildMessage("lock_writer_header", (Object[])null) + Helper.cr());
        IdentityMap identityMap = getIdentityMap(descriptor);
        identityMap.collectLocks(threadCollection);

        Object[] parameters = new Object[1];
        for (Iterator threads = threadCollection.keySet().iterator(); threads.hasNext();) {
            Thread activeThread = (Thread)threads.next();
            parameters[0] = activeThread.getName();
            writer.write(TraceLocalization.buildMessage("active_thread", parameters) + Helper.cr());
            for (Iterator cacheKeys = ((HashSet)threadCollection.get(activeThread)).iterator();
                     cacheKeys.hasNext();) {
                CacheKey cacheKey = (CacheKey)cacheKeys.next();
                parameters[0] = cacheKey.getObject();
                writer.write(TraceLocalization.buildMessage("locked_object", parameters) + Helper.cr());
                parameters[0] = new Integer(cacheKey.getMutex().getDepth());
                writer.write(TraceLocalization.buildMessage("depth", parameters) + Helper.cr());
            }
            DeferredLockManager deferredLockManager = ConcurrencyManager.getDeferredLockManager(activeThread);
            if (deferredLockManager != null) {
                for (Iterator deferredLocks = deferredLockManager.getDeferredLocks().iterator();
                         deferredLocks.hasNext();) {
                    ConcurrencyManager lock = (ConcurrencyManager)deferredLocks.next();
                    parameters[0] = lock.getOwnerCacheKey().getObject();
                    writer.write(TraceLocalization.buildMessage("deferred_locks", parameters) + Helper.cr());
                }
            }
        }
        writer.write(Helper.cr() + TraceLocalization.buildMessage("lock_writer_footer", (Object[])null) + Helper.cr());
        getSession().log(SessionLog.FINEST, SessionLog.CACHE, writer.toString(), null, null, false);
    
public oracle.toplink.essentials.internal.identitymaps.CacheKeyputInIdentityMap(java.lang.Object domainObject, java.util.Vector keys, java.lang.Object writeLockValue, long readTime, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
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

        ObjectBuilder builder = descriptor.getObjectBuilder();
        Object implementation = builder.unwrapObject(domainObject, getSession());

        IdentityMap map = getIdentityMap(descriptor);
        CacheKey cacheKey;

        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            // This is atomic so considered a read lock.
            acquireReadLock();
            try {
                cacheKey = map.put(keys, implementation, writeLockValue, readTime);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            cacheKey = map.put(keys, implementation, writeLockValue, readTime);
        }
        return cacheKey;
    
protected voidreleaseReadLock()
Read-release the local-map and the entire cache.

        if (getSession().getDatasourceLogin().shouldSynchronizedReadOnWrite()) {
            getCacheMutex().releaseReadLock();
        }
    
public voidreleaseWriteLock()
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.

       if (getSession().getDatasourceLogin().shouldSynchronizedReadOnWrite() || getSession().getDatasourceLogin().shouldSynchronizeWrites()) {
             getCacheMutex().release();
        }
    
public java.lang.ObjectremoveFromIdentityMap(java.util.Vector key, java.lang.Class domainClass, oracle.toplink.essentials.descriptors.ClassDescriptor descriptor)
Remove the object from the object cache.

        IdentityMap map = getIdentityMap(descriptor);
        Object value;

        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            // This is atomic so considered a read lock.
            acquireReadLock();
            try {
                value = map.remove(key);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            value = map.remove(key);
        }
        return value;
    
protected voidsetCacheMutex(oracle.toplink.essentials.internal.helper.ConcurrencyManager cacheMutex)
Set the cache mutex. This allows for the entire cache to be locked. This is done for transaction isolations on merges, although never locked by default.

        this.cacheMutex = cacheMutex;
    
public voidsetIdentityMaps(java.util.Hashtable identityMaps)

        clearLastAccessedIdentityMap();
        this.identityMaps = identityMaps;
    
protected voidsetSession(oracle.toplink.essentials.internal.sessions.AbstractSession session)

        this.session = session;
    
public voidsetWrapper(java.util.Vector primaryKey, java.lang.Class theClass, java.lang.Object wrapper)
Update the wrapper object the cache key associated with the given primary key, this is used for EJB.

        ClassDescriptor descriptor = getSession().getDescriptor(theClass);
        IdentityMap map = getIdentityMap(descriptor);

        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            // This is atomic so considered a read lock.
            acquireReadLock();
            try {
                map.setWrapper(primaryKey, wrapper);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            map.setWrapper(primaryKey, wrapper);
        }
    
public voidsetWriteLockValue(java.util.Vector primaryKey, java.lang.Class theClass, java.lang.Object writeLockValue)
Update the write lock value of the cache key associated with the given primary key,

        ClassDescriptor descriptor = getSession().getDescriptor(theClass);
        IdentityMap map = getIdentityMap(descriptor);

        if (isCacheAccessPreCheckRequired()) {
            getSession().startOperationProfile(SessionProfiler.CACHE);
            // This is atomic so considered a read lock.
            acquireReadLock();
            try {
                map.setWriteLockValue(primaryKey, writeLockValue);
            } finally {
                releaseReadLock();
            }
            getSession().endOperationProfile(SessionProfiler.CACHE);
        } else {
            map.setWriteLockValue(primaryKey, writeLockValue);
        }