fixed the User element and the form of the ApplicationData dataType.xsd definition.
[vamsas.git] / src / org / vamsas / client / object.java
1 /**
2  * 
3  */
4 package org.vamsas.client;
5
6 import java.lang.reflect.Field;
7 import java.lang.reflect.InvocationTargetException;
8 import java.lang.reflect.Method;
9 import java.util.Iterator;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.exolab.castor.mapping.FieldDescriptor;
14 import org.exolab.castor.mapping.FieldHandler;
15 import org.exolab.castor.xml.util.XMLClassDescriptorImpl;
16 import org.vamsas.test.simpleclient.VamsasArchive;
17
18 /**
19  * Base class for all Vamsas objects extracted from an IClientDocument. An
20  * object maybe registered or unregistered.
21  * 
22  * @author jimp
23  * 
24  */
25 public abstract class object {
26   static Log log = LogFactory.getLog(object.class);
27   
28   /**
29    * unique id for all vamsas objects allows unambiguous referencing to any
30    * object in the vamsas document
31    */
32   protected boolean __stored_in_document = false;
33
34   protected long __last_hash = 0;
35
36   protected boolean registerable = false;
37
38   protected VorbaId vorbaId = null;
39
40   protected IVorbaIdFactory __vorba = null;
41
42   /**
43    * 
44    */
45   protected object() {
46     super();
47     testInstanceForIdField();
48   }
49
50   /**
51    * set the isRegisterable flag based on the presence of a 'String id' field in
52    * the reflected class instance.
53    */
54   private void testInstanceForIdField() {
55     // look for the id field (should be an NCName string)
56     // TODO: decide if 'id' is an appropriate reserved attribute name for the VorbaId
57     try {
58       java.lang.reflect.Field fd = this.getClass().getDeclaredField("_id");
59       if (String.class.isAssignableFrom(fd.getType())) {
60         this.setRegisterable(true);
61       }
62     } catch (SecurityException e) {
63       e.printStackTrace();
64     } catch (NoSuchFieldException e) {
65       this.setRegisterable(false);
66     }
67   }
68
69   /**
70    * update the object instance's String id field, based on the contents of the
71    * VorbaId. Only call this if you mean to do it!
72    */
73   protected void setInstanceIdField() {
74     if (registerable) {
75       if (__vorba != null)
76         try {
77           Method fd = this.getClass().getMethod("setId", new Class[] { String.class });
78           fd.invoke((Object) this, new Object[] {new String(this.getVorbaId().id)});
79           log.info(this.getClass().getName()+" called setInstanceIdField!");
80         } catch (InvocationTargetException e) { 
81           System.err
82           .println("SourceGeneration of "
83               + this.getClass().toString()
84               + "\n has resulted in an inaccessible 'setId' method!\nCannot set ID from the vorbaId object.");
85           e.printStackTrace(System.err);
86         }
87         catch (IllegalAccessException e) {
88           System.err
89               .println("SourceGeneration of "
90                   + this.getClass().toString()
91                   + "\n has resulted in an inaccessible 'setId' method!\nCannot set ID from the vorbaId object.");
92           e.printStackTrace(System.err);
93         } catch (SecurityException e) {
94           e.printStackTrace(System.err);
95         } catch (NoSuchMethodException e) {
96           this.setRegisterable(false);
97         }
98     } else {
99       System.err.println("Client error. Trying to setInstanceIdField on a "
100           + this.getClass().toString() + " (which cannot be given a vorbaId)");
101     }
102   }
103
104   /**
105    * calculate a hash for the object with all housekeeping fields at standard
106    * values. (isRegisterable is an immutable attribute property)
107    */
108   synchronized protected void doHash() {
109     __last_hash = 0;
110     VorbaId thisid = vorbaId;
111     IVorbaIdFactory factory = __vorba;
112     boolean stored = __stored_in_document;
113     vorbaId = null;
114     __vorba = null;
115     __last_hash = this.hashCode();
116     vorbaId = thisid;
117     __vorba = factory;
118     __stored_in_document = stored;
119   }
120
121   /**
122    * TODO: combine two versions of the same collection object to resolve
123    * asynchronous updates to the same vamsas object Merges two vamsas objects,
124    * one of which is a later version of the earlier (ie they have the same
125    * vorbaId but one is a later version recently read from the vamsasDocument
126    * collection.
127    * 
128    * @return
129    */
130   protected boolean merge(object laterCopy) {
131     return true;
132   }
133
134   /**
135    * 
136    * @return true if object is registered
137    */
138   public boolean isRegistered() {
139     return (registerable) ? (vorbaId != null) : false;
140   }
141
142   /**
143    * Method to get fixed reference for the object in the vamsas document.
144    * 
145    * @returns null if object is neither registered or not associated with a
146    *          properly instantiated VorbaIdFactory.
147    */
148   public VorbaId getVorbaId() {
149     if (registerable && vorbaId == null) {
150       // Try to use the associated factory.
151       if (__vorba != null)
152         if ((vorbaId = __vorba.makeVorbaId()) == null)
153           return null; // Factory not valid.
154         else {
155           this.setInstanceIdField();
156           return vorbaId;
157         }
158     }
159     return vorbaId;
160   }
161
162   /**
163    * used by the IClient implementation to generate unique Id based on client
164    * applications current namespace.
165    */
166   protected void setVorbaId(VorbaId newid) {
167     vorbaId = newid;
168   }
169
170   /**
171    * @return true if object is present in Vamsas Document.
172    */
173   public boolean is__stored_in_document() {
174     return __stored_in_document;
175   }
176
177   /**
178    * for use by Vorba agent to reflect state of vamsas object to client
179    * application.
180    * 
181    * @param __stored_in_document
182    *          The __stored_in_document to set.
183    */
184   protected void set__stored_in_document(boolean __stored_in_document) {
185     this.__stored_in_document = __stored_in_document;
186   }
187
188   /**
189    * __last_hash is the hash value computed when the object was last checked
190    * against a IClientDocument generated by the object's parent IClient
191    * instance.
192    * 
193    * @return Returns the __last_hash.
194    */
195   public long get__last_hash() {
196     return __last_hash;
197   }
198
199   /**
200    * @return Returns the registerable.
201    */
202   public boolean isRegisterable() {
203     return registerable;
204   }
205
206   /**
207    * Called during unmarshalling - if object has an id string, it is
208    * registerable.
209    * 
210    * @param registerable
211    *          The registerable to set.
212    */
213   protected void setRegisterable(boolean registerable) {
214     this.registerable = registerable;
215   }
216   /**
217    * ensure's internal id field corresponds to vorbaId and
218    * cascade through all fields referring to an instance of object
219    * calling the same method on them.
220    * TODO: LATER: properly apply castors own field mechanisms to get at accessors
221    * TODO: FIX CYCLIC __ensure+instance_ids
222    */
223   protected void __ensure_instance_ids() {
224     if (__vorba==null)
225       throw new Error("Improperly intialised org.vamsas.client.object - no VorbaFactory given.");
226     log.info(this.getClass()+".__ensure_instance_ids()");
227     if (!__stored_in_document && registerable)
228       setInstanceIdField();
229     Class descriptor = null;
230     XMLClassDescriptorImpl descimpl = null;
231     try {
232       // castor descriptor resolver magic
233       descriptor = this.getClass().getClassLoader().loadClass(this.getClass().getName()+"Descriptor");
234       descimpl = (XMLClassDescriptorImpl) descriptor.getConstructor(null).newInstance(null);
235     } catch (Exception e) {
236       log.error("Couldn't resolve descriptor for "+this.getClass().getName());
237       return;
238     }
239     FieldDescriptor fields[] = descimpl.getFields();
240     for (int i=0,j=fields.length; i<j; i++) {
241       Class type= fields[i].getFieldType();
242       if (type.isArray()) {
243         if (object[].class.isAssignableFrom(type)) {
244           try {
245             Object val = fields[i].getHandler().getValue(this);
246             if (val!=null) {
247               object vals[] = (object[]) val; 
248               for (int k=0, l=vals.length; k<l; k++) {
249                 if (vals[k].__vorba==null)
250                   vals[k].__vorba = __vorba; // propagate IVorbaIdFactory
251                 vals[k].__ensure_instance_ids();
252               }
253             }
254           }
255           catch (Exception e) {
256             log.error("Client error - could not access array "+type.getName()+" in "+this.getClass().getName(), e);
257           }
258         }
259       } else
260         if (object.class.isAssignableFrom(type)) {
261           try {
262             FieldHandler fh = fields[i].getHandler();
263             object rf = null;
264             if (fh != null) {
265               Object fval = fh.getValue(this);
266               if (fval!=null) {
267                 if (fval.getClass().isArray()) {
268                   //if (object[].class.isAssignableFrom(type)) {
269                     try {
270                       object vals[] = (object[]) fval; 
271                       for (int k=0, l=vals.length; k<l; k++) {
272                         if (vals[k].__vorba==null)
273                           vals[k].__vorba = __vorba; // propagate IVorbaIdFactory
274                         vals[k].__ensure_instance_ids();
275                       }
276                     }
277                     catch (Exception e) {
278                       log.error("Client error - could not access (fhval)array "+type.getName()+" in "+this.getClass().getName(), e);
279                     }
280                   //}
281                 } else {
282                   rf = (object) fval;
283                   log.info("Got value for "+fields[i].getFieldName());
284                 }
285               }
286             } else {
287               // fuck around, fuck around, jump up jump up and get down! */
288               Object o = fields[i].getClassDescriptor();
289               if (o!=null) {
290                 // XMLClassDescriptorImpl fclasdes = (XMLClassDescriptorImpl) o;
291                 String methname = "get"+fields[i].getFieldName();
292                 Method fgetmeth = this.getClass().getMethod(methname,null);
293                 if (fgetmeth!=null) {
294                   Object fval = fgetmeth.invoke(this,null);
295                   if (fval!=null)
296                     rf = (object) fval;
297                 } else {
298                   log.warn("Couldn't find "+this.getClass().getName()+"."+methname);
299                 }
300               }
301             }
302             if (rf!=null) {
303               if (rf.__vorba==null)
304                 rf.__vorba = __vorba; // propagate IVorbaIdFactory
305               rf.__ensure_instance_ids();
306             }
307           }
308           catch (Exception e) {
309             log.error("Client error - could not access "+type.getName()+" in "+this.getClass().getName(), e);
310           }
311         }
312     }
313     
314   }
315 }