updated test cases for spring 2006 schema, and major debug of locking system
[vamsas.git] / src / org / vamsas / test / simpleclient / ClientDoc.java
1 package org.vamsas.test.simpleclient;
2
3 import java.util.Hashtable;
4 import java.util.Vector;
5
6 import org.apache.commons.logging.Log;
7 import org.apache.commons.logging.LogFactory;
8 import org.vamsas.client.Vobject;
9 import org.vamsas.client.VorbaId;
10 import org.vamsas.client.simpleclient.ClientDocument;
11 import org.vamsas.client.simpleclient.VamsasArchive;
12 import org.vamsas.client.simpleclient.VamsasArchiveReader;
13 import org.vamsas.objects.core.Entry;
14 import org.vamsas.objects.core.VAMSAS;
15 import org.vamsas.objects.core.VamsasDocument;
16 import org.vamsas.objects.utils.ProvenanceStuff;
17
18 // simple holder to pass to client.
19 public class ClientDoc {
20   protected boolean isModified=false;
21   private Log log = LogFactory.getLog(ClientDoc.class);
22   protected VamsasDocument doc;
23   public org.vamsas.objects.core.VAMSAS[] _VamsasRoots;
24   protected VamsasArchive iohandler=null;
25   protected VamsasArchiveReader reader=null;
26   private String user=null;
27   private String app=null;
28   
29   /**
30    * @param doc
31    * @param iohandler
32    * @param reader
33    * @param app
34    * @param user
35    */
36   public ClientDoc(VamsasDocument doc, VamsasArchive iohandler, VamsasArchiveReader reader, String app, String user, Hashtable objrefs) {
37     super();
38     this.doc = doc;
39     this.iohandler = iohandler;
40     this.reader = reader;
41     this.app = app;
42     this.user = user;
43     this.objrefs = objrefs;
44     _VamsasRoots = doc.getVAMSAS();
45   }
46   // AppDataOutputStream appd;
47   //AppDataOutputStream userd;
48   /* (non-Javadoc)
49    * @see java.lang.Object#finalize()
50    */
51   protected Entry getProvenanceEntry(String action) {
52     // VAMSAS: modify schema to allow referencing of user field (plus other issues, ClientUrn field, machine readable action, input parameters, additional data generated notes
53     Entry prov = ProvenanceStuff.newProvenanceEntry(app, user, action);
54     return prov;
55   }
56   public VAMSAS[] getVamsasRoots() {
57     if (doc==null) {
58       log.debug("Null document for getVamsasRoots(), returning null");
59       return null;
60     }
61     if (iohandler==null) {
62       // LATER: decide on read-only status of ClientDocument object
63       log.warn("getVamsasRoots() called on possibly read-only document.");
64     }
65     if (_VamsasRoots!=null)
66       return _VamsasRoots;
67     VAMSAS[] roots = doc.getVAMSAS();
68     if (roots == null) {
69       // Make a new one to return to client to get filled. 
70       _VamsasRoots = new VAMSAS[] { new VAMSAS() };
71       // Do provenance now. just in case.
72       doc.getProvenance().addEntry(getProvenanceEntry("Created new document root [id="+_VamsasRoots[0].getId()+"]"));
73       doc.addVAMSAS(_VamsasRoots[0]);
74     } else {
75       _VamsasRoots = new VAMSAS[roots.length];
76       for (int r=0;r<roots.length; r++)
77         _VamsasRoots[r] = roots[r];
78     }
79     return _VamsasRoots;
80   }
81   
82   private int _contains(VAMSAS root, VAMSAS[] docRoots) {
83     if (root==null)
84       return -1;
85     if (docRoots==null || docRoots.length==0)
86       return -1;
87     VorbaId r_id = root.getVorbaId();
88     for (int i=0,j=docRoots.length; i<j; i++) {
89       VorbaId n_id=null;
90       if (docRoots[i]==root || (docRoots[i]!=null && (n_id=docRoots[i].getVorbaId())!=null && n_id.equals(r_id)))
91         return i;
92     }
93     return -1;
94   }
95 /**
96  * verify that newr version is really an intact version of the 
97  * @param newVersion (may be modified)
98  * @param oldVersion 
99  * @return true if newVersion is a valid root that preserves original references
100  */
101   private boolean isValidUpdate(VAMSAS newVersion, final VAMSAS oldVersion) {
102     // ideal - this cascades down the two structures, ensuring that all ID'd objects in one are present in the other.
103     if (oldVersion==newVersion) {
104       // may be a virgin root element.
105       if (!newVersion.isRegistered())
106         iohandler.getVorba().makeVorbaId(newVersion);
107       // Should retrieve original version and compare - unless local hashes can be used to determine if resultSet has been truncated.
108       // just do internal validation for moment.
109       if (newVersion.isValid())
110         return true;
111       return false;
112     } else {
113       // redundant ? if (oldVersion.is__stored_in_document())
114       if (!newVersion.isRegistered())
115         iohandler.getVorba().makeVorbaId(newVersion);
116       if (newVersion.isValid())
117         return true;
118     }
119     return false;
120   }
121     /**
122   /**
123    * merge old and new root vectors
124    * @param newr This array may be written to
125    * @param original
126    * @param the client document (usually this) which this root set belongs to.
127    * @return merged vector of vamsas roots
128    */
129   private VAMSAS[] _combineRoots(VAMSAS[] newr, final VAMSAS[] original, ClientDoc modflag) {
130     Vector rts = new Vector();
131     boolean modified=false;
132     for (int i=0,j=original.length; i<j; i++) {
133       int k = _contains(original[i], newr);
134       if (k>-1) {
135         if (isValidUpdate(newr[k], original[i])) {
136           modified=true;
137           rts.add(newr[k]);
138           newr[k]=null;
139         } else {
140           // LATER: try harder to merge ducument roots.
141           log.warn("Couldn't merge new VAMSAS root "+newr[k].getId());
142           newr[k] = null; // LATER: this means we ignore mangled roots. NOT GOOD
143         }
144       } else {
145         // add in order.
146         rts.add(original[i]);
147       }
148     }
149     // add remaining (new) roots
150     for (int i=0,j=newr.length; i<j; i++) {
151       if (newr[i]!=null) {
152         rts.add(newr[i]);
153         modified=true;
154       }
155     }
156     newr = new VAMSAS[rts.size()];
157     for (int i=0,j=rts.size(); i<j; i++)
158       newr[i] = (VAMSAS) rts.get(i);
159     if (modflag!=null)
160       modflag.isModified = modified;
161     return newr;
162   }
163   
164   /**
165    * update the document with new roots.
166    * LATER: decide: this affects the next call to getVamsasRoots()
167    * @see org.vamsas.IClientDocument.setVamsasRoots
168    */
169   public void setVamsasRoots(VAMSAS[] newroots) {
170     if (doc==null) {
171       log.debug("setVamsasRoots called on null document.");
172       return;
173     }
174     VAMSAS[] newr;
175     if (newroots==null) {
176       log.debug("setVamsasRoots(null) - do nothing.");
177       return;
178     }
179     // are we dealing with same array ?
180     if (_VamsasRoots!=newroots) {
181       // merge roots into local version.
182       newr = new VAMSAS[newroots.length];
183       for (int i=0;i<newr.length;i++)
184         newr[i] = newroots[i];
185       newr=_combineRoots(newr,_VamsasRoots,this);
186     } else {
187       newr = new VAMSAS[_VamsasRoots.length];
188       for (int i=0;i<newr.length;i++)
189         newr[i]=_VamsasRoots[i];
190     }
191     //  actually compare with document root set for final combination (to ensure nothing is lost)
192     _VamsasRoots = _combineRoots(newr, doc.getVAMSAS(), this); 
193   }
194   
195   
196   /* (non-Javadoc)
197    * LATER: decide: this affects the next call to getVamsasRoots()
198    * @see org.vamsas.client.IClientDocument#addVamsasRoot(org.vamsas.objects.core.VAMSAS)
199    */
200   public void addVamsasRoot(VAMSAS newroot) {
201     if (doc==null) {
202       log.debug("addVamsasRoots called on null document.");
203       return;
204     }
205     VAMSAS[] newroots = _combineRoots(new VAMSAS[] {newroot}, _VamsasRoots, this);
206     _VamsasRoots = newroots;  
207   }
208
209   public VamsasArchiveReader getReader() {
210     return reader;
211   }
212   private void _finalize() {
213     log.debug("finalizing clientDoc");
214     if (doc!=null) {
215       doc = null;
216     }
217     if (_VamsasRoots!=null) {
218       for (int i=0; i<_VamsasRoots.length; i++)
219         _VamsasRoots[i]=null;
220       _VamsasRoots=null;
221        
222     }
223       
224     if (reader!=null) {
225       log.debug("Closing and removing reader reference");
226       reader.close();
227       reader=null;
228     }
229     if (iohandler!=null) {
230       log.debug("Removing ioHandler reference.");
231       iohandler.cancelArchive();
232       iohandler=null;
233     }
234   }
235   protected void finalize() throws Throwable {
236     _finalize();
237     super.finalize();
238   }
239   private java.util.Hashtable objrefs=null;
240   
241   public VorbaId[] registerObjects(Vobject[] unregistered) {
242     if (doc==null) {
243       log.warn("registerObjects[] called on null document.");
244       return null;
245     }
246     if (objrefs==null) {
247       log.warn("registerObjects[] called for null objrefs hasharray.");
248       return null;
249     }
250     if (unregistered!=null) {
251       VorbaId ids[] = new VorbaId[unregistered.length];
252       for (int i=0,k=unregistered.length; i<k; i++)
253         if (unregistered[i]!=null) {
254           log.warn("Null Vobject passed to registerObject[] at position "+i);
255           return null;
256         } else {
257           ids[i]=registerObject(unregistered[i]);
258         }
259       log.debug("Registered "+unregistered.length+" objects - total of "+objrefs.size()+" ids.");
260       return ids;
261     }
262     return null;
263   }
264   /* (non-Javadoc)
265    * @see org.vamsas.client.IClientDocument#registerObject(org.vamsas.client.Vobject)
266    */
267   public VorbaId registerObject(Vobject unregistered) {
268     if (doc==null) {
269       log.warn("registerObjects called on null document.");
270       return null;
271     }
272     if (objrefs==null) {
273       log.warn("registerObjects called for null objrefs hasharray.");
274       return null;
275     }
276     if (iohandler==null) {
277       log.warn("registerObjects called for read only document.");
278       return null;
279     }
280     
281     if (unregistered!=null) {
282       VorbaId id = iohandler.getVorba().makeVorbaId(unregistered);
283       log.debug("Registered object - total of "+objrefs.size()+" ids.");
284       return id;
285     }
286     log.warn("Null Vobject passed to registerObject.");
287     return null;
288   }
289
290   /*
291    * (non-Javadoc)
292    * 
293    * @see org.vamsas.client.IClientDocument#getObject(org.vamsas.client.VorbaId)
294    */
295   public Vobject getObject(VorbaId id) {
296     if (objrefs==null) {
297       log.debug("getObject called on null objrefs list.");
298       return null;
299     }
300     if (objrefs.containsKey(id))
301       return (Vobject) objrefs.get(id);
302     log.debug("Returning null Vobject reference for id "+id.getId());
303     return null;
304   }
305   
306   /*
307    * (non-Javadoc)
308    * 
309    * @see org.vamsas.client.IClientDocument#getObjects(org.vamsas.client.VorbaId[])
310    */
311   public Vobject[] getObjects(VorbaId[] ids) {
312     if (objrefs==null) {
313       log.debug("getObject[]  called on null objrefs list.");
314       return null;
315     }
316     Vobject[] vo = new Vobject[ids.length];
317     for (int i=0,j=ids.length; i<j;i++) 
318       if (objrefs.containsKey(ids[i]))
319         vo[i] = (Vobject) objrefs.get(ids[i]);
320       else
321         log.debug("Returning null Vobject reference for id "+ids[i].getId());
322     return vo;
323   }
324   protected void updateDocumentRoots() {
325     if (doc==null) {
326       log.error("updateDocumentRoots called on null document. Probably an implementation error.");
327       return;
328     }
329     if (isModified) {
330       if (_VamsasRoots!=null) {
331         doc.setVAMSAS(_VamsasRoots);
332         _VamsasRoots=null;
333       }
334     }
335   }
336   /**
337    * tell vamsas client to close the document and reset the object. Once closed, nothing can be done with the object.
338    *
339    */
340   public void closeDoc() {
341     if (doc!=null) {
342       log.debug("Closing open document.");
343       _finalize();
344     } else {
345       log.warn("Ignoring closeDoc on invalid document.");
346     }
347   }
348   
349 }