bugfixed org.vamsas.test.simpleclient.ArchiveClient and made VorbaId mechanism more...
[vamsas.git] / src / org / vamsas / client / VorbaXmlBinder.java
index 9fc6965..0f4feb1 100644 (file)
@@ -4,6 +4,7 @@
 package org.vamsas.client;
 
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.Writer;
 import java.lang.reflect.Field;
@@ -11,16 +12,20 @@ import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.Vector;
 
+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 org.vamsas.objects.core.VamsasDocument;
 /**
- * Implements the Vamsas object ID machinery for translating 
- * between non-volatile XML IDs and object references. Use the
+ * 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
  * into the vamsas document.
@@ -53,6 +58,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);
+      }
+    }
   }
 
   /*
@@ -62,23 +73,23 @@ public class VorbaXmlBinder implements UnmarshalListener {
    */
   public void initialized(Object object) {
   }
-
+  
   /*
    * Check if the object has an 'id' field - if it does, copy the value into
-   * the VorbaId field of object, and add the object to the VorbaId hash.
+   * 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 object) {
-      object nobj = (object) newobj;
+    if (newobj instanceof Vobject) {
+      Vobject nobj = (Vobject) newobj;
       nobj.set__stored_in_document(true);
       Field fd = null;
       try {
         if (nobj.isRegisterable()) {
           // look for the id field (should be an NCName string)
           nobj.__vorba = vorbafactory;
-          fd = nobj.getClass().getField("id");
+          fd = nobj.getClass().getDeclaredField("_id");
           String idstring;
           if (fd.get(nobj) != null) {
             idstring = (String) fd.get(nobj);
@@ -112,33 +123,58 @@ public class VorbaXmlBinder implements UnmarshalListener {
    * 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
    */
-  private static void setVamsasDocument(Writer outstream, VamsasDocument doc)
+  public static void putVamsasDocument(PrintWriter outstream, VorbaIdFactory vorba, VamsasDocument doc)
       throws IOException, MarshalException, ValidationException {
-    Marshaller marshaller = new Marshaller(outstream);
-    marshaller.marshal(doc);
+    // Ensure references
+    if (vorba==null)
+      throw new Error("Null VorbaIdVactory 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);
   }
 
+  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.id, o);
+        } else {
+          throw new Error("Serious! Duplicate reference made by vorbaIdFactory!");
+        }
+      }
+    }
+    return sync;
+  }
   /**
-     * Unmarshals a vamsasDocument object from a stream, registers
+     * Unmarshals a vamsasDocument Vobject from a stream, registers
      * unregistered objects, records existing VorbaIds, and completes 
-     * the org.vamsas.client.object housekeeping fields.
+     * the org.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
      * @param instream - the XML input stream 
-     * @param factory - the SimpleClient's properly configured VorbaId factory to make new references.
-     * @return null or {(Object) VamsasDocument object, (Object) Hashtable of object references, (Object) Boolean(sync) }
+   * @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) }
      */
-  public static Object[] getVamsasDocument(Reader instream,
-        IVorbaIdFactory factory) {
-      Unmarshaller unmarshaller = new Unmarshaller(instream);
+  public static Object[] getVamsasObjects(Reader instream,
+        IVorbaIdFactory factory, Vobject root) {
+      Unmarshaller unmarshaller = new Unmarshaller(root);
       unmarshaller.setIDResolver(new IDResolver() {
         public Object resolve(String id) {
           System.err.println("Warning - id " + id
@@ -156,25 +192,11 @@ public class VorbaXmlBinder implements UnmarshalListener {
       try {
         while (instream.ready()) {
           Object obj = unmarshaller.unmarshal(instream);
-          boolean sync=true;
-          if (obj instanceof VamsasDocument) {
-            if (unrefed.size()>0) {
-              sync=false; // document is out of sync - ids have been created.
-              java.util.Iterator newobj = unrefed.listIterator();
-              while (newobj.hasNext()) {
-                object o = (object) newobj.next();
-                // forces registration and id field update.
-                VorbaId id = o.getVorbaId();
-                if (!objrefs.containsKey(id)) {
-                  objrefs.put(id.id, o);
-                } else {
-                  throw new Error("Serious! Duplicate reference made by vorbaIdFactory!");
-                }
-              }
-            }
-            return new Object[] { obj, objrefs, new Boolean(sync)};
+          boolean sync=ensure_references(unrefed, objrefs);
+          if (!(obj instanceof Vobject))
+            return null;
+          return new Object[] { obj, objrefs, new Boolean(sync)};
           }
-        }
       } catch (MarshalException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();