From: jprocter Date: Tue, 20 Mar 2007 14:27:01 +0000 (+0000) Subject: update detection mechanism based comparing the difference between the position of... X-Git-Tag: Release_0.2~148 X-Git-Url: http://source.jalview.org/gitweb/?p=vamsas.git;a=commitdiff_plain;h=4b707f884b9300b927dba2fbfccfe2694eef7894 update detection mechanism based comparing the difference between the position of start and end tags of a Vobject between successive document unmarshallings. git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@372 be28352e-c001-0410-b1a7-c7978e42abec --- diff --git a/src/uk/ac/vamsas/client/Vobject.java b/src/uk/ac/vamsas/client/Vobject.java index 5029a31..8e9fc51 100644 --- a/src/uk/ac/vamsas/client/Vobject.java +++ b/src/uk/ac/vamsas/client/Vobject.java @@ -183,8 +183,8 @@ public abstract class Vobject { /** * 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; @@ -199,6 +199,11 @@ public abstract class Vobject { 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; @@ -212,7 +217,10 @@ public abstract class Vobject { __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); } /** @@ -295,6 +303,8 @@ public abstract class Vobject { */ 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()); } /** @@ -368,7 +378,7 @@ public abstract class Vobject { if (__visited==visited) return; __visited=visited; - __vorba.updateHashValue(this); + //__vorba.updateHashValue(this); Class descriptor = null; XMLClassDescriptorImpl descimpl = null; @@ -479,4 +489,29 @@ public abstract class Vobject { 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; + } } diff --git a/src/uk/ac/vamsas/client/Vobjhash.java b/src/uk/ac/vamsas/client/Vobjhash.java index f2feab9..767a9a6 100644 --- a/src/uk/ac/vamsas/client/Vobjhash.java +++ b/src/uk/ac/vamsas/client/Vobjhash.java @@ -2,24 +2,27 @@ package uk.ac.vamsas.client; /** * Holds information about Vobj instances that is held over between different writes to the document. + * Currently records the LhashValue obtained from Vobject * @author JimP * */ public class Vobjhash { - int hashvalue; + long hashvalue; /** * creates a record of the hash value for a vamsas document object * @param tobemarshalled */ public Vobjhash(Vobject tobemarshalled) { - hashvalue = tobemarshalled.get__last_hash(); + hashvalue = tobemarshalled.__getLHash(); } /** - * compares the old hash value with the unmarshalled object's most recently computed hash value. + * compares the old hash value with the unmarshalled object's most recently computed hash value and updates internal record. * @param unmarshalled * @return true if the hash values differ */ public boolean isUpdated(Vobject unmarshalled) { - return hashvalue==unmarshalled.get__last_hash(); + long oldhash = hashvalue; + hashvalue=unmarshalled.__getLHash(); + return oldhash!=hashvalue; } } diff --git a/src/uk/ac/vamsas/client/VorbaXmlBinder.java b/src/uk/ac/vamsas/client/VorbaXmlBinder.java index 9a94047..12543f2 100644 --- a/src/uk/ac/vamsas/client/VorbaXmlBinder.java +++ b/src/uk/ac/vamsas/client/VorbaXmlBinder.java @@ -25,6 +25,7 @@ import org.exolab.castor.xml.UnmarshalListener; 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 @@ -41,14 +42,20 @@ public class VorbaXmlBinder implements UnmarshalListener { 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; } /* @@ -57,6 +64,7 @@ public class VorbaXmlBinder implements UnmarshalListener { * @see org.exolab.castor.xml.UnmarshalListener#attributesProcessed(java.lang.Object) */ public void attributesProcessed(Object object) { + } /* @@ -80,6 +88,11 @@ public class VorbaXmlBinder implements UnmarshalListener { * @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 + } } /* @@ -94,6 +107,8 @@ public class VorbaXmlBinder implements UnmarshalListener { 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; @@ -116,7 +131,8 @@ public class VorbaXmlBinder implements UnmarshalListener { // 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)) { @@ -131,7 +147,6 @@ public class VorbaXmlBinder implements UnmarshalListener { // 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)); @@ -227,13 +242,14 @@ public class VorbaXmlBinder implements UnmarshalListener { 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; diff --git a/src/uk/ac/vamsas/client/utils/ChecksummedReader.java b/src/uk/ac/vamsas/client/utils/ChecksummedReader.java new file mode 100644 index 0000000..9861e1d --- /dev/null +++ b/src/uk/ac/vamsas/client/utils/ChecksummedReader.java @@ -0,0 +1,60 @@ +/** + * + */ +package uk.ac.vamsas.client.utils; + +import java.io.IOException; +import java.io.Reader; + +/** + * @author JimP + * Simple wrapper for reader to keep track of position in stream. + * This is used in the document unmarshalling mechanism to compute + * a simple hash based on the distance between the read blocks containing + * the start and end tags of the XML. + */ +public class ChecksummedReader extends Reader { + private Reader myReader=null; + private long count=0; + public ChecksummedReader(Reader myReader) { + super(); + this.myReader = myReader; + count=0; + } + + /* (non-Javadoc) + * @see java.io.Reader#close() + */ + public void close() throws IOException { + if (myReader!=null) + myReader.close(); + else + throw new IOException("Close called on un-inited ChecksummedReader"); + } + + /* (non-Javadoc) + * @see java.io.Reader#read(char[], int, int) + */ + public int read(char[] cbuf, int off, int len) throws IOException { + int rlen = myReader.read(cbuf, off, len); + if (rlen>0) + count+=cbuf.hashCode(); + return rlen; + } + /** + * Return current checksum of read bytes. + * @return stream checksum + */ + public long getChecksum() { + return count; + } + /** + * Return existing checksum value and reset + * @return old count + */ + public long getAndResetChecksum() { + long cnt=count; + count=0; + return cnt; + } +}