Home
Overview
Architecture
Language
Weave
Implementation
Licence

Persist Architecture

The object of Persist is to automate the storage of a class hierarchy. It is intended to be transparent and inobtrusive to the application developers. To achieve this, we take the code of the nonpersistent class, transform it, add necessary components, and compile the transformed code.

We have to differenciate between the persistent domain and the 'outside world'. Any changes we made need to be consistent in the domain, and transparent to the outside world. For this reason, the domain's interfaces must not be changed.

We face a few problems in implementing persistency. First, object references are inherently not persistent. Also, we have to keep track of an object's reference count, so we can remove it from the project when necessary. JVM's garbage collection is of no use here, as it runs at unspecified intervals, or may not be running at all. We also have to support separate persistent object hierarchies, such as a multiple-document word processor.

To solve these problems, we change every reference to our own persistent object ID's. An object manager is used to resolve OID's to references, and OID's are always resolved before they are passed to the outside world. Ideally, we could detect references passed to us from the outside world, however, the Java language makes this next to impossible. Imagine an array of Objects being passed to us, some of the Objects being persistent and some not. (*shiver*)

The heart of Persist if the object manager, PersistOM, which is a reusable component for keeping track of objects, references between objects, and stores and retrieves objects as necessary. All persistent object references are replaced by object ID's (PersistOID), which are handled by PersistOM. Dereferencing is replaced by a call to OID.getObject().

For every persistent object we implement the PersistObject interface, which is used by PersistOM.

PersistOID

PersistOID's are used to replace object references. The reason for this design is that object references are always session-specific, and cannot be saved and retrieved directly. Also, we need to keep track of references to know which objects need to be updated or deleted from the database. PersistOIDs store the reference to the Object Manager that they are managed by. All classes that are part of the same Persist hierarchy must be managed by the same PersistOM. It is possible for several PersistOMs to exist, even if they manage the same Classes.

Example: A word processor might create a separate PersistOM object for each loaded document, or it might use the same PersistOM.

public class PersistOID
{
    PersistOID()
    PersistOID( int, int, PersistOM )
    PersistOID( PersistOID value )
    
    PersistObject getObject()
    PersistOM getOM()
    void assign( PersistOID oid )
    
    String toString()
    boolean equals( Object obj )
    boolean isNull()
    int hashCode()
}

PersistObject

During the program transformation all persistent objects are made to implement this interface. It provides the OM the necessary methods to load the object from the database, or store it, when necessary. All methods defined are preficed with _persist_, in an attempt to avoid namespace collision.

PersistObjects should already implement Serializable. If they don't, Persist creates a default implementation, storing and retrieving every persistant attribute, while leaving the others. This may not be desirable, as other attributes may be derived from these.

public interface PersistObject: extends Serializable
{
    PersistOID _persist_getOID()
}

PersistOM

PersistOM is the heart of Persist. It handles the transition from object references to PersistOID's.

public class PersistOM
{
    static PersistOM createOM()
    PersistOID registerObject( PersistObject object )
    PersistObject getObject( persistOID oid )
    void changeReference( persistOID referer,
       persistOID oldReference, persistOID newReference )
    void deleteObject( persistOID object )

    void load(...)
    void save(...)
    void clear(...)
}