X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Forg%2Fvamsas%2Fclient%2FVobject.java;h=d7bd6ebb6d33e68eb897f2bf8ff7227079d2066c;hb=ea8b10ee787a2b1e2b35f2acb4dccaf12fd2a6fd;hp=cb2738f3f5e3822e7cb2651ebf4a5dd914aee29b;hpb=f0307c09bb32271a55b287b06f9e4b9f71526c04;p=vamsas.git diff --git a/src/org/vamsas/client/Vobject.java b/src/org/vamsas/client/Vobject.java index cb2738f..d7bd6eb 100644 --- a/src/org/vamsas/client/Vobject.java +++ b/src/org/vamsas/client/Vobject.java @@ -30,16 +30,23 @@ 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. + */ + protected Vobject V_parent=null; /** * unique id for all vamsas objects allows unambiguous referencing to any * Vobject in the vamsas document @@ -50,6 +57,16 @@ public abstract class Vobject { * the source of unique VorbaIds. */ protected IVorbaIdFactory __vorba = null; + + /* (non-Javadoc) + * @see java.lang.Object#finalize() + */ + protected void finalize() throws Throwable { + V_parent=null; + __vorba=null; + vorbaId=null; + super.finalize(); + } /** * @@ -58,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 { @@ -109,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 @@ -119,15 +184,29 @@ public abstract class Vobject { synchronized protected boolean doHash() { long __old_hash = __last_hash; __last_hash = 0; + Vobject _V_parent=V_parent; + V_parent=null; 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); } @@ -161,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) @@ -189,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 @@ -207,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; } @@ -234,24 +332,32 @@ 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 { // castor descriptor resolver magic descriptor = this.getClass().getClassLoader().loadClass(this.getClass().getName()+"Descriptor"); - descimpl = (XMLClassDescriptorImpl) descriptor.getConstructor(null).newInstance(null); + descimpl = (XMLClassDescriptorImpl) descriptor.getConstructor((Class[])null).newInstance((Object[])null); } catch (Exception e) { log.fatal("Source Generation Error!: Couldn't resolve descriptor for " +this.getClass().getName() @@ -270,7 +376,9 @@ public abstract class Vobject { for (int k=0, l=vals.length; k