| 1 23 24 25 package com.lutris.appserver.server.sessionEnhydra; 26 27 import java.lang.reflect.Constructor ; 28 import java.util.Date ; 29 import java.util.Enumeration ; 30 31 import javax.servlet.http.HttpSession ; 32 import javax.servlet.http.HttpSessionBindingEvent ; 33 import javax.servlet.http.HttpSessionBindingListener ; 34 35 import com.lutris.appserver.server.Application; 36 import com.lutris.appserver.server.Enhydra; 37 import com.lutris.appserver.server.httpPresentation.HttpPresentationComms; 38 import com.lutris.appserver.server.httpPresentation.HttpPresentationException; 39 import com.lutris.appserver.server.session.MemoryPersistence; 40 import com.lutris.appserver.server.session.Session; 41 import com.lutris.appserver.server.session.SessionException; 42 import com.lutris.appserver.server.session.SessionManager; 43 import com.lutris.appserver.server.sessionEnhydra.persistent.PersistentSessionHome; 44 import com.lutris.appserver.server.sessionEnhydra.persistent.PersistentSessionUserTable; 45 import com.lutris.appserver.server.user.User; 46 import com.lutris.logging.LogChannel; 47 import com.lutris.logging.Logger; 48 import com.lutris.util.Config; 49 import com.lutris.util.ConfigException; 50 import com.lutris.util.KeywordValueException; 51 52 53 151 public class StandardSessionManager 152 implements SessionManager, StandardSessionIdleHandler { 153 156 protected int mode; 157 163 public static final int MODE_BASIC = 1; 164 170 public static final int MODE_PAGE_TO_DISK = 2; 171 177 public static final int MODE_PAGE_TO_DB = 3; 178 183 public static final int MODE_CUSTOM = 4; 184 188 public static final String ENCODE_URL_NEVER = "Never"; 189 193 public static final String ENCODE_URL_ALWAYS = "Always"; 194 200 public static final String ENCODE_URL_AUTO = "Auto"; 201 public static final String ENCODE_RANDOM_YES = "Yes"; 202 public static final String ENCODE_RANDOM_NO = "No"; 203 211 protected static long defaultMaxSessionLifeTime = 0; 212 222 protected static long defaultMaxSessionIdleTime = 30*60; 223 236 protected static String defaultEncodeUrlState = "Auto"; 237 242 protected static long defaultIdleScanInterval = 30; 243 248 protected static long[] defaultRandomizerIntervals = { 249 301, 1001, 5003 250 }; 251 254 public static final String CFG_LIFE = "SessionLifetimeMax"; 255 258 public static final String CFG_IDLE = "SessionIdleTimeMax"; 259 262 public static final String CFG_ENCODE_URL_STATE = "SessionEncodeUrlState"; 263 267 public static final String CFG_ENCODE_FIRST_URL = "SessionEncodeFirstUrl"; 268 272 public static final String CFG_NOUSER_IDLE = "SessionNoUserIdleTimeMax"; 273 277 public static final String CFG_SCAN = "IdleScanInterval"; 278 282 public static final String CFG_RANDOM = "RandomizerIntervals"; 283 286 public static final String CFG_SESSION_HOME = "SessionHome"; 287 290 public static final String CFG_SESSION_HOME_TYPE = "SessionHome.Mode"; 291 296 public static final int SESSION_ACTIVE = 0; 297 303 public static final int SESSION_MAX_TIME = 1; 304 310 public static final int SESSION_IDLE_EXPIRE = 2; 311 316 public static final int SESSION_EXPLICT_DELETE = 3; 317 323 protected StandardSessionHome sessionHome; 325 331 private StandardSessionUserTable sessionUserTable; 332 protected int maxSessions; 334 protected Date maxSessionsDate; 335 341 private StandardSessionKeyGen keyGenerator; 342 348 private long maxSessionLifeTime; 349 355 protected long maxSessionIdleTime; 356 360 protected String encodeUrlState; 361 364 protected boolean encodeFirstUrl; 365 372 private StandardSessionIdleTimer idleTimer; 373 380 protected long maxNoUserSessionIdleTime; 381 384 protected long scanInterval; 385 388 LogChannel logChannel = null; 389 392 Application app = null; 393 396 ClassLoader classLoader; 397 400 private static final String BASIC = "BASIC"; 401 private static final String PAGE_TO_DISK = "PAGE_TO_DISK"; 402 private static final String PAGE_TO_DB = "PAGE_TO_DB"; 403 private static final String CUSTOM = "CUSTOM"; 404 407 String sessionHomeType = BASIC; 408 412 private boolean isMemoryPersistence = false; 413 414 417 private void logConfig () { 418 if (logChannel != null) { 419 logChannel.write(Logger.DEBUG, 420 "SessionManager." + CFG_LIFE + " = " 421 + maxSessionLifeTime + " sec"); 422 logChannel.write(Logger.DEBUG, 423 "SessionManager." + CFG_IDLE + " = " 424 + maxSessionIdleTime + " sec"); 425 logChannel.write(Logger.DEBUG, 426 "SessionManager." + CFG_NOUSER_IDLE + " = " 427 + maxNoUserSessionIdleTime + " sec"); 428 logChannel.write(Logger.DEBUG, 429 "SessionManager." + CFG_SCAN + " = " 430 + scanInterval + " sec"); 431 logChannel.write(Logger.DEBUG, 432 "SessionManager." + CFG_ENCODE_URL_STATE + " = " 433 + encodeUrlState); 434 logChannel.write(Logger.DEBUG, 435 "SessionManager." + CFG_ENCODE_FIRST_URL + " = " 436 + encodeFirstUrl); 437 } 438 } 439 public StandardSessionManager (){} 440 459 public StandardSessionManager (Application application, Config config, 460 LogChannel sessionMgrLogChannel) 461 throws ConfigException, SessionException { 462 app = application; 464 initManager(application.getClass().getClassLoader(),config,sessionMgrLogChannel); 465 } 466 467 public StandardSessionManager (ClassLoader classLoader, Config config, 468 LogChannel sessionMgrLogChannel) throws ConfigException, SessionException { 469 initManager(classLoader,config,sessionMgrLogChannel); 470 } 471 472 private void initManager (ClassLoader classLoader, Config config, 473 LogChannel sessionMgrLogChannel) throws ConfigException, SessionException { 474 this.classLoader = classLoader; 475 logChannel = sessionMgrLogChannel; 476 maxSessions = 0; 478 maxSessionsDate = new Date (); 479 483 if (config.containsKey("MemoryPersistence")) { 484 String mp = config.getString("MemoryPersistence"); 485 if (mp.equals("true")) 486 isMemoryPersistence = true; 487 } 488 492 if (config.containsKey(CFG_LIFE)) { 494 maxSessionLifeTime = config.getLong(CFG_LIFE)*60; 495 } 496 else if (config.containsKey("Lifetime")) { 497 maxSessionLifeTime = config.getLong("Lifetime")*60; 499 } 500 else { 501 maxSessionLifeTime = defaultMaxSessionLifeTime; 502 } 503 if (config.containsKey(CFG_IDLE)) { 505 maxSessionIdleTime = config.getLong(CFG_IDLE)*60; 506 } 507 else if (config.containsKey("MaxIdleTime")) { 508 maxSessionIdleTime = config.getLong("MaxIdleTime")*60; 510 } 511 else { 512 maxSessionIdleTime = defaultMaxSessionIdleTime; 513 } 514 if (config.containsKey(CFG_ENCODE_URL_STATE)) { 516 encodeUrlState = config.getString(CFG_ENCODE_URL_STATE); 517 } 518 else if (config.containsKey("EncodeUrlState")) { 519 encodeUrlState = config.getString("EncodeUrlState"); 521 } 522 else { 523 encodeUrlState = defaultEncodeUrlState; 524 } 525 if (!encodeUrlState.equalsIgnoreCase(ENCODE_URL_NEVER) && !encodeUrlState.equalsIgnoreCase(ENCODE_URL_ALWAYS) 526 && !encodeUrlState.equalsIgnoreCase(ENCODE_URL_AUTO)) { 527 throw new ConfigException("EncodeUrlState must be one of the following: " 528 + ENCODE_URL_NEVER + ", " + ENCODE_URL_ALWAYS + ", or " + ENCODE_URL_AUTO 529 + "."); 530 } 531 532 536 if (config.containsKey(CFG_ENCODE_FIRST_URL)) { 537 encodeFirstUrl = config.getBoolean(CFG_ENCODE_FIRST_URL, false); 538 } else { 539 encodeFirstUrl = false; 540 } 541 542 547 if (encodeUrlState.equalsIgnoreCase(ENCODE_URL_ALWAYS)){ 548 encodeFirstUrl = true; 549 } else if (encodeUrlState.equalsIgnoreCase(ENCODE_URL_NEVER)) { 550 encodeFirstUrl = false; 551 } 552 553 if (config.containsKey(CFG_NOUSER_IDLE)) { 554 maxNoUserSessionIdleTime = config.getLong(CFG_NOUSER_IDLE)*60; 555 } 556 else if (config.containsKey("MaxNoUserIdleTime")) { 557 maxNoUserSessionIdleTime = config.getLong("MaxNoUserIdleTime")*60; 559 } 560 else { 561 maxNoUserSessionIdleTime = maxSessionIdleTime; 562 } 563 scanInterval = defaultIdleScanInterval; 564 if (config.containsKey(CFG_SCAN)) { 565 scanInterval = config.getLong(CFG_SCAN); 566 } 567 else if (config.containsKey("IdleScanInterval")) { 568 scanInterval = config.getLong("IdleScanInterval"); 570 } 571 if (scanInterval <= 0) { 572 throw new ConfigException("IdleScanInterval must be greater than zero."); 573 } 574 idleTimer = new StandardSessionIdleTimer(this, app, scanInterval); 575 if (config.containsKey(CFG_SESSION_HOME_TYPE)) { 576 sessionHomeType = config.getString(CFG_SESSION_HOME_TYPE); 577 } 578 if (!sessionHomeType.equalsIgnoreCase(BASIC) && !sessionHomeType.equalsIgnoreCase(PAGE_TO_DISK) 579 && !sessionHomeType.equalsIgnoreCase(PAGE_TO_DB) && !sessionHomeType.equalsIgnoreCase(CUSTOM)) { 580 throw new ConfigException("Invalid " + CFG_SESSION_HOME_TYPE + ": '" 581 + sessionHomeType + "'"); 582 } 583 sessionHome = loadSessionHome(config); 585 sessionUserTable = loadSessionUserTable(config); 587 long[] intervals = config.getLongs(CFG_RANDOM, defaultRandomizerIntervals); 589 if (intervals.length == 0) { 590 throw new ConfigException(CFG_RANDOM + " must contain some values."); 591 } 592 for (int i = 0; i < intervals.length; i++) { 593 if (intervals[i] <= 0) { 594 throw new ConfigException(CFG_RANDOM + " must contain positive integers."); 595 } 596 } 597 keyGenerator = new StandardSessionKeyGen(intervals); 598 keyGenerator.start(); 600 idleTimer.start(); 601 logConfig(); 602 } 603 604 614 protected StandardSessionHome loadSessionHome (Config config) throws ConfigException, 615 SessionException { 616 try { 617 StandardSessionHome sessionHome = null; 618 Config homeConfig = null; 619 if (config.containsKey(CFG_SESSION_HOME)) { 620 homeConfig = (Config)config.getSection(CFG_SESSION_HOME); 621 } 622 else { 623 homeConfig = new Config(); 624 } 625 if (sessionHomeType.equalsIgnoreCase(CUSTOM)) { 626 if (homeConfig.containsKey("Class")) { 627 String homeClassName = homeConfig.getString("Class"); 628 try { 629 Class [] paramTypes = new Class [3]; 630 Object [] args = new Object [3]; 631 paramTypes[0] = Class.forName("com.lutris.appserver.server.sessionEnhydra.StandardSessionManager"); 632 paramTypes[1] = Class.forName("com.lutris.util.Config"); 633 paramTypes[2] = Class.forName("java.lang.ClassLoader"); 634 args[0] = this; 635 args[1] = homeConfig; 636 args[2] = classLoader; 637 Constructor c = Class.forName(homeClassName).getConstructor(paramTypes); 638 sessionHome = (StandardSessionHome)c.newInstance(args); 639 if (logChannel != null) { 640 logChannel.write(Logger.DEBUG, "SessionMgr: " 641 + "StandardSessionHome: " + homeClassName); 642 } 643 } catch (Exception e) { 644 throw new SessionException("Unable to load " + homeClassName, 645 e); 646 } 647 } 648 mode = MODE_CUSTOM; 649 } 650 else if (sessionHomeType.equalsIgnoreCase(PAGE_TO_DISK)) { 651 sessionHome = new DiskPagedSessionHome(this, homeConfig, classLoader); 652 mode = MODE_PAGE_TO_DISK; 653 } 654 else if (sessionHomeType.equalsIgnoreCase(PAGE_TO_DB)) { 655 sessionHome = new PersistentSessionHome(this, homeConfig, classLoader); 656 mode = MODE_PAGE_TO_DB; 657 } 658 else { 659 sessionHome = new BasicSessionHome(this, homeConfig); 660 mode = MODE_BASIC; 661 } 662 if (logChannel != null) { 663 logChannel.write(Logger.DEBUG, "SessionMgr: " 664 + "StandardSessionHome: " + sessionHomeType + "\n"); 665 } 666 return sessionHome; 667 } catch (KeywordValueException e) { 668 e.printStackTrace(); 669 throw new ConfigException("SessionMgr: unable to load StandardSessionHome: " 670 + e); 671 } 672 } 673 674 682 protected StandardSessionUserTable loadSessionUserTable (Config config) throws ConfigException, 683 SessionException { 684 try { 685 StandardSessionUserTable sessionUserTable = null; 686 Config userTableConfig = null; 687 if (config.containsKey("SessionUserTable")) { 688 userTableConfig = (Config)config.getSection("SessionUserTable"); 689 } 690 else { 691 userTableConfig = new Config(); 692 } 693 if (sessionHomeType.equalsIgnoreCase(CUSTOM)) { 694 String tableClassName = userTableConfig.getString("Class"); 695 try { 696 Class [] paramTypes = new Class [1]; 697 Object [] args = new Object [1]; 698 paramTypes[0] = Class.forName("com.lutris.util.Config"); 699 args[0] = userTableConfig; 700 Constructor c = Class.forName(tableClassName).getConstructor(paramTypes); 701 sessionUserTable = (StandardSessionUserTable)c.newInstance(args); 702 if (logChannel != null) { 703 logChannel.write(Logger.DEBUG, "SessionMgr: " 704 + "StandardSessionUserTable: " + tableClassName); 705 } 706 } catch (NoSuchMethodException e) { 707 throw new SessionException("Unable to load " + tableClassName + 708 ": " + "Constructor not found.", e); 709 } catch (Exception e) { 710 throw new SessionException("Unable to create instance of " + tableClassName, 711 e); 712 } 713 } 714 else if (sessionHomeType.equalsIgnoreCase(PAGE_TO_DISK)) { 715 sessionUserTable = new PagedSessionUserTable(userTableConfig); 716 } 717 else if (sessionHomeType.equalsIgnoreCase(PAGE_TO_DB)) { 718 sessionUserTable = new PersistentSessionUserTable(userTableConfig); 719 } 720 else { 721 sessionUserTable = new BasicSessionUserTable(userTableConfig); 722 } 723 return sessionUserTable; 724 } catch (KeywordValueException e) { 725 throw new ConfigException("SessionMgr: unable to load StandardSessionUserTable: " 726 + e); 727 } 728 } 729 730 734 public synchronized void shutdown () { 735 if (isMemoryPersistence) 736 MemoryPersistence.putSessionManager(app.getName(), this); 737 else { 738 if (keyGenerator != null) { 739 keyGenerator.shutdown(); 740 keyGenerator = null; 741 } 742 if (idleTimer != null) { 743 idleTimer.shutdown(); 744 idleTimer = null; 745 } 746 if (sessionHome != null) { 747 sessionHome.shutdown(); 748 sessionHome = null; 749 } 750 if (sessionUserTable != null) { 751 sessionUserTable.shutdown(); 752 sessionUserTable = null; 753 } 754 } 755 } 756 757 770 protected StandardSession newSession (String sessionKey) throws CreateSessionException, 771 SessionException { 772 return (StandardSession)sessionHome.createSession(sessionKey); 773 } 774 775 785 public Session createSession () throws SessionException { 786 return createSession(""); 787 } 788 789 801 public Session createSession (String ipPortToken) throws SessionException { 802 StandardSession session = null; 803 String sessionKey = null; 804 809 do { 810 try { 811 sessionKey = keyGenerator.newSessionKey(); 812 if (ipPortToken != null && ipPortToken.length() > 0) { 813 sessionKey = sessionKey.substring(0,sessionKey.length()-2)+ipPortToken; 814 } 815 session = sessionHome.createSession(sessionKey); 816 } catch (DuplicateKeyException e) { 817 session = null; 819 } 820 } while (session == null); 821 int currentSize = sessionHome.size(); 822 if (currentSize > maxSessions) { 823 maxSessions = currentSize; 824 maxSessionsDate = new Date (); 825 } 826 keyGenerator.incrementRandomCounter(); 827 if (logChannel != null) { 828 logChannel.write(Logger.DEBUG, "SessionMgr: createSession: " + sessionKey); 829 } 830 return session; 831 } 832 833 public Session createSession (HttpPresentationComms comms) throws SessionException { 834 Session s = null; 835 String saTok = null; 836 try { 837 saTok = comms.request.getHeader(":aff:"); 838 } catch (HttpPresentationException hpe) { 839 saTok = null; 840 } 841 if (saTok == null) { 842 s = createSession(); 843 } 844 else { 845 s = createSession(saTok); 846 if (logChannel != null) { 847 logChannel.write(Logger.DEBUG, 848 "SessionKey created for EnhydraDirector"); 849 } 850 } 851 return s; 852 } 853 854 857 private void logRegisterUser (Session session, String which) { 858 if (logChannel != null) { 859 String userName = null; 860 User user = session.getUser(); 861 if (user != null) { 862 userName = user.getName(); 863 } 864 logChannel.write(Logger.DEBUG, "SessionMgr: " 865 + which + ": " + session.getSessionKey() + 866 " user = \"" + userName + "\""); 867 } 868 } 869 870 883 protected synchronized void registerUser (Session session) throws SessionException { 884 sessionUserTable.add(session.getSessionKey(), session.getUser()); 885 logRegisterUser(session, "registerUser"); 886 } 887 888 899 protected synchronized void unregisterUser (Session session) throws SessionException { 900 logRegisterUser(session, "unregisterUser"); 901 sessionUserTable.remove(session.getSessionKey(), session.getUser()); 902 } 903 904 |