Methods Summary |
---|
protected synchronized void | abort()When a save to the data store is aborted for any reason, this
method gets called in order to give the object a chance to
clean up. The object should be restored to its state
immediately before a save was attempted. Within the
Persistent class, that simply means changing the flag indicating
a save is in progress. Of course, objects extending this class
may or may not have their own clean up to do.
if( !isSaving() ) { // If this object is not saving, it needs no abort
return;
}
saving = false; // stop it from saving
// keep the lock in place
|
protected synchronized void | commit()When one or more saves have been sent to the data store successfully,
they are committed. This method allows an object to know the
pending save was successful and release any locks.
Transaction t;
// If the object is not being saved, commit not needed
if( !isSaving() ) {
return;
}
if( lock == null ) {
throw new PersistenceException("Attempt to commit an unlocked " +
"object.");
}
// end saving
saving = false;
// release lock
lock.releaseLock(this);
lock = null;
// reset modification state
if( isDeleted() ) {
modifications = Persistent.DELETED;
}
else {
modifications = Persistent.UNMODIFIED;
}
|
public synchronized int | getId()The ID is a unique identifier for this type of object. In real
situations, you probably cannot always use an int for an ID field.
To keep this library simple, however, we have assumed that all ID's
are integers.
return id;
|
public synchronized int | getModifications()Modifications is a bitmask of changes which have occurred to
an object since it was either restored or created. Unmodified
objects have a Modifications value equal to Persistent.UNMODIFIED.
return modifications;
|
public static imaginary.persist.Persistent | getPersistent(Transaction trans, java.util.Hashtable data, java.lang.String class_name)Gives a hashtable of values taken from a data store, this class
method will find an existing object for that data or instantiate
a new one. Once it has created that object, it will tell the
object to restore itself using that data.
Persistent p;
Hashtable h;
Integer i;
// create an instance of the specified class name
// so that we know what the ID is
try {
p = (Persistent)Class.forName(class_name).newInstance();
p.setId(data);
}
catch( ClassNotFoundException e ) {
e.printStackTrace();
return null;
}
catch( InstantiationException e ) {
e.printStackTrace();
return null;
}
catch( IllegalAccessException e ) {
e.printStackTrace();
return null;
}
// find the hashtable for this class in the objects hashtable
if( objects.containsKey(class_name) ) {
h = (Hashtable)objects.get(class_name);
}
else {
h = new Hashtable();
objects.put(class_name, h);
}
// see if this object is already in that list
i = new Integer(p.getId());
if( h.containsKey(i) ) {
return (Persistent)h.get(i);
}
else {
h.put(i, p);
// restore the new object
p.restore(trans, data);
return p;
}
|
public static imaginary.persist.Persistent | getPersistent(Transaction trans, int id, java.lang.String class_name)Find or restore an object of the specified class based on an ID.
Integer i = new Integer(id);
Hashtable h;
// get the hashtable of objects for that class
if( objects.containsKey(class_name) ) {
h = (Hashtable)objects.get(class_name);
}
else {
h = new Hashtable();
objects.put(class_name, h);
}
// check if the object already exists
if( h.containsKey(i) ) {
return (Persistent)h.get(i);
}
else {
Persistent p;
try {
// no instance found, load a new one
p = (Persistent)Class.forName(class_name).newInstance();
// set its ID
p.setId(id);
h.put(i, p);
// restore it from the data store
p.restore();
}
catch( ClassNotFoundException e ) {
e.printStackTrace();
return null;
}
catch( InstantiationException e ) {
e.printStackTrace();
return null;
}
catch( IllegalAccessException e ) {
e.printStackTrace();
return null;
}
return p;
}
|
protected abstract PersistentPeer | getPersistentPeer()Persistent prescribes that a subclass implement this method to
provide it with an instance of the peer which will perform
all data store access for it.
|
public synchronized boolean | isDeleted()Checks to see if the object will be deleted from the data store
at the next save.
return ((modifications & Persistent.DELETED) != 0);
|
public synchronized boolean | isLocked()Checks to see if a lock is being held on this object.
return (lock != null);
|
public synchronized boolean | isModified()Checks to see if this object differs from the data store.
// if any modifiers are present, it has been modified
return !(modifications == Persistent.UNMODIFIED);
|
public synchronized boolean | isNew()Checks to see if this object is new and not yet in the data store.
This will also return false if the object has been deleted.
if( isDeleted() ) {
return false;
}
else {
return ((modifications & Persistent.NEW) != 0);
}
|
public synchronized boolean | isSaving()Checks to see if a save operation is in progress.
return saving;
|
protected synchronized void | loseLock()For any number of reasons, a client holding a lock might
unexpectedly lose that lock. The most common reason is simply
a network failure between client and server. In that event,
we want to release the lock and restore the object to its
unmodified state.
lock = null;
modifications = Persistent.UNMODIFIED;
|
protected synchronized void | modify(RemoteLockHolder h)Whenever an attribute in this object changes from its initial state,
this method should be called in order to change the object's state.
If an attempt is made to modify a locked by object a RemoteLockHolder
that does not hold the lock, then a LockException gets thrown.
// Someone is doing something they should not!
if( lock != null ) {
if( h.hashCode() != lock.getHolder().hashCode() ) {
throw new LockException("Illegal attempt to modify " +
"object without a lock.");
}
}
// First modification!
if( lock == null ) {
lock = Lock.createLock(h, this);
}
// Add Persistent.MODIFIED to the bitmask
modifications |= Persistent.MODIFIED;
setChanged();
|
protected synchronized void | monitorLock()The lock has a thread that simply triggers this method
every now and then. If the criteria for maintaining a lock are
still in force, then everything is ok. Otherwise, a LockException
is thrown. The only criteria for this lock is that the
client holding the lock is still accessible. You could add
timeouts or whatever you like.
// If we cared, we might add a last touched check in here
// to have the lock timeout
// If so, we would throw a LockException
notifyObservers();
|
public synchronized void | remove(RemoteLockHolder h)This method flags the object for deletion.
// Check for a lock
if( lock != null ) {
if( h.hashCode() != lock.getHolder().hashCode() ) {
throw new LockException("Illegal attempt to delete object " +
"without a lock.");
}
}
// Create the lock if it does not exist
if( lock == null ) {
lock = Lock.createLock(h, this);
}
// Mark the object deleted
modifications |= Persistent.DELETED;
setChanged();
|
protected synchronized void | restore()This version of restore() is called for a one-off restore. In
other words, you know the object ID and you want to restore just
this object.
Transaction t = Transaction.getTransaction();
t.restore(this);
|
protected final synchronized void | restore(java.util.Hashtable data)Given a set of query data, restore this object.
Transaction t = Transaction.getTransaction();
t.restore(this, data);
|
public void | restore(Transaction t)Restore this object using only its ID for the query.
getPersistentPeer().restore(this, t);
|
public abstract void | restore(Transaction t, java.util.Hashtable data)This object's peer will go to the data store and grab all of the
attributes for this object. Once it has those values, it will shove
them into a Hashtable and pass them to this method. Objects extending
the Persistent class should therefore implement this method so
that it takes the values out of the Hashtable and assigns them to the
appropriate object attributes.
|
protected synchronized void | save()This method flags the object as saving and then tells its
peer to perform the actual save.
PersistentPeer peer;
if( lock == null ) {
throw new PersistenceException("Attempt to save an unlocked: " +
"object.");
}
peer = getPersistentPeer();
// flag the object as saving
saving = true;
// determine what sort of operation is required and tell the
// peer to do it
if( isDeleted() ) {
peer.remove(this, lock.getTransaction());
}
else if( isNew() ) {
peer.insert(this, lock.getTransaction());
}
else {
peer.update(this, lock.getTransaction());
}
|
public abstract void | setId(java.util.Hashtable h)Classes extending Persistent must know how to pull an ID field
from a Hashtable describing restoration values. Any such class
should implement this method by grabbing the ID field and
calling setId(int). Example:
public void setId(Hashtable h) {
setId(((Integer)h.get("t_customer.cust_id")).intValue());
}
|
public synchronized void | setId(int i)Sets the id field for the object. Once an id is set, it cannot
be changed.
if( id != -1 ) {
return;
}
id = i;
|
public synchronized void | setNew()Sets the modifications bitmask to NEW
modifications = Persistent.NEW;
|