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.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
+ * 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 extends GeneralizedFieldHandler implements UnmarshalListener, MarshalListener {
+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;
-
- public VorbaXmlBinder(IVorbaIdFactory vorbafactory, Vector obj, Hashtable objrefs) {
+ private final Vector updatedobjs;
+
+ public VorbaXmlBinder(IVorbaIdFactory vorbafactory, Vector obj, Hashtable objrefs, Hashtable oldobjhashes, Vector updatedobjs) {
this.vorbafactory = vorbafactory;
this.obj = obj;
this.objrefs = objrefs;
+ this.oldobjhashes = oldobjhashes;
+ this.updatedobjs = updatedobjs;
}
/*
* 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);
+ }
+ }
}
/*
/*
* 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()) {
+ if (nobj.isRegisterable() && nobj.___id_field!=null) {
+ VorbaId nobj_id=null;
// look for the id field (should be an NCName string)
nobj.__vorba = vorbafactory;
- fd = nobj.getClass().getField("id");
- String idstring;
- if (fd.get(nobj) != null) {
- idstring = (String) fd.get(nobj);
+ // use the Vobject accessor method to avoid unpleasant security exceptions.
+ String idstring = nobj.__getInstanceIdField();
+ if (idstring!=null) {
if (idstring.length() > 0) {
- if (!objrefs.containsKey(idstring)) {
- objrefs.put(idstring, nobj);
- nobj.setVorbaId(VorbaId.newId(idstring));
- } else {
+ nobj.setVorbaId(VorbaId.newId(idstring));
+ if (objrefs.containsKey(nobj_id=nobj.getVorbaId()) && !objrefs.get(nobj.getVorbaId()).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 {
- // add to list of objects without a valid vorbaId
+ // TODO: add to list of objects without a valid vorbaId
obj.add(nobj);
}
nobj.doHash();
+ // check to see if new object was present in old object hash
+ if (oldobjhashes.containsKey(nobj.getVorbaId())) {
+ Vobjhash oldhash = (Vobjhash) oldobjhashes.get(nobj.getVorbaId());
+ if (oldhash.isUpdated(nobj)) {
+ // mark the object as updated in this document read.
+ nobj.set__updated_since_last_read(true);
+ oldobjhashes.put(nobj_id, new Vobjhash(nobj));
+ updatedobjs.addElement(nobj);
+ }
+ }
}
} catch (Exception e) {
return;
throws IOException, MarshalException, ValidationException {
// Ensure references
if (vorba==null)
- throw new Error("Null VorbaIdVactory Parameter");
+ 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 ?
- final Vector refstomake = new Vector();
- VorbaXmlBinder binder = new VorbaXmlBinder(vorba, refstomake, vorba.extantids);
- Marshaller marshaller = new Marshaller(outstream);
- marshaller.setMarshalAsDocument(true);
- marshaller.setMarshalListener(binder);
- marshaller.marshal(doc);
+ doc.marshal(outstream);
+
}
-
+ /**
+ * 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()) {
- object o = (object) newobj.next();
+ Vobject o = (Vobject) newobj.next();
// forces registration and id field update.
VorbaId id = o.getVorbaId();
if (!objrefs.containsKey(id)) {
- objrefs.put(id.id, o);
+ objrefs.put(id, o);
} else {
- throw new Error("Serious! Duplicate reference made by vorbaIdFactory!");
+ if (!objrefs.get(id).equals(o))
+ 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
+ * 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 org.vamsas.objects.core object.
- * @return null or {(Object) VamsasDocument object, (Object) Hashtable of object references, (Object) Boolean(sync) }
+ * @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), (Object) Vector of updated objects in document }
*/
public static Object[] getVamsasObjects(Reader instream,
- IVorbaIdFactory factory, object root) {
- Unmarshaller unmarshaller = new Unmarshaller(root);
+ VorbaIdFactory factory, Vobject root) {
+ Unmarshaller unmarshaller = new Unmarshaller(root);
unmarshaller.setIDResolver(new IDResolver() {
public Object resolve(String id) {
- System.err.println("Warning - id " + id
- + " is not found in the VamsasDocument!");
+ VorbaXmlBinder.log.warn("Warning - id " + id
+ + " is not found in the Vamsas XML!");
return null;
}
});
- Hashtable refbase = new Hashtable();
- Vector unrefed = new Vector();
- final Hashtable objrefs = refbase;
- final IVorbaIdFactory vorbafactory = factory;
- final Vector unrefedObj = unrefed;
- unmarshaller.setUnmarshalListener(new VorbaXmlBinder(vorbafactory, unrefedObj, objrefs));
+ 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(unrefed, objrefs);
- if (!(obj instanceof object))
+ boolean sync=ensure_references(unrefedObj, objrefs);
+ if (!(obj instanceof Vobject))
return null;
- return new Object[] { obj, objrefs, new Boolean(sync)};
+ 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
}
return null;
}
-
- /* (non-Javadoc)
- * @see org.exolab.castor.xml.MarshalListener#postMarshal(java.lang.Object)
- */
- public void postMarshal(Object object) {
- // TODO Auto-generated method stub
-
- }
-
- /* (non-Javadoc)
- * @see org.exolab.castor.xml.MarshalListener#preMarshal(java.lang.Object)
- */
- public boolean preMarshal(Object newobj) {
- if (newobj instanceof object) {
- object nobj = (object) newobj;
- nobj.set__stored_in_document(true);
- Field fd = null;
- try {
- if (nobj.isRegisterable()) {
- // make sure the id field is set
- nobj.__vorba = vorbafactory;
- fd = nobj.getClass().getField("_id");
- if (fd.get(nobj) != null) {
- fd.set(nobj, nobj.getVorbaId().getId());
- /* all thats needed perhaps
- *
- *if (idstring.length() > 0) {
- if (!objrefs.containsKey(idstring)) {
- objrefs.put(idstring, nobj);
- nobj.setVorbaId(VorbaId.newId(idstring));
- } else {
- System.err.println("Serious problem : duplicate id '"+idstring+"' found! expect badness.");
- return false; // TODO: HANDLE duplicate XML ids correctly
- }*/
- }
- }
- } catch (Exception e) {
- return false;
- };
-
- }
- return false;
- }
-
- /* (non-Javadoc)
- * @see org.exolab.castor.mapping.GeneralizedFieldHandler#convertUponGet(java.lang.Object)
- */
- public Object convertUponGet(Object value) {
- // TODO Auto-generated method stub
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.exolab.castor.mapping.GeneralizedFieldHandler#convertUponSet(java.lang.Object)
- */
- public Object convertUponSet(Object value) {
- // TODO Auto-generated method stub
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.exolab.castor.mapping.GeneralizedFieldHandler#getFieldType()
- */
- public Class getFieldType() {
- // TODO Auto-generated method stub
- return null;
- }
-
- /* (non-Javadoc)
- * @see org.exolab.castor.mapping.GeneralizedFieldHandler#newInstance(java.lang.Object, java.lang.Object[])
- */
- public Object newInstance(Object parent, Object[] args) throws IllegalStateException {
- // TODO Auto-generated method stub
- return super.newInstance(parent, args);
- }
-
- /* (non-Javadoc)
- * @see org.exolab.castor.mapping.GeneralizedFieldHandler#newInstance(java.lang.Object)
- */
- public Object newInstance(Object parent) throws IllegalStateException {
- // TODO Auto-generated method stub
- return super.newInstance(parent);
- }
-
- /* (non-Javadoc)
- * @see org.exolab.castor.mapping.GeneralizedFieldHandler#setCollectionIteration(boolean)
- */
- public void setCollectionIteration(boolean autoCollectionIteration) {
- // TODO Auto-generated method stub
- super.setCollectionIteration(autoCollectionIteration);
- }
-
- /* (non-Javadoc)
- * @see org.exolab.castor.mapping.AbstractFieldHandler#hasValue(java.lang.Object)
- */
- public boolean hasValue(Object object) {
- // TODO Auto-generated method stub
- return super.hasValue(object);
- }
}
\ No newline at end of file