update detection mechanism based comparing the difference between the position of...
authorjprocter <jprocter@compbio.dundee.ac.uk>
Tue, 20 Mar 2007 14:27:01 +0000 (14:27 +0000)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Tue, 20 Mar 2007 14:27:01 +0000 (14:27 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@372 be28352e-c001-0410-b1a7-c7978e42abec

src/uk/ac/vamsas/client/Vobject.java
src/uk/ac/vamsas/client/Vobjhash.java
src/uk/ac/vamsas/client/VorbaXmlBinder.java
src/uk/ac/vamsas/client/utils/ChecksummedReader.java [new file with mode: 0644]

index 5029a31..8e9fc51 100644 (file)
@@ -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;
+  }
 }
index f2feab9..767a9a6 100644 (file)
@@ -2,24 +2,27 @@ package uk.ac.vamsas.client;
 \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
index 9a94047..12543f2 100644 (file)
@@ -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 (file)
index 0000000..9861e1d
--- /dev/null
@@ -0,0 +1,60 @@
+/**\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