1 29 30 package com.caucho.server.session; 31 32 import com.caucho.config.Config; 33 import com.caucho.config.ConfigException; 34 import com.caucho.config.types.JndiBuilder; 35 import com.caucho.config.types.Period; 36 import com.caucho.management.server.SessionManagerMXBean; 37 import com.caucho.server.cluster.Cluster; 38 import com.caucho.server.cluster.ClusterObject; 39 import com.caucho.server.cluster.ClusterServer; 40 import com.caucho.server.cluster.ObjectManager; 41 import com.caucho.server.cluster.Store; 42 import com.caucho.server.cluster.StoreManager; 43 import com.caucho.server.dispatch.DispatchServer; 44 import com.caucho.server.dispatch.InvocationDecoder; 45 import com.caucho.server.security.ServletAuthenticator; 46 import com.caucho.server.webapp.WebApp; 47 import com.caucho.util.Alarm; 48 import com.caucho.util.AlarmListener; 49 import com.caucho.util.L10N; 50 import com.caucho.util.LruCache; 51 import com.caucho.util.RandomUtil; 52 import com.caucho.vfs.Path; 53 import com.caucho.vfs.Vfs; 54 55 import javax.naming.Context ; 56 import javax.naming.InitialContext ; 57 import javax.servlet.http.HttpServletRequest ; 58 import javax.servlet.http.HttpSessionActivationListener ; 59 import javax.servlet.http.HttpSessionAttributeListener ; 60 import javax.servlet.http.HttpSessionEvent ; 61 import javax.servlet.http.HttpSessionListener ; 62 import java.io.IOException ; 63 import java.io.ObjectInputStream ; 64 import java.io.ObjectOutputStream ; 65 import java.util.ArrayList ; 66 import java.util.Iterator ; 67 import java.util.logging.Level ; 68 import java.util.logging.Logger ; 69 70 73 76 public final class SessionManager implements ObjectManager, AlarmListener 77 { 78 static protected final L10N L = new L10N(SessionManager.class); 79 static protected final Logger log 80 = Logger.getLogger(SessionManager.class.getName()); 81 82 private static final int FALSE = 0; 83 private static final int COOKIE = 1; 84 private static final int TRUE = 2; 85 86 private static final int UNSET = 0; 87 private static final int SET_TRUE = 1; 88 private static final int SET_FALSE = 2; 89 90 private static final int SAVE_BEFORE_HEADERS = 0x1; 91 private static final int SAVE_BEFORE_FLUSH = 0x2; 92 private static final int SAVE_AFTER_REQUEST = 0x4; 93 private static final int SAVE_ON_SHUTDOWN = 0x8; 94 95 private static final int DECODE[]; 96 97 private WebApp _webApp; 98 private final SessionManagerAdmin _admin; 99 100 103 private LruCache<String ,SessionImpl> _sessions; 105 private int _totalSessions; 107 108 private Iterator <SessionImpl> _sessionIter; 110 private ArrayList <SessionImpl> _sessionList = new ArrayList <SessionImpl>(); 112 private boolean _enableSessionCookies = true; 114 private boolean _enableSessionUrls = true; 116 117 private boolean _isModuloSessionId = false; 118 private boolean _isAppendServerIndex = false; 119 private boolean _isTwoDigitSessionIndex = false; 120 121 private boolean _isInvalidateAfterListener; 123 124 private int _sessionMax = 4096; 126 private long _sessionTimeout = 30 * 60 * 1000; 128 129 private String _cookieName = "JSESSIONID"; 130 private String _sslCookieName; 131 132 private String _sessionSuffix = ";jsessionid="; 134 private String _sessionPrefix; 135 136 private int _cookieVersion; 138 private String _cookieDomain; 139 private long _cookieMaxAge; 140 private boolean _cookieSecure; 141 private int _isCookieHttpOnly; 142 private String _cookiePort; 143 private int _reuseSessionId = COOKIE; 144 private int _cookieLength = 18; 145 146 private int _sessionSaveMode = SAVE_AFTER_REQUEST; 147 148 private StoreManager _storeManager; 150 151 private boolean _ignoreSerializationErrors = false; 153 154 private ArrayList <HttpSessionListener > _listeners; 156 157 private ArrayList <HttpSessionActivationListener > _activationListeners; 159 160 private ArrayList <HttpSessionAttributeListener > _attributeListeners; 162 163 167 private boolean _isWebAppStore; private Store _sessionStore; 169 private int _alwaysLoadSession; 170 private int _alwaysSaveSession; 171 172 private boolean _distributedRing; 173 private Path _persistentPath; 174 175 private boolean _isClosed; 176 177 private String _distributionId; 178 private Cluster _cluster; 179 private ClusterServer _selfServer; 180 private ClusterServer []_srunGroup = new ClusterServer[0]; 181 182 private int _srunIndex; 183 private int _srunLength; 184 185 private Alarm _alarm = new Alarm(this); 186 187 private Object _statisticsLock = new Object (); 189 private long _sessionCreateCount; 190 private long _sessionTimeoutCount; 191 private long _sessionInvalidateCount; 192 193 199 public SessionManager(WebApp app) 200 throws Exception 201 { 202 _webApp = app; 203 204 DispatchServer server = app.getDispatchServer(); 205 if (server != null) { 206 InvocationDecoder decoder = server.getInvocationDecoder(); 207 208 _sessionSuffix = decoder.getSessionURLPrefix(); 209 _sessionPrefix = decoder.getAlternateSessionURLPrefix(); 210 211 _cookieName = decoder.getSessionCookie(); 212 _sslCookieName = decoder.getSSLSessionCookie(); 213 } 214 215 218 String hostName = app.getHostName(); 219 String contextPath = app.getContextPath(); 220 221 if (hostName == null || hostName.equals("")) 222 hostName = "default"; 223 224 String name = hostName + contextPath; 225 226 _distributionId = name; 227 228 _persistentPath = Vfs.lookup("WEB-INF/sessions"); 229 230 _admin = new SessionManagerAdmin(this); 231 } 232 233 236 public SessionManagerMXBean getAdmin() 237 { 238 return _admin; 239 } 240 241 244 protected Cluster getCluster() 245 { 246 synchronized (this) { 247 if (_cluster == null) { 248 _cluster = Cluster.getLocal(); 249 ClusterServer selfServer = null; 250 251 if (_cluster != null) { 252 _srunLength = _cluster.getServerList().length; 253 254 selfServer = _cluster.getSelfServer(); 255 _selfServer = selfServer; 256 257 if (selfServer != null) { 258 _srunGroup = _cluster.getServerList(); 259 _srunIndex = selfServer.getIndex(); 260 } 261 } 262 } 263 } 264 265 return _cluster; 266 } 267 268 271 public String getSessionPrefix() 272 { 273 return _sessionSuffix; 274 } 275 276 279 public String getAlternateSessionPrefix() 280 { 281 return _sessionPrefix; 282 } 283 284 287 public int getCookieVersion() 288 { 289 return _cookieVersion; 290 } 291 292 295 public void setCookieVersion(int cookieVersion) 296 { 297 _cookieVersion = cookieVersion; 298 } 299 300 303 public void setCookiePort(String port) 304 { 305 _cookiePort = port; 306 } 307 308 311 public String getCookiePort() 312 { 313 return _cookiePort; 314 } 315 316 319 public Logger getDebug() 320 { 321 return log; 322 } 323 324 327 WebApp getWebApp() 328 { 329 return _webApp; 330 } 331 332 335 ServletAuthenticator getAuthenticator() 336 { 337 return _webApp.getAuthenticator(); 338 } 339 340 343 public void setPersistentStore(JndiBuilder store) 344 throws javax.naming.NamingException , ConfigException 345 { 346 _storeManager = (StoreManager) store.getObject(); 347 348 if (_storeManager == null) 349 throw new ConfigException(L.l("{0} is an unknown persistent store.", 350 store.getJndiName())); 351 } 352 353 356 boolean getAlwaysLoadSession() 357 { 358 return _alwaysLoadSession == SET_TRUE; 359 } 360 361 364 public void setAlwaysLoadSession(boolean load) 365 { 366 _alwaysLoadSession = load ? SET_TRUE : SET_FALSE; 367 } 368 369 372 boolean getAlwaysSaveSession() 373 { 374 return _alwaysSaveSession == SET_TRUE; 375 } 376 377 380 public void setAlwaysSaveSession(boolean save) 381 { 382 _alwaysSaveSession = save ? SET_TRUE : SET_FALSE; 383 } 384 385 388 public boolean isSaveOnShutdown() 389 { 390 return (_sessionSaveMode & SAVE_ON_SHUTDOWN) != 0; 391 } 392 393 396 public boolean isSaveOnlyOnShutdown() 397 { 398 return (_sessionSaveMode & SAVE_ON_SHUTDOWN) == SAVE_ON_SHUTDOWN; 399 } 400 401 404 public boolean isSaveBeforeHeaders() 405 { 406 return (_sessionSaveMode & SAVE_BEFORE_HEADERS) != 0; 407 } 408 409 412 public boolean isSaveBeforeFlush() 413 { 414 return (_sessionSaveMode & SAVE_BEFORE_FLUSH) != 0; 415 } 416 417 420 public boolean isSaveAfterRequest() 421 { 422 return (_sessionSaveMode & SAVE_AFTER_REQUEST) != 0; 423 } 424 425 429 public void setSaveMode(String mode) 430 throws ConfigException 431 { 432 441 442 if ("before-headers".equals(mode)) { 443 _sessionSaveMode = (SAVE_BEFORE_HEADERS| 444 SAVE_AFTER_REQUEST| 445 SAVE_ON_SHUTDOWN); 446 } 447 else if ("after-request".equals(mode)) { 448 _sessionSaveMode = (SAVE_AFTER_REQUEST| 449 SAVE_ON_SHUTDOWN); 450 } 451 else if ("on-shutdown".equals(mode)) { 452 _sessionSaveMode = (SAVE_ON_SHUTDOWN); 453 } 454 else 455 throw new ConfigException(L.l("'{0}' is an unknown session save-mode. Values are: before-headers, after-request, and on-shutdown.", 456 mode)); 457 458 } 459 460 463 public String getSaveMode() 464 { 465 if (isSaveBeforeFlush()) 466 return "before-flush"; 467 else if (isSaveBeforeHeaders()) 468 return "before-headers"; 469 else if (isSaveAfterRequest()) 470 return "after-request"; 471 else if (isSaveOnShutdown()) 472 return "on-shutdown"; 473 else 474 return "unknown"; 475 } 476 477 480 public void setSaveOnlyOnShutdown(boolean save) 481 { 482 log.warning("<save-only-on-shutdown> is deprecated. Use <save-mode>on-shutdown</save-mode> instead"); 483 484 if (save) 485 _sessionSaveMode = SAVE_ON_SHUTDOWN; 486 } 487 488 491 public void setSaveOnShutdown(boolean save) 492 { 493 log.warning("<save-on-shutdown> is deprecated. Use <save-only-on-shutdown> instead"); 494 495 setSaveOnlyOnShutdown(save); 496 } 497 498 501 public void setInvalidateAfterListener(boolean inv) 502 { 503 _isInvalidateAfterListener = inv; 504 } 505 506 509 public boolean isInvalidateAfterListener() 510 { 511 return _isInvalidateAfterListener; 512 } 513 514 517 public int getActiveSessionCount() 518 { 519 if (_sessions == null) 520 return -1; 521 else 522 return _sessions.size(); 523 } 524 525 528 public int getSessionActiveCount() 529 { 530 return getActiveSessionCount(); 531 } 532 533 536 public long getSessionCreateCount() 537 { 538 return _sessionCreateCount; 539 } 540 541 544 public long getSessionTimeoutCount() 545 { 546 return _sessionTimeoutCount; 547 } 548 549 552 public long getSessionInvalidateCount() 553 { 554 return _sessionInvalidateCount; 555 } 556 557 560 public void addListener(HttpSessionListener listener) 561 { 562 if (_listeners == null) 563 _listeners = new ArrayList <HttpSessionListener >(); 564 565 _listeners.add(listener); 566 } 567 568 571 ArrayList <HttpSessionListener > getListeners() 572 { 573 return _listeners; 574 } 575 576 579 public void addActivationListener(HttpSessionActivationListener listener) 580 { 581 if (_activationListeners == null) 582 _activationListeners = new ArrayList <HttpSessionActivationListener >(); 583 584 _activationListeners.add(listener); 585 } 586 587 590 ArrayList <HttpSessionActivationListener > getActivationListeners() 591 { 592 return _activationListeners; 593 } 594 595 598 public void addAttributeListener(HttpSessionAttributeListener listener) 599 { 600 if (_attributeListeners == null) 601 _attributeListeners = new ArrayList <HttpSessionAttributeListener >(); 602 603 _attributeListeners.add(listener); 604 } 605 606 609 ArrayList <HttpSessionAttributeListener > getAttributeListeners() 610 { 611 return _attributeListeners; 612 } 613 614 617 boolean getIgnoreSerializationErrors() 618 { 619 return _ignoreSerializationErrors; 620 } 621 622 625 public void setIgnoreSerializationErrors(boolean ignore) 626 { 627 _ignoreSerializationErrors = ignore; 628 } 629 630 634 public int getReuseSessionId() 635 { 636 return _reuseSessionId; 637 } 638 639 643 public boolean reuseSessionId(boolean fromCookie) 644 { 645 int reuseSessionId = _reuseSessionId; 646 647 return reuseSessionId == TRUE || fromCookie && reuseSessionId == COOKIE; 648 } 649 650 654 public void setReuseSessionId(String reuse) 655 throws ConfigException 656 { 657 if (reuse == null) 658 _reuseSessionId = COOKIE; 659 else if (reuse.equalsIgnoreCase("true") || 660 reuse.equalsIgnoreCase("yes") || 661 reuse.equalsIgnoreCase("cookie")) 662 _reuseSessionId = COOKIE; 663 else if (reuse.equalsIgnoreCase("false") || reuse.equalsIgnoreCase("no")) 664 _reuseSessionId = FALSE; 665 else if (reuse.equalsIgnoreCase("all")) 666 _reuseSessionId = TRUE; 667 else 668 throw new ConfigException(L.l("'{0}' is an invalid value for reuse-session-id. 'true' or 'false' are the allowed values.", 669 reuse)); 670 } 671 672 675 ClusterServer getServer(int index) 676 { 677 Cluster cluster = getCluster(); 678 679 if (cluster != null) 680 return cluster.getServer(index); 681 else 682 return null; 683 } 684 685 688 public int getSrunIndex() 689 { 690 return _srunIndex; 691 } 692 693 696 public int getSrunLength() 697 { 698 return _srunLength; 699 } 700 701 704 public boolean isClosed() 705 { 706 return _isClosed; 707 } 708 709 712 public StoreManager createFileStore() 713 throws ConfigException 714 { 715 Cluster cluster = getCluster(); 716 717 if (cluster == null) 718 throw new ConfigException(L.l("<file-store> needs a defined <cluster>.")); 719 720 if (cluster.getStore() != null) 721 throw new ConfigException(L.l("<file-store> may not be used with a defined <persistent-store>. Use <use-persistent-store> instead.")); 722 723 StoreManager fileStore = cluster.createPrivateFileStore(); 724 725 _storeManager = fileStore; 726 727 _isWebAppStore = true; 728 729 return fileStore; 730 } 731 732 735 public StoreManager createJdbcStore() 736 throws ConfigException 737 { 738 Cluster cluster = getCluster(); 739 740 if (cluster == null) 741 throw new ConfigException(L.l("<jdbc-store> needs a defined <cluster>.")); 742 743 if (cluster.getStore() != null) 744 throw new ConfigException(L.l("<jdbc-store> may not be used with a defined <persistent-store>. Use <use-persistent-store> instead.")); 745 746 _storeManager = cluster.createJdbcStore(); 747 748 _isWebAppStore = true; 749 750 return _storeManager; 751 } 752 753 756 public void setTcpStore(boolean isEnable) 757 throws Exception 758 { 759 setClusterStore(isEnable); 760 } 761 762 765 public void setClusterStore(boolean isEnable) 766 throws Exception 767 { 768 if (! isEnable) 769 return; 770 771 Cluster cluster = getCluster(); 772 773 if (cluster == null) 774 throw new ConfigException(L.l("<cluster-store> needs a defined <cluster>.")); 775 776 StoreManager store = cluster.getStore(); 777 778 if (store == null) 779 throw new ConfigException(L.l("cluster-store in <session-config> requires a configured cluster-store in the <cluster>")); 780 781 _storeManager = store; 782 } 783 784 787 public void setUsePersistentStore(boolean enable) 788 throws Exception 789 { 790 if (! enable) 791 return; 792 793 Cluster cluster = getCluster(); 794 795 if (cluster == null) 796 throw new ConfigException(L.l("<use-persistent-store> needs a defined <cluster>.")); 797 798 StoreManager store = cluster.getStore(); 799 800 if (store == null) { 801 try { 802 Context ic = new InitialContext (); 803 store = (StoreManager) ic.lookup("java:comp/env/caucho/persistent-store"); 804 } catch (Throwable e) { 805 log.log(Level.FINER, e.toString(), e); 806 } 807 } 808 809 if (store != null) { 810 } 811 else if (! Config.evalBoolean("${resin.isProfessional()}")) { 812 throw new ConfigException(L.l("use-persistent-store in <session-config> requires Resin professional.")); 813 } 814 else 815 throw new ConfigException(L.l("use-persistent-store in <session-config> requires a configured <persistent-store> in the <server>")); 816 817 if (_isWebAppStore) 818 throw new ConfigException(L.l("use-persistent-store may not be used with <jdbc-store> or <file-store>.")); 819 820 _storeManager = store; 821 } 822 823 826 public void setPersistentPath(Path path) 827 { 828 _persistentPath = path; 829 } 830 831 public String getDistributionId() 832 { 833 return _distributionId; 834 } 835 836 839 public long getSessionTimeout() 840 { 841 return _sessionTimeout; 842 } 843 844 847 public void setSessionTimeout(long timeout) 848 { 849 if (timeout <= 0 || Integer.MAX_VALUE / 2 < timeout) 850 _sessionTimeout = Long.MAX_VALUE / 2; 851 else 852 _sessionTimeout = 60000L * timeout; 853 } 854 855 858 public long getMaxIdleTime() 859 { 860 return _sessionTimeout; 861 } 862 863 866 public int getSessionMax() 867 { 868 return _sessionMax; 869 } 870 871 874 public void setSessionMax(int max) 875 { 876 _sessionMax = max; 877 } 878 879 882 public boolean enableSessionCookies() 883 { 884 return _enableSessionCookies; 885 } 886 887 890 public void setEnableCookies(boolean enableCookies) 891 { 892 _enableSessionCookies = enableCookies; 893 } 894 895 898 public boolean enableSessionUrls() 899 { 900 return _enableSessionUrls; 901 } 902 903 906 public void setEnableUrlRewriting(boolean enableUrls) 907 { 908 _enableSessionUrls = enableUrls; 909 } 910 911 914 public String getCookieName() 915 { 916 return _cookieName; 917 } 918 919 922 public String getSSLCookieName() 923 { 924 if (_sslCookieName != null) 925 return _sslCookieName; 926 else 927 return _cookieName; 928 } 929 930 933 public String getCookieDomain() 934 { 935 return _cookieDomain; 936 } 937 938 941 public void setCookieDomain(String domain) 942 { 943 _cookieDomain = domain; 944 } 945 946 949 public long getCookieMaxAge() 950 { 951 return _cookieMaxAge; 952 } 953 954 957 public void setCookieMaxAge(Period maxAge) 958 { 959 _cookieMaxAge = maxAge.getPeriod(); 960 } 961 962 965 public boolean getCookieSecure() 966 { 967 if (_cookieSecure) 968 return true; 969 else 970 return ! _cookieName.equals(_sslCookieName); 971 } 972 973 976 public void setCookieSecure(boolean secure) 977 { 978 _cookieSecure = secure; 979 } 980 981 984 public boolean isCookieHttpOnly() 985 { 986 if (_isCookieHttpOnly == SET_TRUE) 987 return true; 988 else if (_isCookieHttpOnly == SET_FALSE) 989 return true; 990 else 991 return getWebApp().getCookieHttpOnly(); 992 } 993 994 997 public void setCookieHttpOnly(boolean httpOnly) 998 { 999 _isCookieHttpOnly = httpOnly ? SET_TRUE : SET_FALSE; 1000 } 1001 1002 1005 public void setCookieLength(int cookieLength) 1006 { 1007 if (cookieLength < 7) 1008 cookieLength = 7; 1009 1010 _cookieLength = cookieLength; 1011 } 1012 1013 1016 public long getCookieLength() 1017 { 1018 return _cookieLength; 1019 } 1020 1021 1024 public void setCookieModuloCluster(boolean isModulo) 1025 { 1026 _isModuloSessionId = isModulo; 1027 } 1028 1029 1032 public void setCookieAppendServerIndex(boolean isAppend) 1033 { 1034 _isAppendServerIndex = isAppend; 1035 } 1036 1037 1040 public boolean isCookieAppendServerIndex() 1041 { 1042 return _isAppendServerIndex; 1043 } 1044 1045 public void init() 1046 { 1047 if (_sessionSaveMode == SAVE_ON_SHUTDOWN 1048 && (_alwaysSaveSession == SET_TRUE 1049 || _alwaysLoadSession == SET_TRUE)) 1050 throw new ConfigException(L.l("save-mode='on-shutdown' cannot be used with <always-save-session/> or <always-load-session/>")); 1051 } 1052 1053 public void start() 1054 throws Exception 1055 { 1056 _sessions = new LruCache<String ,SessionImpl>(_sessionMax); 1057 _sessionIter = _sessions.values(); 1058 1059 if (_cluster == null) 1060 getCluster(); 1061 1062 if (_isWebAppStore) { 1063 1065 if (_alwaysLoadSession == SET_TRUE) 1066 _storeManager.setAlwaysLoad(true); 1067 else if (_alwaysLoadSession == SET_FALSE) 1068 _storeManager.setAlwaysLoad(false); 1069 1070 if (_alwaysSaveSession == SET_TRUE) 1071 _sessionStore.setAlwaysSave(true); 1072 else if (_alwaysSaveSession == SET_FALSE) 1073 _sessionStore.setAlwaysSave(false); 1074 1075 _storeManager.init(); 1076 1077 _storeManager.updateIdleCheckInterval(_sessionTimeout); 1078 } 1079 1080 if (_storeManager != null) { 1081 _sessionStore = _storeManager.createStore(_distributionId, this); 1082 _sessionStore.setMaxIdleTime(_sessionTimeout); 1083 1084 if (_alwaysLoadSession == SET_TRUE) 1085 _sessionStore.setAlwaysLoad(true); 1086 else if (_alwaysLoadSession == SET_FALSE) 1087 _sessionStore.setAlwaysLoad(false); 1088 1089 if (_alwaysSaveSession == SET_TRUE) 1090 _sessionStore.setAlwaysSave(true); 1091 else if (_alwaysSaveSession == SET_FALSE) 1092 _sessionStore.setAlwaysSave(false); 1093 } 1094 1095 _alarm.queue(60000); 1096 } 1097 1098 1101 public Store getSessionStore() 1102 { 1103 return _sessionStore; 1104 } 1105 1106 1113 public SessionImpl createSession(String oldId, long now, 1114 HttpServletRequest request, 1115 boolean fromCookie) 1116 { 1117 String id = oldId; 1118 1119 if (id == null || id.length() < 4 || 1120 ! isInSessionGroup(id) || ! reuseSessionId(fromCookie)) { 1121 id = createSessionId(request, true); 1122 } 1123 1124 SessionImpl session = create(id, now, true); 1125 1126 if (session == null) 1127 return null; 1128 1129 session.addUse(); 1130 1131 synchronized (_statisticsLock) { 1132 _sessionCreateCount++; 1133 } 1134 1135 synchronized (session) { 1136 if (_sessionStore != null && id.equals(oldId)) 1137 load(session, now); 1138 else 1139 session.create(now); 1140 } 1141 1142 handleCreateListeners(session); 1144 1145 return session; 1146 } 1147 1148 1155 public String createSessionId(HttpServletRequest request) 1156 { 1157 return createSessionId(request, false); 1158 } 1159 1160 1167 public String createSessionId(HttpServletRequest request, 1168 boolean create) 1169 { 1170 String id; 1171 1172 do { 1173 id = createSessionIdImpl(); 1174 } while (create && getSession(id, 0, create, true) != null); 1175 1176 if (id == null || id.equals("")) 1177 throw new RuntimeException (); 1178 1179 return id; 1180 } 1181 1182 public String createSessionIdImpl() 1183 { 1184 StringBuffer cb = new StringBuffer (); 1185 int index = _srunIndex; 1188 1189 if (index < 0) 1190 index = 0; 1191 1192 int length = _cookieLength; 1193 1194 addBackup(cb, index); 1195 1196 long random = RandomUtil.getRandomLong(); 1197 1198 for (int i = 0; i < 11 && length-- > 0; i++) { 1199 cb.append(convert(random)); 1200 random = random >> 6; 1201 } 1202 1203 if (length > 0) { 1204 long time = Alarm.getCurrentTime(); 1205 for (int i = 0; i < 7 && length-- > 0; i++) { 1206 cb.append(convert(time)); 1207 time = time >> 6; 1208 } 1209 } 1210 1211 while (length > 0) { 1212 random = RandomUtil.getRandomLong(); 1213 for (int i = 0; i < 11 && length-- > 0; i++) { 1214 cb.append(convert(random)); 1215 random = random >> 6; 1216 } 1217 } 1218 1219 if (_isAppendServerIndex) { 1220 cb.append('.'); 1221 cb.append((index + 1)); 1222 } 1223 1224 return cb.toString(); 1225 } 1226 1227 1230 private void addBackup(StringBuffer cb, int index) 1231 { 1232 long backupCode; 1233 1234 if (_selfServer != null) 1235 backupCode = _selfServer.generateBackupCode(); 1236 else 1237 backupCode = 0x000200010000L; 1238 1239 addDigit(cb, (int) (backupCode & 0xffff)); 1240 addDigit(cb, (int) ((backupCode >> 16) & 0xffff)); 1241 addDigit(cb, (int) ((backupCode >> 32) & 0xffff)); 1242 } 1243 1244 private void addDigit(StringBuffer cb, int digit) 1245 { 1246 if (_srunLength <= 64 && ! _isTwoDigitSessionIndex) 1247 cb.append(convert(digit)); 1248 else { 1249 cb.append(convert(digit / 64)); 1250 cb.append(convert(digit)); 1251 } 1252 } 1253 1254 1263 public SessionImpl getSession(String key, long now, 1264 boolean create, boolean fromCookie) 1265 { 1266 SessionImpl session; 1267 boolean isNew = false; 1268 boolean killSession = false; 1269 1270 if (_sessions == null) 1271 return null; 1272 1273 session = _sessions.get(key); 1274 1275 if (session != null && ! session.getId().equals(key)) 1276 throw new IllegalStateException (key + " != " + session.getId()); 1277 1278 if (now <= 0) return session; 1280 1281 if (session != null && ! session.addUse()) { 1282 session = null; 1283 } 1284 1285 if (session == null && _sessionStore != null) { 1286 if (! isInSessionGroup(key)) 1287 return null; 1288 1289 session = create(key, now, create); 1290 1291 if (! session.addUse()) 1292 session = null; 1293 isNew = true; 1294 } 1295 1296 if (session == null) 1297 return null; 1298 1299 if (isNew) { 1300 killSession = ! load(session, now); 1301 isNew = killSession; 1302 } 1303 else if (! session.load()) { 1304 session.reset(now); 1306 isNew = true; 1307 } 1308 1309 if (killSession && (! create || ! reuseSessionId(fromCookie))) { 1310 session.endUse(); 1312 session._isValid = false; 1313 _sessions.remove(key); 1314 1315 return null; 1316 } 1317 else if (isNew) 1318 handleCreateListeners(session); 1319 else 1320 session.setAccess(now); 1321 1322 return session; 1323 } 1324 1325 public boolean isInSessionGroup(String id) 1326 { 1327 if (_srunLength == 0 || _srunGroup.length == 0) 1328 return true; 1329 1330 int group = decode(id.charAt(0)) % _srunLength; 1331 1332 for (int i = _srunGroup.length - 1; i >= 0; i--) { 1333 ClusterServer server = _srunGroup[i]; 1334 1335 if (server != null && group == server.getIndex()) 1336 return true; 1337 } 1338 1339 return false; 1340 } 1341 1342 1346 private SessionImpl create(String key, long now, boolean isCreate) 1347 { 1348 SessionImpl session = new SessionImpl(this, key, now); 1349 1350 session = _sessions.putIfNew(key, session); 1353 1354 if (! key.equals(session.getId())) 1355 throw new IllegalStateException (key + " != " + session.getId()); 1356 1357 Store sessionStore = _sessionStore; 1358 if (sessionStore != null) { 1359 ClusterObject clusterObject = sessionStore.createClusterObject(key); 1360 session.setClusterObject(clusterObject); 1361 } 1362 1363 return session; 1364 } 1365 1366 1369 public void notifyRemove(String id) 1370 { 1371 SessionImpl session = _sessions.remove(id); 1372 1373 if (session != null) 1374 session.invalidateImpl(true); 1375 } 1376 1377 1380 public void notifyUpdate(String id) 1381 { 1382 } 1383 1384 1387 private static char convert(long code) 1388 { 1389 code = code & 0x3f; 1390 1391 if (code < 26) 1392 return (char) ('a' + code); 1393 else if (code < 52) 1394 return (char) ('A' + code - 26); 1395 else if (code < 62) 1396 return (char) ('0' + code - 52); 1397 else if (code == 62) 1398 return '_'; 1399 else 1400 return '-'; 1401 } 1402 1403 public static int decode(int code) 1404 { 1405 return DECODE[code & 0x7f]; 1406 } 1407 1408 private void handleCreateListeners(SessionImpl session) 1409 { 1410 if (_listeners != null) { 1411 HttpSessionEvent event = new HttpSessionEvent (session); 1412 1413 for (int i = 0; i < _listeners.size(); i++) { 1414 HttpSessionListener listener = _listeners.get(i); 1415 1416 listener.sessionCreated(event); 1417 } 1418 } 1419 } 1420 1421 1428 private boolean load(SessionImpl session, long now) 1429 { 1430 try { 1431 1433 if (now <= 0) { 1439 return false; 1440 } 1441 else if (session.load()) { 1442 session.setAccess(now); 1443 return true; 1444 } 1445 else { 1446 session.create(now); 1447 } 1448 } catch (Exception e) { 1449 e.printStackTrace(); 1450 log.log(Level.FINE, e.toString(), e); 1451 session.reset(now); 1452 } 1453 1454 return false; 1455 } 1456 1457 1460 void addSession(SessionImpl session) 1461 { 1462 _sessions.put(session.getId(), session); 1463 } 1464 1465 1468 public void invalidateSession(SessionImpl session) 1469 { 1470 removeSession(session); 1471 1472 synchronized (_statisticsLock) { 1473 _sessionInvalidateCount++; 1474 } 1475 1476 if (_sessionStore != null) { 1477 try { 1478 _sessionStore.remove(session.getId()); 1479 } catch (Exception e) { 1480 log.log(Level.WARNING, e.toString(), e); 1481 } 1482 } 1483 } 1484 1485 1488 public void removeSession(SessionImpl session) 1489 { 1490 _sessions.remove(session.getId()); 1491 } 1492 1493 1499 public void load(ObjectInputStream in, Object obj) 1500 throws IOException 1501 { 1502 SessionImpl session = (SessionImpl) obj; 1503 1504 session.load(in); 1505 } 1506 1507 1510 public boolean isEmpty(Object obj) 1511 { 1512 SessionImpl session = (SessionImpl) obj; 1513 1514 return session.isEmpty(); 1515 } 1516 1517 1520 public void store(ObjectOutputStream out, Object obj) 1521 throws IOException 1522 { 1523 SessionImpl session = (SessionImpl) obj; 1524 1525 session.store(out); 1526 } 1527 1528 1533 public void handleAlarm(Alarm alarm) 1534 { 1535 try { 1536 _sessionList.clear(); 1537 1538 int liveSessions = 0; 1539 1540 if (_isClosed) 1541 return; 1542 1543 long now = Alarm.getCurrentTime(); 1544 long accessWindow = 0; 1545 1546 if (_sessionStore != null) 1547 accessWindow = _sessionStore.getAccessWindowTime(); 1548 1549 synchronized (_sessions) { 1550 _sessionIter = _sessions.values(_sessionIter); 1551 while (_sessionIter.hasNext()) { 1552 SessionImpl session = _sessionIter.next(); 1553 1554 long maxIdleTime = session._maxInactiveInterval + accessWindow; 1555 1556 if (session.inUse()) 1557 liveSessions++; 1558 else if (session._accessTime + maxIdleTime < now) 1559 _sessionList.add(session); 1560 else 1561 liveSessions++; 1562 } 1563 } 1564 1565 synchronized (_statisticsLock) { 1566 _sessionTimeoutCount += _sessionList.size(); 1567 } 1568 1569 for (int i = 0; i < _sessionList.size(); i++) { 1570 SessionImpl session = _sessionList.get(i); 1571 1572 try { 1573 long maxIdleTime = session._maxInactiveInterval; 1574 1575 if (_storeManager == null) { 1576 session.invalidate(); 1579 } 1580 else if (session.getSrunIndex() != _srunIndex && _srunIndex >= 0) { 1581 _sessions.remove(session.getId()); 1583 } 1584 else { 1585 session.invalidate(); 1586 } 1587 } catch (Throwable e) { 1588 log.log(Level.FINER, e.toString(), e); 1589 } 1590 } 1591 } finally { 1592 if (! _isClosed) 1593 _alarm.queue(60000); 1594 } 1595 } 1596 1597 1600 public void close() 1601 { 1602 synchronized (this) { 1603 if (_isClosed) 1604 return; 1605 _isClosed = true; 1606 } 1607 1608 if (_sessions == null) 1609 return; 1610 1611 _alarm.dequeue(); 1612 1613 _sessionList.clear(); 1614 1615 ArrayList <SessionImpl> list = new ArrayList <SessionImpl>(); 1616 1617 boolean isError = false; 1618 synchronized (_sessions) { 1620 _sessionIter = _sessions.values(_sessionIter); 1621 while (_sessionIter.hasNext()) { 1622 SessionImpl session = _sessionIter.next(); 1623 1624 if (session.isValid()) 1625 list.add(session); 1626 } 1627 1628 } 1631 1632 for (int i = list.size() - 1; i >= 0; i--) { 1633 SessionImpl session = list.get(i); 1634 1635 if (log.isLoggable(Level.FINE)) 1636 log.fine("close session " + session.getId()); 1637 1638 try { 1639 if (session.isValid()) { 1640 synchronized (session) { 1641 if (! session.isEmpty()) 1643 session.saveOnShutdown(); 1644 } 1645 } 1646 1647 _sessions.remove(session.getId()); 1648 } catch (Exception e) { 1649 if (! isError) 1650 log.log(Level.WARNING, "Can't store session: " + e, e); 1651 isError = true; 1652 } 1653 } 1654 1655 if (_admin != null) 1656 _admin.unregister(); 1657 1658 1662 } 1663 1664 static { 1665 DECODE = new int[128]; 1666 for (int i = 0; i < 64; i++) 1667 DECODE[(int) convert(i)] = i; 1668 } 1669} 1670 | Popular Tags |