1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package net.jot.web.server; import java.math.BigInteger; import java.util.Date; import java.util.Hashtable; import java.security.SecureRandom; import java.util.Enumeration; import javax.servlet.ServletContext; import net.jot.logger.JOTLogger; /** * Manage Web sessions * TODO: session cleanup thread * @author thibautc */ public class JOTSessionManager { private static final JOTSessionManager instance = new JOTSessionManager(); private final SecureRandom random = new SecureRandom(); private int uniq = 1; private final JOTServletContext context = new JOTServletContext(); private JOTSessionManagerThread thread = new JOTSessionManagerThread(); // cleanup every 5mn private final static long CLEANUP_INTERVAL = 1000 * 300; /** * TODO: synchronized, faster to use hashmap instead(safe?) ? -> research later */ private Hashtable sessions = new Hashtable(); private boolean inUse=false; public static JOTSessionManager getInstance() { if(!instance.inUse && !instance.thread.isAlive()) { instance.thread.start(); } instance.inUse=true; return instance; } /** * if session does not exist yet, then create one (with a new sessionId, not the one passed) * @param sessionId * @return */ public JOTWebSession getOrCreateSession(String sessionId) { JOTWebSession session = getSession(sessionId); if (session == null) { session = createSession(); } return session; } /** * returns null if does not exists or invalid / expired * @param sessionId * @return */ public JOTWebSession getSession(String sessionId) { JOTWebSession session = (JOTWebSession) sessions.get(sessionId); if (session != null && (isExpired(sessionId) || session.isInvalidated())) { session = null; } if (session != null) { session.setLastAccessTime(new Date().getTime()); /** TODO: this is probably not the right way to set isNew * If the user calls craete and then get again it would set to new where it should noit * Probably OK though * */ session.setNew(false); } return session; } /** * Create a new session witha new unique ID * @return */ public JOTWebSession createSession() { String sessionId = getUniqueSessionID(); JOTWebSession session = new JOTWebSession(sessionId); return session; } private synchronized String getUniqueSessionID() { String sessionId = null; do { byte[] id = new byte[32]; random.nextBytes(id); id[31] = (byte) uniq; id[30] = (byte) (uniq << 8); BigInteger bi = new BigInteger(id); sessionId = bi.toString(16); // still check for collision just in case. } while (sessions.containsKey(sessionId)); // not used as a unique identifier, just to avoid random number collisions uniq++; if (uniq < 0) { uniq = 0; } return sessionId; } public boolean isExpired(String sessionId) { JOTWebSession session = (JOTWebSession) sessions.get(sessionId); boolean expired = false; if (session != null) { expired = new Date().getTime() - session.getLastAccessedTime() > session.getMaxInactiveInterval() * 1000; } return expired; } ServletContext getServletContext() { throw (new UnsupportedOperationException("Not supported yet.")); } public void finalize() throws Throwable { shutdown(); super.finalize(); } public static void shutdown() { if (instance != null) { getInstance().thread.shutdown(); } } /** * session cleanup thread */ private class JOTSessionManagerThread extends Thread implements Runnable { volatile boolean stop = false; public JOTSessionManagerThread() { } public void run() { while (!stop) { try { sleep(CLEANUP_INTERVAL); if (inUse) { //if nobody is using this, no point wasting time. long start = new Date().getTime(); int startSize = sessions.size(); cleanup(); long end = new Date().getTime(); int endSize = sessions.size(); if (JOTLogger.isDebugEnabled()) { JOTLogger.debug(this, "Session cleanup from:" + startSize + " to:" + endSize + " took:" + (end - start) + "ms."); } } } catch (InterruptedException ie) { // stop was set. } } } private void cleanup() { Enumeration e = sessions.keys(); while (e.hasMoreElements()) { String key = (String) e.nextElement(); JOTWebSession session = (JOTWebSession) sessions.get(key); if (session.isInvalidated() || session.isExpired()) { sessions.remove(key); session = null; } } } private void shutdown() { stop = true; // stop sleeping. interrupt(); } } }