/******************************************************************************* | |
* Copyright (c) 1998, 2013 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 v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* 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.*; | |
/** | |
* @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 extends DatabaseValueHolder { | |
/** | |
* 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 theMethod The method that returns the object when executed. | |
* @param object 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. | |
*/ | |
protected Object instantiate() throws DescriptorException { | |
return instantiate(getObject(), getSession()); | |
} | |
protected Object instantiate(Object object, AbstractSession session) throws DescriptorException { | |
try { | |
return 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 | |
*/ | |
public Object instantiateForUnitOfWorkValueHolder(UnitOfWorkValueHolder 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 | |
*/ | |
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; | |
} | |
} |