1 package org.vamsas.client.simpleclient;
3 import java.io.BufferedWriter;
5 import java.io.IOException;
6 import java.io.PrintStream;
7 import java.io.PrintWriter;
10 import org.apache.commons.logging.Log;
11 import org.apache.commons.logging.LogFactory;
12 import org.apache.log4j.Appender;
13 import org.apache.log4j.Logger;
14 import org.apache.log4j.FileAppender;
15 import org.vamsas.client.ClientHandle;
16 import org.vamsas.client.UserHandle;
18 * Holds the file handlers and watchers for a session.
20 * TODO: delete the stuff below - prolly irrelevant now
21 * Vamsas client is intialised with a path to create live session directories.
22 * This path may contain a vamsas.properties file
23 * that sets additional parameters (otherwise client
24 * just uses the one on the classpath).
26 * A vamsas session consists of :
27 * SessionDir - translates to urn of a live session.
28 * Contains: Vamsas Document (as a jar), Session client list file,
29 * both of which may be locked, and additional
30 * temporary versions of these files when write
31 * operations are taking place.
34 * - vamsasdocument.xml : core info
36 * - <applicationname>.version.sessionnumber.raw (string given in vamsasdocument.xml applicationData entry)
39 * - filename given in the vamsasdocument.xml. Should be checked for validity by any client and rewritten if necessary.
40 * The lockfile can point to the jar itself.
42 * Initially - documentHandler either:
43 * - creates a zip for a new session for the client
44 * - connect to an existing session zip
45 * 1. reads session urn file
47 * 3. examines session - decide whether to create new application data slice or connect to one stored in session.
48 * 4. writes info into session file
49 * 5. releases lock and generates local client events.
50 * 6. Creates Watcher thread to generate events.
53 * - Update watcher checks for file change -
57 public class VamsasSession {
59 * indicator file for informing other processes that
60 * they should finalise their vamsas datasets for
61 * storing into a vamsas archive.
63 public static final String CLOSEANDSAVE_FILE="stored.log";
65 * state of vamsas document when it was last stored outside the session directory
67 protected long last_stored_stat[]=null;
68 protected void updateLastStoredStat() {
74 public static final String SESSION_LOG="Log.txt";
75 private static Log log = LogFactory.getLog(VamsasSession.class);
76 protected Logger slog = Logger.getLogger("org.vamsas.client.SessionLog");
78 * setup the sessionLog using Log4j.
81 private void initLog() throws IOException {
82 // TODO: LATER: make dedicated appender format for session log.
83 Appender app = slog.getAppender("SESSION_LOG");
84 slog.addAppender(new FileAppender(app.getLayout(), new File(sessionDir, SESSION_LOG).getAbsolutePath()));
88 * the sessionDir is given as the session location for new clients.
92 * holds the list of attached clients
95 public static final String CLIENT_LIST="Clients.obj";
99 VamsasFile vamArchive;
100 public static final String VAMSAS_OBJ="VamDoc.jar";
103 * sets up the vamsas session files and watchers in sessionDir
106 protected VamsasSession(File sessionDir) throws IOException {
107 if (sessionDir==null)
108 throw new Error("Null directory for VamsasSession.");
109 if (sessionDir.exists()) {
110 if (!sessionDir.isDirectory() || !sessionDir.canWrite() || sessionDir.canRead())
111 throw new IOException("Cannot access '"+sessionDir+"' as a read/writable Directory.");
112 if (checkSessionFiles(sessionDir)) {
113 // session files exist in the directory
114 this.sessionDir = sessionDir;
115 initSessionObjects();
116 slog.debug("Initialising additional VamsasSession instance");
117 log.debug("Attached to VamsasSession in "+sessionDir);
120 // start from scratch
121 if (!sessionDir.mkdir())
122 throw new IOException("Failed to make VamsasSession directory in "+sessionDir);
123 this.sessionDir = sessionDir;
124 createSessionFiles();
125 initSessionObjects();
126 slog.debug("Session directory created.");
127 log.debug("Initialised VamsasSession in "+sessionDir);
131 * tests presence of existing sessionfiles files in dir
135 private boolean checkSessionFiles(File dir) throws IOException {
136 File c_file = new File(dir,CLIENT_LIST);
137 File v_doc = new File(dir,VAMSAS_OBJ);
138 if (c_file.exists() && v_doc.exists())
143 * create new empty files in dir
146 private void createSessionFiles() throws IOException {
147 if (sessionDir==null)
148 throw new IOException("Invalid call to createSessionFiles() with null sessionDir");
149 File c_file = new File(sessionDir,CLIENT_LIST);
150 File v_doc = new File(sessionDir,VAMSAS_OBJ);
151 if (c_file.createNewFile())
152 log.debug("Created new ClientFile "+c_file); // don't care if this works or not
153 if (v_doc.createNewFile())
154 log.debug("Created new Vamsas Session Document File "+v_doc);
157 * construct SessionFile objects and watchers for each
159 private void initSessionObjects() throws IOException {
160 if (clist!=null || vamArchive!=null)
161 throw new IOException("initSessionObjects called for initialised VamsasSession object.");
162 clist = new ClientsFile(new File(sessionDir,CLIENT_LIST));
163 vamArchive = new VamsasFile(new File(sessionDir,VAMSAS_OBJ));
167 * make a new watcher object for the clientFile
168 * @return new ClientFile watcher instance
170 public FileWatcher getClientWatcher() {
171 return new FileWatcher(clist.sessionFile);
174 * make a new watcher object for the vamsas Document
175 * @return new ClientFile watcher instance
177 public FileWatcher getDocWatcher() {
178 return new FileWatcher(vamArchive.sessionFile);
180 FileWatcher store_doc_file=null;
182 * make a new watcher object for the messages file
183 * @return new watcher instance
185 public FileWatcher getStoreWatcher() {
186 return store_doc_file = new FileWatcher(new File(CLOSEANDSAVE_FILE));
189 * write to the StoreWatcher file to indicate that a storeDocumentRequest has been made.
190 * The local client's storeWatcher FileWatcher object is updated so the initial change is not registered.
195 public void addStoreDocumentRequest(ClientHandle client, UserHandle user) throws IOException {
196 SessionFile sfw = new SessionFile(new File(sessionDir, CLOSEANDSAVE_FILE));
197 while (!sfw.lockFile())
198 log.debug("Trying to get lock for "+CLOSEANDSAVE_FILE);
199 sfw.fileLock.rafile.setLength(0); // wipe out any old info.
200 // TODO: rationalise what gets written to this file (ie do we want other clients to read the id of the requestor?)
201 sfw.fileLock.rafile.writeUTF(client.getClientUrn()+":"+user.getFullName()+"@"+user.getOrganization());
203 if (store_doc_file!=null)
204 store_doc_file.setState();
205 slog.info("FinalizeAppData request from "+user.getFullName()+" using "+client.getClientUrn()+"");
208 * create a new session with an existing vamsas Document - by copying it into the session.
211 protected void setVamsasDocument(File archive) throws IOException {
212 log.debug("Transferring vamsas data from "+archive+" to session:"+vamArchive.sessionFile);
213 SessionFile xtantdoc = new SessionFile(archive);
214 vamArchive.updateFrom(null, xtantdoc);
215 // LATER: decide if session archive provenance should be updated to reflect access.
216 // TODO: soon! do a proper import objects from external file
217 log.debug("Transfer complete.");
220 * write session as a new vamsas Document (this will overwrite any existing file without warning)
222 * TODO: verify that lock should be released for vamsas document.
225 protected void writeVamsasDocument(File destarchive, Lock extlock) throws IOException {
226 log.debug("Transferring vamsas data from "+vamArchive.sessionFile+" to session:"+destarchive);
227 SessionFile newdoc = new SessionFile(destarchive);
228 if (extlock==null && !vamArchive.lockFile())
229 while (!vamArchive.lockFile())
230 log.info("Trying to get lock for "+vamArchive.sessionFile);
231 // TODO: LATER: decide if session archive provenance should be written in vamsasDocument file for this export.
232 newdoc.updateFrom(extlock, vamArchive);
233 // TODO: SOON: fix use of updateFrom for file systems where locks cannot be made (because they don't have a lockManager, ie NFS/Unix, etc).
236 log.debug("Transfer complete.");
240 * Creates a VamsasArchive object for accessing and updating document
241 * Note: this will lock the Vamsas Document for exclusive access to the client.
242 * @return session vamsas document
243 * @throws IOException if locks fail or vamsas document read fails.
245 protected VamsasArchive getVamsasDocument() throws IOException {
246 // TODO: check we haven't already done this once
247 if (!vamArchive.lockFile())
248 throw new IOException("Failed to get lock for vamsas archive.");
250 VamsasArchive va = new VamsasArchive(vamArchive.sessionFile, false, true, vamArchive);