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