Java tutorial
/* * Copyright 2005 jWic group (http://www.jwic.de) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * de.jwic.base.SessionStorage * Created on 08.11.2005 * $Id: SessionManager.java,v 1.5 2010/07/15 08:19:27 lordsam Exp $ */ package de.jwic.base; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import de.jwic.events.SessionEvent; /** * Manages the SessionContainer objects. It is used by the JWicRuntime * to create, retrieve, serialize, deserialize and destroy applications. * * @author Florian Lippisch * @version $Revision: 1.5 $ */ public class SessionManager { protected final Log log = LogFactory.getLog(getClass()); private final static long DELAY = 1000 * 60 * 5; // wait 5 minutes before the first run. private final static long INTERVALL = 1000 * 60 * 5; // run every 5 minutes. // client map private Map<String, Map<String, SessionContainer>> clientSessions = new HashMap<String, Map<String, SessionContainer>>(); private File serDir = null; private long idCount = 10000; private int storeTime = 0; private Timer timer = null; private class RefreshDeamon extends TimerTask { /* (non-Javadoc) * @see java.util.TimerTask#run() */ public void run() { storeOldSessions(); } } /** * Default Constructor. */ public SessionManager(String tempDir) { serDir = new File(tempDir); if (!serDir.exists()) { serDir.mkdirs(); } timer = new Timer(true); timer.schedule(new RefreshDeamon(), DELAY, INTERVALL); } /** * Cancles the RefreshDeamon task and destroys. * all open sessions. */ public void destroy() { // stop timer. timer.cancel(); String[] clients = new String[clientSessions.size()]; getClientIDs().toArray(clients); // destroy all clients. for (String clientID : clients) { destroyClient(clientID); } } /** * */ public void storeOldSessions() { if (storeTime > 0) { // serialization is not disabled log.debug("Searching for out-timed sessions to store..."); long maxAge = System.currentTimeMillis() - (storeTime * 1000 * 60); for (Iterator<String> it = getClientIDs().iterator(); it.hasNext();) { String clientID = it.next(); Collection<SessionContainer> c = getSessions(clientID); if (c != null) { for (Iterator<SessionContainer> itS = c.iterator(); itS.hasNext();) { SessionContainer container = itS.next(); if (container.getState() == SessionContainer.STATE_NORMAL && container.getLastAccess() < maxAge) { if (container.getSessionContext().getApplicationSetup().isSerializable()) { try { log.debug("Auto-Serializing container " + container); serialize(container); } catch (Exception e) { log.error("Error serializing container " + container, e); } } } } } } } } /** * Create a new SessionStore object. * @param clientID - String * @param applicationID - String * @param singleSession - boolean * @return */ public SessionContainer create(String clientID, String applicationID) { Map<String, SessionContainer> sessionMap = getSessionMap(clientID); long idNum = idCount++; String id = idNum + "-" + System.currentTimeMillis(); SessionContainer store = new SessionContainer(id, clientID); store.setApplicationId(applicationID); sessionMap.put(id, store); return store; } /** * @param clientID * @return */ private Map<String, SessionContainer> getSessionMap(String clientID) { Map<String, SessionContainer> map = clientSessions.get(clientID); if (map == null) { synchronized (clientSessions) { map = clientSessions.get(clientID); if (map == null) { map = new HashMap<String, SessionContainer>(); clientSessions.put(clientID, map); } } } return map; } /** * Returns the SessionStore with the specified id. Returns <code>null</code> * if no SessionStore was found. * @param clientID * @param id * @return */ public SessionContainer get(String clientID, String id) { Map<String, SessionContainer> sessionMap = getSessionMap(clientID); return sessionMap.get(id); } /** * Returns the SessionStore for the specified applicationId * @param clientID * @param applicationID * @return */ public SessionContainer getByAppID(String clientID, String applicationID) { Map<String, SessionContainer> sessionMap = getSessionMap(clientID); // iterate through the sessions to find one with the specified appId for (Iterator<SessionContainer> it = sessionMap.values().iterator(); it.hasNext();) { SessionContainer store = it.next(); if (applicationID.equals(store.getApplicationId())) { return store; } } return null; } /** * Removes the SessionStore. * @param store */ public void remove(SessionContainer store) { Map<String, SessionContainer> sessionMap = getSessionMap(store.getClientId()); sessionMap.remove(store.getId()); synchronized (clientSessions) { if (sessionMap.size() == 0) { clientSessions.remove(store.getClientId()); } } } /** * Write the session to a temporary directory. * @param container */ public void serialize(SessionContainer container) { log.debug("Serializing container " + container); String filename = container.getClientId() + "_" + container.getId() + ".ser"; try { SessionContext sc = container.getSessionContext(); sc.fireEvent(new SessionEvent(null), SessionContext.BEFORE_SERIALIZATION); FileOutputStream fos = new FileOutputStream(new File(serDir, filename)); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(sc); oos.close(); container.setState(SessionContainer.STATE_STORED); container.setSessionContext(null); // release SessionContext } catch (Exception e) { log.error("Error storing session", e); throw new JWicException("Serialization failed. Can not serialize session.", e); } } /** * Reactivate the session. * @param container */ public void deserialize(SessionContainer container) { log.debug("Deserializing container " + container); try { String filename = container.getClientId() + "_" + container.getId() + ".ser"; File file = new File(serDir, filename); if (file.exists()) { FileInputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); SessionContext sc = (SessionContext) ois.readObject(); ois.close(); sc.fireEvent(new SessionEvent(null), SessionContext.AFTER_DESERIALIZATION); container.setSessionContext(sc); container.setState(SessionContainer.STATE_NORMAL); fis.close(); if (!file.delete()) { // remove the serialized file. log.warn("Can't delete serialization file " + file.getName()); } } else { throw new JWicException("The session can not be desrialized because the data can not be found."); } } catch (Exception e) { log.error("Error deserializing session", e); throw new JWicException("Deserialization failed. Can not deserialize session.", e); } } /** * Destroys all sessions store for the specified clientID. * @param clientID */ public void destroyClient(String clientID) { Map<String, SessionContainer> map = clientSessions.get(clientID); if (map != null) { // Iterate through all sessions and destroy them. // 2005-12-06 JBO: replaced usage of Iterator to solve ConcurrentModificationException bug while (map.size() > 0) { Map.Entry<String, SessionContainer> entry = map.entrySet().iterator().next(); SessionContainer container = entry.getValue(); try { switch (container.getState()) { // destroy the session case SessionContainer.STATE_NORMAL: { container.getSessionContext().destroy(); container.setState(SessionContainer.STATE_DESTROYED); break; } // desrialize and destroy the session. case SessionContainer.STATE_STORED: { deserialize(container); container.getSessionContext().destroy(); container.setState(SessionContainer.STATE_DESTROYED); break; } default: // ignore others, just remove from map. break; } } catch (Exception e) { log.error("Exception while destroying session " + container, e); } map.remove(entry.getKey()); clientSessions.remove(clientID); } } } /** * Returns the clientIDs that have one or more sessions. * @return */ public Collection<String> getClientIDs() { return clientSessions.keySet(); } /** * Returns the sessions assigned to the specified client ID. * @param clientID * @return */ public Collection<SessionContainer> getSessions(String clientID) { Map<String, SessionContainer> map = clientSessions.get(clientID); if (map != null) { return map.values(); } return null; } /** * Returns the time after a session is serialized. * @return */ public int getStoreTime() { return storeTime; } /** * @param sessionStoreTime */ public void setStoreTime(int sessionStoreTime) { this.storeTime = sessionStoreTime; } }