ccs.cdb
Class CDBObject

java.lang.Object
  extended by ccs.beetree.BeeObject
      extended by ccs.cdb.CDBObject
All Implemented Interfaces:
java.io.Serializable
Direct Known Subclasses:
BrowserExecutable, CDBFileSysObject, MKCDBObject

public abstract class CDBObject
extends BeeObject
implements java.io.Serializable

CDBObject is the abstract base class of all objects which can be persisted in a Checkpoint persistent object store, or "CDB". See the package description for an explanation of the "CDB" prefix.

A CDB is managed by a CDBeeTree object (q.v.), which maintains the set-management information, and provides methods analogous to those provided by BeeTree.

To implement setting, key management and some of the marshalling methods of BeeObject have been hijacked - well, finalised anyway. This allows set-management information to be added to the keys which subclassers know about, without them needing to worry about it. Other methods have been provided which bear the same names as the finalised ones, but with a "cp" prefix. These are used in the same way as their finalised counterparts.

If a CDBeeTree method finds itself about to unmarshal an object of one class into a supplied object of another class, it will instead create a new object of the correct class and unmarshal into that instead. This is essential since the set may be heterogenous, and there is no way for the calling program to know in advance of what class a retreived object will be. The new object appears in the clone member of the object which was supplied to the CDBeeTree method involved.

Note. All fields must be initialised non-null; the dynamic-access mechanism can't cope with null fields.

Note. All CDBObject subclasses must define a sensible default constructor. This will be called to create a clone when necessary (see above).

A CDBObject may be "bodiless" - ie. all its state is contained in its key. An object defines itself to be bodiless by setting the isBodiless flag. This saves a useful amount of overhead compared to just having empty marshal / unmarshal methods. Bodiless objects do not have meaningful marshal versions, and must belong to a set which only has one sub-class (this will be the set class).

Multithread-Safety. CDBeeTree operations are MT-safe. However, other operations involving CDBObject and its subclasses are MT-unsafe, especially direct access to data members. MT apps should take their own precautions, such as use of synchronized accessor methods.

See Also:
CDBeeTree, BeeObject, Serialized Form

Field Summary
 CDBObject clone
          For dynamic type resolution.
 java.lang.String key
          The key of the object.
protected  int marshalVersion
          The marshal version.
protected  CDBeeTree owner
          The CDB to which this belongs.
 
Fields inherited from class ccs.beetree.BeeObject
cipher, encodedLength, isBodiless, isForceDirectDecrypt, isZip, slack
 
Constructor Summary
CDBObject()
          construct a new CDBObject.
 
Method Summary
 boolean canChangeKeyProgrammatically()
          Some objects have immutable keys; the key must not be changed even programmatically.
 boolean canDeleteProgrammatically()
          Some objects are immortal, and must not be deleted even programmatically.
 boolean canUpdateProgrammatically()
          Some objects are immutable, and must not be modified even programmatically.
protected  java.lang.String cpgetKey()
          Returns the object's key.
protected  long cpgetMarshalledLength()
          return the marshalled data length if known, just like getMarshalledLength
protected abstract  void cpmarshal(java.io.DataOutputStream dest)
          override this to marshal your data, just like marshal.
protected  void cppreMarshal()
          Override this to check your object for validity just before marshalling it, just like preMarshal.
protected  void cppreUnmarshal()
          override this to check that your object is fit to have information unmarshalled into it, just like preUnmarshal.
protected  void cpsetKey(java.lang.String key)
          Sets the object's key.
protected abstract  void cpunmarshal(java.io.DataInputStream src, int marshalver)
          override this to unmarshal your data, just like unmarshal.
 CDBeeTree getCDB()
          returns the CDBeeTree to which the object currently belongs.
 java.lang.String getKey()
          Finalised for set management.
 long getMarshalledLength()
          Finalised for set management.
 void marshal(java.io.DataOutputStream dest)
          Finalised for set management - do not invoke.
 void preMarshal()
          Finalised for set management - do not invoke.
 void preUnmarshal()
          Finalised for set management - do not invoke.
 void setCDB(CDBeeTree owner)
          Sets which CDB currently owns this object.
 void setKey(java.lang.String key)
          Finalised for set management.
 void transientMarshal(java.io.DataOutputStream dest)
          Sometimes a CDBObject will be used as a transient data container rather than as a persistent one stored in a CDBeeTree.
 void transientUnmarshal(java.io.DataInputStream src)
          The counterpart on the other end of the link to transientMarshal.
 void unmarshal(java.io.DataInputStream src)
          Finalised for set management - do not invoke.
 
