1 29 30 package com.caucho.server.session; 31 32 import com.caucho.log.Log; 33 import com.caucho.server.cluster.ClusterObject; 34 import com.caucho.server.cluster.Store; 35 import com.caucho.server.security.AbstractAuthenticator; 36 import com.caucho.server.security.ServletAuthenticator; 37 import com.caucho.util.Alarm; 38 import com.caucho.util.CacheListener; 39 import com.caucho.util.L10N; 40 import com.caucho.vfs.IOExceptionWrapper; 41 42 import javax.servlet.ServletContext ; 43 import javax.servlet.http.*; 44 import java.io.IOException ; 45 import java.io.NotSerializableException ; 46 import java.io.ObjectInputStream ; 47 import java.io.ObjectOutputStream ; 48 import java.io.Serializable ; 49 import java.security.Principal ; 50 import java.util.*; 51 import java.util.logging.Level ; 52 import java.util.logging.Logger ; 53 54 57 public class SessionImpl implements HttpSession, CacheListener { 58 static protected final Logger log = Log.open(SessionImpl.class); 59 static final L10N L = new L10N(SessionImpl.class); 60 61 static final String LOGIN = "caucho.login"; 62 63 private String _id; 65 66 protected SessionManager _manager; 68 70 protected Map<String ,Object > _values; 72 73 private long _creationTime; 75 long _accessTime; 77 long _maxInactiveInterval; 79 private boolean _isNew = true; 81 boolean _isValid = true; 83 boolean _isClosing = false; 85 boolean _isInvalidating = false; 87 private int _useCount; 89 90 private ClusterObject _clusterObject; 91 private Principal _user; 93 94 private int _srunIndex = -1; 96 97 104 public SessionImpl(SessionManager manager, String id, long creationTime) 105 { 106 _manager = manager; 107 108 _creationTime = creationTime; 109 _accessTime = creationTime; 110 _maxInactiveInterval = manager.getSessionTimeout(); 111 112 _id = id; 113 114 char ch = id.charAt(0); 116 int length = manager.getSrunLength(); 117 118 if (length > 0) 119 _srunIndex = SessionManager.decode(ch) % length; 120 else 121 _srunIndex = 0; 122 123 _values = createValueMap(); 124 125 if (log.isLoggable(Level.FINE)) 126 log.fine("create session " + id); 127 } 128 129 132 public long getCreationTime() 133 { 134 if (! _isValid) 136 throw new IllegalStateException (L.l("Can't call getCreationTime() when session is no longer valid.")); 137 138 return _creationTime; 139 } 140 141 144 public String getId() 145 { 146 return _id; 147 } 148 149 152 int getSrunIndex() 153 { 154 return _srunIndex; 155 } 156 157 160 void setClusterObject(ClusterObject clusterObject) 161 { 162 _clusterObject = clusterObject; 163 if (clusterObject != null) 164 clusterObject.update(); 165 } 166 167 170 public long getLastAccessedTime() 171 { 172 if (! _isValid) 174 throw new IllegalStateException (L.l("Can't call getLastAccessedTime() when session is no longer valid.")); 175 176 return _accessTime; 177 } 178 179 184 public int getMaxInactiveInterval() 185 { 186 if (Long.MAX_VALUE / 2 <= _maxInactiveInterval) 187 return -1; 188 else 189 return (int) (_maxInactiveInterval / 1000); 190 } 191 192 197 public void setMaxInactiveInterval(int value) 198 { 199 if (value < 0) 200 _maxInactiveInterval = Long.MAX_VALUE / 2; 201 else 202 _maxInactiveInterval = ((long) value) * 1000; 203 204 if (_clusterObject != null) 205 _clusterObject.setExpireInterval(_maxInactiveInterval); 206 } 207 208 213 public HttpSessionContext getSessionContext() 214 { 215 return null; 216 } 217 218 221 public ServletContext getServletContext() 222 { 223 return _manager.getWebApp(); 224 } 225 226 229 public SessionManager getManager() 230 { 231 return _manager; 232 } 233 234 237 public ServletAuthenticator getAuthenticator() 238 { 239 return _manager.getWebApp().getAuthenticator(); 240 } 241 242 245 public Principal getUser() 246 { 247 if (_user != null) 248 return _user; 249 250 if (_isValid) { 251 _user = (Principal ) getAttribute(LOGIN); 252 } 253 254 return _user; 255 } 256 257 260 public void setUser(Principal user) 261 { 262 _user = user; 263 264 setAttribute(LOGIN, user); 265 } 266 267 270 public Object getAttribute(String name) 271 { 272 if (! _isValid) 273 throw new IllegalStateException (L.l("Can't call getAttribute() when session is no longer valid.")); 274 275 synchronized (_values) { 276 return _values.get(name); 277 } 278 } 279 280 288 public void setAttribute(String name, Object value) 289 { 290 if (! _isValid) 291 throw new IllegalStateException (L.l("Can't call setAttribute(String, Object) when session is no longer valid.")); 292 293 Object oldValue; 294 295 if (value != null && 296 ! (value instanceof Serializable ) && 297 log.isLoggable(Level.FINE)) { 298 log.fine(L.l("session attribute '{0}' value is non-serializable type '{1}'", 299 name, value.getClass().getName())); 300 } 301 302 synchronized (_values) { 303 if (value != null) 304 oldValue = _values.put(name, value); 305 else 306 oldValue = _values.remove(name); 307 } 308 309 if (_clusterObject != null) _clusterObject.change(); 312 313 if (oldValue instanceof HttpSessionBindingListener) { 314 HttpSessionBindingListener listener; 315 listener = (HttpSessionBindingListener) oldValue; 316 317 listener.valueUnbound(new HttpSessionBindingEvent(SessionImpl.this, 318 name, oldValue)); 319 } 320 321 if (value instanceof HttpSessionBindingListener) { 322 HttpSessionBindingListener listener; 323 listener = (HttpSessionBindingListener) value; 324 325 listener.valueBound(new HttpSessionBindingEvent(SessionImpl.this, 326 name, value)); 327 } 328 329 ArrayList listeners = _manager.getAttributeListeners(); 331 if (listeners != null) { 332 HttpSessionBindingEvent event; 333 334 if (oldValue != null) 335 event = new HttpSessionBindingEvent(this, name, oldValue); 336 else 337 event = new HttpSessionBindingEvent(this, name, value); 338 339 for (int i = 0; i < listeners.size(); i++) { 340 HttpSessionAttributeListener listener; 341 listener = (HttpSessionAttributeListener) listeners.get(i); 342 343 if (oldValue != null) 344 listener.attributeReplaced(event); 345 else 346 listener.attributeAdded(event); 347 } 348 } 349 } 350 351 354 protected Map<String ,Object > createValueMap() 355 { 356 return new Hashtable<String ,Object >(8); 357 } 358 359 365 public void removeAttribute(String name) 366 { 367 if (! _isValid) 368 throw new IllegalStateException (L.l("Can't call removeAttribute(String) when session is no longer valid.")); 369 370 Object oldValue = _values.remove(name); 371 372 if (_clusterObject != null && oldValue != null) 373 _clusterObject.change(); 374 375 notifyValueUnbound(name, oldValue); 376 } 377 378 383 public Enumeration getAttributeNames() 384 { 385 synchronized (_values) { 386 if (! _isValid) 387 throw new IllegalStateException (L.l("Can't call getAttributeNames() when session is no longer valid.")); 388 389 return Collections.enumeration(_values.keySet()); 390 } 391 } 392 393 396 public Object getValue(String name) 397 { 398 return getAttribute(name); 399 } 400 401 404 public void putValue(String name, Object value) 405 { 406 setAttribute(name, value); 407 } 408 409 412 public void removeValue(String name) 413 { 414 removeAttribute(name); 415 } 416 417 420 public String []getValueNames() 421 { 422 synchronized (_values) { 423 if (! _isValid) 424 throw new IllegalStateException (L.l("Can't call getValueNames() when session is no longer valid.")); 425 426 if (_values == null) 427 return new String [0]; 428 429 String []s = new String [_values.size()]; 430 431 Enumeration e = getAttributeNames(); 432 int count = 0; 433 while (e.hasMoreElements()) 434 s[count++] = (String ) e.nextElement(); 435 436 return s; 437 } 438 } 439 440 443 public boolean isNew() 444 { 445 if (! _isValid) 446 throw new IllegalStateException (L.l("Can't call isNew() when session is no longer valid.")); 447 448 return _isNew; 449 } 450 451 454 public boolean isValid() 455 { 456 return _isValid; 457 } 458 459 462 void setValid(boolean isValid) 463 { 464 _isValid = isValid; 465 } 466 467 boolean isClosing() 468 { 469 return _isClosing; 470 } 471 472 476 public void removeEvent() 477 { 478 synchronized (this) { 479 if (_isInvalidating || _useCount <= 0) 480 _isClosing = true; 481 } 482 483 if (! _isClosing) { 485 log.warning(L.l("session {0} LRU while in use. Consider increasing session-count.", 486 _id)); 487 } 488 489 boolean isValid = _isValid; 490 491 if (log.isLoggable(Level.FINE)) 492 log.fine("remove session " + _id); 493 494 long now = Alarm.getCurrentTime(); 495 496 Store store = _manager.getSessionStore(); 497 498 if (_isInvalidating || 500 store == null || _accessTime + getMaxInactiveInterval() < now) 501 notifyDestroy(); 502 503 invalidateLocal(); 504 } 505 506 private void notifyDestroy() 507 { 508 ArrayList listeners = _manager.getListeners(); 509 510 if (listeners != null) { 511 HttpSessionEvent event = new HttpSessionEvent(this); 512 513 for (int i = listeners.size() - 1; i >= 0; i--) { 514 HttpSessionListener listener; 515 listener = (HttpSessionListener) listeners.get(i); 516 517 listener.sessionDestroyed(event); 518 } 519 } 520 } 521 522 525 public void invalidate() 526 { 527 _isInvalidating = true; 528 529 invalidate(false); 530 } 531 532 535 public void invalidate(boolean isLRU) 536 { 537 if (log.isLoggable(Level.FINE)) { 538 539 if (log.isLoggable(Level.FINEST)) 540 log.log(Level.FINEST, "invalidate session " + _id, new Exception ()); 541 else 542 log.fine("invalidate session " + _id); 543 } 544 545 if (! _isValid) 546 throw new IllegalStateException (L.l("Can't call invalidate() when session is no longer valid.")); 547 548 ServletAuthenticator auth = getAuthenticator(); 549 if (! isLRU 550 || ! (auth instanceof AbstractAuthenticator) 551 || ((AbstractAuthenticator) auth).getLogoutOnSessionTimeout()) { 552 logout(isLRU ? this : null); 554 } 555 556 561 562 try { 563 570 571 _manager.removeSession(this); 572 573 invalidateImpl(isLRU); 574 575 _isValid = false; 576 } finally { 577 _isValid = false; 578 } 579 } 580 581 584 public void logout() 585 { 586 logout(null); 588 } 589 590 595 public void logout(SessionImpl timeoutSession) 596 { 597 if (_user != null) { 598 if (_isValid) 599 removeAttribute(LOGIN); 600 Principal user = _user; 601 _user = null; 602 603 try { 604 ServletAuthenticator auth = getAuthenticator(); 605 606 if (auth != null) 607 auth.logout(_manager.getWebApp(), timeoutSession, _id, user); 608 } catch (Exception e) { 609 log.log(Level.WARNING, e.toString(), e); 610 } 611 } 612 } 613 614 618 void invalidateImpl(boolean isLRU) 619 { 620 boolean invalidateAfterListener = _manager.isInvalidateAfterListener(); 621 if (! invalidateAfterListener) 622 _isValid = false; 623 624 try { 625 ClusterObject clusterObject = _clusterObject; 626 628 if (clusterObject != null && _isInvalidating) 629 clusterObject.remove(); 630 } catch (Throwable e) { 631 log.log(Level.FINE, e.toString(), e); 632 } 633 634 invalidateLocal(); 635 } 636 637 640 private void invalidateLocal() 641 { 642 ClusterObject clusterObject = _clusterObject; 643 if (_isValid && ! _isInvalidating && clusterObject != null) { 644 if (_manager.isSaveOnlyOnShutdown()) { 645 clusterObject.update(); 646 647 try { 648 clusterObject.store(this); 649 } catch (Throwable e) { 650 log.log(Level.WARNING, "Can't serialize session", e); 651 } 652 } 653 } 654 655 unbind(); } 657 658 661 void create(long now) 662 { 663 if (log.isLoggable(Level.FINE)) { 664 log.fine("create session " + _id); 665 } 666 667 if (_isValid) 669 unbind(); 670 671 _isValid = true; 672 _isNew = true; 673 _accessTime = now; 674 _creationTime = now; 675 676 if (_clusterObject != null) 677 _clusterObject.setValid(); 678 } 679 680 683 public boolean inUse() 684 { 685 return _useCount > 0; 686 } 687 688 691 boolean addUse() 692 { 693 synchronized (this) { 694 if (_isClosing) 695 return false; 696 697 _useCount++; 698 699 return true; 700 } 701 } 702 703 706 void endUse() 707 { 708 synchronized (this) { 709 _useCount--; 710 } 711 } 712 713 716 void reset(long now) 717 { 718 if (log.isLoggable(Level.FINE)) 719 log.fine("reset session " + _id); 720 721 unbind(); 722 _isValid = true; 723 _isNew = true; 724 _accessTime = now; 725 _creationTime = now; 726 } 727 728 731 public boolean load() 732 { 733 boolean isValid; 734 735 if (_useCount > 1) 737 return true; 738 739 ClusterObject clusterObject = _clusterObject; 740 if (clusterObject != null) 741 isValid = clusterObject.load(this); 742 else 743 isValid = true; 744 745 return isValid; 746 } 747 748 751 public void passivate() 752 { 753 unbind(); 754 } 755 756 759 public void unbind() 760 { 761 if (_values.size() == 0) 762 return; 763 764 ClusterObject clusterObject = _clusterObject; 765 766 ArrayList<String > names = new ArrayList<String >(); 767 ArrayList<Object > values = new ArrayList<Object >(); 768 769 synchronized (this) { 770 772 776 777 Iterator<Map.Entry<String ,Object >> iter = _values.entrySet().iterator(); 778 while (iter.hasNext()) { 779 Map.Entry<String ,Object > entry = iter.next(); 780 781 names.add(entry.getKey()); 782 values.add(entry.getValue()); 783 } 784 785 _values.clear(); 786 787 if (clusterObject != null) 788 clusterObject.update(); 789 } 790 791 for (int i = 0; i < names.size(); i++) { 792 String name = names.get(i); 793 Object value = values.get(i); 794 795 notifyValueUnbound(name, value); 796 } 797 } 798 799 802 private void notifyValueUnbound(String name, Object oldValue) 803 { 804 if (oldValue == null) 805 return; 806 807 if (oldValue instanceof HttpSessionBindingListener) { 808 HttpSessionBindingListener listener; 809 listener = (HttpSessionBindingListener) oldValue; 810 811 listener.valueUnbound(new HttpSessionBindingEvent(this, 812 name, 813 oldValue)); 814 } 815 816 ArrayList listeners = _manager.getAttributeListeners(); 818 if (listeners != null) { 819 HttpSessionBindingEvent event; 820 821 event = new HttpSessionBindingEvent(this, name, oldValue); 822 823 for (int i = 0; i < listeners.size(); i++) { 824 HttpSessionAttributeListener listener; 825 listener = (HttpSessionAttributeListener) listeners.get(i); 826 827 listener.attributeRemoved(event); 828 } 829 } 830 } 831 832 835 void setAccess(long now) 836 { 837 _isNew = false; 838 839 if (_clusterObject != null) 840 _clusterObject.access(); 841 842 _accessTime = now; 843 } 844 845 852 public void finish() 853 { 854 int count; 855 856 _accessTime = Alarm.getCurrentTime(); 857 858 synchronized (this) { 859 if (_useCount > 1) { 860 _useCount--; 861 return; 862 } 863 } 864 865 try { 866 saveAfterRequest(); 867 } finally { 868 synchronized (this) { 869 _useCount--; 870 } 871 } 872 } 873 874 877 public final void saveBeforeFlush() 878 { 879 if (_manager == null || ! _manager.isSaveBeforeFlush()) 880 return; 881 882 save(); 883 } 884 885 888 public final void saveBeforeHeaders() 889 { 890 if (_manager == null || ! _manager.isSaveBeforeHeaders()) 891 return; 892 893 save(); 894 } 895 896 899 public final void saveAfterRequest() 900 { 901 if (_manager == null || ! _manager.isSaveAfterRequest()) 902 return; 903 904 save(); 905 } 906 907 910 public final void save() 911 { 912 try { 913 ClusterObject clusterObject = _clusterObject; 914 if (clusterObject != null) { 915 clusterObject.store(this); 916 } 917 } catch (Throwable e) { 918 log.log(Level.WARNING, "Can't serialize session", e); 919 } 920 } 921 922 925 void saveOnShutdown() 926 { 927 try { 928 ClusterObject clusterObject = _clusterObject; 929 930 if (clusterObject != null) { 931 clusterObject.change(); 932 clusterObject.store(this); 933 } 934 } catch (Throwable e) { 935 log.log(Level.WARNING, "Can't serialize session", e); 936 } 937 } 938 939 942 public void load(ObjectInputStream in) 943 throws IOException 944 { 945 synchronized (_values) { 946 unbind(); 947 948 try { 949 int size = in.readInt(); 950 951 953 for (int i = 0; i < size; i++) { 954 String key = in.readUTF(); 955 Object value = in.readObject(); 956 957 if (value != null) 958 setAttribute(key, value); 959 } 960 } catch (Exception e) { 961 e.printStackTrace(); 962 963 throw IOExceptionWrapper.create(e); 964 } 965 966 ArrayList<HttpSessionActivationListener> listeners; 967 listeners = _manager.getActivationListeners(); 968 for (int i = 0; listeners != null && i < listeners.size(); i++) { 969 HttpSessionActivationListener listener = listeners.get(i); 970 HttpSessionEvent event = new HttpSessionEvent(this); 971 972 listener.sessionDidActivate(event); 973 } 974 } 975 } 976 977 980 public boolean isEmpty() 981 { 982 return _values == null || _values.size() == 0; 983 } 984 985 988 public void store(ObjectOutputStream out) 989 throws IOException 990 { 991 synchronized (_values) { 992 Set set = getEntrySet(); 993 994 int size = set == null ? 0 : set.size(); 995 996 out.writeInt(size); 997 998 if (size == 0) 999 return; 1000 1001 ArrayList<HttpSessionActivationListener> listeners; 1002 listeners = _manager.getActivationListeners(); 1003 for (int i = 0; listeners != null && i < listeners.size(); i++) { 1004 HttpSessionActivationListener listener = listeners.get(i); 1005 HttpSessionEvent event = new HttpSessionEvent(this); 1006 listener.sessionWillPassivate(event); 1007 } 1008 1009 boolean ignoreNonSerializable = 1010 getManager().getIgnoreSerializationErrors(); 1011 1012 Map.Entry []entries = new Map.Entry[set.size()]; 1013 1014 Iterator iter = set.iterator(); 1015 int i = 0; 1016 while (iter.hasNext()) { 1017 entries[i++] = (Map.Entry) iter.next(); 1018 } 1019 1020 Arrays.sort(entries, KEY_COMPARATOR); 1021 1022 for (i = 0; i < entries.length; i++) { 1023 Map.Entry entry = entries[i]; 1024 Object value = entry.getValue(); 1025 1026 out.writeUTF((String ) entry.getKey()); 1027 if (ignoreNonSerializable && ! (value instanceof Serializable )) { 1028 out.writeObject(null); 1029 continue; 1030 } 1031 1032 try { 1033 out.writeObject(value); 1034 } catch (NotSerializableException e) { 1035 log.warning(L.l("Failed storing persistent session attribute `{0}'. Persistent session values must extend java.io.Serializable.\n{1}", entry.getKey(), String.valueOf(e))); 1036 throw e; 1037 } 1038 } 1039 } 1040 } 1041 1042 1045 Set getEntrySet() 1046 { 1047 synchronized (_values) { 1048 if (! _isValid) 1049 throw new IllegalStateException (L.l("Can't call getEntrySet() when session is no longer valid.")); 1050 1051 return _values.entrySet(); 1052 } 1053 } 1054 1055 public boolean canLog() 1056 { 1057 return log.isLoggable(Level.FINE); 1058 } 1059 1060 public void log(String value) 1061 { 1062 log.fine(value); 1063 } 1064 1065 public String toString() 1066 { 1067 return "SessionImpl[" + getId() + "]"; 1068 } 1069 1070 private static Comparator KEY_COMPARATOR = new Comparator() { 1071 public int compare(Object aObj, Object bObj) 1072 { 1073 Map.Entry a = (Map.Entry) aObj; 1074 Map.Entry b = (Map.Entry) bObj; 1075 1076 String aStr = (String ) a.getKey(); 1077 String bStr = (String ) b.getKey(); 1078 1079 return aStr.compareTo(bStr); 1080 } 1081 }; 1082} 1083 | Popular Tags |