X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Forg%2Fvamsas%2Fclient%2FVorbaXmlBinder.java;h=556386d3305da0772c4bcdec951e0df0589d96b2;hb=5c0c34895c290164caad28e0aeac86b5a52ee655;hp=22d537905607211b1686bacf69414dfe51a26720;hpb=f0307c09bb32271a55b287b06f9e4b9f71526c04;p=vamsas.git diff --git a/src/org/vamsas/client/VorbaXmlBinder.java b/src/org/vamsas/client/VorbaXmlBinder.java index 22d5379..556386d 100644 --- a/src/org/vamsas/client/VorbaXmlBinder.java +++ b/src/org/vamsas/client/VorbaXmlBinder.java @@ -12,6 +12,8 @@ import java.util.Hashtable; import java.util.Iterator; import java.util.Vector; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.exolab.castor.mapping.FieldHandler; import org.exolab.castor.mapping.GeneralizedFieldHandler; import org.exolab.castor.mapping.ValidityException; @@ -27,20 +29,25 @@ import org.vamsas.objects.core.VamsasDocument; * Implements the Vamsas Vobject ID machinery for translating * between non-volatile XML IDs and Vobject references. Use the * marshalling and unmarshalling methods in this class in order - * to avoid validation exceptions when marshalling new objects + * to add automatically computed values for required fields in objects, + * so as to avoid validation exceptions when marshalling new objects * into the vamsas document. */ public class VorbaXmlBinder implements UnmarshalListener { + private static Log log = LogFactory.getLog(VorbaXmlBinder.class); private final IVorbaIdFactory vorbafactory; private final Vector obj; - + private final Hashtable oldobjhashes; private final Hashtable objrefs; - - public VorbaXmlBinder(IVorbaIdFactory vorbafactory, Vector obj, Hashtable objrefs) { + private final Vector updatedobjs; + + public VorbaXmlBinder(IVorbaIdFactory vorbafactory, Vector obj, Hashtable objrefs, Hashtable oldobjhashes, Vector updatedobjs) { this.vorbafactory = vorbafactory; this.obj = obj; this.objrefs = objrefs; + this.oldobjhashes = oldobjhashes; + this.updatedobjs = updatedobjs; } /* @@ -58,6 +65,12 @@ public class VorbaXmlBinder implements UnmarshalListener { * java.lang.Object, java.lang.Object) */ public void fieldAdded(String fieldName, Object parent, Object child) { + if (parent instanceof Vobject && child instanceof Vobject) { + if (((Vobject) child).V_parent==null) { + // System.err.println("Setting parent of "+fieldName); + ((Vobject) child).setV_parent((Vobject) parent); + } + } } /* @@ -78,33 +91,41 @@ public class VorbaXmlBinder implements UnmarshalListener { if (newobj instanceof Vobject) { Vobject nobj = (Vobject) newobj; nobj.set__stored_in_document(true); - Field fd = null; try { - if (nobj.isRegisterable()) { + if (nobj.isRegisterable() && nobj.___id_field!=null) { + VorbaId nobj_id=null; // look for the id field (should be an NCName string) nobj.__vorba = vorbafactory; - fd = nobj.getClass().getDeclaredField("_id"); - String idstring; - if (fd.get(nobj) != null) { - idstring = (String) fd.get(nobj); + // use the Vobject accessor method to avoid unpleasant security exceptions. + String idstring = nobj.__getInstanceIdField(); + if (idstring!=null) { if (idstring.length() > 0) { - if (!objrefs.containsKey(idstring)) { - objrefs.put(idstring, nobj); - nobj.setVorbaId(VorbaId.newId(idstring)); - } else { + nobj.setVorbaId(VorbaId.newId(idstring)); + if (objrefs.containsKey(nobj_id=nobj.getVorbaId()) && !objrefs.get(nobj.getVorbaId()).equals(nobj)) { System.err.println("Serious problem : duplicate id '"+idstring+"' found! expect badness."); // TODO: HANDLE duplicate XML ids correctly } + objrefs.put(nobj_id, nobj); } else { // add to list of objects without a valid vorbaId obj.add(nobj); } } else { - // add to list of objects without a valid vorbaId + // TODO: add to list of objects without a valid vorbaId obj.add(nobj); } nobj.doHash(); + // check to see if new object was present in old object hash + if (oldobjhashes.containsKey(nobj.getVorbaId())) { + Vobjhash oldhash = (Vobjhash) oldobjhashes.get(nobj.getVorbaId()); + 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); + } + } } } catch (Exception e) { return; @@ -127,13 +148,19 @@ public class VorbaXmlBinder implements UnmarshalListener { throws IOException, MarshalException, ValidationException { // Ensure references if (vorba==null) - throw new Error("Null VorbaIdVactory Parameter"); + throw new Error("Null VorbaIdFactory Parameter"); if (doc.__vorba==null) doc.__vorba = vorba; doc.__ensure_instance_ids(); // this may take a while. Do we allow for cyclic references ? doc.marshal(outstream); + } - + /** + * creates new VorbaId references where necessary for newly unmarshalled objects + * @param unrefed + * @param objrefs + * @return false if any new object references were made + */ private static boolean ensure_references(Vector unrefed, Hashtable objrefs) { boolean sync=true; if (unrefed.size()>0) { @@ -144,9 +171,10 @@ public class VorbaXmlBinder implements UnmarshalListener { // forces registration and id field update. VorbaId id = o.getVorbaId(); if (!objrefs.containsKey(id)) { - objrefs.put(id.id, o); + objrefs.put(id, o); } else { - throw new Error("Serious! Duplicate reference made by vorbaIdFactory!"); + if (!objrefs.get(id).equals(o)) + throw new Error("Serious! Duplicate reference made by vorbaIdFactory!"); } } } @@ -161,35 +189,42 @@ public class VorbaXmlBinder implements UnmarshalListener { * were created. If sync is false, then the caller should ensure that the * vamsasDocument is written back to disk to propagate the new VorbaIds. * TODO: ensure that provenance is correct for newly registered objects + * as getVamsasObjects but will detect updated objects based on differing hash values + * obtained from the VorbaIdFactory's VorbaId, Vobject.get__last_Hash() pairs (if any) * @param instream - the XML input stream * @param factory - the SimpleClient's properly configured VorbaId factory to make new references. * @param root the root element's org.vamsas.objects.core Vobject. - * @return null or {(Object) VamsasDocument Vobject, (Object) Hashtable of Vobject references, (Object) Boolean(sync) } + * @return null or {(Object) VamsasDocument Vobject, (Object) Hashtable of Vobject references, (Object) Boolean(sync), (Object) Vector of updated objects in document } */ public static Object[] getVamsasObjects(Reader instream, - IVorbaIdFactory factory, Vobject root) { - Unmarshaller unmarshaller = new Unmarshaller(root); + VorbaIdFactory factory, Vobject root) { + Unmarshaller unmarshaller = new Unmarshaller(root); unmarshaller.setIDResolver(new IDResolver() { public Object resolve(String id) { - System.err.println("Warning - id " + id - + " is not found in the VamsasDocument!"); + VorbaXmlBinder.log.warn("Warning - id " + id + + " is not found in the Vamsas XML!"); return null; } }); - Hashtable refbase = new Hashtable(); - Vector unrefed = new Vector(); - final Hashtable objrefs = refbase; - final IVorbaIdFactory vorbafactory = factory; - final Vector unrefedObj = unrefed; - unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory, unrefedObj, objrefs)); + final Hashtable objrefs = new Hashtable(); + if (factory.extanthashv==null) + factory.extanthashv=new Hashtable(); + final Hashtable oobjhashes=factory.extanthashv; + final VorbaIdFactory vorbafactory = factory; + final Vector unrefedObj = new Vector(); + final Vector updatedObj = new Vector(); + 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(instream); - boolean sync=ensure_references(unrefed, objrefs); + boolean sync=ensure_references(unrefedObj, objrefs); if (!(obj instanceof Vobject)) return null; - return new Object[] { obj, objrefs, new Boolean(sync)}; + vorbafactory.setNewIdHash(objrefs); // update the Document IO Handler's set of vorbaId<>Object bindings. + return new Object[] { obj, objrefs, new Boolean(sync),updatedObj}; } } catch (MarshalException e) { // TODO Auto-generated catch block