| /* |
| * 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.indirection; |
| |
| import java.lang.reflect.InvocationTargetException; |
| |
| import org.eclipse.persistence.exceptions.DescriptorException; |
| import org.eclipse.persistence.internal.sessions.AbstractRecord; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| import org.eclipse.persistence.mappings.transformers.AttributeTransformer; |
| |
| /** |
| * @version $Header: TransformerBasedValueHolder.java 30-aug-2006.11:32:36 gyorke Exp $ |
| * @author mmacivor |
| * @since release specific (what release of product did this appear in) |
| * This class is to replace the MethodBasedValueHolder for TransformationMappings |
| * Holds on to an AttributeTransformer and uses it to generate the attribute value when triggered. |
| * That Transformer may be a MethodBasedAttributeTransformer or a user defined implementation. |
| * |
| */ |
| public class TransformerBasedValueHolder<T> extends DatabaseValueHolder<T> { |
| |
| /** |
| * Stores the method to be executed. The method can take |
| * one (the row) or two parameters (the row and session). |
| */ |
| protected transient AttributeTransformer transformer; |
| |
| /** |
| * Stores the object which owns this attribute. |
| */ |
| protected transient Object object; |
| |
| /** |
| * Initialize the method-based value holder. |
| * @param theTransformer The method that returns the object when executed. |
| * @param theObject the Object which owns this attribute. |
| * @param theRow The row representation of the object. |
| * @param theSession The session to the database that stores the object. |
| */ |
| public TransformerBasedValueHolder(AttributeTransformer theTransformer, Object theObject, AbstractRecord theRow, AbstractSession theSession) { |
| super(); |
| row = theRow; |
| session = theSession; |
| |
| // Make sure not to put a ClientSession or IsolatedClientSession in |
| // the shared cache (indirectly). |
| // Skip this if unitOfWork, for we use session.isUnitOfWork() to implement |
| // isTransactionalValueholder(), saving us from needing a boolean instance variable. |
| // If unitOfWork this safety measure is deferred until merge time with |
| // releaseWrappedValuehHolder. |
| // Note that if isolated session & query will return itself, which is safe |
| // for if isolated this valueholder is not in the shared cache. |
| if (!session.isUnitOfWork()) { |
| this.session = session.getRootSession(null); |
| } |
| transformer = theTransformer; |
| object = theObject; |
| } |
| |
| /** |
| * Return the method. |
| */ |
| protected AttributeTransformer getTransformer() { |
| return transformer; |
| } |
| |
| /** |
| * Return the receiver. |
| */ |
| protected Object getObject() { |
| return object; |
| } |
| |
| /** |
| * Instantiate the object by executing the method on the transformer. |
| */ |
| @Override |
| protected T instantiate() throws DescriptorException { |
| return instantiate(getObject(), getSession()); |
| } |
| |
| @SuppressWarnings({"unchecked"}) |
| protected T instantiate(Object object, AbstractSession session) throws DescriptorException { |
| try { |
| return (T) transformer.buildAttributeValue(getRow(), object, session); |
| } catch (DescriptorException ex) { |
| Throwable nestedException = ex.getInternalException(); |
| if (nestedException instanceof IllegalAccessException) { |
| throw DescriptorException.illegalAccessWhileInstantiatingMethodBasedProxy(nestedException); |
| } else if (nestedException instanceof IllegalArgumentException) { |
| throw DescriptorException.illegalArgumentWhileInstantiatingMethodBasedProxy(nestedException); |
| } else if (nestedException instanceof InvocationTargetException) { |
| throw DescriptorException.targetInvocationWhileInstantiatingMethodBasedProxy(nestedException); |
| } else { |
| throw ex; |
| } |
| } |
| } |
| |
| /** |
| * 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(getObject(), unitOfWorkValueHolder.getUnitOfWork()); |
| } |
| |
| /** |
| * INTERNAL: |
| * Answers if this valueholder is a pessimistic locking one. Such valueholders |
| * are special in that they can be triggered multiple times by different |
| * UnitsOfWork. Each time a lock query will be issued. Hence even if |
| * instantiated it may have to be instantiated again, and once instantiated |
| * all fields can not be reset. |
| * Note: This method is not thread-safe. It must be used in a synchronized manner |
| */ |
| @Override |
| public boolean isPessimisticLockingValueHolder() { |
| // there is no way to tell, as a transformation mapping may have |
| // a reference class or query to check, but by design there is no |
| // way we can access at it. |
| return false; |
| } |
| |
| /** |
| * Set the transformer. |
| */ |
| protected void setTransformer(AttributeTransformer theTransformer) { |
| transformer = theTransformer; |
| } |
| |
| /** |
| * Set the receiver. |
| */ |
| protected void setObject(Object theObject) { |
| object = theObject; |
| } |
| } |