All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.sessions.UnitOfWorkIdentityMapAccessor Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 1998, 2024 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 org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.QueryException;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.internal.descriptors.PersistenceEntity;
import org.eclipse.persistence.internal.identitymaps.CacheKey;
import org.eclipse.persistence.internal.identitymaps.IdentityMapManager;
import org.eclipse.persistence.queries.ReadQuery;
import org.eclipse.persistence.sessions.DataRecord;

import java.util.List;
import java.util.Vector;

/**
 * INTERNAL:
 * IdentityMapAccessor subclass for UnitOfWork
 * Overrides some initialization functionality and some behavior having to do with
 * getting objects from identity maps.
 */
public class UnitOfWorkIdentityMapAccessor extends IdentityMapAccessor {

    public UnitOfWorkIdentityMapAccessor() {
    }

    public UnitOfWorkIdentityMapAccessor(AbstractSession session, IdentityMapManager identityMapManager) {
        super(session, identityMapManager);
    }

    /**
     * ADVANCED:
     * Clear all the query caches
     */
    @Override
    public void clearQueryCache() {
        this.session.getParent().getIdentityMapAccessor().clearQueryCache();
    }

    /**
     * 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) {
        this.session.getParent().getIdentityMapAccessor().invalidateQueryCache(classThatChanged);
    }

    /**
     * ADVANCED:
     * Clear the query class associated with the passed-in read query
     */
    @Override
    public void clearQueryCache(ReadQuery query) {
        this.session.getParent().getIdentityMapAccessor().clearQueryCache(query);
    }

    /**
     * ADVANCED:
     * Clear the query cache associated with the named query on the session
     */
    @Override
    public void clearQueryCache(String sessionQueryName) {
        this.session.getParent().getIdentityMapAccessor().clearQueryCache((ReadQuery)session.getQuery(sessionQueryName));
    }

    /**
     * ADVANCED:
     * Clear the query cache associated with the named query on the descriptor for the given class
     */
    @Override
    public void clearQueryCache(String descriptorQueryName, Class queryClass) {
        this.session.getParent().getIdentityMapAccessor().clearQueryCache((ReadQuery)session.getDescriptor(queryClass).getQueryManager().getQuery(descriptorQueryName));
    }

    /**
     * INTERNAL:
     * Return if their is an object for the primary key.
     */
    @Override
    public boolean containsObjectInIdentityMap(Object primaryKey, Class theClass, ClassDescriptor descriptor) {
        if (getIdentityMapManager().containsKey(primaryKey, theClass, descriptor)) {
            return true;
        }
        return this.session.getParent().getIdentityMapAccessorInstance().containsObjectInIdentityMap(primaryKey, theClass, descriptor);
    }

    /**
     * INTERNAL:
     * This method overrides the getAllFromIdentityMap method in Session.  Invalidated Objects
     * will always be returned from a UnitOfWork.
     */
    @Override
    public Vector getAllFromIdentityMap(Expression selectionCriteria, Class theClass, DataRecord translationRow, int valueHolderPolicy, boolean shouldReturnInvalidatedObjects) throws QueryException {
        return super.getAllFromIdentityMap(selectionCriteria, theClass, translationRow, valueHolderPolicy, true);
    }

    /**
     * INTERNAL:
     * Override the getFromIdentityMapWithDeferredLock method on the session to ensure that
     * invalidated objects are always returned since this is a UnitOfWork
     */
    @Override
    public Object getFromIdentityMapWithDeferredLock(Object primaryKey, Class theClass, boolean shouldReturnInvalidatedObjects, ClassDescriptor descriptor) {
        Object objectFromCache = super.getFromIdentityMapWithDeferredLock(primaryKey, theClass, true, descriptor);
        if (objectFromCache != null){
            return objectFromCache;
        }
        return getAndCloneCacheKeyFromParent(primaryKey, null, theClass, shouldReturnInvalidatedObjects, descriptor);
    }

    /**
     * INTERNAL:
     * Return the object from the identity map with the primary key and class.
     * The parent's cache must be checked after the child's,
     * if found in the parent, it must be registered/cloned (but must avoid looping).
     * Note: in a UnitOfWork, invalidated objects will always be returned from the identity map
     * In the parent session, only return the object if it has not been Invalidated
     */
    @Override
    public Object getFromIdentityMap(Object primaryKey, Object object, Class theClass, boolean shouldReturnInvalidatedObjects, ClassDescriptor descriptor) {
        Object objectFromCache = super.getFromIdentityMap(primaryKey, object, theClass, true, descriptor);

        if (objectFromCache != null) {
            return objectFromCache;
        }
        //Bug#4613774  In the parent session, only return the object if it has not been Invalidated
        return getAndCloneCacheKeyFromParent(primaryKey, object, theClass, shouldReturnInvalidatedObjects, descriptor);
    }

