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