27aaf771cb12e73ba08a35080acd1f5922942b46
[vamsas.git] / src / uk / ac / vamsas / client / simpleclient / SimpleClientFactory.java
1 /**
2  * 
3  * VAMSAS Project
4  *
5  * 
6  * Dec 13, 2006 
7  *
8  */
9
10 package uk.ac.vamsas.client.simpleclient;
11
12 import java.io.File;
13
14 import java.io.IOException;
15 import java.net.MalformedURLException;
16
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19
20 import uk.ac.vamsas.client.ClientHandle;
21 import uk.ac.vamsas.client.IClient;
22 import uk.ac.vamsas.client.IClientFactory;
23 import uk.ac.vamsas.client.InvalidSessionDocumentException;
24 import uk.ac.vamsas.client.InvalidSessionUrnException;
25 import uk.ac.vamsas.client.NoDefaultSessionException;
26 import uk.ac.vamsas.client.SessionHandle;
27 import uk.ac.vamsas.client.UserHandle;
28
29 /**
30  * 
31  * creates a session arena in the user home directory under .vamsas. Each
32  * session has its own subdirectory.
33  */
34 public class SimpleClientFactory implements IClientFactory {
35
36   private static Log log = LogFactory.getLog(SimpleClientFactory.class);
37
38   private File sessionArena = null;
39
40   private String vamsasSubdirectoryName = ".vamsas";
41
42   private SimpleSessionManager sessionManager = null;
43
44   private static final String SESSION_LIST = "sessions.obj";
45
46   // private String[] currentlyAvailableDessions = null;
47
48   /**
49    * default constructor - called by CreateClientFactory only.
50    * 
51    * Inits the sessionarena to the directory .vamsas of the user home directory.
52    * 
53    */
54   public SimpleClientFactory() throws IOException {
55     // sessionArena
56
57     // retrieves user home directory
58     String userHomeDirectory = System.getProperty("user.home");
59     if (userHomeDirectory == null || userHomeDirectory.length() < 1) {
60       new IOException("Unable to detect user home directory");
61     }
62     String sessionArenaPath = userHomeDirectory.concat(File.separator
63         .concat(this.vamsasSubdirectoryName));
64
65     this.initSessionArena(sessionArenaPath);
66     // this.initFactoryObjects();
67   }
68
69   /**
70    * Create a client factory that works with sessions at the given path.
71    * 
72    * @param path
73    *          path to directory called session arena, where will be created
74    *          session directories and session files.
75    */
76   public SimpleClientFactory(String path) throws IOException {
77     this.initSessionArena(path);
78   }
79
80   /**
81    * Inits sessionArena to a given path. checks if path is valid.
82    * 
83    * @param path
84    *          path to a directory to use
85    * @throws IOException
86    *           if the path is incorrect
87    */
88   private void initSessionArena(String path) throws IOException {
89     // Check path is valid and read/writeable.
90     File arenaFile = new File(path);
91     if (!arenaFile.exists()) {
92       if (!arenaFile.mkdirs()) {
93         this.sessionArena = null;
94         throw (new IOException("Unable to create a directory called " + path));
95       }
96     }
97     if (arenaFile.exists() && arenaFile.isDirectory() && arenaFile.canRead()
98         && arenaFile.canWrite()) {
99       this.sessionArena = arenaFile;
100     } else {
101       this.sessionArena = null;
102       throw (new IOException("Cannot read and write to a directory called "
103           + path));
104     }
105   }
106
107   /**
108    * @see uk.ac.vamsas.client.IClientFactory#getIClient(uk.ac.vamsas.client.ClientHandle)
109    * 
110    * Creates a IClient object, using default UserHandle with system
111    * variables:"user.name" or "USERNAME")), "host.name" or "HOSTNAME"
112    */
113   public IClient getIClient(ClientHandle applicationHandle)
114       throws NoDefaultSessionException {
115     // create a new session
116     // register new ClientHandle in session
117     // create SimpleClient instance
118     return this.getIClient(applicationHandle, (UserHandle) null);
119   }
120
121   /**
122    * the URN should be something like simpleclient:FILEPATH URL encoded
123    * 
124    * @see uk.ac.vamsas.client.IClientFactory#getIClient(uk.ac.vamsas.client.ClientHandle,
125    *      java.lang.String)
126    */
127   public IClient getIClient(ClientHandle applicationHandle, String sessionUrn) {
128     // locate session from Urn
129     // check that clientHandle is unique (with default user) - if not update the
130     // clientHandle urn to make it unique.
131     // wait for lock and attach to session
132     // create SimpleClient instance
133     log.debug("Trying to create session with URN " + sessionUrn);
134     return this.getIClient(applicationHandle, null, sessionUrn);
135
136   }
137
138   private File convertSessionUrnToFile(String sessionUrn)
139       throws InvalidSessionUrnException {
140     if (sessionUrn == null) {
141       log.debug("Incorrect URN: can not open session.");
142       throw new InvalidSessionUrnException();
143     }
144
145     SessionUrn urn = new SessionUrn(sessionUrn);
146     return urn.asFile();
147
148   }
149
150   /**
151    * @see uk.ac.vamsas.client.IClientFactory#getIClient(uk.ac.vamsas.client.ClientHandle,
152    *      uk.ac.vamsas.client.UserHandle, java.lang.String)
153    */
154   public IClient getIClient(ClientHandle applicationHandle, UserHandle userId,
155       String sessionUrn) {
156     // locate session from Urn
157     // check Uniqueness of user + ClientHandle in the session. Update
158     // clientHandle urn accordingly.
159     // wait for lock, attach to session
160     // create client instance
161     IClient client = null;
162
163     // TODO: implement 'opening stored session' opening mechanism
164     // 1. existing session document URL is vdoc://... ?
165     // 2. check for sessionUrn being of this form.
166     // 3. if it is - locate the file and pass to new VamsasSession
167
168     try {
169       File sessionDirectory = this.convertSessionUrnToFile(sessionUrn);
170       // create session
171       log
172           .debug("found session directory "
173               + sessionDirectory.getAbsolutePath());
174       VamsasSession vamsasSession = new VamsasSession(sessionDirectory);
175       
176       /*
177        * if (userId == null) { //create a default userHandle //with current OS
178        * user and hostname userId = new UserHandle(System.getProperty("user.name",
179        * System.getProperty("USERNAME","Joe Doe")),
180        * System.getProperty("host.name",System.getProperty("HOSTNAME", "Unknown")
181        * ));// clientName, clientVersion, sessionPath); }
182        * 
183        * 
184        * //create simple client client = new SimpleClient(userId,
185        * applicationHandle, vamsasSession);
186        */
187       client = this.initClient(sessionDirectory, userId, applicationHandle, null);
188     } catch (MalformedURLException e) {
189       log.error("error while creating new IClient: incorrect session urn", e);
190       client = null;
191     } catch (InvalidSessionDocumentException e)
192     {
193       log.error("error while creating new IClient: invalid session document", e);
194       client = null;
195     } catch (InvalidSessionUrnException e) {
196       log.error("error while creating new IClient: incorrect session urn", e);
197       client = null;
198     } catch (IOException e) {
199       log.error("error while creating new IClient: file access error", e);
200       client = null;
201     }
202     return client;
203   }
204   /**
205    * initialise the vamsas session state and create a SimpleClient object to connect to it
206    * @param sessdir newly created or existing session directory
207    * @param userId 
208    * @param clientHandle
209    * @param vamsasDocument null or a document to pass to SimpleCLient to write into the sessdir
210    * @return the client
211    * @throws IOException if there are problems in session or client creation or if the session already has a vamsasDocument
212    * @throws InvalidSessionUrnException for a malformed sessdir
213    */
214   private IClient initClient(File sessdir, UserHandle userId,
215       ClientHandle clientHandle, File vamsasDocument) throws IOException, InvalidSessionUrnException, InvalidSessionDocumentException {
216     IClient client = null;
217     // create session
218     VamsasSession vamsasSession = null;
219     if (vamsasDocument==null)
220     {
221       vamsasSession = new VamsasSession(sessdir);
222     } else {
223       vamsasSession = new VamsasSession(sessdir, vamsasDocument);
224     }
225
226     this.getSessionManager().addSession(
227         new SessionHandle(new SessionUrn(vamsasSession).getSessionUrn()));
228     if (userId == null) {
229       // create a default userHandle
230       // userId = new UserHandle(System.getProperty("user.name",
231       // System.getProperty("USERNAME","Joe Doe")),
232       // System.getProperty("host.name",System.getProperty("HOSTNAME",
233       // "Unknown") ));// clientName, clientVersion, sessionPath);
234       userId = new UserHandle(null, null);
235     }
236
237     // FullName and organisation should not be null (otherwise UserHandle equals
238     // method raises an java.lang.NullPointerException )
239     // use current OS user and hostname, if null
240     if (userId.getFullName() == null) {
241       userId.setFullName(System.getProperty("user.name", System.getProperty(
242           "USERNAME", "Joe Doe")));
243     }
244
245     if (userId.getOrganization() == null) {
246       userId.setOrganization(System.getProperty("host.name", System
247           .getProperty("HOSTNAME", "Unknown")));
248     }
249
250     if (clientHandle == null)
251       clientHandle = new ClientHandle("SimpleVamsasClientApp", "0.1");
252     else {
253       if (clientHandle.getClientName() == null) {
254         clientHandle.setClientName("SimpleVamsasClientApp");
255       }
256       if (clientHandle.getVersion() == null) {
257         clientHandle.setVersion("0.1");
258       }
259     }
260
261     // create simple client
262     client = new SimpleClient(userId, clientHandle, vamsasSession);
263     vamsasSession.addClient((SimpleClient) client);
264     vamsasSession.setSessionManager(this.getSessionManager());
265     return client;
266   }
267
268   /**
269    * @see uk.ac.vamsas.client.IClientFactory#getIClient(uk.ac.vamsas.client.ClientHandle,
270    *      uk.ac.vamsas.client.UserHandle)
271    */
272   public IClient getIClient(ClientHandle applicationHandle, UserHandle userId)
273       throws NoDefaultSessionException {
274     // create new session
275     // register SimpleClient and UserHandles in session
276     // create client instance
277     IClient client = null;
278     if (this.sessionArena == null)
279       throw new Error(
280           "Improperly initialised SimpleClientFactory object - null sessionArena.");
281
282     ClientHandle clientHandle = applicationHandle;
283     // create default clientHandle with "SimpleVamsasClientApp","0.1",
284     if (clientHandle == null)
285       clientHandle = new ClientHandle("SimpleVamsasClientApp", "0.1");
286     else {
287       if (clientHandle.getClientName() == null) {
288         clientHandle.setClientName("SimpleVamsasClientApp");
289       }
290
291       if (clientHandle.getVersion() == null) {
292         clientHandle.setVersion("0.1");
293       }
294     }
295     // check if any available session(s)
296     String[] availableSessions = this.getCurrentSessions();
297     if (availableSessions != null) {// there are available sessions
298       if (availableSessions.length > 1) {// more than one session if available... can not choose
299
300         // represents list of session as String
301         StringBuffer sessionURNs = new StringBuffer("");
302         for (int i = 0; i < availableSessions.length; i++) {
303           sessionURNs.append(availableSessions[i] + " ");
304         }
305         throw new NoDefaultSessionException(
306             "Several sessions available, please pick one: " + sessionURNs);
307       }
308
309       // check if only one session available. if yes, open it
310       if (availableSessions.length == 1) {
311         // only one session available, open it.
312         return this.getIClient(clientHandle, availableSessions[0]);
313       } else {
314         log.debug("No active session found");
315       }
316     }
317     // no session available - create a new one
318     try {
319       client = clientInNewSession(userId, clientHandle, null);
320     } catch (Exception e)
321     {
322       throw new Error("IMPLEMENTATION ERROR: unexpected exception when creating a new session to connect to.",e);
323     }
324     return client;
325   }
326
327   /**
328    * create a new session directory and possibly import an existing document into it
329    * @param userId
330    * @param clientHandle
331    * @param vamsasDocument null or a document file to copy into the new session
332    * @return null or a valid IClient instance
333    */
334   private IClient clientInNewSession(UserHandle userId,
335       ClientHandle clientHandle, File vamsasDocument) throws InvalidSessionDocumentException, InvalidSessionUrnException{
336
337     IClient client = null;
338     try {
339       // try and make a friendly session name
340       String sesspref = "";
341       if (vamsasDocument!=null)
342       {
343         sesspref = vamsasDocument.getName().replaceAll("([^-A-Za-z0-9]|\\.vdj)", "");
344       }
345       sesspref += (new java.util.Date()).toString().replaceAll("[^-A-Za-z0-9]","_");
346       // create sessionDirectory
347       File sessdir = new File(sessionArena, sesspref+".simpleclient");
348       if (sessdir.exists())
349       {  
350         // make a unique session name
351         sessdir = File.createTempFile(sesspref, ".simpleclient",
352           sessionArena);
353       } else {
354         if (!sessdir.createNewFile())
355         {
356           throw new Error("VAMSAS Implementation error : sesspref friendly session name is invalid on this platform - please tell the authors!");
357         }
358       }
359       log.debug("Creating new session  directory");
360       if (!(sessdir.delete() && sessdir.mkdir()))
361         throw new IOException("Could not make session directory " + sessdir);
362       client = initClient(sessdir, userId, clientHandle, vamsasDocument);
363     } catch (IOException e) {
364       log.error("error while creating new IClient", e);
365     } catch (InvalidSessionUrnException e) {
366       log.error("Unable to create new IClient. The new session urn is malformed.",
367           e);
368     }
369
370     return client;
371   }
372
373   /**
374    * @see uk.ac.vamsas.client.IClientFactory#getCurrentSessions()
375    */
376   public String[] getCurrentSessions() {
377     String[] sessions = null;
378     try {
379       sessions = this.getSessionManager().getCurrentSessions();
380     } catch (IOException e) {
381       log.error("Unable to get available sessions", e);
382       sessions = null;
383     }
384     return sessions;
385   }
386
387   /**
388    * @return the sessionFile
389    */
390   private SimpleSessionManager getSessionManager() throws IOException {
391     if (this.sessionManager == null) {
392       this.sessionManager = new SimpleSessionManager(new File(
393           this.sessionArena, SESSION_LIST));
394     }
395     return this.sessionManager;
396   }
397
398   public IClient getNewSessionIClient(ClientHandle applicationHandle) {
399     try {
400       return clientInNewSession(null, applicationHandle, null);
401     }
402     catch (Exception e) {
403       log.error("Failed to create new session for app with default user.",e);
404     }
405     return null;
406   }
407
408   public IClient getNewSessionIClient(ClientHandle applicationHandle,
409       UserHandle userId) {
410     try {
411       return clientInNewSession(userId, applicationHandle, null);
412     } catch (Exception e) {
413       log.error("Failed to create new session for app and user.",e);
414     }
415     return null;
416   }
417   private void checkImportedDocument(File vamsasDocument) throws InvalidSessionDocumentException 
418   {
419     if (!vamsasDocument.exists())
420     {
421       throw new InvalidSessionDocumentException("File "+vamsasDocument+" does not exist");
422     }
423     if (!vamsasDocument.canRead())
424     {
425       throw new InvalidSessionDocumentException("File "+vamsasDocument+" does not exist");
426     }
427   }
428   public IClient openAsNewSessionIClient(ClientHandle applicationHandle,
429       File vamsasDocument) throws InvalidSessionDocumentException {
430     checkImportedDocument(vamsasDocument);  
431     try {
432       return clientInNewSession(null, applicationHandle, vamsasDocument);
433     } catch (InvalidSessionUrnException e)
434     {
435       throw new InvalidSessionDocumentException("Unexpected exception", e);
436     }
437   }
438
439   public IClient openAsNewSessionIClient(ClientHandle applicationHandle,
440       UserHandle userId, File vamsasDocument) throws InvalidSessionDocumentException {
441     checkImportedDocument(vamsasDocument);  
442     try {
443     return clientInNewSession(userId, applicationHandle, vamsasDocument);
444     } catch (InvalidSessionUrnException e)
445     {
446     throw new InvalidSessionDocumentException("Unexpected exception", e);
447     }
448   }
449
450 }