new marshaller instance ensures we use marshalling properties and correct validation...
[vamsas.git] / src / uk / ac / vamsas / client / Vobject.java
index 5029a31..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,31 +185,66 @@ 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)
-   * 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() {
+    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;
-    vorbaId = null;
-    __vorba = null;
-    __visited=false;
+    long l_hash = __l_hash;
+    __l_hash = 0;
     // compute hash
-    __last_hash = this.hashCode();
+    __last_hash = __callHash();
     // reset houseskeeping variables
     ___id_field=idfield;
     vorbaId = thisid;
@@ -212,7 +253,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 +339,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());
   }
 
   /**
@@ -307,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());
   }
 
   /**
@@ -314,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());
   }
 
   /**
@@ -323,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;
   }
 
@@ -368,13 +419,16 @@ public abstract class Vobject {
     if (__visited==visited)
       return;
     __visited=visited;
-    __vorba.updateHashValue(this);
+    //__vorba.updateHashValue(this);
     
     Class descriptor = null;
     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 "
@@ -479,4 +533,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;
+  }
 }