1 16 package org.mortbay.j2ee.session; 17 18 20 import java.rmi.RemoteException ; 21 import java.util.ArrayList ; 22 import java.util.Collection ; 23 import java.util.EventListener ; 24 import java.util.HashMap ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.Map ; 28 import java.util.Timer ; 29 import java.util.TimerTask ; 30 31 import javax.servlet.ServletContext ; 32 import javax.servlet.http.Cookie ; 33 import javax.servlet.http.HttpServletRequest ; 34 import javax.servlet.http.HttpSession ; 35 import javax.servlet.http.HttpSessionAttributeListener ; 36 import javax.servlet.http.HttpSessionBindingEvent ; 37 import javax.servlet.http.HttpSessionContext ; 38 import javax.servlet.http.HttpSessionEvent ; 39 import javax.servlet.http.HttpSessionListener ; 40 41 import org.jfox.ioc.logger.Logger; 42 import org.mortbay.http.HttpOnlyCookie; 43 import org.mortbay.jetty.servlet.SessionManager; 44 import org.mortbay.jetty.servlet.WebApplicationContext; 45 46 48 51 66 70 75 82 84 public class Manager 85 implements org.mortbay.jetty.servlet.SessionManager 86 { 87 protected static final Logger _log=Logger.getLogger(Manager.class); 88 89 90 protected WebApplicationContext _context; 92 public WebApplicationContext getContext() {return _context;} 93 public void setContext(WebApplicationContext context) {_context=context;} 94 protected int _scavengerPeriod=60; public void setScavengerPeriod(int period) {_scavengerPeriod=period;} 97 public int getScavengerPeriod() {return _scavengerPeriod;} 98 protected StateInterceptor[] _interceptorStack=null; 100 public StateInterceptor[] getInterceptorStack() {return _interceptorStack;} 101 public void setInterceptorStack(StateInterceptor[] interceptorStack) {_interceptorStack=interceptorStack;} 102 protected IdGenerator _idGenerator=null; 104 public IdGenerator getIdGenerator() {return _idGenerator;} 105 public void setIdGenerator(IdGenerator idGenerator) {_idGenerator=idGenerator;} 106 protected int _maxInactiveInterval; 108 public int getMaxInactiveInterval() {return _maxInactiveInterval;} 109 public void setMaxInactiveInterval(int seconds) {_maxInactiveInterval=seconds;} 110 protected Store _store = null; 112 113 private boolean _secureCookies = false; 114 private boolean _httpOnly = false; 115 private boolean _crossContextSessionIDs = false; 116 117 118 public Store 119 getStore() 120 { 121 return _store; 122 } 123 124 public void 125 setStore(Store store) 126 { 127 _store=store; 128 129 if (_store!=null) 130 _store.setManager(this); 131 } 132 133 135 public Object 136 clone() 137 { 138 Manager m=new Manager(); 140 141 Store store=getStore(); 143 if (store!=null) 144 m.setStore((Store)store.clone()); 145 146 IdGenerator ig=getIdGenerator(); 148 if (ig!=null) 149 m.setIdGenerator((IdGenerator)ig.clone()); 150 151 m.setInterceptorStack(getInterceptorStack()); 153 154 m.setMaxInactiveInterval(getMaxInactiveInterval()); 155 m.setScavengerPeriod(getScavengerPeriod()); 156 157 return m; 158 } 159 160 162 final Map _sessions = new HashMap (); 163 164 public String getContextPath() {return _handler.getHttpContext().getContextPath();} 165 166 170 boolean _started=false; 171 Object _startedLock=new Object (); 172 Timer _scavenger; 173 174 class Scavenger 175 extends TimerTask 176 { 177 public void 178 run() 179 { 180 try 181 { 182 scavenge(); 183 } 184 catch (Throwable e) 185 { 186 _log.warn("could not scavenge local sessions", e); 187 } 188 } 189 } 190 191 public void 192 start() 193 { 194 _log.trace("starting..."); 195 synchronized (_startedLock) 196 { 197 if (_started) 198 { 199 _log.warn("already started"); 200 return; 201 } 202 203 if (_store==null) 204 { 205 _log.warn("No Store. Falling back to a local session implementation - NO HTTPSESSION DISTRIBUTION"); 206 setStore(new LocalStore()); 207 } 208 209 if (_idGenerator==null) 210 _idGenerator=new DistributableIdGenerator(); 211 212 try 213 { 214 _store.start(); 215 } 216 catch (Exception e) 217 { 218 _log.warn("Faulty Store. Falling back to a local session implementation - NO HTTPSESSION DISTRIBUTION", e); 219 setStore(new LocalStore()); 220 try{_store.start();}catch(Exception e2){_log.error("could not start Store", e2);} 221 } 222 223 if (_log.isTraceEnabled()) _log.trace("starting local scavenger thread...(period: "+getScavengerPeriod()+" secs)"); 224 long delay=getScavengerPeriod()*1000; 225 boolean isDaemon=true; 226 _scavenger=new Timer (isDaemon); 227 _scavenger.scheduleAtFixedRate(new Scavenger() ,delay,delay); 228 _log.trace("...local scavenger thread started"); 229 _started=true; 230 } 231 232 _log.trace("...started"); 233 } 234 235 public boolean 236 isStarted() 237 { 238 synchronized (_startedLock) {return _started;} 239 } 240 241 public void 242 stop() 243 { 244 _log.trace("stopping..."); 245 246 synchronized (_startedLock) 247 { 248 if (!_started) 249 { 250 _log.warn("already stopped/not yet started"); 251 return; 252 } 253 254 257 synchronized (_sessions) 258 { 259 List copy=new ArrayList (_sessions.values()); 260 for (Iterator i=copy.iterator(); i.hasNext();) 261 ((StateAdaptor)i.next()).migrate(); 262 263 _sessions.clear(); 264 } 265 266 _log.trace("stopping local scavenger thread..."); 267 _scavenger.cancel(); 268 _scavenger=null; 269 _log.trace("...local scavenger thread stopped"); 270 scavenge(); 271 272 _store.stop(); 273 _store.destroy(); 274 setStore(null); 275 _started=false; 276 } 277 278 _log.trace("...stopped"); 279 } 280 281 285 protected org.mortbay.jetty.servlet.ServletHandler _handler; 286 287 public void 288 initialize(org.mortbay.jetty.servlet.ServletHandler handler) 289 { 290 _log.trace("initialising..."); 291 _handler=handler; 292 295 _log.trace("...initialised"); 297 } 298 299 303 public HttpSession 304 getHttpSession(String id) 305 { 306 return findSession(id,true); 307 } 308 309 public boolean 310 sessionExists(String id) 311 { 312 return findSession(id,false)!=null; 313 } 314 315 public HttpSession 316 newHttpSession(HttpServletRequest request) { 318 return newSession(request); 319 } 320 321 324 327 331 final List _sessionListeners =new ArrayList (); 332 final List _sessionAttributeListeners =new ArrayList (); 333 334 public void 335 addEventListener(EventListener listener) 336 throws IllegalArgumentException , IllegalStateException 337 { 338 synchronized (_startedLock) 339 { 340 if (isStarted()) 341 throw new IllegalStateException ("EventListeners must be added before a Session Manager starts"); 342 343 boolean known=false; 344 if (listener instanceof HttpSessionAttributeListener ) 345 { 346 _sessionAttributeListeners.add(listener); 348 known=true; 349 } 350 if (listener instanceof HttpSessionListener ) 351 { 352 _sessionListeners.add(listener); 354 known=true; 355 } 356 357 if (!known) 358 throw new IllegalArgumentException ("Unknown EventListener type "+listener); 359 } 360 } 361 362 public void 363 removeEventListener(EventListener listener) 364 throws IllegalStateException 365 { 366 synchronized (_startedLock) 367 { 368 if (isStarted()) 369 throw new IllegalStateException ("EventListeners may not be removed while a Session Manager is running"); 370 371 if (listener instanceof HttpSessionAttributeListener ) 372 _sessionAttributeListeners.remove(listener); 373 if (listener instanceof HttpSessionListener ) 374 _sessionListeners.remove(listener); 375 } 376 } 377 378 382 public ServletContext 383 getServletContext() 384 { 385 return _handler.getServletContext(); 386 } 387 388 public HttpSessionContext 389 getSessionContext() 390 { 391 return org.mortbay.jetty.servlet.SessionContext.NULL_IMPL; 392 } 393 394 398 399 402 406 409 414 421 423 protected HttpSession 424 newContainer(String id, State state) 425 { 426 428 return Container.newContainer(this, id, state, getMaxInactiveInterval(), currentSecond(), getInterceptorStack()); 429 } 430 431 protected HttpSession 432 newSession(HttpServletRequest request) 433 { 434 String id=null; 435 HttpSession session=null; 436 try 437 { 438 id=_store.allocateId(request); 439 State state=_store.newState(id, getMaxInactiveInterval()); 440 session=newContainer(id, state); 441 } 442 catch (Exception e) 443 { 444 _log.error("could not create HttpSession", e); 445 return null; } 447 448 if (_log.isDebugEnabled()) _log.debug("remembering session - "+id); 449 450 synchronized (_sessions) {_sessions.put(id, session);} 451 452 notifySessionCreated(session); 453 454 return session; 455 } 456 457 protected State 458 destroyContainer(HttpSession session) 459 { 460 return Container.destroyContainer(session, getInterceptorStack()); 461 } 462 463 protected void 464 destroySession(HttpSession container) 465 { 466 String id=container.getId(); 467 if (_log.isDebugEnabled()) _log.debug("forgetting session - "+id); 468 Object tmp; 469 synchronized (_sessions) {tmp=_sessions.remove(id);} 470 container=(HttpSession )tmp; 471 if (_log.isDebugEnabled()) _log.debug("forgetting session - "+ container); 472 473 if (container==null) 474 { 475 _log.warn("session - "+id+" has already been destroyed"); 476 return; 477 } 478 479 485 489 491 492 494 try 495 { 496 State state=((StateAdaptor)container).getState(); 497 498 { 501 State s=state; 502 StateInterceptor si=null; 503 while (s instanceof StateInterceptor) 504 { 505 si=(StateInterceptor)s; 506 s=si.getState(); if (si instanceof ValidatingInterceptor) 508 si.stop(); 509 } 510 } 511 512 String [] names=state.getAttributeNameStringArray(); 513 for (int i=0; i<names.length; i++) 514 state.removeAttribute(names[i], false); 515 516 } 519 catch(RemoteException e) 520 { 521 _log.error("could not raise events on session destruction - problem in distribution layer", e); 522 } 523 524 if (_log.isDebugEnabled()) _log.debug("notifying session - "+id); 525 notifySessionDestroyed(container); 526 527 if (_log.isDebugEnabled()) _log.debug("destroying container - "+id); 528 State state=destroyContainer(container); 529 530 try 531 { 532 if (state!=null) { 536 if (_log.isDebugEnabled()) _log.debug("removing state - "+id); 537 _store.removeState(state); 538 } 539 } 540 catch (Exception e) 541 { 542 _log.error("could not remove session state", e); 543 } 544 } 545 546 547 protected HttpSession 548 findSession(String id,boolean create) 549 { 550 HttpSession container=null; 551 552 try 553 { 554 State state=_store.loadState(id); 556 557 state=((state!=null) && state.isValid())?state:null; 560 if (state!=null) 562 { 563 564 568 synchronized (_sessions) 570 { 571 container=(HttpSession )_sessions.get(id); 573 574 if (container==null && create) 576 { 577 container=newContainer(id, state); _sessions.put(id, container); 580 } 581 } 582 } 583 } 584 catch (Exception ignore) 585 { 586 if (_log.isDebugEnabled()) _log.debug("did not find distributed session: "+id); 587 } 588 589 return container; 590 } 591 592 596 598 public Object 599 notifyAttributeAdded(HttpSession session, String name, Object value) 600 { 601 int n=_sessionAttributeListeners.size(); 602 if (n>0) 603 { 604 HttpSessionBindingEvent event = 605 new HttpSessionBindingEvent (session, name, value); 606 607 for(int i=0;i<n;i++) 608 ((HttpSessionAttributeListener ) 609 _sessionAttributeListeners.get(i)).attributeAdded(event); 610 611 event=null; 612 } 613 614 return value; 615 } 616 617 public Object 618 notifyAttributeReplaced(HttpSession session, String name, Object value) 619 { 620 int n=_sessionAttributeListeners.size(); 621 if (n>0) 622 { 623 HttpSessionBindingEvent event = 624 new HttpSessionBindingEvent (session, name, value); 625 626 for(int i=0;i<n;i++) 627 ((HttpSessionAttributeListener ) 628 _sessionAttributeListeners.get(i)).attributeReplaced(event); 629 630 event=null; 631 } 632 633 return value; 634 } 635 636 public Object 637 notifyAttributeRemoved(HttpSession session, String name, Object value) 638 { 639 int n=_sessionAttributeListeners.size(); 640 if (n>0) 641 { 642 HttpSessionBindingEvent event = 643 new HttpSessionBindingEvent (session, name, value); 644 645 for(int i=0;i<n;i++) 646 ((HttpSessionAttributeListener ) 647 _sessionAttributeListeners.get(i)).attributeRemoved(event); 648 649 event=null; 650 } 651 652 return value; 653 } 654 655 public void 656 notifySessionCreated(HttpSession session) 657 { 658 int n=_sessionListeners.size(); 659 if (n>0) 660 { 661 HttpSessionEvent event = new HttpSessionEvent (session); 662 663 for(int i=0;i<n;i++) 664 ((HttpSessionListener )_sessionListeners.get(i)) .sessionCreated(event); 665 666 event=null; 667 } 668 } 669 670 public void 671 notifySessionDestroyed(HttpSession session) 672 { 673 int n=_sessionListeners.size(); 674 if (n>0) 675 { 676 HttpSessionEvent event = new HttpSessionEvent (session); 677 678 for(int i=0;i<n;i++) 679 ((HttpSessionListener )_sessionListeners.get(i)).sessionDestroyed(event); 680 681 event=null; 682 } 683 } 684 685 690 public long 691 currentSecond() 692 { 693 return System.currentTimeMillis(); 694 } 695 696 protected void 698 scavenge() 699 { 700 _log.trace("starting local scavenging..."); 701 try 702 { 703 AbstractReplicatedStore.setReplicating(true); 707 Collection copy; 710 synchronized (_sessions) {copy=new ArrayList (_sessions.values());} 711 if (_log.isTraceEnabled()) _log.trace(copy.size()+" local sessions"); 712 int n=0; 715 for (Iterator i=copy.iterator(); i.hasNext();) 716 { 717 StateAdaptor sa=null; 723 try 724 { 725 sa=(StateAdaptor)i.next(); 726 long lat=sa.getLastAccessedTime(); 728 } 729 catch (IllegalStateException ignore) 730 { 731 if (_log.isDebugEnabled()) _log.debug("scavenging local session "+sa.getId()); 732 destroySession(sa); 733 i.remove(); 734 ++n; 735 } 736 } 737 if (_log.isTraceEnabled()) _log.trace("scavenged "+n+" local sessions"); 738 } 739 finally 740 { 741 AbstractReplicatedStore.setReplicating(false); 742 } 743 _log.trace("...finished local scavenging"); 744 } 745 746 751 public boolean getSecureCookies() 752 { 753 return _secureCookies; 754 } 755 756 757 760 public void setSecureCookies(boolean secureCookies) 761 { 762 _secureCookies = secureCookies; 763 } 764 765 768 public boolean getHttpOnly() 769 { 770 return _httpOnly; 771 } 772 773 774 777 public void setHttpOnly(boolean httpOnly) 778 { 779 _httpOnly = httpOnly; 780 } 781 782 786 public boolean getCrossContextSessionIDs() 787 { 788 return _crossContextSessionIDs; 789 } 790 791 792 800 public void setCrossContextSessionIDs(boolean useRequestedId) 801 { 802 _crossContextSessionIDs = useRequestedId; 803 } 804 805 public Cookie getSessionCookie(HttpSession session,boolean requestIsSecure) 806 { 807 if (_handler.isUsingCookies()) 808 { 809 Cookie cookie = _handler.getSessionManager().getHttpOnly() 810 ?new HttpOnlyCookie(SessionManager.__SessionCookie,session.getId()) 811 :new Cookie (SessionManager.__SessionCookie,session.getId()); 812 String domain=_handler.getServletContext().getInitParameter(SessionManager.__SessionDomain); 813 String maxAge=_handler.getServletContext().getInitParameter(SessionManager.__MaxAge); 814 String path=_handler.getServletContext().getInitParameter(SessionManager.__SessionPath); 815 if (path==null) 816 path=getCrossContextSessionIDs()?"/":_handler.getHttpContext().getContextPath(); 817 if (path==null || path.length()==0) 818 path="/"; 819 820 if (domain!=null) 821 cookie.setDomain(domain); 822 if (maxAge!=null) 823 cookie.setMaxAge(Integer.parseInt(maxAge)); 824 else 825 cookie.setMaxAge(-1); 826 827 cookie.setSecure(requestIsSecure && getSecureCookies()); 828 cookie.setPath(path); 829 830 return cookie; 831 } 832 return null; 833 } 834 } 835 | Popular Tags |