refactored org to uk
[vamsas.git] / src / org / vamsas / client / Vobject.java
index e27ee86..d7bd6eb 100644 (file)
@@ -30,15 +30,19 @@ public abstract class Vobject {
    */
   protected boolean __stored_in_document = false;
   /**
+   * true if Vobject was updated since the vamsas library last read a Vobj with the same VorbaId from a document.
+   */
+  protected boolean __updated_since_last_read = false;
+  /**
    * memory of the last doHash() value computed for the Vobject 
    * @see doHash()
    */
-  protected long __last_hash = 0; 
+  protected int __last_hash = 0; 
   /**
    * set by testInstanceForIdField() if Vobject should have a VorbaId
    */
   protected boolean registerable = false; 
-
+  protected boolean __visited = false;
   /**
    * reference to containing object for this Vobject.
    */
@@ -71,31 +75,42 @@ public abstract class Vobject {
     super();
     testInstanceForIdField();
   }
-
+  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
    * the reflected class instance.
    */
   private void testInstanceForIdField() {
-    // look for the id field (should be an NCName string)
     // TODO: decide if 'id' is an appropriate reserved attribute name for the VorbaId
-    try {
-      java.lang.reflect.Field fd = this.getClass().getDeclaredField("_id");
-      if (String.class.isAssignableFrom(fd.getType())) {
-        this.setRegisterable(true);
+    // look for the id field in all castor classes (should be an NCName string)
+    
+    Class thisclass=this.getClass();
+    setRegisterable(false);
+    while (!thisclass.equals(Vobject.class)) {
+      try {
+        java.lang.reflect.Field fd = thisclass.getDeclaredField("_id");
+        if (String.class.isAssignableFrom(fd.getType())) {
+          ___id_field=fd;
+          this.setRegisterable(true);
+          break;
+        }
+      } catch (SecurityException e) {
+        log.error("Unexpected Security Exception whilst finding id fields to set!",e);
+      } catch (NoSuchFieldException e) {
+        thisclass=thisclass.getSuperclass();
       }
-    } catch (SecurityException e) {
-      e.printStackTrace();
-    } catch (NoSuchFieldException e) {
-      this.setRegisterable(false);
     }
   }
-
+  // boolean __testedInstance=false;
   /**
    * update the Vobject instance's _id field, based on the contents of the
    * VorbaId. Only call this if you mean to do it!
    */
   protected void setInstanceIdField() {
+    /*if (!registerable && !__testedInstance) {
+      testInstanceForIdField();
+      __testedInstance=true;
+    }*/
     if (registerable) {
       if (__vorba != null)
         try {
@@ -122,6 +137,43 @@ public abstract class Vobject {
           + this.getClass().toString() + " (which cannot be given a vorbaId)");
     }
   }
+  
+  protected String __getInstanceIdField() {
+    /*if (!registerable && !__testedInstance) {
+      testInstanceForIdField();
+      __testedInstance=true;
+    }*/
+    if (registerable) {
+      if (__vorba != null)
+        try {
+          Method fd = this.getClass().getMethod("getId", (Class[]) null);
+          Object idstring = fd.invoke((Object) this, (Object[]) null);
+          log.debug(this.getClass().getName()+" called getInstanceIdField!");
+          if (idstring!=null && idstring instanceof String) {
+            if (((String) idstring).length()>0)
+              return (String) idstring;
+          }
+        } catch (InvocationTargetException e) { 
+          log.error("SourceGeneration of "
+              + this.getClass().toString()
+              + "\n has resulted in an inaccessible 'getId' method!\nCannot set ID from the vorbaId Vobject.", e);
+        }
+        catch (IllegalAccessException e) {
+          log.error("SourceGeneration of "
+                  + this.getClass().toString()
+                  + "\n has resulted in an inaccessible 'getId' method!\nCannot set ID from the vorbaId Vobject.", e);
+        } catch (SecurityException e) {
+          log.error("Security access violation for "+this.getClass().toString(),e);
+        } catch (NoSuchMethodException e) {
+          log.warn(this.getClass().toString()+" was erroneously marked as a Vorba Vobject class (Implementation error?)");
+          this.setRegisterable(false);
+        }
+    } else {
+      System.err.println("Client error. Trying to getInstanceIdField on a "
+          + this.getClass().toString() + " (which cannot be given a vorbaId)");
+    }
+    return null;
+  }
 
   /**
    * calculate a hash for the Vobject with all housekeeping fields at standard
@@ -137,13 +189,24 @@ public abstract class Vobject {
     VorbaId thisid = vorbaId;
     IVorbaIdFactory factory = __vorba;
     boolean stored = __stored_in_document;
+    boolean updated = __updated_since_last_read;
+    boolean visited = __visited;
+    java.lang.reflect.Field idfield = ___id_field;
+    ___id_field=null;
+    __updated_since_last_read=false;
     vorbaId = null;
     __vorba = null;
+    __visited=false;
+    // compute hash
     __last_hash = this.hashCode();
+    // reset houseskeeping variables
+    ___id_field=idfield;
     vorbaId = thisid;
     __vorba = factory;
     __stored_in_document = stored;
+    __updated_since_last_read=updated;
     V_parent=_V_parent;
+    __visited=visited;
     return (__old_hash==0) || (__old_hash == __last_hash);
   }
 
@@ -177,6 +240,10 @@ public abstract class Vobject {
    */
   public VorbaId getVorbaId() {
     if (registerable && vorbaId == null) {
+      if (this.__stored_in_document) {
+        if (__vorba!=null)
+          vorbaId=org.vamsas.client.VorbaId.newId(this.__getInstanceIdField());
+      }
       // Try to use the associated factory.
       if (__vorba != null)
         if ((vorbaId = __vorba.makeVorbaId(this)) == null)
@@ -205,6 +272,21 @@ public abstract class Vobject {
   }
 
   /**
+   * @return true if this object has been updated in the currently stored document since the last time a Vobject with the same ID was read from a Vamsas Document
+   */
+  public boolean is__updated_since_last_read() {
+    return __updated_since_last_read;
+  }
+
+  /**
+   * Set internal flag to indicate this object was updated since the last document read
+   * @param __updated_since_last_read the __updated_since_last_read to set
+   */
+  protected void set__updated_since_last_read(boolean __updated_since_last_read) {
+    this.__updated_since_last_read = __updated_since_last_read;
+  }
+
+  /**
    * for use by Vorba agent to reflect state of vamsas Vobject to client
    * application.
    * Setting stored_in_document on a registerable Vobject without a 
@@ -223,7 +305,7 @@ public abstract class Vobject {
    * 
    * @return Returns the __last_hash.
    */
-  public long get__last_hash() {
+  public int get__last_hash() {
     return __last_hash;
   }
 
@@ -250,18 +332,26 @@ public abstract class Vobject {
    * TODO: FIX CYCLIC __ensure+instance_ids
    * Implementation note for the todo:
    * this works like a depth-first search over all vamsas objects in an vamsasDocument. 
-   * The doHash() function is used as the 'visited' flag - 
+   * __visited is the visited flag, any Vobj who's flag is of a different parity 
+   * to the visited argument will be recursed on. 
+   * note - the doHash() function used to be used as the 'visited' flag - 
    * this *is not* a valid heuristic, although it will work "most of the time".
    * TODO: LATER? Add another method for setDefaultProvenanceField (in the spirit of setInstanceIdField) using the info from the __vorba.getClient/User/Session methods 
    */
   protected void __ensure_instance_ids() {
+    __ensure_instance_ids(!__visited);
+  }
+  protected void __ensure_instance_ids(boolean visited) {
     if (__vorba==null)
       throw new Error("Improperly intialised org.vamsas.client.Vobject - no VorbaFactory given.");
     log.debug("doing "+this.getClass()+".__ensure_instance_ids()");
     if (!__stored_in_document && registerable)
       setInstanceIdField();
-    if (!doHash())
-      return; // nothing has changed in this Vobject - probably visited it before.
+    if (__visited==visited)
+      return;
+    __visited=visited;
+    __vorba.updateHashValue(this);
+    
     Class descriptor = null;
     XMLClassDescriptorImpl descimpl = null;
     try {
@@ -288,7 +378,7 @@ public abstract class Vobject {
                   vals[k].__vorba = __vorba; // propagate IVorbaIdFactory
                 if (vals[k].V_parent==null)
                   vals[k].V_parent=this; // propagate parent reference to this element.
-                vals[k].__ensure_instance_ids();
+                vals[k].__ensure_instance_ids(visited);
               }
             }
           }
@@ -313,7 +403,7 @@ public abstract class Vobject {
                           vals[k].__vorba = __vorba; // propagate IVorbaIdFactory
                         if (vals[k].V_parent==null)
                           vals[k].V_parent=this; // propagate parent reference to this field object
-                        vals[k].__ensure_instance_ids();
+                        vals[k].__ensure_instance_ids(visited);
                       }
                     }
                     catch (Exception e) {
@@ -347,7 +437,7 @@ public abstract class Vobject {
                 rf.__vorba = __vorba; // propagate IVorbaIdFactory
               if (rf.V_parent==null)
                 rf.V_parent=this; // propagate parent reference
-             rf.__ensure_instance_ids();
+             rf.__ensure_instance_ids(visited);
             }
           }
           catch (Exception e) {