+ /**
+ * add a IClient to the session
+ *
+ * add the client to the client list file
+ *
+ * @param client
+ * client to add to the session
+ */
+ protected void addClient(SimpleClient client) {
+ if (client == null)
+ slog.error("Try to add a null client to the session ");
+ else {
+ log.debug("Adding client " + client.getClientHandle().getClientUrn());
+ getClientWatcherElement().haltWatch();
+ clist.addClient(client.getClientHandle());
+
+ log.debug("Added.");
+ log.debug("Register Client as Active.");
+ try {
+ client.createActiveClientFile();
+ } catch (IOException e) {
+ log.debug("Error during active client file creation.");
+ }
+ // tracks modification to the client list and readds client to the list
+ getClientWatcherElement().setHandler(new AddClientWatchCallBack(client));
+ getClientWatcherElement().enableWatch();
+
+ }
+ }
+
+ /**
+ * Handler for the client watcher.
+ *
+ * If (the current client is not in the client list, it is added again;)
+ */
+ private class AddClientWatchCallBack implements WatcherCallBack {
+
+ private SimpleClient client;
+
+ /**
+ * Inits the handler with the client to check in the list
+ *
+ * @param client
+ * client to monitor in the client list
+ */
+ protected AddClientWatchCallBack(SimpleClient client) {
+ this.client = client;
+ }
+
+ /**
+ * If the client list is modified, checks if the current is still in the
+ * list. otherwise, readds ti.
+ *
+ * @return true to enable watcher, or false to disable it in future
+ * WatcherThread cycles.
+ */
+ public boolean handleWatchEvent(WatcherElement watcher, Lock lock) {
+ boolean isWatchEnable = watcher.isWatchEnabled();
+ if (lock == null)// no update on the list
+ return isWatchEnable;
+ log.debug("change on the client list ");
+ if (client != null) {
+
+ // checks if the client is not already in the lists
+ ClientHandle[] cl = clist.retrieveClientList(lock);// clist.retrieveClientList();
+ boolean found = false;
+ if (cl != null) {
+ for (int chi = cl.length - 1; !found && chi > -1; chi--) {
+ found = cl[chi].equals(this.client.getClientHandle());
+ }
+
+ }
+ if (!found) {
+ log.debug("client not in the list ");
+ if (log.isDebugEnabled())
+ log
+ .debug("the client has not been found in the list. Adding it again :"
+ + cl);
+ addClient(client);
+ } else
+ log.debug("client is in the list");
+
+ }
+ log.debug("isWatchEnable " + isWatchEnable);
+ return isWatchEnable;
+ }
+ }
+
+ /**
+ *
+ * removes a client from the current session removes the client from the
+ * session client list if the client is the last one from the session
+ * (ClientList), the current session is removed from active session list.
+ *
+ * The active should add them self to the client list. To insure to close the
+ * session,when the current client is the lact active client, clears the list
+ * of clients and when two cycles to insure there is no more active client,
+ * that otherwise would have readd themself to the list
+ *
+ * @param client
+ * client to remove
+ */
+ protected void removeClient(SimpleClient client)// IClient client)
+ {
+ if (client == null) {
+ log.error("Null client passed to removeClient");
+ return;
+ }
+ // ClientSessionFileWatcherElement cwe=getClientWatcherElement();
+ // if (cwe!=null && cwe.isWatchEnabled()) {
+ // cwe.haltWatch();
+ // };
+ // set handler to check is the the last active client of the session
+ // Wait for several watchers cycle to see if the current client was the last
+ // client active in the session.
+ // if yes, close the session
+
+ // getClientWatcherElement().setHandler(new RemoveClientWatchCallBack
+ // (client));
+ // getClientWatcherElement().setTimeoutBeforeLastCycle(this.watchCycleCountBeforeLastClient);
+ log.info("remove client from list");
+ if (clistWatchElement != null) {
+ clistWatchElement.haltWatch();
+ clistWatchElement.watched.unlockFile();
+ }
+ // clist.clearList();
+ // clist.unlockFile();
+ log.info("list cleared");
+ // if (cwe!=null) {
+ // cwe.enableWatch();
+
+ log.debug("Stopping EventGenerator..");
+ client.evgen.stopWatching();
+ // cwe.setHandler(null);
+ // ask to the client to copy application data into the document
+ client.evgen._raise(Events.DOCUMENT_FINALIZEAPPDATA, null, client, null);
+ boolean closeSession = isLastActiveClient(client);
+ if (closeSession) {
+ if (client.get_session().getUnsavedFlag())
+ {
+ log.debug("Raising request-to-save event");
+ client.evgen._raise(Events.DOCUMENT_REQUESTTOCLOSE, null, client, null);
+ }
+ log.debug("Raising session shutdown event");
+ client.evgen._raise(Events.SESSION_SHUTDOWN, null, client
+ .getSessionHandle(), null);
+ log.debug("All events raised for finalising session "+client.getSessionHandle().toString());
+ }
+ // cwe.haltWatch();
+ client.evgen.stopWatching();
+ try {
+ log.debug("Attempting to release active client locks");
+ client.releaseActiveClientFile();
+ } catch (IOException e) {
+ log.error("error during active file client release");
+ }
+ tidyUp();
+ if (closeSession) {
+ log.debug("Last active client: closing session");
+ log.info("Closing session");
+ getSessionManager().removeSession(client.getSessionHandle());
+ }
+ }
+
+ /**
+ * close every file and stop.
+ */
+ private void tidyUp() {
+ if (clist != null)
+ clist.unlockFile();
+ clist = null;
+ storedocfile.unlockFile();
+ storedocfile = null;
+ closeSessionLog();
+ }
+
+ private boolean isLastActiveClient(SimpleClient client) {
+ log.debug("Testing if current client is the last one.");
+ log
+ .debug("current client lockfile is '" + client.getClientlockFile()
+ + "'");
+ boolean noOtherActiveClient = true;
+ // create, if need, subdirectory to contain client files
+ File clientlockFileDir = new File(this.sessionDir, clientFileDirectory);
+ if (!clientlockFileDir.exists()) {
+ log
+ .error("Something wrong the active client file does not exits... should not happen");
+ return false;
+ }
+
+ try {
+
+ // no check every file in the directory and try to get lock on it.
+ File[] clientFiles = clientlockFileDir.listFiles();
+ if (clientFiles == null || clientFiles.length == 0) {// there is not file
+ // on the directory.
+ // the current
+ // client should be
+ // the last one.
+ return true;
+ }
+
+ for (int i = clientFiles.length - 1; i > -1 && noOtherActiveClient; i--) {
+ File clientFile = clientFiles[i];
+ log.debug("testing file for lock: " + clientFile.getAbsolutePath());
+ if (client.getClientLock().isTargetLockFile(clientFile)) {
+ log.debug("current client file found");
+ continue;
+ }
+ if (clientFile != null && clientFile.exists()) {
+ try {
+ log.debug("Try to acquire a lock on the file");
+ // Get a file channel for the file
+ FileChannel channel = new RandomAccessFile(clientFile, "rw")
+ .getChannel();
+
+ // Use the file channel to create a lock on the file.
+ // This method blocks until it can retrieve the lock.
+ // java.nio.channels.FileLock activeClientFilelock = channel.lock();
+
+ // Try acquiring the lock without blocking. This method returns
+ // null or throws an exception if the file is already locked.
+ try {
+ java.nio.channels.FileLock activeClientFilelock = channel
+ .tryLock();
+
+ // the lock has been acquired.
+ // the file was not lock and so the corresponding application
+ // seems to have die
+ if (activeClientFilelock != null) {
+ log
+ .debug("lock obtained : file must be from a crashed application");
+
+ activeClientFilelock.release();
+ log.debug("lock released");
+
+ channel.close();
+ log.debug("channel closed");
+
+ // delete file
+ clientFile.delete();
+ log.debug("crashed application file deleted");
+
+ } else {
+ noOtherActiveClient = false;
+ log.debug("lock not obtained : another application is active");
+ }
+ } catch (OverlappingFileLockException e) {
+ // File is already locked in this thread or virtual machine
+ // that the expected behaviour
+ log.debug("lock not accessible ", e);
+ }
+ } catch (Exception e) {
+ log.debug("error during lock testing ", e);
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ log.error("error during counting active clients");
+ }
+ return noOtherActiveClient;
+ }