| /* |
| * 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: |
| // Gordon Yorke - initial API and implementation |
| |
| package org.eclipse.persistence.internal.indirection; |
| |
| import java.util.Collection; |
| |
| import org.eclipse.persistence.exceptions.DatabaseException; |
| import org.eclipse.persistence.exceptions.ValidationException; |
| import org.eclipse.persistence.internal.queries.ContainerPolicy; |
| import org.eclipse.persistence.internal.sessions.AbstractRecord; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl; |
| import org.eclipse.persistence.mappings.ForeignReferenceMapping; |
| |
| /** |
| * <p> |
| * <b>Purpose:</b> In certain cases the contents of a relationship may be |
| * retrievable from a cache. This ValueHolder instance provides the mechanism to |
| * store a cached relationship and to load that relationship from a cache. This |
| * functionality requires that the persistent identities of the targets can be |
| * collected as database type foreign key queries are unavailable. |
| * |
| * @author gyorke |
| * @since EclipseLink 1.1 |
| */ |
| public class CacheBasedValueHolder<T> extends DatabaseValueHolder<T> { |
| |
| protected transient ForeignReferenceMapping mapping; |
| protected Object[] references; |
| /** Setting to force the instantiation of the Collection on modification */ |
| protected boolean shouldAllowInstantiationDeferral = true; |
| |
| public CacheBasedValueHolder(Object[] pks, AbstractRecord foreignKeys, AbstractSession session, ForeignReferenceMapping mapping){ |
| super(); |
| this.references = pks; |
| this.mapping = mapping; |
| this.session = session; |
| this.row = foreignKeys; |
| } |
| |
| public Object[] getCachedPKs(){ |
| return this.references; |
| } |
| |
| |
| /** |
| * Process against the UOW and attempt to load a local copy before going to the shared cache |
| * If null is returned then the calling UOW will instantiate as normal. |
| */ |
| @Override |
| @SuppressWarnings({"unchecked"}) |
| public T getValue(UnitOfWorkImpl uow) { |
| if (this.references != null && this.references.length != 0){ |
| if (mapping.isCollectionMapping()){ |
| Collection<Object> result = uow.getIdentityMapAccessorInstance().getAllFromIdentityMapWithEntityPK(this.references, this.mapping.getReferenceDescriptor()).values(); |
| if (result.size() == references.length){ |
| ContainerPolicy cp = mapping.getContainerPolicy(); |
| Object container = cp.containerInstance(result.size()); |
| for (Object object : result){ |
| cp.addInto(object, container, uow); |
| } |
| return (T) container; |
| } |
| }else{ |
| return (T) uow.getIdentityMapAccessorInstance().getFromIdentityMap(this.references[0], this.mapping.getReferenceClass()); |
| } |
| } |
| return null; |
| } |
| |
| @Override |
| protected T instantiate() throws DatabaseException { |
| return instantiate(this.session); |
| } |
| |
| @SuppressWarnings({"unchecked"}) |
| protected T instantiate(AbstractSession localSession) throws DatabaseException { |
| if (session == null){ |
| throw ValidationException.instantiatingValueholderWithNullSession(); |
| } |
| return (T) mapping.valueFromPKList(references, row, localSession); |
| } |
| |
| /** |
| * Triggers UnitOfWork valueholders directly without triggering the wrapped |
| * valueholder (this). |
| * <p> |
| * When in transaction and/or for pessimistic locking the UnitOfWorkValueHolder |
| * needs to be triggered directly without triggering the wrapped valueholder. |
| * However only the wrapped valueholder knows how to trigger the indirection, |
| * i.e. it may be a batchValueHolder, and it stores all the info like the row |
| * and the query. |
| * Note: This method is not thread-safe. It must be used in a synchronized manner |
| */ |
| @Override |
| public T instantiateForUnitOfWorkValueHolder(UnitOfWorkValueHolder<T> unitOfWorkValueHolder) { |
| return instantiate(unitOfWorkValueHolder.getUnitOfWork()); |
| } |
| |
| @Override |
| public boolean isPessimisticLockingValueHolder() { |
| return false; |
| } |
| |
| /** |
| * Set if instantiation deferral on modification should be available. |
| */ |
| public void setShouldAllowInstantiationDeferral(boolean shouldAllowInstantiationDeferral){ |
| this.shouldAllowInstantiationDeferral = shouldAllowInstantiationDeferral; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return if add/remove should trigger instantiation or avoid. |
| * Current instantiation is avoided is using change tracking. |
| */ |
| @Override |
| public boolean shouldAllowInstantiationDeferral() { |
| return this.shouldAllowInstantiationDeferral; |
| } |
| |
| |
| |
| } |