oracle.toplink.essentials.internal.indirection.DatabaseValueHolder Maven / Gradle / Ivy
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the "License"). You may not use this file except
* in compliance with the License.
*
* You can obtain a copy of the license at
* glassfish/bootstrap/legal/CDDLv1.0.txt or
* https://glassfish.dev.java.net/public/CDDLv1.0.html.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* HEADER in each file and include the License file at
* glassfish/bootstrap/legal/CDDLv1.0.txt. If applicable,
* add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your
* own identifying information: Portions Copyright [yyyy]
* [name of copyright owner]
*/
// Copyright (c) 1998, 2007, Oracle. All rights reserved.
package oracle.toplink.essentials.internal.indirection;
import java.io.*;
import oracle.toplink.essentials.internal.helper.*;
import oracle.toplink.essentials.indirection.*;
import oracle.toplink.essentials.exceptions.*;
import oracle.toplink.essentials.internal.localization.*;
import oracle.toplink.essentials.internal.sessions.AbstractRecord;
import oracle.toplink.essentials.internal.sessions.AbstractSession;
/**
* DatabaseValueHolder wraps a database-stored object and implements
* behavior to access it. The object is read only once from database
* after which is cached for faster access.
*
* @see ValueHolderInterface
* @author Dorin Sandu
*/
public abstract class DatabaseValueHolder implements WeavedAttributeValueHolderInterface, Cloneable, Serializable {
/** Stores the object after it is read from the database. */
protected Object value;
/** Indicates whether the object has been read from the database or not. */
protected boolean isInstantiated;
/** Stores the session for the database that contains the object. */
protected transient AbstractSession session;
/** Stores the row representation of the object. */
protected AbstractRecord row;
/**
* The variable below is used as part of the implementation of WeavedAttributeValueHolderInterface
* It is used to track whether a valueholder that has been weaved into a class is coordinated
* with the underlying property
* Set internally in TopLink when the state of coordination between a weaved valueholder and the underlying property is known
*/
protected boolean isCoordinatedWithProperty = false;
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException exception) {
throw new InternalError();
}
}
/**
* Return the row.
*/
public AbstractRecord getRow() {
return row;
}
/**
* Return the session.
*/
public AbstractSession getSession() {
return session;
}
/**
* Return the object.
*/
public synchronized Object getValue() {
if (!isInstantiated()) {
// The value must be set directly because the setValue can also cause instatiation under UOW.
privilegedSetValue(instantiate());
setInstantiated();
resetFields();
}
return value;
}
/**
* Instantiate the object.
*/
protected abstract Object instantiate() throws DatabaseException;
/**
* Triggers UnitOfWork valueholders directly without triggering the wrapped
* valueholder (this).
*
* 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: Implementations of this method are not necessarily thread-safe. They must
* be used in a synchronizaed manner
*/
public abstract Object instantiateForUnitOfWorkValueHolder(UnitOfWorkValueHolder unitOfWorkValueHolder);
/**
* This method is used as part of the implementation of WeavedAttributeValueHolderInterface
* It is used to check whether a valueholder that has been weaved into a class is coordinated
* with the underlying property
*/
public boolean isCoordinatedWithProperty(){
return isCoordinatedWithProperty;
}
/**
* This method is used as part of the implementation of WeavedAttributeValueHolderInterface.
*
* A DatabaseValueHolder is set up by TopLink and will never be a newly weaved valueholder.
* As a result, this method is stubbed out.
*/
public boolean isNewlyWeavedValueHolder(){
return false;
}
/**
* INTERNAL:
* Answers if this valueholder is easy to instantiate.
* @return true if getValue() won't trigger a database read.
*/
public boolean isEasilyInstantiated() {
return isInstantiated();
}
/**
* Return a boolean indicating whether the object
* has been read from the database or not.
*/
public boolean isInstantiated() {
return isInstantiated;
}
/**
* 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 instantatiated
* all fields can not be reset.
* Note: Implementations of this method are not necessarily thread-safe. They must
* be used in a synchronizaed manner
*/
public abstract boolean isPessimisticLockingValueHolder();
/**
* Answers if this valueholder is referenced only by a UnitOfWork valueholder.
* I.e. it was built in valueFromRow which was called by buildCloneFromRow.
*
* Sometimes in transaction a UnitOfWork clone, and all valueholders, are built
* directly from the row; however a UnitOfWorkValueHolder does not know how to
* instantiate itself so wraps this which does.
*
* On a successful merge must be released to the session cache with
* releaseWrappedValueHolder.
*/
protected boolean isTransactionalValueHolder() {
return ((session != null) && session.isUnitOfWork());
}
/**
* Used to determine if this is a remote uow value holder that was serialized to the server.
* It has no reference to its wrapper value holder, so must find its original object to be able to instantiate.
*/
public boolean isSerializedRemoteUnitOfWorkValueHolder() {
return false;
}
/**
* Set the object. This is used only by the privileged methods. One must be very careful in using this method.
*/
public void privilegedSetValue(Object value) {
this.value = value;
isCoordinatedWithProperty = false;
}
/**
* Releases a wrapped valueholder privately owned by a particular unit of work.
*
* When unit of work clones are built directly from rows no object in the shared
* cache points to this valueholder, so it can store the unit of work as its
* session. However once that UnitOfWork commits and the valueholder is merged
* into the shared cache, the session needs to be reset to the root session, ie.
* the server session.
*/
public void releaseWrappedValueHolder() {
AbstractSession session = getSession();
if ((session != null) && session.isUnitOfWork()) {
setSession(session.getRootSession(null));
}
}
/**
* Reset all the fields that are not needed after instantiation.
*/
protected void resetFields() {
setRow(null);
setSession(null);
}
/**
* This method is used as part of the implementation of WeavedAttributeValueHolderInterface
* It is used internally by TopLink to set whether a valueholder that has been weaved into a class is coordinated
* with the underlying property
*/
public void setIsCoordinatedWithProperty(boolean coordinated){
this.isCoordinatedWithProperty = coordinated;
}
/**
* This method is used as part of the implementation of WeavedAttributeValueHolderInterface
*
* A DatabaseValueHolder is set up by TopLink and will never be a newly weaved valueholder
* As a result, this method is stubbed out.
*/
public void setIsNewlyWeavedValueHolder(boolean isNew){
}
/**
* Set the instantiated flag to true.
*/
public void setInstantiated() {
isInstantiated = true;
}
/**
* Set the row.
*/
public void setRow(AbstractRecord row) {
this.row = row;
}
/**
* Set the session.
*/
public void setSession(AbstractSession session) {
this.session = session;
}
/**
* Set the instantiated flag to false.
*/
public void setUninstantiated() {
isInstantiated = false;
}
/**
* Set the object.
*/
public void setValue(Object value) {
this.value = value;
setInstantiated();
}
public String toString() {
if (isInstantiated()) {
return "{" + getValue() + "}";
} else {
return "{" + Helper.getShortClassName(getClass()) + ": " + ToStringLocalization.buildMessage("not_instantiated", (Object[])null) + "}";
}
}
}