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 object ID machinery for translating
28 * between non-volatile XML IDs and object 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 extends GeneralizedFieldHandler implements UnmarshalListener, MarshalListener {
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) {
66 * @see org.exolab.castor.xml.UnmarshalListener#initialized(java.lang.Object)
68 public void initialized(Object object) {
72 * Check if the object has an 'id' field - if it does, copy the value into
73 * the VorbaId field of object, and add the object to the VorbaId hash.
75 * @see org.exolab.castor.xml.UnmarshalListener#unmarshalled(java.lang.Object)
77 public void unmarshalled(Object newobj) {
78 if (newobj instanceof object) {
79 object nobj = (object) newobj;
80 nobj.set__stored_in_document(true);
83 if (nobj.isRegisterable()) {
84 // look for the id field (should be an NCName string)
85 nobj.__vorba = vorbafactory;
86 fd = nobj.getClass().getField("id");
88 if (fd.get(nobj) != null) {
89 idstring = (String) fd.get(nobj);
90 if (idstring.length() > 0) {
91 if (!objrefs.containsKey(idstring)) {
92 objrefs.put(idstring, nobj);
93 nobj.setVorbaId(VorbaId.newId(idstring));
95 System.err.println("Serious problem : duplicate id '"+idstring+"' found! expect badness.");
96 // TODO: HANDLE duplicate XML ids correctly
99 // add to list of objects without a valid vorbaId
103 // add to list of objects without a valid vorbaId
109 } catch (Exception e) {
117 * writes the VamsasDocument to the given stream.
118 * TODO: ensure that (at least) default provenance entries are written for objects.
120 * @param vorba valid VorbaIdFactory to construct any missing IDs
122 * @throws IOException
123 * @throws MarshalException
124 * @throws ValidationException
126 public static void putVamsasDocument(PrintWriter outstream, VorbaIdFactory vorba, VamsasDocument doc)
127 throws IOException, MarshalException, ValidationException {
130 throw new Error("Null VorbaIdVactory Parameter");
131 if (doc.__vorba==null)
133 doc.__ensure_instance_ids(); // this may take a while. Do we allow for cyclic references ?
134 final Vector refstomake = new Vector();
135 VorbaXmlBinder binder = new VorbaXmlBinder(vorba, refstomake, vorba.extantids);
136 Marshaller marshaller = new Marshaller(outstream);
137 marshaller.setMarshalAsDocument(true);
138 marshaller.setMarshalListener(binder);
139 marshaller.marshal(doc);
142 private static boolean ensure_references(Vector unrefed, Hashtable objrefs) {
144 if (unrefed.size()>0) {
145 sync=false; // document is out of sync - ids have been created.
146 java.util.Iterator newobj = unrefed.listIterator();
147 while (newobj.hasNext()) {
148 object o = (object) newobj.next();
149 // forces registration and id field update.
150 VorbaId id = o.getVorbaId();
151 if (!objrefs.containsKey(id)) {
152 objrefs.put(id.id, o);
154 throw new Error("Serious! Duplicate reference made by vorbaIdFactory!");
161 * Unmarshals a vamsasDocument object from a stream, registers
162 * unregistered objects, records existing VorbaIds, and completes
163 * the org.vamsas.client.object housekeeping fields.
164 * For a valid unmarshalling, the array of returned objects also includes
165 * a <return>sync</return> parameter which is true if new VorbaIds
166 * were created. If sync is false, then the caller should ensure that the
167 * vamsasDocument is written back to disk to propagate the new VorbaIds.
168 * TODO: ensure that provenance is correct for newly registered objects
169 * @param instream - the XML input stream
170 * @param factory - the SimpleClient's properly configured VorbaId factory to make new references.
171 * @param root the root element's org.vamsas.objects.core object.
172 * @return null or {(Object) VamsasDocument object, (Object) Hashtable of object references, (Object) Boolean(sync) }
174 public static Object[] getVamsasObjects(Reader instream,
175 IVorbaIdFactory factory, object root) {
176 Unmarshaller unmarshaller = new Unmarshaller(root);
177 unmarshaller.setIDResolver(new IDResolver() {
178 public Object resolve(String id) {
179 System.err.println("Warning - id " + id
180 + " is not found in the VamsasDocument!");
184 Hashtable refbase = new Hashtable();
185 Vector unrefed = new Vector();
186 final Hashtable objrefs = refbase;
187 final IVorbaIdFactory vorbafactory = factory;
188 final Vector unrefedObj = unrefed;
189 unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory, unrefedObj, objrefs));
190 // Call the unmarshaller.
192 while (instream.ready()) {
193 Object obj = unmarshaller.unmarshal(instream);
194 boolean sync=ensure_references(unrefed, objrefs);
195 if (!(obj instanceof object))
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
213 * @see org.exolab.castor.xml.MarshalListener#postMarshal(java.lang.Object)
215 public void postMarshal(Object object) {
216 // TODO Auto-generated method stub
221 * @see org.exolab.castor.xml.MarshalListener#preMarshal(java.lang.Object)
223 public boolean preMarshal(Object newobj) {
224 if (newobj instanceof object) {
225 object nobj = (object) newobj;
226 nobj.set__stored_in_document(true);
229 if (nobj.isRegisterable()) {
230 // make sure the id field is set
231 nobj.__vorba = vorbafactory;
232 fd = nobj.getClass().getField("_id");
233 if (fd.get(nobj) != null) {
234 fd.set(nobj, nobj.getVorbaId().getId());
235 /* all thats needed perhaps
237 *if (idstring.length() > 0) {
238 if (!objrefs.containsKey(idstring)) {
239 objrefs.put(idstring, nobj);
240 nobj.setVorbaId(VorbaId.newId(idstring));
242 System.err.println("Serious problem : duplicate id '"+idstring+"' found! expect badness.");
243 return false; // TODO: HANDLE duplicate XML ids correctly
247 } catch (Exception e) {
256 * @see org.exolab.castor.mapping.GeneralizedFieldHandler#convertUponGet(java.lang.Object)
258 public Object convertUponGet(Object value) {
259 // TODO Auto-generated method stub
264 * @see org.exolab.castor.mapping.GeneralizedFieldHandler#convertUponSet(java.lang.Object)
266 public Object convertUponSet(Object value) {
267 // TODO Auto-generated method stub
272 * @see org.exolab.castor.mapping.GeneralizedFieldHandler#getFieldType()
274 public Class getFieldType() {
275 // TODO Auto-generated method stub
280 * @see org.exolab.castor.mapping.GeneralizedFieldHandler#newInstance(java.lang.Object, java.lang.Object[])
282 public Object newInstance(Object parent, Object[] args) throws IllegalStateException {
283 // TODO Auto-generated method stub
284 return super.newInstance(parent, args);
288 * @see org.exolab.castor.mapping.GeneralizedFieldHandler#newInstance(java.lang.Object)
290 public Object newInstance(Object parent) throws IllegalStateException {
291 // TODO Auto-generated method stub
292 return super.newInstance(parent);
296 * @see org.exolab.castor.mapping.GeneralizedFieldHandler#setCollectionIteration(boolean)
298 public void setCollectionIteration(boolean autoCollectionIteration) {
299 // TODO Auto-generated method stub
300 super.setCollectionIteration(autoCollectionIteration);
304 * @see org.exolab.castor.mapping.AbstractFieldHandler#hasValue(java.lang.Object)
306 public boolean hasValue(Object object) {
307 // TODO Auto-generated method stub
308 return super.hasValue(object);