4 package org.vamsas.client;
6 import java.io.IOException;
7 import java.io.PrintWriter;
10 import java.lang.reflect.Field;
11 import java.util.Hashtable;
12 import java.util.Iterator;
13 import java.util.Vector;
15 import org.exolab.castor.mapping.FieldHandler;
16 import org.exolab.castor.mapping.GeneralizedFieldHandler;
17 import org.exolab.castor.mapping.ValidityException;
18 import org.exolab.castor.xml.IDResolver;
19 import org.exolab.castor.xml.MarshalException;
20 import org.exolab.castor.xml.MarshalListener;
21 import org.exolab.castor.xml.Marshaller;
22 import org.exolab.castor.xml.UnmarshalListener;
23 import org.exolab.castor.xml.Unmarshaller;
24 import org.exolab.castor.xml.ValidationException;
25 import org.vamsas.objects.core.VamsasDocument;
27 * Implements the Vamsas Vobject ID machinery for translating
28 * between non-volatile XML IDs and Vobject references. Use the
29 * marshalling and unmarshalling methods in this class in order
30 * to avoid validation exceptions when marshalling new objects
31 * into the vamsas document.
33 public class VorbaXmlBinder implements UnmarshalListener {
34 private final IVorbaIdFactory vorbafactory;
36 private final Vector obj;
38 private final Hashtable objrefs;
40 public VorbaXmlBinder(IVorbaIdFactory vorbafactory, Vector obj, Hashtable objrefs) {
41 this.vorbafactory = vorbafactory;
43 this.objrefs = objrefs;
49 * @see org.exolab.castor.xml.UnmarshalListener#attributesProcessed(java.lang.Object)
51 public void attributesProcessed(Object object) {
57 * @see org.exolab.castor.xml.UnmarshalListener#fieldAdded(java.lang.String,
58 * java.lang.Object, java.lang.Object)
60 public void fieldAdded(String fieldName, Object parent, Object child) {
61 if (parent instanceof Vobject && child instanceof Vobject) {
62 if (((Vobject) child).V_parent==null) {
63 // System.err.println("Setting parent of "+fieldName);
64 ((Vobject) child).setV_parent((Vobject) parent);
72 * @see org.exolab.castor.xml.UnmarshalListener#initialized(java.lang.Object)
74 public void initialized(Object object) {
78 * Check if the object has an 'id' field - if it does, copy the value into
79 * the VorbaId field of Vobject, and add the Vobject to the VorbaId hash.
81 * @see org.exolab.castor.xml.UnmarshalListener#unmarshalled(java.lang.Object)
83 public void unmarshalled(Object newobj) {
84 if (newobj instanceof Vobject) {
85 Vobject nobj = (Vobject) newobj;
86 nobj.set__stored_in_document(true);
88 if (nobj.isRegisterable() && nobj.___id_field!=null) {
89 // look for the id field (should be an NCName string)
90 nobj.__vorba = vorbafactory;
91 // use the Vobject accessor method to avoid unpleasant security exceptions.
92 String idstring = nobj.__getInstanceIdField();
94 if (idstring.length() > 0) {
95 nobj.setVorbaId(VorbaId.newId(idstring));
96 if (objrefs.containsKey(nobj.getVorbaId()) && !objrefs.get(nobj.getVorbaId()).equals(nobj)) {
97 System.err.println("Serious problem : duplicate id '"+idstring+"' found! expect badness.");
98 // TODO: HANDLE duplicate XML ids correctly
100 objrefs.put(nobj.getVorbaId(), nobj);
102 // add to list of objects without a valid vorbaId
106 // TODO: add to list of objects without a valid vorbaId
112 } catch (Exception e) {
120 * writes the VamsasDocument to the given stream.
121 * TODO: ensure that (at least) default provenance entries are written for objects.
123 * @param vorba valid VorbaIdFactory to construct any missing IDs
125 * @throws IOException
126 * @throws MarshalException
127 * @throws ValidationException
129 public static void putVamsasDocument(PrintWriter outstream, VorbaIdFactory vorba, VamsasDocument doc)
130 throws IOException, MarshalException, ValidationException {
133 throw new Error("Null VorbaIdVactory Parameter");
134 if (doc.__vorba==null)
136 doc.__ensure_instance_ids(); // this may take a while. Do we allow for cyclic references ?
137 doc.marshal(outstream);
140 private static boolean ensure_references(Vector unrefed, Hashtable objrefs) {
142 if (unrefed.size()>0) {
143 sync=false; // document is out of sync - ids have been created.
144 java.util.Iterator newobj = unrefed.listIterator();
145 while (newobj.hasNext()) {
146 Vobject o = (Vobject) newobj.next();
147 // forces registration and id field update.
148 VorbaId id = o.getVorbaId();
149 if (!objrefs.containsKey(id)) {
152 if (!objrefs.get(id).equals(o))
153 throw new Error("Serious! Duplicate reference made by vorbaIdFactory!");
160 * Unmarshals a vamsasDocument Vobject from a stream, registers
161 * unregistered objects, records existing VorbaIds, and completes
162 * the org.vamsas.client.Vobject housekeeping fields.
163 * For a valid unmarshalling, the array of returned objects also includes
164 * a <return>sync</return> parameter which is true if new VorbaIds
165 * were created. If sync is false, then the caller should ensure that the
166 * vamsasDocument is written back to disk to propagate the new VorbaIds.
167 * TODO: ensure that provenance is correct for newly registered objects
168 * @param instream - the XML input stream
169 * @param factory - the SimpleClient's properly configured VorbaId factory to make new references.
170 * @param root the root element's org.vamsas.objects.core Vobject.
171 * @return null or {(Object) VamsasDocument Vobject, (Object) Hashtable of Vobject references, (Object) Boolean(sync) }
173 public static Object[] getVamsasObjects(Reader instream,
174 VorbaIdFactory factory, Vobject root) {
175 Unmarshaller unmarshaller = new Unmarshaller(root);
176 unmarshaller.setIDResolver(new IDResolver() {
177 public Object resolve(String id) {
178 System.err.println("Warning - id " + id
179 + " is not found in the VamsasDocument!");
183 Hashtable refbase = new Hashtable();
184 Vector unrefed = new Vector();
185 final Hashtable objrefs = refbase;
186 final VorbaIdFactory vorbafactory = factory;
187 final Vector unrefedObj = unrefed;
188 unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory, unrefedObj, objrefs));
189 // Call the unmarshaller.
191 while (instream.ready()) {
192 Object obj = unmarshaller.unmarshal(instream);
193 boolean sync=ensure_references(unrefed, objrefs);
194 if (!(obj instanceof Vobject))
196 vorbafactory.setNewIdHash(objrefs); // update the Document IO Handler's set of vorbaId<>Object bindings.
197 return new Object[] { obj, objrefs, new Boolean(sync)};
199 } catch (MarshalException e) {
200 // TODO Auto-generated catch block
202 } catch (ValidationException e) {
203 // TODO Auto-generated catch block
205 } catch (IOException e) {
206 // TODO Auto-generated catch block