applied LGPLv3 and source code formatting.
[vamsas.git] / src / uk / ac / vamsas / client / VorbaXmlBinder.java
index 9462494..b237dcf 100644 (file)
-/**
- * 
- */
-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