introduced hashCode based object change detection that works (see vamsas.test.example...
authorjprocter <jprocter@compbio.dundee.ac.uk>
Tue, 24 Apr 2007 16:13:49 +0000 (16:13 +0000)
committerjprocter <jprocter@compbio.dundee.ac.uk>
Tue, 24 Apr 2007 16:13:49 +0000 (16:13 +0000)
git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@383 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/test/simpleclient/ArchiveReports.java

index 8e9fc51..6603f1a 100644 (file)
@@ -80,6 +80,12 @@ public abstract class Vobject {
     super();
     testInstanceForIdField();
   }
+  /**
+   * Override Object.hashCode with base value for castor generated object hashcodes.
+   */
+  public int hashCode() {
+    return 17;
+  }
   java.lang.reflect.Field ___id_field=null; // set to ease pain of reflection
   /**
    * set the isRegisterable flag based on the presence of a 'private String _id' field in
@@ -179,7 +185,36 @@ public abstract class Vobject {
     }
     return null;
   }
-
+  /**
+   * calls the castor-generated hashCode() method
+   * @return
+   */
+  protected int __callHash() {
+    try {
+      Method fd = this.getClass().getMethod("hashCode", (Class[]) null);
+      Object hashvalue = fd.invoke((Object) this, (Object[]) null);
+      if (log.isDebugEnabled())
+        log.debug(this.getClass().getName()+" called hashCode()!");
+      if (hashvalue!=null && hashvalue instanceof Integer) {
+        return ((Integer) hashvalue).intValue();
+      }
+    } catch (InvocationTargetException e) { 
+      log.error("SourceGeneration of "
+          + this.getClass().toString()
+          + "\n has resulted in an inaccessible 'hashCode' method!\nHave you set org.exolab.castor.builder.equalsmethod=true in castorbuilder.properties ?.", e);
+    }
+    catch (IllegalAccessException e) {
+      log.error("SourceGeneration of "
+              + this.getClass().toString()
+              + "\n has resulted in an inaccessible 'hashCode' method!\nHave you set org.exolab.castor.builder.equalsmethod=true in castorbuilder.properties ?.", e);
+    } catch (SecurityException e) {
+      log.error("Security access violation for "+this.getClass().toString(),e);
+    } catch (NoSuchMethodException e) {
+      log.warn(this.getClass().toString()+" was erroneously extending from a Vorba Vobject class (Implementation error? no hashCode() method)" +
+          "\nHave you set org.exolab.castor.builder.equalsmethod=true in castorbuilder.properties ?.", e);
+    }
+    return 0;
+  }
   /**
    * calculate a hash for the Vobject with all housekeeping fields at standard
    * values. (isRegisterable is an immutable attribute property)
@@ -187,28 +222,29 @@ public abstract class Vobject {
    * @return true if new hash different to last hash (or first time its been computed)
    */
   synchronized protected boolean doHash() {
+    boolean stored = __stored_in_document;
+    __stored_in_document=false;
+    boolean updated = __updated_since_last_read;
+    __updated_since_last_read=false;
+    boolean added_since=__added_since_last_read;
+    __added_since_last_read=false;
     long __old_hash = __last_hash;
     __last_hash = 0;
+    // leave registerable - doesn't change
+    boolean visited = __visited;
+    __visited=false;
     Vobject _V_parent=V_parent;
     V_parent=null;
     VorbaId thisid = vorbaId;
+    vorbaId = null;
     IVorbaIdFactory factory = __vorba;
-    boolean stored = __stored_in_document;
-    boolean updated = __updated_since_last_read;
-    boolean visited = __visited;
+    __vorba = null;
     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;
     // compute hash
-    __last_hash = this.hashCode();
+    __last_hash = __callHash();
     // reset houseskeeping variables
     ___id_field=idfield;
     vorbaId = thisid;
@@ -317,6 +353,8 @@ public abstract class Vobject {
    */
   protected void set__stored_in_document(boolean __stored_in_document) {
     this.__stored_in_document = __stored_in_document;
+    if(__stored_in_document && log.isDebugEnabled())
+      log.debug("Retrieved document object: "+this.getVorbaId());
   }
 
   /**
@@ -324,6 +362,9 @@ public abstract class Vobject {
    */
   protected void set__added_since_last_read(boolean __added_since_last_read) {
     this.__added_since_last_read = __added_since_last_read;
+
+    if(__added_since_last_read && log.isDebugEnabled())
+      log.debug("New object in document: "+this.getVorbaId());
   }
 
   /**
@@ -333,7 +374,7 @@ public abstract class Vobject {
    * 
    * @return Returns the __last_hash.
    */
-  public int get__last_hash() {
+  public long get__last_hash() {
     return __last_hash;
   }
 
@@ -384,7 +425,10 @@ public abstract class Vobject {
     XMLClassDescriptorImpl descimpl = null;
     try {
       // castor descriptor resolver magic
-      descriptor = this.getClass().getClassLoader().loadClass(this.getClass().getName()+"Descriptor");
+      StringBuffer desname = new StringBuffer(this.getClass().getName());
+      desname.insert(desname.lastIndexOf("."), ".descriptors");
+      desname.append("Descriptor");
+      descriptor = this.getClass().getClassLoader().loadClass(desname.toString());
       descimpl = (XMLClassDescriptorImpl) descriptor.getConstructor((Class[])null).newInstance((Object[])null);
     } catch (Exception e) {
       log.fatal("Source Generation Error!: Couldn't resolve descriptor for "
index 767a9a6..1b258dc 100644 (file)
@@ -7,13 +7,17 @@ package uk.ac.vamsas.client;
  *\r
  */\r
 public class Vobjhash {\r
-  long hashvalue;\r
+  private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(Vobjhash.class); \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.__getLHash();\r
+    tobemarshalled.doHash();\r
+    hashvalue = tobemarshalled.get__last_hash();\r
+    if (log.isDebugEnabled())\r
+      log.debug(tobemarshalled.getVorbaId()+":"+hashvalue);\r
   }\r
   /**\r
    * compares the old hash value with the unmarshalled object's most recently computed hash value and updates internal record.\r
@@ -22,7 +26,10 @@ public class Vobjhash {
    */\r
   public boolean isUpdated(Vobject unmarshalled) {\r
     long oldhash = hashvalue;\r
-    hashvalue=unmarshalled.__getLHash();\r
+    unmarshalled.doHash();\r
+    hashvalue=unmarshalled.get__last_hash();\r
+    if (log.isDebugEnabled() && oldhash!=hashvalue)\r
+      log.debug(" has changed."+unmarshalled.getVorbaId());\r
     return oldhash!=hashvalue;\r
   }\r
 }\r
index 12543f2..dadd3fa 100644 (file)
@@ -25,7 +25,6 @@ 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 
@@ -43,14 +42,7 @@ public class VorbaXmlBinder implements UnmarshalListener {
   private final Hashtable oldobjhashes;
   private final Hashtable objrefs;
   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, obj, objrefs, oldobjhashes, updatedobjs, null);
-
-  }
-
-  public VorbaXmlBinder(IVorbaIdFactory vorbafactory2, Vector unrefedObj, Hashtable objrefs2, Hashtable oldobjhashes, Vector updatedObj, ChecksummedReader ckedInstream) {
-    this.inStream = ckedInstream;
+  public VorbaXmlBinder(IVorbaIdFactory vorbafactory2, Vector unrefedObj, Hashtable objrefs2, Hashtable oldobjhashes, Vector updatedObj) {
     this.vorbafactory = vorbafactory2;
     this.obj = unrefedObj;
     this.objrefs = objrefs2;
@@ -90,8 +82,6 @@ public class VorbaXmlBinder implements UnmarshalListener {
   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
     }
   }
 
@@ -107,8 +97,6 @@ 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;
@@ -131,8 +119,7 @@ public class VorbaXmlBinder implements UnmarshalListener {
             // TODO: add to list of objects without a valid vorbaId
             obj.add(nobj);
           }
-          nobj.doHash(); // TODO: DECIDE IF WE NEED TO DO THIS STILL: THIS DOESNT WORK! updates detected by comparing with last hash when marshalling
-
+          nobj.doHash(); // 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)) {
@@ -140,7 +127,6 @@ public class VorbaXmlBinder implements UnmarshalListener {
               if (oldhash.isUpdated(nobj)) {
                 // mark the object as updated in this document read.
                 nobj.set__updated_since_last_read(true);
-                oldobjhashes.put(nobj_id, new Vobjhash(nobj));
                 updatedobjs.addElement(nobj);
               }
             } else {
@@ -242,14 +228,13 @@ public class VorbaXmlBinder implements UnmarshalListener {
     final VorbaIdFactory vorbafactory = factory;
     final Vector unrefedObj =  new Vector();
     final Vector updatedObj = new Vector();
-    ChecksummedReader ckedInstream = new ChecksummedReader(instream);
-    unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory, unrefedObj, objrefs, oobjhashes,updatedObj, ckedInstream));
+    unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory, unrefedObj, objrefs, oobjhashes,updatedObj));
     // 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(ckedInstream);
+        Object obj = unmarshaller.unmarshal(instream);
         boolean sync=ensure_references(unrefedObj, objrefs);
         if (!(obj instanceof Vobject))
           return null;
index 94d06bf..766d6a2 100644 (file)
@@ -41,8 +41,10 @@ public class ArchiveReports {
       return false;
     }
     Entry[] pe = p.getEntry();
-    for (int i=0; i<pe.length; i++)
-      outstr.println(pe[i].getDate()+"\t'"+pe[i].getUser()+"'\t"+pe[i].getApp()+"\t'"+pe[i].getAction()+"'");
+    for (int i=0; i<pe.length; i++) {
+      outstr.print(pe[i].getDate()+"\t'"+pe[i].getUser()+"'\t"+pe[i].getApp()+"\t'"+pe[i].getAction()+"' ");
+      outputVobjectState(pe[i], outstr);
+    }
     return true;
   }
   public static boolean appDataEntryReport(AppData appD, VamsasArchiveReader archive, boolean cascade, PrintStream outstr) {
@@ -138,6 +140,7 @@ public class ArchiveReports {
             +((r.getId()!=null) ? r.getId():"<none>")
             +") contains "+(ds=r.getDataSetCount())+" DataSets, "
             + (tr=r.getTreeCount())+" Global trees\n");
+        outputVobjectState(r, outstr);
         if (cascade) {
           for (int j=0; j<ds; j++) {
             outstr.println("Dataset "+j);
@@ -153,9 +156,31 @@ public class ArchiveReports {
     }
     return false;
   }
+  public static void outputVobjectState(Vobject v, PrintStream outstr) {
+    outstr.print(" (Object is: ");
+    boolean comma=false;
+    if (v.is__stored_in_document()) {
+      outstr.print(" stored");
+      comma=true;
+    }
+    if (v.isNewInDocument()) {
+      if (comma)
+        outstr.print(",");
+      comma=true;
+      outstr.print(" new in document");
+    }
+    if (v.isUpdated()) {
+      if (comma)
+        outstr.print(",");
+      comma=true;
+      outstr.print(" updated since last read");
+    }
+    outstr.println(")");
+  }
   public static boolean datasetReport(DataSet ds, boolean cascade, PrintStream outstr) {
     if (cascade)
       reportProvenance(ds.getProvenance(), outstr);
+    outputVobjectState(ds, outstr);
     outstr.println("Dataset contains : "+ds.getSequenceCount()
         +" sequences, "+ds.getAlignmentCount()+" alignments and "+ds.getTreeCount()+" trees.");
     if (cascade)
@@ -167,6 +192,7 @@ public class ArchiveReports {
     if (al!=null && al.length>0) {
       for (int i=0; i<al.length; i++) {
         outstr.println("Alignment "+i+(al[i].isRegistered() ? " ("+al[i].getVorbaId()+")" : " (unregistered)"));
+        outputVobjectState(al[i], outstr);
         if (cascade)
           reportProvenance(al[i].getProvenance(), outstr);
         outstr.println("Involves "+al[i].getAlignmentSequenceCount()+" sequences, has "
@@ -180,7 +206,8 @@ public class ArchiveReports {
     return val;
   }
   public static boolean treeReport(Tree t, boolean cascade, PrintStream outstr) {
-    outstr.println("Tree: '"+t.getTitle()+"'");
+    outstr.print("Tree: '"+t.getTitle()+"' ");
+    outputVobjectState(t, outstr);
     return !cascade || reportProvenance(t.getProvenance(), outstr);
   }