applied LGPLv3 and source code formatting.
[vamsas.git] / src / uk / ac / vamsas / test / simpleclient / ArchiveClient.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.io.File;\r
25 import java.io.IOException;\r
26 import java.util.Date;\r
27 import java.util.Hashtable;\r
28 import java.util.Vector;\r
29 \r
30 import org.apache.commons.logging.Log;\r
31 import org.apache.commons.logging.LogFactory;\r
32 import org.exolab.castor.xml.MarshalException;\r
33 import org.exolab.castor.xml.ValidationException;\r
34 \r
35 import uk.ac.vamsas.client.AppDataOutputStream;\r
36 import uk.ac.vamsas.client.ClientHandle;\r
37 import uk.ac.vamsas.client.IVorbaIdFactory;\r
38 import uk.ac.vamsas.client.SessionHandle;\r
39 import uk.ac.vamsas.client.UserHandle;\r
40 import uk.ac.vamsas.client.Vobject;\r
41 import uk.ac.vamsas.client.VorbaId;\r
42 import uk.ac.vamsas.client.simpleclient.FileWatcher;\r
43 import uk.ac.vamsas.client.simpleclient.IdFactory;\r
44 import uk.ac.vamsas.client.simpleclient.SessionFile;\r
45 import uk.ac.vamsas.client.simpleclient.SimpleDocBinding;\r
46 import uk.ac.vamsas.client.simpleclient.SimpleDocument;\r
47 import uk.ac.vamsas.client.simpleclient.VamsasArchive;\r
48 import uk.ac.vamsas.client.simpleclient.VamsasArchiveReader;\r
49 import uk.ac.vamsas.client.simpleclient.VamsasFile;\r
50 import uk.ac.vamsas.objects.core.AppData;\r
51 import uk.ac.vamsas.objects.core.ApplicationData;\r
52 import uk.ac.vamsas.objects.core.User;\r
53 import uk.ac.vamsas.objects.core.VamsasDocument;\r
54 import uk.ac.vamsas.objects.utils.AppDataReference;\r
55 import uk.ac.vamsas.objects.utils.DocumentStuff;\r
56 import uk.ac.vamsas.objects.utils.ProvenanceStuff;\r
57 import uk.ac.vamsas.objects.utils.SeqSet;\r
58 import uk.ac.vamsas.objects.utils.document.VersionEntries;\r
59 import uk.ac.vamsas.test.objects.Core;\r
60 \r
61 /**\r
62  * @author jimp test the VamsasFile routines for watching, reading and updating\r
63  *         a vamsas document jar file. simple document access base class.\r
64  */\r
65 public class ArchiveClient extends IdFactory {\r
66 \r
67   private Log log = LogFactory.getLog(ArchiveClient.class);\r
68 \r
69   // protected UserHandle user=null;\r
70   // protected ClientHandle me = new ClientHandle("ArchiveClient","0.01");\r
71   VamsasFile vsess;\r
72 \r
73   /**\r
74    * @param user\r
75    * @param vsess\r
76    */\r
77   public ArchiveClient(UserHandle user, VamsasFile vsess) {\r
78     super(new SessionHandle("vamsasfile://" + vsess.getVamsasFile()),\r
79         new ClientHandle("ArchiveClient", "0.01"), user);\r
80     this.vsess = vsess;\r
81     valid();\r
82   }\r
83 \r
84   private void _openVsess(File vsess) {\r
85     try {\r
86       this.vsess = new VamsasFile(vsess);\r
87     } catch (Exception e) {\r
88       log.error("Couldn't open session for file " + vsess, e);\r
89       this.vsess = null;\r
90     }\r
91   }\r
92 \r
93   public ArchiveClient(String username, String organization, File vsess) {\r
94     super(new SessionHandle("vamsasfile://" + vsess), new ClientHandle(\r
95         "ArchiveClient", "0.01"), new UserHandle(username, organization));\r
96     _openVsess(vsess);\r
97     valid();\r
98   }\r
99 \r
100   public ArchiveClient(String username, String organization, String clientName,\r
101       String clientVersion, File vsess) {\r
102     super(new SessionHandle("vamsasfile://" + vsess), new ClientHandle(\r
103         clientName, clientVersion), new UserHandle(username, organization));\r
104     _openVsess(vsess);\r
105     valid();\r
106   }\r
107 \r
108   public void valid() {\r
109     if (vsess == null)\r
110       throw new Error("ArchiveClient instance is invalid!.");\r
111   }\r
112 \r
113   /**\r
114    * set this to false if watch loop should end immediately\r
115    */\r
116   protected boolean watchForChange = true;\r
117 \r
118   public static int WATCH_SLEEP = 300;\r
119 \r
120   /**\r
121    * watch the document file for updates.\r
122    * \r
123    * @param time\r
124    *          - length of time to watch for.\r
125    * @return read only IO interface for session document.\r
126    */\r
127   public ClientDoc watch(long time) {\r
128     valid();\r
129     vsess.unLock(); // doh.\r
130     FileWatcher watcher = new FileWatcher(vsess.getVamsasFile());\r
131     // watcher.setState();\r
132     watchForChange = true;\r
133     long endtime = System.currentTimeMillis() + time;\r
134     try {\r
135       uk.ac.vamsas.client.simpleclient.Lock doclock;\r
136       do {\r
137         doclock = watcher.getChangedState();\r
138         if (doclock == null)\r
139           Thread.sleep(WATCH_SLEEP);\r
140       } while (watchForChange && doclock == null\r
141           && (time == 0 || endtime > System.currentTimeMillis())); // tuning.\r
142       if (doclock == null)\r
143         return null;\r
144       else {\r
145         return getUpdateable(vsess.getLock(doclock));\r
146         /*\r
147          * VamsasArchiveReader varc = new\r
148          * VamsasArchiveReader(vsess.getVamsasFile()); return\r
149          * _getReadonly(varc);\r
150          */\r
151       }\r
152     } catch (Exception e) {\r
153       log.error("Whilst watching file " + vsess.getVamsasFile(), e);\r
154     }\r
155     return null;\r
156   }\r
157 \r
158   // from ClientDocument.getClientAppdata\r
159   private AppData[] getAppData(VamsasDocument doc) {\r
160     // TODO: codefest - not yet tested or merged in to SimpleClient\r
161     if (doc == null) {\r
162       log.debug("extractAppData called for null document object");\r
163       return null;\r
164     }\r
165     AppData appsGlobal = null, usersData = null;\r
166     Vector apldataset = AppDataReference.getUserandApplicationsData(doc, this\r
167         .getUserHandle(), this.getClientHandle());\r
168     if (apldataset != null) {\r
169       if (apldataset.size() > 0) {\r
170         AppData clientdat = (AppData) apldataset.get(0);\r
171         if (clientdat instanceof ApplicationData) {\r
172           appsGlobal = (ApplicationData) clientdat;\r
173           if (apldataset.size() > 1) {\r
174             clientdat = (AppData) apldataset.get(1);\r
175             if (clientdat instanceof User) {\r
176               usersData = (User) clientdat;\r
177             }\r
178             if (apldataset.size() > 2)\r
179               log.info("Ignoring additional (" + (apldataset.size() - 2)\r
180                   + ") AppDatas returned by document appdata query.");\r
181           }\r
182         } else {\r
183           log.warn("Unexpected entry in AppDataReference query: id="\r
184               + clientdat.getVorbaId() + " type="\r
185               + clientdat.getClass().getName());\r
186         }\r
187         apldataset.removeAllElements(); // destroy references.\r
188       }\r
189     }\r
190     return new AppData[] { appsGlobal, usersData };\r
191   }\r
192 \r
193   protected ClientDoc _getReadonly(VamsasArchiveReader vreader)\r
194       throws IOException, ValidationException, MarshalException {\r
195     valid();\r
196     if (vreader != null) {\r
197       SimpleDocBinding docb = new SimpleDocBinding();\r
198       docb.setVorba(this);\r
199       VamsasDocument d;\r
200       d = docb.getVamsasDocument(vreader);\r
201 \r
202       if (d != null) {\r
203         ClientDoc creader = new ClientDoc(d, null, vreader, getClientHandle()\r
204             .getClientUrn(), getProvenanceUser(), getVorbaIdHash());\r
205         return creader;\r
206       }\r
207     }\r
208     return null;\r
209   }\r
210 \r
211   /**\r
212    * from SimpleClient\r
213    * \r
214    * @return user field for a provenance entry\r
215    */\r
216   protected String getProvenanceUser() {\r
217     return new String(getUserHandle().getFullName() + " ["\r
218         + getClientHandle().getClientUrn() + "]");\r
219   }\r
220 \r
221   public ClientDoc getUpdateable() {\r
222     return getUpdateable(null);\r
223   }\r
224 \r
225   public ClientDoc getUpdateable(uk.ac.vamsas.client.simpleclient.Lock lock) {\r
226     getVorbaIdHash().clear();\r
227     valid();\r
228     try {\r
229       // patiently wait for a lock on the document.\r
230       long tries = 5000;\r
231       while (lock == null\r
232           && ((lock = vsess.getLock()) == null || !lock.isLocked())\r
233           && --tries > 0) {\r
234         // Thread.sleep(1);\r
235         log.debug("Trying to get a document lock for the " + tries\r
236             + "'th time.");\r
237       }\r
238       VamsasArchive varc = new VamsasArchive(vsess, true, false); // read\r
239                                                                   // archive,\r
240                                                                   // write as\r
241                                                                   // vamsasDocument,\r
242                                                                   // don't erase\r
243                                                                   // original\r
244                                                                   // contents.\r
245       varc.setVorba(this);\r
246       VamsasDocument d = varc.getVamsasDocument(getProvenanceUser(),\r
247           "Created new document.", VersionEntries.latestVersion()); // VAMSAS:\r
248                                                                     // provenance\r
249                                                                     // user and\r
250                                                                     // client\r
251                                                                     // combined\r
252 \r
253       if (d == null) {\r
254         log\r
255             .warn("Backing out from opening a VamsasArchive writable IO session");\r
256         varc.cancelArchive();\r
257         return null;\r
258       }\r
259       ClientDoc cdoc = new ClientDoc(d, varc, varc.getOriginalArchiveReader(),\r
260           getClientHandle().getClientUrn(), getProvenanceUser(),\r
261           getVorbaIdHash());\r
262       return cdoc;\r
263       // do appHandle?\r
264     } catch (Exception e) {\r
265       log.error("Failed to get Updateable version of " + vsess.getVamsasFile(),\r
266           e);\r
267     }\r
268     return null;\r
269   }\r
270 \r
271   /**\r
272    * trust client to not do anything stupid to the document roots which will now\r
273    * be written to the archive.\r
274    * \r
275    * @param cdoc\r
276    * @return true if write was a success.\r
277    */\r
278   public boolean doUpdate(ClientDoc cdoc) {\r
279     valid();\r
280     if (cdoc == null) {\r
281       log\r
282           .warn("Invalid ClientDoc passed to uk.ac.vamsas.test.simpleclient.doUpdate()");\r
283       return false;\r
284     }\r
285     if (cdoc.iohandler == null) {\r
286       log\r
287           .warn("Read only ClientDoc object passed to uk.ac.vamsas.test.simpleclient.doUpdate()");\r
288       return false;\r
289     }\r
290     if (cdoc.iohandler.getVorba() != this) {\r
291       log\r
292           .error("Mismatch between ClientDoc instances and ArchiveClient instances!");\r
293       return false;\r
294     }\r
295     try {\r
296       // do any appDatas first.\r
297       if (cdoc.iohandler.transferRemainingAppDatas())\r
298         log.debug("Remaining appdatas were transfered.");\r
299       cdoc.updateDocumentRoots();\r
300       cdoc.iohandler.putVamsasDocument(cdoc.doc);\r
301       cdoc.iohandler.closeArchive();\r
302       this.extantids.clear();// we forget our ids after we close the document.\r
303       cdoc.iohandler = null;\r
304       cdoc = null;\r
305       vsess.unLock();\r
306     } catch (Exception e) {\r
307       log.warn("While updating archive in " + vsess.getVamsasFile(), e);\r
308       return false;\r
309     }\r
310     return true;\r
311   }\r
312 \r
313   /**\r
314    * @param args\r
315    */\r
316   public static void usage() {\r
317     throw new Error("Usage: Username Organization VamsasFile [command,args]*");\r
318   }\r
319 \r
320   public static void main(String[] args) {\r
321     // really simple.\r
322     if (args.length < 3)\r
323       usage();\r
324 \r
325     ArchiveClient client = new ArchiveClient(args[0], args[1],\r
326         new File(args[2]));\r
327     ClientDoc cdoc = null;\r
328     // sanity test.\r
329     try {\r
330       cdoc = client.getUpdateable();\r
331       // ArchiveReports.reportDocument(cdoc.doc, cdoc.getReader(), true,\r
332       // System.out);\r
333       System.out.println("Report Roots :");\r
334       ArchiveReports.rootReport(cdoc.getVamsasRoots(), true, System.out);\r
335       cdoc.addVamsasRoot(Core.getDemoVamsas());\r
336       System.out.println("Doing update.");\r
337       client.doUpdate(cdoc);\r
338       cdoc.closeDoc();\r
339       cdoc = null;\r
340       int u = 5;\r
341       while (--u > 0) {\r
342         System.out.println("Watch for more... (" + u + " left)");\r
343         ClientDoc ucdoc = client.watch(0000);\r
344         if (ucdoc != null) {\r
345           System.out.println("****\nUpdate detected at " + new Date());\r
346           ArchiveReports.reportDocument(ucdoc.doc, ucdoc.getReader(), true,\r
347               System.out);\r
348           ucdoc.closeDoc();\r
349           ucdoc = null;\r
350         } else {\r
351           System.out.println("!!!! Null document update detected at "\r
352               + new Date());\r
353         }\r
354       }\r
355     } catch (Exception e) {\r
356       client.log.error("Broken!", e);\r
357     }\r
358     System.out.println("Finished at " + new Date());\r
359   }\r
360 \r
361   public uk.ac.vamsas.client.Vobject getObject(VorbaId id) {\r
362     Hashtable idhash = this.getVorbaIdHash();\r
363     if (idhash != null && idhash.containsKey(id))\r
364       return (Vobject) idhash.get(id);\r
365     return null;\r
366   }\r
367 }\r