/** Copyright (C) 2012 Delcyon, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.delcyon.capo.protocol.server; import java.util.Random; import java.util.Set; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import com.delcyon.capo.CapoApplication; import com.delcyon.capo.CapoApplication.Location; import com.delcyon.capo.preferences.Preference; import com.delcyon.capo.preferences.PreferenceInfo; import com.delcyon.capo.preferences.PreferenceInfoHelper; import com.delcyon.capo.preferences.PreferenceProvider; import com.delcyon.capo.resourcemanager.remote.RemoteResourceDescriptorProxy; /** * @author jeremiah * */ @PreferenceProvider(preferences=ClientRequestProcessorSessionManager.Preferences.class) public class ClientRequestProcessorSessionManager extends Thread { public enum Preferences implements Preference { @PreferenceInfo(arguments={"min"}, defaultValue="5", description="The number of minutes before an inactive session timesout", longOption="DEFAULT_SESSION_TIMEOUT", option="DEFAULT_SESSION_TIMEOUT") DEFAULT_SESSION_TIMEOUT ; @Override public String[] getArguments() { return PreferenceInfoHelper.getInfo(this).arguments(); } @Override public String getDefaultValue() { return PreferenceInfoHelper.getInfo(this).defaultValue(); } @Override public String getDescription() { return PreferenceInfoHelper.getInfo(this).description(); } @Override public String getLongOption() { return PreferenceInfoHelper.getInfo(this).longOption(); } @Override public String getOption() { return PreferenceInfoHelper.getInfo(this).option(); } @Override public Location getLocation() { return PreferenceInfoHelper.getInfo(this).location(); } } private static Random random = new Random(); /** * Allow a client request processor to register under a different session than its own. * @param clientRequestProcessor * @param sessionID */ public static void registerClientRequestProcessor(ClientRequestProcessor clientRequestProcessor, String sessionID) { ClientRequestProcessorSession clientRequestProcessorSession = getClientRequestProcessorSessionHashtable().get(sessionID); if (clientRequestProcessorSession == null) { clientRequestProcessorSession = new ClientRequestProcessorSession(clientRequestProcessor, sessionID); getClientRequestProcessorSessionHashtable().put(sessionID,clientRequestProcessorSession); } else { clientRequestProcessorSession.setClientRequestProcessor(clientRequestProcessor); } clientRequestProcessorSession.updateLastAactivityTime(); } public static void removeClientRequestProcessor(ClientRequestProcessor clientRequestProcessor) { removeClientRequestProcessor(clientRequestProcessor.getSessionId()); } public static void removeClientRequestProcessor(String sessionID) { getClientRequestProcessorSessionHashtable().remove(sessionID); } //SS public static ClientRequestProcessor getClientRequestProcessor(String sessionID) { ClientRequestProcessorSession clientRequestProcessorSession = getClientRequestProcessorSessionHashtable().get(sessionID); if (clientRequestProcessorSession == null) { return null; } else { clientRequestProcessorSession.updateLastAactivityTime(); return clientRequestProcessorSession.getClientRequestProcessor(); } } public static String generateSessionID() { return System.nanoTime()+""+random.nextLong(); } public static void registerClientRequestProcessor(ClientRequestProcessor clientRequestProcessor) { registerClientRequestProcessor(clientRequestProcessor,clientRequestProcessor.getSessionId()); } private boolean interrupted = false; private boolean isFinished = false; public ClientRequestProcessorSessionManager() { super("Client Request Processor Session Manager Thread"); CapoApplication.setGlobalObject("clientRequestProcessorSessionHashtable", new ConcurrentHashMap<String, ClientRequestProcessorSession>()); } @SuppressWarnings("unchecked") private static ConcurrentHashMap<String, ClientRequestProcessorSession> getClientRequestProcessorSessionHashtable() { return (ConcurrentHashMap<String, ClientRequestProcessorSession>)CapoApplication.getGlobalObject("clientRequestProcessorSessionHashtable"); } public void shutdown() throws Exception { this.interrupted = true; while(isFinished == false) { Thread.sleep(1000); } } private void cleanup() { Set<Entry<String, ClientRequestProcessorSession>> clientRequestProcessorSessionHashtableEntrySet = getClientRequestProcessorSessionHashtable().entrySet(); for (Entry<String, ClientRequestProcessorSession> entry : clientRequestProcessorSessionHashtableEntrySet) { CapoApplication.logger.log(Level.INFO, "Killing session: "+entry.getKey()+" - "+entry.getValue().getClientRequestProcessor().getClass().getCanonicalName()); getClientRequestProcessorSessionHashtable().remove(entry.getKey()); } } @Override public void run() { try { while(interrupted == false) { sleep(1000); Set<Entry<String, ClientRequestProcessorSession>> clientRequestProcessorSessionHashtableEntrySet = getClientRequestProcessorSessionHashtable().entrySet(); for (Entry<String, ClientRequestProcessorSession> entry : clientRequestProcessorSessionHashtableEntrySet) { if (entry.getValue().isTimedOut()) { CapoApplication.logger.log(Level.INFO, "Removing expired session: "+entry.getKey()+" - "+entry.getValue().getClientRequestProcessor().getClass().getCanonicalName()); if(entry.getValue().getClientRequestProcessor() instanceof RemoteResourceDescriptorProxy) { CapoApplication.logger.log(Level.WARNING,"Resource was still open:"+((RemoteResourceDescriptorProxy) entry.getValue().getClientRequestProcessor()).getResourceURI()); } getClientRequestProcessorSessionHashtable().remove(entry.getKey()); } else { //do nothing } } } } catch (Exception exception) { CapoApplication.logger.log(Level.WARNING, "Error in SessionManager", exception); } finally { cleanup(); isFinished = true; } } }