1 7 8 package org.jboss.ha.httpsession.server; 9 10 import java.util.Collection ; 11 import java.util.Iterator ; 12 import java.util.Random ; 13 import java.security.MessageDigest ; 14 import java.security.NoSuchAlgorithmException ; 15 import java.security.SecureRandom ; 16 17 import javax.ejb.EJBException ; 18 import javax.naming.InitialContext ; 19 import javax.rmi.PortableRemoteObject ; 20 21 import org.jboss.system.ServiceMBeanSupport; 22 23 import org.jboss.ha.httpsession.beanimpl.interfaces.ClusteredHTTPSession; 24 import org.jboss.ha.httpsession.beanimpl.interfaces.LocalClusteredHTTPSession; 25 import org.jboss.ha.httpsession.beanimpl.interfaces.ClusteredHTTPSessionBusiness; 26 import org.jboss.ha.httpsession.beanimpl.interfaces.ClusteredHTTPSessionHome; 27 import org.jboss.ha.httpsession.beanimpl.interfaces.LocalClusteredHTTPSessionHome; 28 import org.jboss.ha.httpsession.interfaces.SerializableHttpSession; 29 30 45 public class ClusteredHTTPSessionService 46 extends ServiceMBeanSupport 47 implements ClusteredHTTPSessionServiceMBean 48 { 49 protected final static long CLEANUP_FREQUENCY = 30000; protected final static int SESSION_ID_BYTES = 16; protected final static String SESSION_ID_HASH_ALGORITHM = "MD5"; 52 protected final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG"; 53 protected final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom"; 54 55 56 protected ClusteredHTTPSessionHome httpSessionHome = null; 57 protected LocalClusteredHTTPSessionHome localHttpSessionHome = null; 58 protected ClusteredHTTPSessionService.CleanupDaemon cleanup = null; 59 protected long sessionTimeout = 15*60*1000; 60 protected boolean useLocalBean = false; 61 62 protected MessageDigest digest=null; 63 protected Random random=null; 64 65 public ClusteredHTTPSessionService() 66 { 67 super(); 68 } 69 70 72 public void setHttpSession (String sessionId, SerializableHttpSession session) throws EJBException 73 { 74 if (log.isDebugEnabled ()) 75 log.debug ("setHttpSession called for session: "+ sessionId); 76 77 ClusteredHTTPSessionBusiness bean = null; 78 79 try 82 { 83 if (useLocalBean) 84 { 85 bean = localHttpSessionHome.findByPrimaryKey (sessionId); 86 } 87 else 88 { 89 bean = httpSessionHome.findByPrimaryKey (sessionId); 90 } 91 92 try 95 { 96 bean.setSession (session); 97 } 98 catch (Exception e) 99 { 100 throw new EJBException ("Exception in setHttpSession: ", e); 101 } 102 103 } 104 catch (javax.ejb.FinderException fe) 105 { 106 try 107 { 108 bean = createSession (sessionId, session); 109 } 110 catch (Exception e) 111 { 112 throw new EJBException ("Exception in setHttpSession while creating unexisting session: ", e); 113 } 114 } 115 catch (Exception e) 116 { 117 throw new EJBException ("Exception in setHttpSession: ", e); 118 } 119 120 } 121 122 public SerializableHttpSession getHttpSession (String sessionId, ClassLoader tcl) 123 throws EJBException 124 { 125 if (log.isDebugEnabled ()) 126 log.debug ("getHttpSession called for session: "+ sessionId); 127 128 ClassLoader prevTCL = Thread.currentThread().getContextClassLoader(); 129 try 130 { 131 Thread.currentThread().setContextClassLoader(tcl); 132 if (useLocalBean) 133 { 134 LocalClusteredHTTPSession sessionBean = localHttpSessionHome.findByPrimaryKey (sessionId); 135 return sessionBean.getSession (); 136 } 137 else 138 { 139 ClusteredHTTPSession sessionBean = httpSessionHome.findByPrimaryKey (sessionId); 140 return sessionBean.getSession (); 141 } 142 } 143 catch (Exception e) 144 { 145 throw new EJBException ("Exception in setHttpSession: ", e); 146 } 147 finally 148 { 149 Thread.currentThread().setContextClassLoader(prevTCL); 150 } 151 } 152 153 public void removeHttpSession (String sessionId) throws EJBException 154 { 155 if (log.isDebugEnabled ()) 156 log.debug ("removeHttpSession called for session: "+ sessionId); 157 try 158 { 159 if (useLocalBean) 160 { 161 localHttpSessionHome.remove (sessionId); 162 } 163 else 164 { 165 httpSessionHome.remove (sessionId); 166 } 167 } 168 catch (Exception e) 169 { 170 throw new EJBException ("Exception in removeHttpSession: ", e); 171 } 172 } 173 174 public long getSessionTimeout () { return this.sessionTimeout; } 175 public void setSessionTimeout (long miliseconds) { this.sessionTimeout = miliseconds; } 176 177 public synchronized String getSessionId () 178 { 179 String id=generateSessionId(); 180 if (log.isDebugEnabled ()) 181 log.debug ("getSessionId called: " + id); 182 return id; 183 } 184 185 public void setUseLocalBean (boolean useLocal) 186 { 187 int state = this.getState (); 188 if (state == this.STARTED || state == this.STARTING) 189 return; 190 else 191 this.useLocalBean = useLocal; 192 } 193 194 public boolean getUseLocalBean () 195 { 196 return this.useLocalBean; 197 } 198 199 201 protected void startService () 202 throws Exception 203 { 204 this.initRefToBean (); 207 cleanup = new ClusteredHTTPSessionService.CleanupDaemon (); 208 cleanup.start (); 209 } 210 211 protected void stopService () 212 throws Exception 213 { 214 cleanup.stop (); 215 httpSessionHome = null; 216 } 217 218 protected void initRefToBean () throws Exception 219 { 220 InitialContext jndiContext = new InitialContext (); 221 if (useLocalBean) 222 { 223 localHttpSessionHome = (LocalClusteredHTTPSessionHome) 224 jndiContext.lookup (LocalClusteredHTTPSessionHome.JNDI_NAME); 225 } 226 else 227 { 228 Object ref = jndiContext.lookup (ClusteredHTTPSessionHome.JNDI_NAME); 229 httpSessionHome = (ClusteredHTTPSessionHome) 230 PortableRemoteObject.narrow (ref, ClusteredHTTPSessionHome.class); 231 } 232 } 233 234 protected ClusteredHTTPSessionBusiness createSession (String id, SerializableHttpSession session) throws Exception 235 { 236 try 237 { 238 ClusteredHTTPSessionBusiness sessionBean = null; 239 if (useLocalBean) 240 { 241 sessionBean = localHttpSessionHome.create (id, session); 242 } 243 else 244 { 245 sessionBean = httpSessionHome.create (id, session); 246 } 247 return sessionBean; 248 } 249 catch (Exception e) 250 { 251 throw new EJBException ("Exception in createSession : ", e); 252 } 253 } 254 255 259 protected synchronized String generateSessionId() 260 { 261 if (this.digest==null) { 262 this.digest=getDigest(); 263 } 264 265 if (this.random==null) { 266 this.random=getRandom(); 267 } 268 269 byte[] bytes=new byte[SESSION_ID_BYTES]; 270 271 this.random.nextBytes(bytes); 273 274 bytes=this.digest.digest(bytes); 276 277 return encode(bytes); 279 } 280 281 288 protected String encode(byte[] data) 289 { 290 char[] out = new char[((data.length + 2) / 3) * 4]; 291 char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*".toCharArray(); 292 293 for (int i=0, index=0; i<data.length; i+=3, index+=4) { 298 boolean quad = false; 299 boolean trip = false; 300 301 int val = (0xFF & (int) data[i]); 302 val <<= 8; 303 if ((i+1) < data.length) { 304 val |= (0xFF & (int) data[i+1]); 305 trip = true; 306 } 307 val <<= 8; 308 if ((i+2) < data.length) { 309 val |= (0xFF & (int) data[i+2]); 310 quad = true; 311 } 312 out[index+3] = alphabet[(quad? (val & 0x3F): 64)]; 313 val >>= 6; 314 out[index+2] = alphabet[(trip? (val & 0x3F): 64)]; 315 val >>= 6; 316 out[index+1] = alphabet[val & 0x3F]; 317 val >>= 6; 318 out[index+0] = alphabet[val & 0x3F]; 319 } 320 return new String (out); 321 } 322 323 327 protected synchronized Random getRandom() 328 { 329 long seed; 330 Random random=null; 331 332 seed=System.currentTimeMillis(); 334 seed^=Runtime.getRuntime().freeMemory(); 335 336 try { 337 random=SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM); 338 } 339 catch (NoSuchAlgorithmException e) 340 { 341 try 342 { 343 random=SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT); 344 } 345 catch (NoSuchAlgorithmException e_alt) 346 { 347 log.error("Could not generate SecureRandom for session-id randomness",e); 348 log.error("Could not generate SecureRandom for session-id randomness",e_alt); 349 return null; 350 } 351 } 352 353 random.setSeed(seed); 355 356 return random; 357 } 358 359 363 protected synchronized MessageDigest getDigest() 364 { 365 MessageDigest digest=null; 366 367 try { 368 digest=MessageDigest.getInstance(SESSION_ID_HASH_ALGORITHM); 369 } catch (NoSuchAlgorithmException e) { 370 log.error("Could not generate MessageDigest for session-id hashing",e); 371 return null; 372 } 373 374 return digest; 375 } 376 377 protected class CleanupDaemon 378 implements Runnable 379 { 380 protected boolean stopping = false; 381 382 public CleanupDaemon () throws Exception 383 { 384 } 385 386 public void start () 387 { 388 stopping = false; 389 Thread t = new Thread (this, "ClusteredHTTPSessionService - CleanupDaemon"); 390 t.start (); 391 } 392 393 public void stop () 394 { 395 stopping = true; 396 } 397 398 public void run () 399 { 400 while (!stopping) 401 { 402 try 403 { 404 Collection allBeans = null; 409 410 if (useLocalBean) 411 allBeans = localHttpSessionHome.findAll (); 412 else 413 allBeans = httpSessionHome.findAll (); 414 415 Iterator iter = allBeans.iterator (); 416 long now = System.currentTimeMillis (); 417 while (iter.hasNext ()) 418 { 419 try 420 { 421 ClusteredHTTPSessionBusiness sessionBean = (ClusteredHTTPSessionBusiness)iter.next (); 422 long lastAccess = sessionBean.getLastAccessedTime (); 423 424 if ( ( now - lastAccess) > sessionTimeout ) 425 { 426 if (useLocalBean) 427 ((LocalClusteredHTTPSession)sessionBean).remove (); 428 else 429 ((ClusteredHTTPSession)sessionBean).remove (); 430 } 431 } 432 catch(Exception notImportant) 433 { 434 log.debug(notImportant); 435 } 436 437 438 if (stopping) 439 return; 440 } 441 } 442 catch (Exception e) 443 { 444 log.info ("unexpected exception while removing orphean replicated sessions", e); 445 } 446 finally 447 { 448 if (!stopping) 449 try 452 { 453 synchronized (this) 454 { 455 this.wait (CLEANUP_FREQUENCY); 456 } 457 } 458 catch (InterruptedException gameOver) 459 { 460 stopping = true; 461 return; 462 } 463 464 } 465 } 466 } 467 } 468 } 469 | Popular Tags |