/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the LICENSE file that accompanied
* this code.
*
* --
*/
package com.sun.sgs.app;
import java.io.DataInput;
import java.io.Serializable;
import java.math.BigInteger;
/**
* Provides facilities for managing access to shared, persistent objects.
* Managed objects are objects that implement the {@link ManagedObject} and
* {@link Serializable} interfaces. Each managed object is stored separately
* along with all of the serializable, non-managed objects it refers to. If a
* managed object refers to another managed object, it must do so through an
* instance of {@link ManagedReference}, created by the {@link #createReference
* createReference} method. Attempting to store a reference to a managed
* object using a standard reference rather than an instance of
* <code>ManagedReference</code> will typically result in an {@link
* ObjectIOException} being thrown when the current transaction commits. <p>
*
* Managed objects that are bound to names, and any managed objects they refer
* to directly or indirectly, are stored by the <code>DataManager</code>. It
* is up to the application to determine when managed objects are no longer
* needed and to remove them explicitly from the <code>DataManager</code> using
* the {@link #removeObject removeObject} method. <p>
*
* Managed objects are in one of the following states with respect to the data
* manager: <ul>
*
* <li><a name="transient"><b>Transient</b></a> - A managed object that has
* been created directly by the application and has not been supplied in a
* call to {@link #setBinding setBinding}, {@code createReference}, or
* {@link #getObjectId getObjectId}. Transient objects are not known to
* the data manager and are not stored persistently. <p>
*
* Passing a transient object to {@code setBinding}, {@code
* createReference}, or {@code getObjectId} creates a new entry for the
* object in the data manager. Calling {@code removeObject} or {@link
* #markForUpdate markForUpdate} on a transient object does not change the
* state of the object. If a transient object implements {@link
* ManagedObjectRemoval}, though, then calling {@code removeObject} will
* cause its {@link ManagedObjectRemoval#removingObject removingObject}
* method to be called. <p>
*
* <li><a name="persistent"><b>Persistent</b></a> - A managed object that has
* been stored in the data manager by calling {@code setBinding}, {@code
* createReference}, or {@code getObjectId} in the current transaction, or
* else retrieved from the data manager by calling {@link #getBinding
* getBinding}, {@link #getBindingForUpdate getBindingForUpdate}, {@link
* ManagedReference#get ManagedReference.get}, or {@link
* ManagedReference#getForUpdate ManagedReference.getForUpdate}. <p>
*
* Passing a persistent object to {@code setBinding}, {@code
* createReference}, {@code markForUpdate}, or {@code getObjectId} does not
* create a new entry for that object in the data manager, but rather
* reuses the existing one. Calling {@code removeObject} on a persistent
* object removes it from the data manager, meaning it will no longer be
* stored persistently, and changes its state to <i>removed</i>. Note that
* a managed object made persistent in the current transaction is
* automatically marked for update, so there is no need to call {@code
* markForUpdate} for such objects, in particular in their
* constructors. <p>
*
* <li><a name="removed"><b>Removed</b></a> - A managed object that has been
* removed from the data manager by calling {@code removeObject}. Removed
* objects are no longer stored persistently, although the data manager
* makes an effort to track which managed objects have been removed. <p>
*
* Only persistent managed objects can become removed; calling {@code
* removeObject} on a transient managed object leaves it as a transient
* object. Passing a removed managed object to {@code setBinding}, {@code
* removeObject}, {@code markForUpdate}, {@code createReference}, or {@code
* getObjectId}, as well as calling {@code ManagedReference.get} or {@code
* ManagedReference.getForUpdate} on a reference to the removed object,
* will cause a {@link ObjectNotFoundException} to be thrown, if the system
* has tracked the object's removed state. <p>
*
* <li><a name="stale"><b>Stale</b></a> - A managed object that was persistent
* or removed in another, completed transaction. Stale objects are objects
* that have become detached from the data manager, and should not be
* visible to applications that avoid using static fields, but may be
* encountered under some circumstances. The data manager implementation
* may or may not track stale objects. If stale objects are not tracked,
* they will be considered transient. <p>
*
* Passing a stale object to {@code setBinding}, {@code removeObject},
* {@code markForUpdate}, {@code createReference}, or {@code getObjectId},
* as well as calling {@code ManagedReference.get} or {@code
* ManagedReference.getForUpdate} on a reference to the stale object, will
* cause a {@link TransactionNotActiveException} to be thrown, if the
* system has tracked the object's stale state. <p>
*
* </ul> <p>
*
* Because storing a managed object in a name binding or creating a managed
* reference to it causes the object to be stored in data manager, applications
* should insure that they remove such objects if they end up not referring to
* them persistently. The {@code removeObject} method does not throw
* exceptions when called on a transient object, so applications should call
* {@code removeObject} whenever there is an object that may have become
* persistent and they are sure is no longer used. <p>
*
* Some implementations may need to be notified when managed objects and the
* objects they refer to are modified, while other implementations may be
* configurable to detect these modifications automatically. Applications are
* always permitted to mark objects that have been modified, and doing so may
* produce performance improvements regardless of whether modifications are
* detected automatically.
*
* @see AppContext#getDataManager
* @see ManagedObject
* @see ManagedReference
* @see Serializable
*/
public interface DataManager {
/**
* Obtains the object bound to a name. For implementations that need to be
* notified of object modifications, applications should call {@link
* #markForUpdate markForUpdate} or {@link ManagedReference#getForUpdate
* ManagedReference.getForUpdate} before modifying the returned object or
* any of the non-managed objects it refers to.
*
* @param name the name
* @return the object bound to the name
* @throws NameNotBoundException if no object is bound to the name
* @throws ObjectNotFoundException if the object bound to the name is not
* found
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
* @see #markForUpdate markForUpdate
* @see ManagedReference#getForUpdate ManagedReference.getForUpdate
* @see #getBindingForUpdate getBindingForUpdate
*/
ManagedObject getBinding(String name);
/**
* Obtains the object bound to a name, and notifies the system that the
* object is going to be modified.
*
* @param name the name
* @return the object bound to the name
* @throws NameNotBoundException if no object is bound to the name
* @throws ObjectNotFoundException if the object bound to the name is not
* found
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
*/
ManagedObject getBindingForUpdate(String name);
/**
* Binds an object to a name, replacing any previous binding, and storing
* the object in the data manager if it is <a
* href="#transient">transient</a>. The object must implement {@link
* ManagedObject}, and both the object and any objects it refers to must
* implement {@link Serializable}. Note that this method will throw {@link
* IllegalArgumentException} if <code>object</code> does not implement
* <code>Serializable</code>, but is not guaranteed to check that all
* referred to objects implement <code>Serializable</code>. Any instances
* of {@link ManagedObject} that <code>object</code> refers to directly, or
* indirectly through non-managed objects, need to be referred to through
* instances of {@link ManagedReference}.
*
* @param name the name
* @param object the object
* @throws IllegalArgumentException if <code>object</code> does not
* implement both {@link ManagedObject} and {@link Serializable}
* @throws ObjectNotFoundException if the object has been removed
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
*/
void setBinding(String name, Object object);
/**
* Removes the binding for a name. Note that the object previously bound
* to the name, if any, is not removed; only the binding between the name
* and the object is removed. To remove the object, use the {@link
* #removeObject removeObject} method.
*
* @param name the name
* @throws NameNotBoundException if the name is not bound
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
* @see #removeObject removeObject
*/
void removeBinding(String name);
/**
* Returns the next name after the specified name that has a binding, or
* <code>null</code> if there are no more bound names. If
* <code>name</code> is <code>null</code>, then the search starts at the
* beginning. <p>
*
* The order of the names corresponds to the ordering of the UTF-8 encoding
* of the names. To provide flexibility to the implementation, the UTF-8
* encoding used can be either <em>standard UTF-8</em>, as defined by the
* IETF in <a href="http://tools.ietf.org/html/rfc3629">RFC 3629</a>, or
* <em>modified UTF-8</em>, as used by serialization and defined by the
* {@link DataInput} interface.
*
* @param name the name to search after, or <code>null</code> to start at
* the beginning
* @return the next name with a binding following <code>name</code>, or
* <code>null</code> if there are no more bound names
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
*/
String nextBoundName(String name);
/**
* Removes an object from the <code>DataManager</code>, if the object is <a
* href="#persistent">persistent</a>. The system will make an effort to
* flag subsequent references to the removed object through {@link
* #getBinding getBinding} or {@link ManagedReference} by throwing {@link
* ObjectNotFoundException}, although this behavior is not guaranteed. <p>
*
* If {@code object} implements {@link ManagedObjectRemoval}, even if it is
* <a href="#transient">transient</a>, then this method first calls the
* {@link ManagedObjectRemoval#removingObject
* ManagedObjectRemoval.removingObject} method on the object, to notify it
* that it is being removed. If the call to {@code removingObject} throws
* a {@code RuntimeException}, then this method will throw that exception
* without removing the object. A call to {@code removingObject} that
* causes {@code removeObject} to be called recursively on the same object
* will result in an {@code IllegalStateException} being thrown.
*
* @param object the object
* @throws IllegalArgumentException if {@code object} does not implement
* both {@link ManagedObject} and {@link Serializable}
* @throws IllegalStateException if {@code object} implements {@code
* ManagedObjectRemoval} and {@code removeObject} is called
* recursively on the object through a call to {@link
* ManagedObjectRemoval#removingObject
* ManagedObjectRemoval.removingObject}
* @throws ObjectNotFoundException if the object has already been removed
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
* @throws RuntimeException if {@code object} implements {@code
* ManagedObjectRemoval} and calling {@link
* ManagedObjectRemoval#removingObject
* ManagedObjectRemoval.removingObject} on the object throws a
* runtime exception
* @see ManagedObjectRemoval
*/
void removeObject(Object object);
/**
* Notifies the system that an object is going to be modified, doing
* nothing if the object is <a href="#transient">transient</a>.
*
* @param object the object
* @throws IllegalArgumentException if <code>object</code> does not
* implement both {@link ManagedObject} and {@link Serializable}
* @throws ObjectNotFoundException if the object has been removed
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
* @see ManagedReference#getForUpdate ManagedReference.getForUpdate
*/
void markForUpdate(Object object);
/**
* Creates a managed reference to an object, storing the object in the data
* manager if it is <a href="#transient">transient</a>. Applications
* should use managed references when a managed object refers to another
* managed object, either directly or indirectly through non-managed
* objects.
*
* @param <T> the type of the object
* @param object the object
* @return the managed reference
* @throws IllegalArgumentException if <code>object</code> does not
* implement both {@link ManagedObject} and {@link Serializable}
* @throws ObjectNotFoundException if the object has been removed
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
*/
<T> ManagedReference<T> createReference(T object);
/**
* Returns a unique identifier for the object, storing the object in the
* data manager if it is <a href="#transient">transient</a>. The value
* returned by this method is the same as the one that would be obtained by
* calling {@link ManagedReference#getId ManagedReference.getId} on a
* managed reference associated with the object produced by {@link
* #createReference createReference}.
*
* @param object the object
* @return a unique identifier for the object
* @throws IllegalArgumentException if <code>object</code> does not
* implement both {@link ManagedObject} and {@link Serializable}
* @throws ObjectNotFoundException if the object has been removed
* @throws TransactionException if the operation failed because of a
* problem with the current transaction
*/
BigInteger getObjectId(Object object);
}