applied LGPLv3 and source code formatting.
[vamsas.git] / src / uk / ac / vamsas / test / simpleclient / ClientDoc.java
1 /*\r
2  * This file is part of the Vamsas Client version 0.1. \r
3  * Copyright 2009 by Jim Procter, Iain Milne, Pierre Marguerite, \r
4  *  Andrew Waterhouse and Dominik Lindner.\r
5  * \r
6  * Earlier versions have also been incorporated into Jalview version 2.4 \r
7  * since 2008, and TOPALi version 2 since 2007.\r
8  * \r
9  * The Vamsas Client is free software: you can redistribute it and/or modify\r
10  * it under the terms of the GNU Lesser General Public License as published by\r
11  * the Free Software Foundation, either version 3 of the License, or\r
12  * (at your option) any later version.\r
13  *  \r
14  * The Vamsas Client is distributed in the hope that it will be useful,\r
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17  * GNU Lesser General Public License for more details.\r
18  * \r
19  * You should have received a copy of the GNU Lesser General Public License\r
20  * along with the Vamsas Client.  If not, see <http://www.gnu.org/licenses/>.\r
21  */\r
22 package uk.ac.vamsas.test.simpleclient;\r
23 \r
24 import java.util.Hashtable;\r
25 import java.util.Vector;\r
26 \r
27 import org.apache.commons.logging.Log;\r
28 import org.apache.commons.logging.LogFactory;\r
29 \r
30 import uk.ac.vamsas.client.IClientAppdata;\r
31 import uk.ac.vamsas.client.Vobject;\r
32 import uk.ac.vamsas.client.VorbaId;\r
33 import uk.ac.vamsas.client.simpleclient.ClientDocument;\r
34 import uk.ac.vamsas.client.simpleclient.VamsasArchive;\r
35 import uk.ac.vamsas.client.simpleclient.VamsasArchiveReader;\r
36 import uk.ac.vamsas.objects.core.Entry;\r
37 import uk.ac.vamsas.objects.core.VAMSAS;\r
38 import uk.ac.vamsas.objects.core.VamsasDocument;\r
39 import uk.ac.vamsas.objects.utils.ProvenanceStuff;\r
40 \r
41 // simple holder to pass to client.\r
42 public class ClientDoc extends uk.ac.vamsas.client.ClientDocument {\r
43   /*\r
44    * (non-Javadoc)\r
45    * \r
46    * @see uk.ac.vamsas.client.IClientDocument#getClientAppdata()\r
47    */\r
48   public IClientAppdata getClientAppdata() {\r
49     throw new Error(\r
50         "Appdata access is not implemented in the test.simpleclient.ClientDoc instance."); // TODO\r
51                                                                                            // Auto-generated\r
52                                                                                            // method\r
53                                                                                            // stub\r
54   }\r
55 \r
56   protected boolean isModified = false;\r
57 \r
58   private Log log = LogFactory.getLog(ClientDoc.class);\r
59 \r
60   protected VamsasDocument doc;\r
61 \r
62   public uk.ac.vamsas.objects.core.VAMSAS[] _VamsasRoots;\r
63 \r
64   protected VamsasArchive iohandler = null;\r
65 \r
66   protected VamsasArchiveReader reader = null;\r
67 \r
68   private String user = null;\r
69 \r
70   private String app = null;\r
71 \r
72   /**\r
73    * @param doc\r
74    * @param iohandler\r
75    * @param reader\r
76    * @param app\r
77    * @param user\r
78    */\r
79   public ClientDoc(VamsasDocument doc, VamsasArchive iohandler,\r
80       VamsasArchiveReader reader, String app, String user, Hashtable objrefs) {\r
81     super(objrefs, (iohandler != null) ? iohandler.getVorba() : null);\r
82     this.doc = doc;\r
83     this.iohandler = iohandler;\r
84     this.reader = reader;\r
85     this.app = app;\r
86     this.user = user;\r
87     this.objrefs = objrefs;\r
88     _VamsasRoots = doc.getVAMSAS();\r
89   }\r
90 \r
91   // AppDataOutputStream appd;\r
92   // AppDataOutputStream userd;\r
93   /*\r
94    * (non-Javadoc)\r
95    * \r
96    * @see java.lang.Object#finalize()\r
97    */\r
98   protected Entry getProvenanceEntry(String action) {\r
99     // VAMSAS: modify schema to allow referencing of user field (plus other\r
100     // issues, ClientUrn field, machine readable action, input parameters,\r
101     // additional data generated notes\r
102     Entry prov = ProvenanceStuff.newProvenanceEntry(app, user, action);\r
103     return prov;\r
104   }\r
105 \r
106   public VAMSAS[] getVamsasRoots() {\r
107     if (doc == null) {\r
108       log.debug("Null document for getVamsasRoots(), returning null");\r
109       return null;\r
110     }\r
111     if (iohandler == null) {\r
112       // LATER: decide on read-only status of ClientDocument object\r
113       log.warn("getVamsasRoots() called on possibly read-only document.");\r
114     }\r
115     if (_VamsasRoots != null)\r
116       return _VamsasRoots;\r
117     VAMSAS[] roots = doc.getVAMSAS();\r
118     if (roots == null) {\r
119       // Make a new one to return to client to get filled.\r
120       _VamsasRoots = new VAMSAS[] { new VAMSAS() };\r
121       // Do provenance now. just in case.\r
122       doc.getProvenance().addEntry(\r
123           getProvenanceEntry("Created new document root [id="\r
124               + _VamsasRoots[0].getId() + "]"));\r
125       doc.addVAMSAS(_VamsasRoots[0]);\r
126     } else {\r
127       _VamsasRoots = new VAMSAS[roots.length];\r
128       for (int r = 0; r < roots.length; r++)\r
129         _VamsasRoots[r] = roots[r];\r
130     }\r
131     return _VamsasRoots;\r
132   }\r
133 \r
134   private int _contains(VAMSAS root, VAMSAS[] docRoots) {\r
135     if (root == null)\r
136       return -1;\r
137     if (docRoots == null || docRoots.length == 0)\r
138       return -1;\r
139     VorbaId r_id = root.getVorbaId();\r
140     for (int i = 0, j = docRoots.length; i < j; i++) {\r
141       VorbaId n_id = null;\r
142       if (docRoots[i] == root\r
143           || (docRoots[i] != null && (n_id = docRoots[i].getVorbaId()) != null && n_id\r
144               .equals(r_id)))\r
145         return i;\r
146     }\r
147     return -1;\r
148   }\r
149 \r
150   /**\r
151    * verify that newr version is really an intact version of the\r
152    * \r
153    * @param newVersion\r
154    *          (may be modified)\r
155    * @param oldVersion\r
156    * @return true if newVersion is a valid root that preserves original\r
157    *         references\r
158    */\r
159   private boolean isValidUpdate(VAMSAS newVersion, final VAMSAS oldVersion) {\r
160     // ideal - this cascades down the two structures, ensuring that all ID'd\r
161     // objects in one are present in the other.\r
162     if (oldVersion == newVersion) {\r
163       // may be a virgin root element.\r
164       if (!newVersion.isRegistered())\r
165         iohandler.getVorba().makeVorbaId(newVersion);\r
166       // Should retrieve original version and compare - unless local hashes can\r
167       // be used to determine if resultSet has been truncated.\r
168       // just do internal validation for moment.\r
169       if (newVersion.isValid())\r
170         return true;\r
171       return false;\r
172     } else {\r
173       // redundant ? if (oldVersion.is__stored_in_document())\r
174       if (!newVersion.isRegistered())\r
175         iohandler.getVorba().makeVorbaId(newVersion);\r
176       if (newVersion.isValid())\r
177         return true;\r
178     }\r
179     return false;\r
180   }\r
181 \r
182   /**\r
183    * /** merge old and new root vectors\r
184    * \r
185    * @param newr\r
186    *          This array may be written to\r
187    * @param original\r
188    * @param the\r
189    *          client document (usually this) which this root set belongs to.\r
190    * @return merged vector of vamsas roots\r
191    */\r
192   private VAMSAS[] _combineRoots(VAMSAS[] newr, final VAMSAS[] original,\r
193       ClientDoc modflag) {\r
194     Vector rts = new Vector();\r
195     boolean modified = false;\r
196     for (int i = 0, j = original.length; i < j; i++) {\r
197       int k = _contains(original[i], newr);\r
198       if (k > -1) {\r
199         if (isValidUpdate(newr[k], original[i])) {\r
200           modified = true;\r
201           rts.add(newr[k]);\r
202           newr[k] = null;\r
203         } else {\r
204           // LATER: try harder to merge ducument roots.\r
205           log.warn("Couldn't merge new VAMSAS root " + newr[k].getId());\r
206           newr[k] = null; // LATER: this means we ignore mangled roots. NOT GOOD\r
207         }\r
208       } else {\r
209         // add in order.\r
210         rts.add(original[i]);\r
211       }\r
212     }\r
213     // add remaining (new) roots\r
214     for (int i = 0, j = newr.length; i < j; i++) {\r
215       if (newr[i] != null) {\r
216         rts.add(newr[i]);\r
217         modified = true;\r
218       }\r
219     }\r
220     newr = new VAMSAS[rts.size()];\r
221     for (int i = 0, j = rts.size(); i < j; i++)\r
222       newr[i] = (VAMSAS) rts.get(i);\r
223     if (modflag != null)\r
224       modflag.isModified = modified;\r
225     return newr;\r
226   }\r
227 \r
228   /**\r
229    * update the document with new roots. LATER: decide: this affects the next\r
230    * call to getVamsasRoots()\r
231    * \r
232    * @see org.vamsas.IClientDocument.setVamsasRoots\r
233    */\r
234   public void setVamsasRoots(VAMSAS[] newroots) {\r
235     if (doc == null) {\r
236       log.debug("setVamsasRoots called on null document.");\r
237       return;\r
238     }\r
239     VAMSAS[] newr;\r
240     if (newroots == null) {\r
241       log.debug("setVamsasRoots(null) - do nothing.");\r
242       return;\r
243     }\r
244     // are we dealing with same array ?\r
245     if (_VamsasRoots != newroots) {\r
246       // merge roots into local version.\r
247       newr = new VAMSAS[newroots.length];\r
248       for (int i = 0; i < newr.length; i++)\r
249         newr[i] = newroots[i];\r
250       newr = _combineRoots(newr, _VamsasRoots, this);\r
251     } else {\r
252       newr = new VAMSAS[_VamsasRoots.length];\r
253       for (int i = 0; i < newr.length; i++)\r
254         newr[i] = _VamsasRoots[i];\r
255     }\r
256     // actually compare with document root set for final combination (to ensure\r
257     // nothing is lost)\r
258     _VamsasRoots = _combineRoots(newr, doc.getVAMSAS(), this);\r
259   }\r
260 \r
261   /*\r
262    * (non-Javadoc) LATER: decide: this affects the next call to getVamsasRoots()\r
263    * \r
264    * @see\r
265    * uk.ac.vamsas.client.IClientDocument#addVamsasRoot(uk.ac.vamsas.objects.\r
266    * core.VAMSAS)\r
267    */\r
268   public void addVamsasRoot(VAMSAS newroot) {\r
269     if (doc == null) {\r
270       log.debug("addVamsasRoots called on null document.");\r
271       return;\r
272     }\r
273     VAMSAS[] newroots = _combineRoots(new VAMSAS[] { newroot }, _VamsasRoots,\r
274         this);\r
275     _VamsasRoots = newroots;\r
276   }\r
277 \r
278   public VamsasArchiveReader getReader() {\r
279     return reader;\r
280   }\r
281 \r
282   private void _finalize() {\r
283     log.debug("finalizing clientDoc");\r
284     if (doc != null) {\r
285       doc = null;\r
286     }\r
287     if (_VamsasRoots != null) {\r
288       for (int i = 0; i < _VamsasRoots.length; i++)\r
289         _VamsasRoots[i] = null;\r
290       _VamsasRoots = null;\r
291 \r
292     }\r
293 \r
294     if (reader != null) {\r
295       log.debug("Closing and removing reader reference");\r
296       reader.close();\r
297       reader = null;\r
298     }\r
299     if (iohandler != null) {\r
300       log.debug("Removing ioHandler reference.");\r
301       iohandler.cancelArchive();\r
302       iohandler = null;\r
303     }\r
304   }\r
305 \r
306   protected void finalize() throws Throwable {\r
307     _finalize();\r
308     super.finalize();\r
309   }\r
310 \r
311   private java.util.Hashtable objrefs = null;\r
312 \r
313   public VorbaId[] registerObjects(Vobject[] unregistered) {\r
314     if (doc == null) {\r
315       log.warn("registerObjects[] called on null document.");\r
316       return null;\r
317     }\r
318     if (objrefs == null) {\r
319       log.warn("registerObjects[] called for null objrefs hasharray.");\r
320       return null;\r
321     }\r
322     if (unregistered != null) {\r
323       VorbaId ids[] = new VorbaId[unregistered.length];\r
324       for (int i = 0, k = unregistered.length; i < k; i++)\r
325         if (unregistered[i] != null) {\r
326           log.warn("Null Vobject passed to registerObject[] at position " + i);\r
327           return null;\r
328         } else {\r
329           ids[i] = registerObject(unregistered[i]);\r
330         }\r
331       log.debug("Registered " + unregistered.length + " objects - total of "\r
332           + objrefs.size() + " ids.");\r
333       return ids;\r
334     }\r
335     return null;\r
336   }\r
337 \r
338   /*\r
339    * (non-Javadoc)\r
340    * \r
341    * @see\r
342    * uk.ac.vamsas.client.IClientDocument#registerObject(uk.ac.vamsas.client.\r
343    * Vobject)\r
344    */\r
345   public VorbaId registerObject(Vobject unregistered) {\r
346     if (doc == null) {\r
347       log.warn("registerObjects called on null document.");\r
348       return null;\r
349     }\r
350     if (objrefs == null) {\r
351       log.warn("registerObjects called for null objrefs hasharray.");\r
352       return null;\r
353     }\r
354     if (iohandler == null) {\r
355       log.warn("registerObjects called for read only document.");\r
356       return null;\r
357     }\r
358 \r
359     if (unregistered != null) {\r
360       VorbaId id = this._registerObject(unregistered);\r
361       log.debug("Registered object - total of " + objrefs.size() + " ids.");\r
362       return id;\r
363     }\r
364     log.warn("Null Vobject passed to registerObject.");\r
365     return null;\r
366   }\r
367 \r
368   /*\r
369    * (non-Javadoc)\r
370    * \r
371    * @see\r
372    * uk.ac.vamsas.client.IClientDocument#getObject(uk.ac.vamsas.client.VorbaId)\r
373    */\r
374   public Vobject getObject(VorbaId id) {\r
375     if (objrefs == null) {\r
376       log.debug("getObject called on null objrefs list.");\r
377       return null;\r
378     }\r
379     if (objrefs.containsKey(id.getId()))\r
380       return (Vobject) objrefs.get(id.getId());\r
381     log.debug("Returning null Vobject reference for id " + id.getId());\r
382     return null;\r
383   }\r
384 \r
385   /*\r
386    * (non-Javadoc)\r
387    * \r
388    * @see\r
389    * uk.ac.vamsas.client.IClientDocument#getObjects(uk.ac.vamsas.client.VorbaId\r
390    * [])\r
391    */\r
392   public Vobject[] getObjects(VorbaId[] ids) {\r
393     if (objrefs == null) {\r
394       log.debug("getObject[]  called on null objrefs list.");\r
395       return null;\r
396     }\r
397     Vobject[] vo = new Vobject[ids.length];\r
398     for (int i = 0, j = ids.length; i < j; i++)\r
399       if (objrefs.containsKey(ids[i]))\r
400         vo[i] = (Vobject) objrefs.get(ids[i]);\r
401       else\r
402         log.debug("Returning null Vobject reference for id " + ids[i].getId());\r
403     return vo;\r
404   }\r
405 \r
406   protected void updateDocumentRoots() {\r
407     if (doc == null) {\r
408       log\r
409           .error("updateDocumentRoots called on null document. Probably an implementation error.");\r
410       return;\r
411     }\r
412     if (isModified) {\r
413       if (_VamsasRoots != null) {\r
414         doc.setVAMSAS(_VamsasRoots);\r
415         _VamsasRoots = null;\r
416       }\r
417     }\r
418   }\r
419 \r
420   /**\r
421    * tell vamsas client to close the document and reset the object. Once closed,\r
422    * nothing can be done with the object.\r
423    * \r
424    */\r
425   public void closeDoc() {\r
426     if (doc != null) {\r
427       log.debug("Closing open document.");\r
428       _finalize();\r
429     } else {\r
430       log.warn("Ignoring closeDoc on invalid document.");\r
431     }\r
432   }\r
433 \r
434 }\r