-/**
- *
- */
-package uk.ac.vamsas.client;
-
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.lang.reflect.Field;
-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;
-import org.exolab.castor.xml.IDResolver;
-import org.exolab.castor.xml.MarshalException;
-import org.exolab.castor.xml.MarshalListener;
-import org.exolab.castor.xml.Marshaller;
-import org.exolab.castor.xml.UnmarshalListener;
-import org.exolab.castor.xml.Unmarshaller;
-import org.exolab.castor.xml.ValidationException;
-
-import uk.ac.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 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;
- private final Vector updatedobjs; // not yet used elswhere ?
- public VorbaXmlBinder(IVorbaIdFactory vorbafactory2, Vector unrefedObj, Hashtable objrefs2, Hashtable oldobjhashes, Vector updatedObj) {
- this.vorbafactory = vorbafactory2;
- this.obj = unrefedObj;
- this.objrefs = objrefs2;
- this.oldobjhashes = oldobjhashes;
- this.updatedobjs = updatedObj;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.exolab.castor.xml.UnmarshalListener#attributesProcessed(java.lang.Object)
- */
- public void attributesProcessed(Object object) {
-
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.exolab.castor.xml.UnmarshalListener#fieldAdded(java.lang.String,
- * 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);
- }
- }
- }
-
- /*
- * (non-Javadoc)
- *
- * @see org.exolab.castor.xml.UnmarshalListener#initialized(java.lang.Object)
- */
- public void initialized(Object object) {
- if (object instanceof Vobject) {
- Vobject nobj = (Vobject) object;
- }
- }
-
- /*
- * Check if the object has an 'id' field - if it does, copy the value into
- * the VorbaId field of Vobject, and add the Vobject to the VorbaId hash.
- *
- * @see org.exolab.castor.xml.UnmarshalListener#unmarshalled(java.lang.Object)
- */
- public void unmarshalled(Object newobj) {
- if (newobj instanceof Vobject) {
- Vobject nobj = (Vobject) newobj;
- nobj.set__stored_in_document(true);
- try {
- if (nobj.isRegisterable() && nobj.___id_field!=null) {
- VorbaId nobj_id=null;
- // look for the id field (should be an NCName string)
- nobj.__vorba = vorbafactory;
- // use the Vobject accessor method to avoid unpleasant security exceptions.
- String idstring = nobj.__getInstanceIdField();
- if (idstring!=null) {
- if (idstring.length() > 0) {
- nobj.setVorbaId(VorbaId.newId(idstring));
- nobj_id=nobj.getVorbaId();
- if (objrefs.containsKey(nobj_id) && !objrefs.get(nobj_id).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 {
- // TODO: add to list of objects without a valid vorbaId
- obj.add(nobj);
- }
- 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)) {
- Vobjhash oldhash = (Vobjhash) oldobjhashes.get(nobj_id);
- if (oldhash.isUpdated(nobj)) {
- // mark the object as updated in this document read.
- nobj.set__updated_since_last_read(true);
- updatedobjs.addElement(nobj);
- }
- } else {
- // object has no entry in the oldhashvalue list but
- // there is a valid vorbaId so
- nobj.set__added_since_last_read(true);
- }
- // and record the just-unmarshalled hash value
- oldobjhashes.put(nobj_id, new Vobjhash(nobj));
- } else {
- // for objects yet to get a valid vorba_id
- nobj.set__added_since_last_read(true);
- }
- }
-
- } catch (Exception e) {
- return;
- };
-
- }
- }
-
- /**
- * writes the VamsasDocument to the given stream.
- * TODO: ensure that (at least) default provenance entries are written for objects.
- * @param outstream
- * @param vorba valid VorbaIdFactory to construct any missing IDs
- * @param doc
- * @throws IOException
- * @throws MarshalException
- * @throws ValidationException
- */
- public static void putVamsasDocument(PrintWriter outstream, VorbaIdFactory vorba, VamsasDocument doc)
- throws IOException, MarshalException, ValidationException {
- // Ensure references
- if (vorba==null)
- 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 ?
- Marshaller mshl = new Marshaller(outstream);
- mshl.marshal(doc);
-
- }
- /**
- * 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) {
- sync=false; // document is out of sync - ids have been created.
- java.util.Iterator newobj = unrefed.listIterator();
- while (newobj.hasNext()) {
- Vobject o = (Vobject) newobj.next();
- // forces registration and id field update.
- VorbaId id = o.getVorbaId();
- if (!objrefs.containsKey(id)) {
- objrefs.put(id, o);
- } else {
- if (!objrefs.get(id).equals(o))
- throw new Error("Serious! Duplicate reference made by vorbaIdFactory!");
- }
- }
- }
- return sync;
- }
- /**
- * Unmarshals a vamsasDocument Vobject from a stream, registers
- * unregistered objects, records existing VorbaIds, and completes
- * the uk.ac.vamsas.client.Vobject housekeeping fields.
- * For a valid unmarshalling, the array of returned objects also includes
- * a <return>sync</return> parameter which is true if new VorbaIds
- * 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 uk.ac.vamsas.objects.core Vobject.
- * @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,
- VorbaIdFactory factory, Vobject root) {
- Unmarshaller unmarshaller = new Unmarshaller(root);
- unmarshaller.setIDResolver(new IDResolver() {
- public Object resolve(String id) {
- // TODO: allow for external ID resolution
- VorbaXmlBinder.log.warn("Warning - id " + id
- + " is not found in the Vamsas XML! (TODO: Ignore if this is a forward reference!)");
- return null;
- }
- });
- 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(unrefedObj, objrefs);
- if (!(obj instanceof Vobject))
- return null;
- 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
- e.printStackTrace();
- } catch (ValidationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
-}
\ No newline at end of file
+/*\r
+ * This file is part of the Vamsas Client version 0.1. \r
+ * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite, \r
+ * Andrew Waterhouse and Dominik Lindner.\r
+ * \r
+ * Earlier versions have also been incorporated into Jalview version 2.4 \r
+ * since 2008, and TOPALi version 2 since 2007.\r
+ * \r
+ * The Vamsas Client is free software: you can redistribute it and/or modify\r
+ * it under the terms of the GNU Lesser General Public License as published by\r
+ * the Free Software Foundation, either version 3 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * The Vamsas Client is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ * GNU Lesser General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with the Vamsas Client. If not, see <http://www.gnu.org/licenses/>.\r
+ */\r
+package uk.ac.vamsas.client;\r
+\r
+import java.io.IOException;\r
+import java.io.PrintWriter;\r
+import java.io.Reader;\r
+import java.io.Writer;\r
+import java.lang.reflect.Field;\r
+import java.util.Hashtable;\r
+import java.util.Iterator;\r
+import java.util.Vector;\r
+\r
+import org.apache.commons.logging.Log;\r
+import org.apache.commons.logging.LogFactory;\r
+import org.exolab.castor.mapping.FieldHandler;\r
+import org.exolab.castor.mapping.GeneralizedFieldHandler;\r
+import org.exolab.castor.mapping.ValidityException;\r
+import org.exolab.castor.xml.IDResolver;\r
+import org.exolab.castor.xml.MarshalException;\r
+import org.exolab.castor.xml.MarshalListener;\r
+import org.exolab.castor.xml.Marshaller;\r
+import org.exolab.castor.xml.UnmarshalListener;\r
+import org.exolab.castor.xml.Unmarshaller;\r
+import org.exolab.castor.xml.ValidationException;\r
+\r
+import uk.ac.vamsas.objects.core.VamsasDocument;\r
+\r
+/**\r
+ * Implements the Vamsas Vobject ID machinery for translating between\r
+ * non-volatile XML IDs and Vobject references. Use the marshalling and\r
+ * unmarshalling methods in this class in order to add automatically computed\r
+ * values for required fields in objects, so as to avoid validation exceptions\r
+ * when marshalling new objects into the vamsas document.\r
+ */\r
+public class VorbaXmlBinder implements UnmarshalListener {\r
+ private static Log log = LogFactory.getLog(VorbaXmlBinder.class);\r
+\r
+ private final IVorbaIdFactory vorbafactory;\r
+\r
+ private final Vector obj;\r
+\r
+ private final Hashtable oldobjhashes;\r
+\r
+ private final Hashtable objrefs;\r
+\r
+ private final Vector updatedobjs; // not yet used elswhere ?\r
+\r
+ public VorbaXmlBinder(IVorbaIdFactory vorbafactory2, Vector unrefedObj,\r
+ Hashtable objrefs2, Hashtable oldobjhashes, Vector updatedObj) {\r
+ this.vorbafactory = vorbafactory2;\r
+ this.obj = unrefedObj;\r
+ this.objrefs = objrefs2;\r
+ this.oldobjhashes = oldobjhashes;\r
+ this.updatedobjs = updatedObj;\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see\r
+ * org.exolab.castor.xml.UnmarshalListener#attributesProcessed(java.lang.Object\r
+ * )\r
+ */\r
+ public void attributesProcessed(Object object) {\r
+\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see org.exolab.castor.xml.UnmarshalListener#fieldAdded(java.lang.String,\r
+ * java.lang.Object, java.lang.Object)\r
+ */\r
+ public void fieldAdded(String fieldName, Object parent, Object child) {\r
+ if (parent instanceof Vobject && child instanceof Vobject) {\r
+ if (((Vobject) child).V_parent == null) {\r
+ // System.err.println("Setting parent of "+fieldName);\r
+ ((Vobject) child).setV_parent((Vobject) parent);\r
+ }\r
+ }\r
+ }\r
+\r
+ /*\r
+ * (non-Javadoc)\r
+ * \r
+ * @see org.exolab.castor.xml.UnmarshalListener#initialized(java.lang.Object)\r
+ */\r
+ public void initialized(Object object) {\r
+ if (object instanceof Vobject) {\r
+ Vobject nobj = (Vobject) object;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Check if the object has an 'id' field - if it does, copy the value into the\r
+ * VorbaId field of Vobject, and add the Vobject to the VorbaId hash.\r
+ * \r
+ * @see org.exolab.castor.xml.UnmarshalListener#unmarshalled(java.lang.Object)\r
+ */\r
+ public void unmarshalled(Object newobj) {\r
+ if (newobj instanceof Vobject) {\r
+ Vobject nobj = (Vobject) newobj;\r
+ nobj.set__stored_in_document(true);\r
+ try {\r
+ if (nobj.isRegisterable() && nobj.___id_field != null) {\r
+ VorbaId nobj_id = null;\r
+ // look for the id field (should be an NCName string)\r
+ nobj.__vorba = vorbafactory;\r
+ // use the Vobject accessor method to avoid unpleasant security\r
+ // exceptions.\r
+ String idstring = nobj.__getInstanceIdField();\r
+ if (idstring != null) {\r
+ if (idstring.length() > 0) {\r
+ nobj.setVorbaId(VorbaId.newId(idstring));\r
+ nobj_id = nobj.getVorbaId();\r
+ if (objrefs.containsKey(nobj_id)\r
+ && !objrefs.get(nobj_id).equals(nobj)) {\r
+ System.err.println("Serious problem : duplicate id '"\r
+ + idstring + "' found! expect badness.");\r
+ // TODO: HANDLE duplicate XML ids correctly\r
+ }\r
+ objrefs.put(nobj_id, nobj);\r
+ } else {\r
+ // add to list of objects without a valid vorbaId\r
+ obj.add(nobj);\r
+ }\r
+ } else {\r
+ // TODO: add to list of objects without a valid vorbaId\r
+ obj.add(nobj);\r
+ }\r
+ nobj.doHash(); // updates detected by comparing with last hash when\r
+ // marshalling\r
+ // check to see if new object was present in old object hash\r
+ if (nobj_id != null) {\r
+ if (oldobjhashes.containsKey(nobj_id)) {\r
+ Vobjhash oldhash = (Vobjhash) oldobjhashes.get(nobj_id);\r
+ if (oldhash.isUpdated(nobj)) {\r
+ // mark the object as updated in this document read.\r
+ nobj.set__updated_since_last_read(true);\r
+ updatedobjs.addElement(nobj);\r
+ }\r
+ } else {\r
+ // object has no entry in the oldhashvalue list but\r
+ // there is a valid vorbaId so\r
+ nobj.set__added_since_last_read(true);\r
+ }\r
+ // and record the just-unmarshalled hash value\r
+ oldobjhashes.put(nobj_id, new Vobjhash(nobj));\r
+ } else {\r
+ // for objects yet to get a valid vorba_id\r
+ nobj.set__added_since_last_read(true);\r
+ }\r
+ }\r
+\r
+ } catch (Exception e) {\r
+ return;\r
+ }\r
+ ;\r
+\r
+ }\r
+ }\r
+\r
+ /**\r
+ * writes the VamsasDocument to the given stream. TODO: ensure that (at least)\r
+ * default provenance entries are written for objects.\r
+ * \r
+ * @param outstream\r
+ * @param vorba\r
+ * valid VorbaIdFactory to construct any missing IDs\r
+ * @param doc\r
+ * @throws IOException\r
+ * @throws MarshalException\r
+ * @throws ValidationException\r
+ */\r
+ public static void putVamsasDocument(PrintWriter outstream,\r
+ VorbaIdFactory vorba, VamsasDocument doc) throws IOException,\r
+ MarshalException, ValidationException {\r
+ // Ensure references\r
+ if (vorba == null)\r
+ throw new Error("Null VorbaIdFactory Parameter");\r
+ if (doc.__vorba == null)\r
+ doc.__vorba = vorba;\r
+ doc.__ensure_instance_ids(); // this may take a while. Do we allow for\r
+ // cyclic references ?\r
+ Marshaller mshl = new Marshaller(outstream);\r
+ mshl.marshal(doc);\r
+\r
+ }\r
+\r
+ /**\r
+ * creates new VorbaId references where necessary for newly unmarshalled\r
+ * objects\r
+ * \r
+ * @param unrefed\r
+ * @param objrefs\r
+ * @return false if any new object references were made\r
+ */\r
+ private static boolean ensure_references(Vector unrefed, Hashtable objrefs) {\r
+ boolean sync = true;\r
+ if (unrefed.size() > 0) {\r
+ sync = false; // document is out of sync - ids have been created.\r
+ java.util.Iterator newobj = unrefed.listIterator();\r
+ while (newobj.hasNext()) {\r
+ Vobject o = (Vobject) newobj.next();\r
+ // forces registration and id field update.\r
+ VorbaId id = o.getVorbaId();\r
+ if (!objrefs.containsKey(id)) {\r
+ objrefs.put(id, o);\r
+ } else {\r
+ if (!objrefs.get(id).equals(o))\r
+ throw new Error(\r
+ "Serious! Duplicate reference made by vorbaIdFactory!");\r
+ }\r
+ }\r
+ }\r
+ return sync;\r
+ }\r
+\r
+ /**\r
+ * Unmarshals a vamsasDocument Vobject from a stream, registers unregistered\r
+ * objects, records existing VorbaIds, and completes the\r
+ * uk.ac.vamsas.client.Vobject housekeeping fields. For a valid unmarshalling,\r
+ * the array of returned objects also includes a <return>sync</return>\r
+ * parameter which is true if new VorbaIds were created. If sync is false,\r
+ * then the caller should ensure that the vamsasDocument is written back to\r
+ * disk to propagate the new VorbaIds. TODO: ensure that provenance is correct\r
+ * for newly registered objects as getVamsasObjects but will detect updated\r
+ * objects based on differing hash values obtained from the VorbaIdFactory's\r
+ * VorbaId, Vobject.get__last_Hash() pairs (if any)\r
+ * \r
+ * @param instream\r
+ * - the XML input stream\r
+ * @param factory\r
+ * - the SimpleClient's properly configured VorbaId factory to make\r
+ * new references.\r
+ * @param root\r
+ * the root element's uk.ac.vamsas.objects.core Vobject.\r
+ * @return null or {(Object) VamsasDocument Vobject, (Object) Hashtable of\r
+ * Vobject references, (Object) Boolean(sync), (Object) Vector of\r
+ * updated objects in document }\r
+ */\r
+ public static Object[] getVamsasObjects(Reader instream,\r
+ VorbaIdFactory factory, Vobject root) {\r
+ Unmarshaller unmarshaller = new Unmarshaller(root);\r
+ unmarshaller.setIDResolver(new IDResolver() {\r
+ public Object resolve(String id) {\r
+ // TODO: allow for external ID resolution\r
+ VorbaXmlBinder.log\r
+ .warn("Warning - id "\r
+ + id\r
+ + " is not found in the Vamsas XML! (TODO: Ignore if this is a forward reference!)");\r
+ return null;\r
+ }\r
+ });\r
+ final Hashtable objrefs = new Hashtable();\r
+ if (factory.extanthashv == null)\r
+ factory.extanthashv = new Hashtable();\r
+ final Hashtable oobjhashes = factory.extanthashv;\r
+ final VorbaIdFactory vorbafactory = factory;\r
+ final Vector unrefedObj = new Vector();\r
+ final Vector updatedObj = new Vector();\r
+ unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory,\r
+ unrefedObj, objrefs, oobjhashes, updatedObj));\r
+ // Call the unmarshaller.\r
+ try {\r
+ while (instream.ready()) {\r
+ // TODO: mark objects in oobjhash prior to unmarshalling, to detect when\r
+ // objects have been lost through an update.\r
+ // tohere\r
+ Object obj = unmarshaller.unmarshal(instream);\r
+ boolean sync = ensure_references(unrefedObj, objrefs);\r
+ if (!(obj instanceof Vobject))\r
+ return null;\r
+ vorbafactory.setNewIdHash(objrefs); // update the Document IO Handler's\r
+ // set of vorbaId<>Object bindings.\r
+ return new Object[] { obj, objrefs, new Boolean(sync), updatedObj };\r
+ }\r
+ } catch (MarshalException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (ValidationException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+ return null;\r
+ }\r
+}\r