Methods inherited from class ccs.beetree.BeeObject
lock, unlock
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

owner

protected CDBeeTree owner
The CDB to which this belongs. This may change with time - for example, when transferring an object from one CDB to another.


clone

public CDBObject clone
For dynamic type resolution. See introductory essay.


key

public java.lang.String key
The key of the object. Often this attribute is "denormalised", i.e. the key is generated from other fields. If you don't want to use this field, override the default key handling in cpgetKey and cpsetKey; this default handling is provided as a potential convenience and nothing more.


marshalVersion

protected int marshalVersion
The marshal version. Objects have a habit of mutating over time, and you have to give your users an upgrade path or they tend to lynch you. The way to do this is:
  1. Have your ctor set the marshal version of the object. E.g. 0 = first public beta, 1 = full release, 2 = patch 1, 10 = version 2... No need to marshal this in your cpmarshal method, CDBObject will do it for you.
  2. Have your cpmarshal always marshal the current (most modern) version of the object, ignoring the marshal version.
  3. Have your cpunmarshal check the object's marshal version. If it's an older than the current version, read whatever was there before and make up some sensible defaults for the missing fields. How many versions back you want to be compatible with is a design decision. One would be reasonable, more might make your users happier at the cost of some code bloat.
The upshot of this is that the entire CDB becomes upgraded to the current version if all the objects are read, and then updated without any changes.

Constructor Detail

CDBObject

public CDBObject()
construct a new CDBObject. All subclasses are encouraged to provide a sane default constructor; where the CDBObject is part of a set which contains several different classes, this is required. This CDBObject does not belong to any CDBeeTree.

Method Detail

setCDB

public void setCDB(CDBeeTree owner)
Sets which CDB currently owns this object. This will be called automatically during any CDBeeTree operation, so apps will not normally need to bother with it.

Parameters:
owner - The CDBeeTree that gains ownership of the object.

getCDB

public CDBeeTree getCDB()
returns the CDBeeTree to which the object currently belongs.

Returns:
The current owner.

preMarshal

public final void preMarshal()
                      throws java.io.IOException
Finalised for set management - do not invoke. Use cppreMarshal instead, in exactly the same way.

Overrides:
preMarshal in class BeeObject
Throws:
java.io.IOException - if the object isn't ready.

preUnmarshal

public final void preUnmarshal()
                        throws java.io.IOException
Finalised for set management - do not invoke. Use cppreUnmarshal instead, in exactly the same way.

Overrides:
preUnmarshal in class BeeObject
Throws:
java.io.IOException - if the object isn't ready.

marshal

public final void marshal(java.io.DataOutputStream dest)
                   throws java.io.IOException
Finalised for set management - do not invoke. Use cpmarshal instead, in exactly the same way.

Specified by:
marshal in class BeeObject
Parameters:
dest - the Stream to write onto.
Throws:
java.io.IOException - if the write fails.
See Also:
BeeObject.marshal(java.io.DataOutputStream)

unmarshal

public final void unmarshal(java.io.DataInputStream src)
                     throws java.io.IOException
Finalised for set management - do not invoke. Use cpunmarshal instead, in exactly the same way.

Specified by:
unmarshal in class BeeObject
Parameters:
src - the Stream to read from.
Throws:
java.io.IOException - if the read fails.
See Also:
BeeObject.unmarshal(java.io.DataInputStream)

getMarshalledLength

public final long getMarshalledLength()
Finalised for set management. Use cpgetMarshalledLength instead, in exactly the same way.

Overrides:
getMarshalledLength in class BeeObject
Returns:
The marshalled length of this object.
See Also:
BeeObject.getMarshalledLength()

getKey

public final java.lang.String getKey()
Finalised for set management. Use cpgetKey in exactly the same way.

Overrides:
getKey in class BeeObject
Returns:
The key.
See Also:
BeeObject.getKey()