    /**
     * INTERNAL:
     * This method will return the object from the parent and clone it.
     */
    protected Object getAndCloneCacheKeyFromParent(Object primaryKey, Object objectToClone, Class theClass, boolean shouldReturnInvalidatedObjects, ClassDescriptor descriptor) {
        // Note: Objects returned from the parent's identity map should include invalidated
        // objects. This is important because this internal method is used in the existence
        // check in the UnitOfWork.
        UnitOfWorkImpl unitOfWork = (UnitOfWorkImpl)this.session;
        CacheKey cacheKey = null;
        if (objectToClone != null && objectToClone instanceof PersistenceEntity){
            cacheKey = ((PersistenceEntity)objectToClone)._persistence_getCacheKey();
        }

        if (cacheKey == null || cacheKey.getOwningMap() == null){
            org.eclipse.persistence.internal.sessions.IdentityMapAccessor parentIdentityMapAccessor = unitOfWork.getParentIdentityMapSession(descriptor, false, false).getIdentityMapAccessorInstance();
            cacheKey = parentIdentityMapAccessor.getCacheKeyForObject(primaryKey, theClass, descriptor, false);
        }
        if ((cacheKey == null) && unitOfWork.getParentIdentityMapSession(descriptor, false, false).isUnitOfWork()) {
            //for nested unit of work
            //make parent clone and register object
            org.eclipse.persistence.internal.sessions.IdentityMapAccessor parentIdentityMapAccessor = unitOfWork.getParentIdentityMapSession(descriptor, false, false).getIdentityMapAccessorInstance();
            ((UnitOfWorkIdentityMapAccessor)parentIdentityMapAccessor).getAndCloneCacheKeyFromParent(primaryKey, null, theClass, shouldReturnInvalidatedObjects, descriptor);
            //get the cachekey that was created in the parent.
            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) {
                }
            }

            // check for inheritance.
            objectFromCache = checkForInheritance(objectFromCache, theClass, descriptor);
            if (objectFromCache == null) {
                return null;
            }
        } else {
            return null;
        }

        // Consider read-only class CR#4094
        if (this.session.isClassReadOnly(theClass, descriptor)) {
            // PERF: Just return the original object.
            return objectFromCache;
        }

        if (this.session instanceof RepeatableWriteUnitOfWork) {
            Object unregisteredDeletedClone = ((RepeatableWriteUnitOfWork)this.session).getUnregisteredDeletedCloneForOriginal(objectFromCache);
            if(unregisteredDeletedClone != null) {
                return unregisteredDeletedClone;
            }
        }

        return unitOfWork.cloneAndRegisterObject(objectFromCache, cacheKey, descriptor);
    }

    /**
     * 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.
     * 

* results are only cached in the parent session for UnitOfWorks */ @Override public Object getQueryResult(ReadQuery query, List parameters, boolean checkExpiry) { return this.session.getParent().getIdentityMapAccessorInstance().getQueryResult(query, parameters, checkExpiry); } /** * 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. *

* Results are only cached in the parent session for UnitOfWorks */ @Override public void putQueryResult(ReadQuery query, List parameters, Object results) { this.session.getParent().getIdentityMapAccessorInstance().putQueryResult(query, parameters, results); } /** * INTERNAL: * Reset the entire object cache, * ** be careful using this. * 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. * 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 initializeAllIdentityMaps() { super.initializeAllIdentityMaps(); this.session.getParent().getIdentityMapAccessor().initializeAllIdentityMaps(); } /** * This method is used to resolve the inheritance issues arise while trying to get object from * identity map of parent session. Avoid reading the unintended subclass during in-memory query * (e.g. when querying on large project, do not want to check small project, both are inherited * from the project, and stored in the same identity map). */ protected Object checkForInheritance(Object domainObject, Class superClass, ClassDescriptor descriptor) { if ((domainObject != null) && ((domainObject.getClass() != superClass) && (!superClass.isInstance(domainObject)))) { if (descriptor.hasInheritance() && descriptor.getInheritancePolicy().getUseDescriptorsToValidateInheritedObjects()) { if (descriptor.getInheritancePolicy().getSubclassDescriptor(domainObject.getClass()) == null) { return null; } return domainObject; } return null; } return domainObject; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy