/**
* calculate a hash for the Vobject with all housekeeping fields at standard
* values. (isRegisterable is an immutable attribute property)
- * TODO: decide if __stored_in_document should be included in the hash or not.
- * @return true if new hash different to last hash
+ * TODO: LATER: make this hash function compute a hash that truly reflects changes in Vobject attributes for benefit of update mechanism
+ * @return true if new hash different to last hash (or first time its been computed)
*/
synchronized protected boolean doHash() {
long __old_hash = __last_hash;
java.lang.reflect.Field idfield = ___id_field;
___id_field=null;
__updated_since_last_read=false;
+ __stored_in_document=false;
+ boolean added_since=__added_since_last_read;
+ __added_since_last_read=false;
+ long l_hash = __l_hash;
+ __l_hash = 0;
vorbaId = null;
__vorba = null;
__visited=false;
__updated_since_last_read=updated;
V_parent=_V_parent;
__visited=visited;
- return (__old_hash==0) || (__old_hash == __last_hash);
+ __added_since_last_read=added_since;
+ __l_hash = l_hash;
+ // return true if first time hash was computed or if hash has changed
+ return (__old_hash==0) || (__old_hash != __last_hash);
}
/**
*/
protected void set__updated_since_last_read(boolean __updated_since_last_read) {
this.__updated_since_last_read = __updated_since_last_read;
+ if(__updated_since_last_read && log.isDebugEnabled())
+ log.debug("Registered update for "+this.getVorbaId());
}
/**
if (__visited==visited)
return;
__visited=visited;
- __vorba.updateHashValue(this);
+ //__vorba.updateHashValue(this);
Class descriptor = null;
XMLClassDescriptorImpl descimpl = null;
protected void setV_parent(Vobject V_parent) {
this.V_parent = V_parent;
}
+ /**
+ * LhashValue - used for change detection between document updates.
+ */
+ private long __l_hash=0;
+ /**
+ * set the base LhashValue for this object
+ * @param checksum
+ */
+ protected void __setInitHash(long checksum) {
+ __l_hash = checksum;
+ }
+ /**
+ * compute the final LhashValue as a difference between checksum and the current base
+ * @param checksum
+ */
+ protected void __setFinalHash(long checksum) {
+ __l_hash = checksum - __l_hash;
+ }
+ /**
+ * get the LhashValue for this object
+ * @return the difference in values passed to __setFinalHash less __setInitHash
+ */
+ protected long __getLHash() {
+ return __l_hash;
+ }
}
\r
/**\r
* Holds information about Vobj instances that is held over between different writes to the document.\r
+ * Currently records the LhashValue obtained from Vobject\r
* @author JimP\r
*\r
*/\r
public class Vobjhash {\r
- int hashvalue;\r
+ long hashvalue;\r
/**\r
* creates a record of the hash value for a vamsas document object\r
* @param tobemarshalled\r
*/\r
public Vobjhash(Vobject tobemarshalled) {\r
- hashvalue = tobemarshalled.get__last_hash();\r
+ hashvalue = tobemarshalled.__getLHash();\r
}\r
/**\r
- * compares the old hash value with the unmarshalled object's most recently computed hash value.\r
+ * compares the old hash value with the unmarshalled object's most recently computed hash value and updates internal record.\r
* @param unmarshalled\r
* @return true if the hash values differ\r
*/\r
public boolean isUpdated(Vobject unmarshalled) {\r
- return hashvalue==unmarshalled.get__last_hash();\r
+ long oldhash = hashvalue;\r
+ hashvalue=unmarshalled.__getLHash();\r
+ return oldhash!=hashvalue;\r
}\r
}\r
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.ValidationException;
+import uk.ac.vamsas.client.utils.ChecksummedReader;
import uk.ac.vamsas.objects.core.VamsasDocument;
/**
* Implements the Vamsas Vobject ID machinery for translating
private final Vector obj;
private final Hashtable oldobjhashes;
private final Hashtable objrefs;
- private final Vector updatedobjs;
-
+ private final Vector updatedobjs; // not yet used elswhere ?
+ private final ChecksummedReader inStream;
public VorbaXmlBinder(IVorbaIdFactory vorbafactory, Vector obj, Hashtable objrefs, Hashtable oldobjhashes, Vector updatedobjs) {
- this.vorbafactory = vorbafactory;
- this.obj = obj;
- this.objrefs = objrefs;
+ this(vorbafactory, obj, objrefs, oldobjhashes, updatedobjs, null);
+
+ }
+
+ public VorbaXmlBinder(IVorbaIdFactory vorbafactory2, Vector unrefedObj, Hashtable objrefs2, Hashtable oldobjhashes, Vector updatedObj, ChecksummedReader ckedInstream) {
+ this.inStream = ckedInstream;
+ this.vorbafactory = vorbafactory2;
+ this.obj = unrefedObj;
+ this.objrefs = objrefs2;
this.oldobjhashes = oldobjhashes;
- this.updatedobjs = updatedobjs;
+ this.updatedobjs = updatedObj;
}
/*
* @see org.exolab.castor.xml.UnmarshalListener#attributesProcessed(java.lang.Object)
*/
public void attributesProcessed(Object object) {
+
}
/*
* @see org.exolab.castor.xml.UnmarshalListener#initialized(java.lang.Object)
*/
public void initialized(Object object) {
+ if (object instanceof Vobject) {
+ Vobject nobj = (Vobject) object;
+ if (nobj.isRegisterable() && nobj.___id_field!=null && inStream!=null)
+ nobj.__setInitHash(inStream.getChecksum()); // record start tag position
+ }
}
/*
nobj.set__stored_in_document(true);
try {
if (nobj.isRegisterable() && nobj.___id_field!=null) {
+ if (inStream!=null)
+ nobj.__setFinalHash(inStream.getChecksum()); // compute LHash as difference between end and start tag positions
VorbaId nobj_id=null;
// look for the id field (should be an NCName string)
nobj.__vorba = vorbafactory;
// TODO: add to list of objects without a valid vorbaId
obj.add(nobj);
}
- nobj.doHash();
+ nobj.doHash(); // TODO: DECIDE IF WE NEED TO DO THIS STILL: THIS DOESNT WORK! updates detected by comparing with last hash when marshalling
+
// check to see if new object was present in old object hash
if (nobj_id!=null) {
if (oldobjhashes.containsKey(nobj_id)) {
// object has no entry in the oldhashvalue list but
// there is a valid vorbaId so
nobj.set__added_since_last_read(true);
-
}
// and record the just-unmarshalled hash value
oldobjhashes.put(nobj_id, new Vobjhash(nobj));
final VorbaIdFactory vorbafactory = factory;
final Vector unrefedObj = new Vector();
final Vector updatedObj = new Vector();
- unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory, unrefedObj, objrefs, oobjhashes, updatedObj));
+ ChecksummedReader ckedInstream = new ChecksummedReader(instream);
+ unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory, unrefedObj, objrefs, oobjhashes,updatedObj, ckedInstream));
// Call the unmarshaller.
try {
while (instream.ready()) {
// TODO: mark objects in oobjhash prior to unmarshalling, to detect when objects have been lost through an update.
//tohere
- Object obj = unmarshaller.unmarshal(instream);
+ Object obj = unmarshaller.unmarshal(ckedInstream);
boolean sync=ensure_references(unrefedObj, objrefs);
if (!(obj instanceof Vobject))
return null;
--- /dev/null
+/**\r
+ * \r
+ */\r
+package uk.ac.vamsas.client.utils;\r
+\r
+import java.io.IOException;\r
+import java.io.Reader;\r
+\r
+/**\r
+ * @author JimP\r
+ * Simple wrapper for reader to keep track of position in stream.\r
+ * This is used in the document unmarshalling mechanism to compute\r
+ * a simple hash based on the distance between the read blocks containing\r
+ * the start and end tags of the XML.\r
+ */\r
+public class ChecksummedReader extends Reader {\r
+ private Reader myReader=null;\r
+ private long count=0;\r
+ public ChecksummedReader(Reader myReader) {\r
+ super();\r
+ this.myReader = myReader;\r
+ count=0;\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see java.io.Reader#close()\r
+ */\r
+ public void close() throws IOException {\r
+ if (myReader!=null)\r
+ myReader.close();\r
+ else\r
+ throw new IOException("Close called on un-inited ChecksummedReader");\r
+ }\r
+\r
+ /* (non-Javadoc)\r
+ * @see java.io.Reader#read(char[], int, int)\r
+ */\r
+ public int read(char[] cbuf, int off, int len) throws IOException {\r
+ int rlen = myReader.read(cbuf, off, len);\r
+ if (rlen>0)\r
+ count+=cbuf.hashCode();\r
+ return rlen;\r
+ }\r
+ /**\r
+ * Return current checksum of read bytes.\r
+ * @return stream checksum\r
+ */\r
+ public long getChecksum() {\r
+ return count;\r
+ }\r
+ /**\r
+ * Return existing checksum value and reset\r
+ * @return old count\r
+ */\r
+ public long getAndResetChecksum() {\r
+ long cnt=count;\r
+ count=0;\r
+ return cnt;\r
+ }\r
+}\r