setKey

public final void setKey(java.lang.String key)
Finalised for set management. Use cpsetKey in exactly the same way.

Overrides:
setKey in class BeeObject
Parameters:
key - The new key.

cppreMarshal

protected void cppreMarshal()
                     throws java.io.IOException
Override this to check your object for validity just before marshalling it, just like preMarshal. The default implementation does nothing.

Throws:
java.io.IOException - if the object is not fit to be marshalled.

cppreUnmarshal

protected void cppreUnmarshal()
                       throws java.io.IOException
override this to check that your object is fit to have information unmarshalled into it, just like preUnmarshal. The default implementation does nothing.

Note: This method is not called on objects created through the "cloning" method employed when the supplied object is not of the correct class - see introductory essay. This is a misfeature. The reason that it persists is that if the method _were_ called and then threw, the CDB would be marked as corrupt, which would be highly undesirable. The method is therefore only really useful for set classes which have no sub-classes other than the set class itself (i.e. give a homogeneous set, where cloning is never needed).

Throws:
java.io.IOException - If the object is not fit to be unmarshalled into.

cpmarshal

protected abstract void cpmarshal(java.io.DataOutputStream dest)
                           throws java.io.IOException
override this to marshal your data, just like marshal. The data will be in the object's fields when this is called (rather than within any UI objects).

Parameters:
dest - The stream to marshal onto.
Throws:
java.io.IOException - If this breaks (breaks the CDB too).

cpgetMarshalledLength

protected long cpgetMarshalledLength()
return the marshalled data length if known, just like getMarshalledLength

Returns:
the marshalled length if known, -1 if not.

cpunmarshal

protected abstract void cpunmarshal(java.io.DataInputStream src,
                                    int marshalver)
                             throws java.io.IOException
override this to unmarshal your data, just like unmarshal.

Parameters:
src - The stream to unmarshal from
marshalver - The marshal version of the data in src - i.e. the version of this class which wrote the data. This may be different from the current marshalVersion. If so (i.e. the stored data is the wrong version) your method should allow for it. This allows comparatively painless data migration between versions of your objects.
Throws:
java.io.IOException - if this breaks (breaks the CDB too).

cpgetKey

protected java.lang.String cpgetKey()
Returns the object's key. By default, this is the contents of the key member. Override if you need different handling.

Returns:
The key.

cpsetKey

protected void cpsetKey(java.lang.String key)
Sets the object's key. If the key is denormal - generated from several fields - don't try to analyse it and hence obtain the contributory fields here. This is because this method is called several times during each find / next / prev operation and hence should be kept tight. Instead, store it somewhere (or let the default handling store it in the key member on your behalf) and do the analysis within cpunmarshal instead.

Parameters:
key - The key.

transientMarshal

public void transientMarshal(java.io.DataOutputStream dest)
                      throws java.io.IOException

Sometimes a CDBObject will be used as a transient data container rather than as a persistent one stored in a CDBeeTree. For this kind of use, the CDBObject has no owner (and so cannot be fully marshalled in the usual way).

Use this method to marshal a transient CDBObject onto a stream you supply. It will invoke cpmarshal in turn. Note: Ensure that both ends of the stream expect the same kind of object. The cloning mechanism is not implemented for transient objects.

Key fields will be transferred correctly, as well as body fields.

Parameters:
dest - The stream to marshal onto.
Throws:
java.io.IOException

transientUnmarshal

public void transientUnmarshal(java.io.DataInputStream src)
                        throws java.io.IOException
The counterpart on the other end of the link to transientMarshal. It invokes cppreUnmarshal with the current marshal version.

Parameters:
src - The stream to unmarshal from.
Throws:
java.io.IOException

canUpdateProgrammatically

public boolean canUpdateProgrammatically()
Some objects are immutable, and must not be modified even programmatically. To enforce this restriction, override this method to return false.


canDeleteProgrammatically

public boolean canDeleteProgrammatically()
Some objects are immortal, and must not be deleted even programmatically. To enforce this restriction, override this method to return false.


canChangeKeyProgrammatically

public boolean canChangeKeyProgrammatically()
Some objects have immutable keys; the key must not be changed even programmatically. To enforce such a restriction, override this method to return false.