package org.vamsas.client.simpleclient;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.io.Writer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Appender;
import org.apache.log4j.Logger;
import org.apache.log4j.FileAppender;
+import org.vamsas.client.ClientHandle;
+import org.vamsas.client.UserHandle;
/**
+ * Does all the IO operations for a SimpleClient instance accessing
+ * a SimpleClient vamsas session.
*
+ * Basically, it defines the various standard names for the files
+ * in the session directory (that maps to the sessionUrn),
+ * provides constructors for the file handlers and watchers of
+ * those file entities, and some higher level methods
+ * to check and change the state flags for the session.
+ *
+ * TODO: move the stuff below to the SimpleClientFactory documentation.
+ * much may not be valid now :
* Vamsas client is intialised with a path to create live session directories.
* This path may contain a vamsas.properties file
* that sets additional parameters (otherwise client
* During the session
* - Update watcher checks for file change -
*
+ * Procedures for file based session message exchange
+ * - session document modification flag
+ *
*/
public class VamsasSession {
/**
- * Holds the file handlers and watchers for a session.
+ * indicator file for informing other processes that
+ * they should finalise their vamsas datasets for
+ * storing into a vamsas archive.
*/
+ public static final String CLOSEANDSAVE_FILE="stored.log";
/**
- * TODO: make sessionDir signature to allow VamsasSession instances to recognise the form of the directory
+ * session file storing the last_stored_stat data
*/
+ public static final String MODIFIEDDOC_FILE="modified";
+
/**
- * indicator file for informing other processes that
- * they should finalise their vamsas datasets for
- * storing in a vamsas archive.
+ * called to clear update flag after a successful offline storage event
*/
- public static final String CLOSEANDSAVE_FILE="exiting";
+ protected void clearUnsavedFlag() {
+ SessionFlagFile laststored = new SessionFlagFile(new File(sessionDir, MODIFIEDDOC_FILE));
+ if (!laststored.clearFlag())
+ log.warn("Unsaved flag was not cleared for "+sessionDir);
+ }
+ /**
+ * called to indicate session document has been modified.
+ *
+ */
+ protected void setUnsavedFlag() {
+ SessionFlagFile laststored = new SessionFlagFile(new File(sessionDir, MODIFIEDDOC_FILE));
+ if (!laststored.setFlag())
+ log.warn("Couldn't set the Unsaved flag for "+sessionDir);
+ }
+ /**
+ *
+ * @return true if session document has been modified since last offline storage event
+ */
+ protected boolean getUnsavedFlag() {
+ SessionFlagFile laststored = new SessionFlagFile(new File(sessionDir, MODIFIEDDOC_FILE));
+ return laststored.checkFlag();
+ }
/**
* log file location
*/
* @throws IOException
*/
private void initLog() throws IOException {
+ // LATER: make dedicated appender format for session log.
Appender app = slog.getAppender("SESSION_LOG");
slog.addAppender(new FileAppender(app.getLayout(), new File(sessionDir, SESSION_LOG).getAbsolutePath()));
}
throw new IOException("initSessionObjects called for initialised VamsasSession object.");
clist = new ClientsFile(new File(sessionDir,CLIENT_LIST));
vamArchive = new VamsasFile(new File(sessionDir,VAMSAS_OBJ));
+ initLog();
}
/**
* make a new watcher object for the clientFile
public FileWatcher getClientWatcher() {
return new FileWatcher(clist.sessionFile);
}
+ FileWatcher session_doc_watcher=null;
/**
* make a new watcher object for the vamsas Document
* @return new ClientFile watcher instance
*/
public FileWatcher getDocWatcher() {
+ if (session_doc_watcher==null)
+ return session_doc_watcher = new FileWatcher(vamArchive.sessionFile);
return new FileWatcher(vamArchive.sessionFile);
}
-
+ FileWatcher store_doc_file=null;
/**
* make a new watcher object for the messages file
+ * (thread safe - keeps a reference to the first watcher)
* @return new watcher instance
*/
public FileWatcher getStoreWatcher() {
+ if (store_doc_file==null)
+ return store_doc_file = new FileWatcher(new File(CLOSEANDSAVE_FILE));
return new FileWatcher(new File(CLOSEANDSAVE_FILE));
+
+ }
+ /**
+ * write to the StoreWatcher file to indicate that a storeDocumentRequest has been made.
+ * The local client's storeWatcher FileWatcher object is updated so the initial change is not registered.
+ * @param client
+ * @param user
+ * @return
+ */
+ public void addStoreDocumentRequest(ClientHandle client, UserHandle user) throws IOException {
+ SessionFile sfw = new SessionFile(new File(sessionDir, CLOSEANDSAVE_FILE));
+ while (!sfw.lockFile())
+ log.debug("Trying to get lock for "+CLOSEANDSAVE_FILE);
+ sfw.fileLock.rafile.setLength(0); // wipe out any old info.
+ // TODO: rationalise what gets written to this file (ie do we want other clients to read the id of the requestor?)
+ sfw.fileLock.rafile.writeUTF(client.getClientUrn()+":"+user.getFullName()+"@"+user.getOrganization());
+ sfw.unlockFile();
+ if (store_doc_file!=null)
+ store_doc_file.setState();
+ slog.info("FinalizeAppData request from "+user.getFullName()+" using "+client.getClientUrn()+"");
+ }
+ /**
+ * create a new session with an existing vamsas Document - by copying it into the session.
+ * @param archive
+ */
+ protected void setVamsasDocument(File archive) throws IOException {
+ log.debug("Transferring vamsas data from "+archive+" to session:"+vamArchive.sessionFile);
+ SessionFile xtantdoc = new SessionFile(archive);
+ vamArchive.updateFrom(null, xtantdoc);
+ // LATER: decide if session archive provenance should be updated to reflect access.
+ // TODO: soon! do a proper import objects from external file
+ log.debug("Transfer complete.");
+ }
+ /**
+ * write session as a new vamsas Document (this will overwrite any existing file without warning)
+ * TODO: test
+ * TODO: verify that lock should be released for vamsas document.
+ * @param destarchive
+ */
+ protected void writeVamsasDocument(File destarchive, Lock extlock) throws IOException {
+ log.debug("Transferring vamsas data from "+vamArchive.sessionFile+" to session:"+destarchive);
+ SessionFile newdoc = new SessionFile(destarchive);
+ if (extlock==null && !vamArchive.lockFile())
+ while (!vamArchive.lockFile())
+ log.info("Trying to get lock for "+vamArchive.sessionFile);
+ // TODO: LATER: decide if session archive provenance should be written in vamsasDocument file for this export.
+ newdoc.updateFrom(extlock, vamArchive);
+ // LATER: LATER: fix use of updateFrom for file systems where locks cannot be made (because they don't have a lockManager, ie NFS/Unix, etc).
+ vamArchive.unLock();
+ newdoc.unlockFile();
+ log.debug("Transfer complete.");
+ }
+
+ /**
+ * Creates a VamsasArchive Vobject for accessing and updating document
+ * Note: this will lock the Vamsas Document for exclusive access to the client.
+ * @return session vamsas document
+ * @throws IOException if locks fail or vamsas document read fails.
+ */
+ protected VamsasArchive getVamsasDocument() throws IOException {
+ // TODO: check we haven't already done this once
+ if (!vamArchive.lockFile())
+ throw new IOException("Failed to get lock for vamsas archive.");
+
+ VamsasArchive va = new VamsasArchive(vamArchive.sessionFile, false, true, vamArchive);
+
+ return va;
}
}