From 1f066b7b070342e9a41189e039e80d2fefb57976 Mon Sep 17 00:00:00 2001 From: jprocter Date: Mon, 16 Jan 2006 20:05:03 +0000 Subject: [PATCH] minimally debugged idFactory and vorbaId mechanism. Inelegant! git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@138 be28352e-c001-0410-b1a7-c7978e42abec --- src/org/vamsas/client/SessionHandle.java | 7 + src/org/vamsas/client/VorbaIdFactory.java | 22 +++ src/org/vamsas/client/VorbaXmlBinder.java | 170 +++++++++++++++++--- src/org/vamsas/client/object.java | 141 ++++++++++++++-- src/org/vamsas/client/simpleclient/IdFactory.java | 137 ++++++++++++++++ .../vamsas/client/simpleclient/VamsasArchive.java | 125 ++++++++++---- src/org/vamsas/objects/utils/Seq.java | 1 - .../vamsas/test/simpleclient/VamsasArchive.java | 14 +- 8 files changed, 549 insertions(+), 68 deletions(-) create mode 100644 src/org/vamsas/client/simpleclient/IdFactory.java diff --git a/src/org/vamsas/client/SessionHandle.java b/src/org/vamsas/client/SessionHandle.java index 1c26bfe..736fee3 100644 --- a/src/org/vamsas/client/SessionHandle.java +++ b/src/org/vamsas/client/SessionHandle.java @@ -12,6 +12,13 @@ package org.vamsas.client; public class SessionHandle { /** + * @param sessionUrn + */ + public SessionHandle(String sessionUrn) { + super(); + SessionUrn = sessionUrn; + } + /** * @return Returns the sessionUrn. */ public String getSessionUrn() { diff --git a/src/org/vamsas/client/VorbaIdFactory.java b/src/org/vamsas/client/VorbaIdFactory.java index ece1357..335c710 100644 --- a/src/org/vamsas/client/VorbaIdFactory.java +++ b/src/org/vamsas/client/VorbaIdFactory.java @@ -6,6 +6,8 @@ */ package org.vamsas.client; +import java.util.Hashtable; + /** * A VorbaIdFactory is constructed by an IClient instance. * It guarantees that any new VorbaId objects are unique @@ -14,6 +16,7 @@ package org.vamsas.client; * @author jimp */ public abstract class VorbaIdFactory implements IVorbaIdFactory { + protected Hashtable extantids=null; /** * construct a new id appropriate for this client in the vamsas session. * @@ -21,6 +24,25 @@ public abstract class VorbaIdFactory implements IVorbaIdFactory { * correctly. */ public abstract VorbaId makeVorbaId(); + + /** + * internal method to access the protected VorbaId object constructor + * This shennanigan is to prevent casual generation of VorbaIds + * (which may destroy the integrity of a Vamsas Document!) + * @param id + * @return new VorbaId object + */ + protected VorbaId newId(String id) { + return VorbaId.newId(id); + } + /** + * Called by VorbaXmlBinder so the record of newly unmarshalled object Ids + * is accessible to the Document's VorbaIdFactory instance. + * @param idtable + */ + protected void setNewIdHash(Hashtable idtable) { + extantids = idtable; + } /** * TODO: decide if these are needed. * diff --git a/src/org/vamsas/client/VorbaXmlBinder.java b/src/org/vamsas/client/VorbaXmlBinder.java index 9fc6965..ec6c7f4 100644 --- a/src/org/vamsas/client/VorbaXmlBinder.java +++ b/src/org/vamsas/client/VorbaXmlBinder.java @@ -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,8 +12,12 @@ 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; @@ -25,7 +30,7 @@ import org.vamsas.objects.core.VamsasDocument; * to avoid validation exceptions when marshalling new objects * into the vamsas document. */ -public class VorbaXmlBinder implements UnmarshalListener { +public class VorbaXmlBinder extends GeneralizedFieldHandler implements UnmarshalListener, MarshalListener { private final IVorbaIdFactory vorbafactory; private final Vector obj; @@ -62,7 +67,7 @@ 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. @@ -112,17 +117,46 @@ 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 { + // 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 ? + 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); } + 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(); + // 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 * unregistered objects, records existing VorbaIds, and completes @@ -133,12 +167,13 @@ public class VorbaXmlBinder implements UnmarshalListener { * 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. + * @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) } */ - public static Object[] getVamsasDocument(Reader instream, - IVorbaIdFactory factory) { - Unmarshaller unmarshaller = new Unmarshaller(instream); + public static Object[] getVamsasObjects(Reader instream, + IVorbaIdFactory factory, object root) { + Unmarshaller unmarshaller = new Unmarshaller(root); unmarshaller.setIDResolver(new IDResolver() { public Object resolve(String id) { System.err.println("Warning - id " + id @@ -156,25 +191,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 object)) + return null; + return new Object[] { obj, objrefs, new Boolean(sync)}; } - } } catch (MarshalException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -187,4 +208,103 @@ public class VorbaXmlBinder implements UnmarshalListener { } 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 diff --git a/src/org/vamsas/client/object.java b/src/org/vamsas/client/object.java index 040222a..6498d70 100644 --- a/src/org/vamsas/client/object.java +++ b/src/org/vamsas/client/object.java @@ -3,6 +3,18 @@ */ package org.vamsas.client; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Iterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.exolab.castor.mapping.FieldDescriptor; +import org.exolab.castor.mapping.FieldHandler; +import org.exolab.castor.xml.util.XMLClassDescriptorImpl; +import org.vamsas.test.simpleclient.VamsasArchive; + /** * Base class for all Vamsas objects extracted from an IClientDocument. An * object maybe registered or unregistered. @@ -11,7 +23,8 @@ package org.vamsas.client; * */ public abstract class object { - + static Log log = LogFactory.getLog(object.class); + /** * unique id for all vamsas objects allows unambiguous referencing to any * object in the vamsas document @@ -40,11 +53,10 @@ public abstract class object { */ private void testInstanceForIdField() { // look for the id field (should be an NCName string) - // TODO: decide if 'id' is an appropriate reserved attribute name for the - // VorbaId + // TODO: decide if 'id' is an appropriate reserved attribute name for the VorbaId try { - java.lang.reflect.Field fd = this.getClass().getField("id"); - if (fd.getType().getClass().equals("astring".getClass())) { + java.lang.reflect.Field fd = this.getClass().getDeclaredField("_id"); + if (String.class.isAssignableFrom(fd.getType())) { this.setRegisterable(true); } } catch (SecurityException e) { @@ -60,19 +72,27 @@ public abstract class object { */ protected void setInstanceIdField() { if (registerable) { - if (vorbaId != null) + if (__vorba != null) try { - java.lang.reflect.Field fd = this.getClass().getField("id"); - fd.set((Object) this, (Object) new String(vorbaId.id)); - } catch (IllegalAccessException e) { + Method fd = this.getClass().getMethod("setId", new Class[] { String.class }); + fd.invoke((Object) this, new Object[] {new String(this.getVorbaId().id)}); + log.info(this.getClass().getName()+" called setInstanceIdField!"); + } catch (InvocationTargetException e) { + System.err + .println("SourceGeneration of " + + this.getClass().toString() + + "\n has resulted in an inaccessible 'setId' method!\nCannot set ID from the vorbaId object."); + e.printStackTrace(System.err); + } + catch (IllegalAccessException e) { System.err .println("SourceGeneration of " + this.getClass().toString() - + "\n has resulted in an inaccessible 'id' field!\nCannot set ID from the vorbaId object."); + + "\n has resulted in an inaccessible 'setId' method!\nCannot set ID from the vorbaId object."); e.printStackTrace(System.err); } catch (SecurityException e) { e.printStackTrace(System.err); - } catch (NoSuchFieldException e) { + } catch (NoSuchMethodException e) { this.setRegisterable(false); } } else { @@ -193,4 +213,103 @@ public abstract class object { protected void setRegisterable(boolean registerable) { this.registerable = registerable; } + /** + * ensure's internal id field corresponds to vorbaId and + * cascade through all fields referring to an instance of object + * calling the same method on them. + * TODO: LATER: properly apply castors own field mechanisms to get at accessors + * + */ + protected void __ensure_instance_ids() { + if (__vorba==null) + throw new Error("Improperly intialised org.vamsas.client.object - no VorbaFactory given."); + log.info(this.getClass()+".__ensure_instance_ids()"); + if (!__stored_in_document && registerable) + setInstanceIdField(); + Class descriptor = null; + XMLClassDescriptorImpl descimpl = null; + try { + // castor descriptor resolver magic + descriptor = this.getClass().getClassLoader().loadClass(this.getClass().getName()+"Descriptor"); + descimpl = (XMLClassDescriptorImpl) descriptor.getConstructor(null).newInstance(null); + } catch (Exception e) { + log.error("Couldn't resolve descriptor for "+this.getClass().getName()); + return; + } + FieldDescriptor fields[] = descimpl.getFields(); + for (int i=0,j=fields.length; i