1 17 18 19 package org.apache.catalina.session; 20 21 22 import java.beans.PropertyChangeListener ; 23 import java.beans.PropertyChangeSupport ; 24 import java.io.DataInputStream ; 25 import java.io.File ; 26 import java.io.FileInputStream ; 27 import java.io.IOException ; 28 import java.lang.reflect.Method ; 29 import java.security.AccessController ; 30 import java.security.MessageDigest ; 31 import java.security.NoSuchAlgorithmException ; 32 import java.security.PrivilegedAction ; 33 import java.util.Date ; 34 import java.util.Enumeration ; 35 import java.util.HashMap ; 36 import java.util.Iterator ; 37 import java.util.Map ; 38 import java.util.Random ; 39 import java.util.concurrent.ConcurrentHashMap ; 40 41 import javax.management.MBeanRegistration ; 42 import javax.management.MBeanServer ; 43 import javax.management.ObjectName ; 44 45 import org.apache.catalina.Container; 46 import org.apache.catalina.Engine; 47 import org.apache.catalina.Manager; 48 import org.apache.catalina.Session; 49 import org.apache.catalina.core.StandardContext; 50 import org.apache.catalina.core.StandardHost; 51 import org.apache.catalina.util.StringManager; 52 import org.apache.commons.logging.Log; 53 import org.apache.commons.logging.LogFactory; 54 import org.apache.tomcat.util.modeler.Registry; 55 56 57 65 66 public abstract class ManagerBase implements Manager, MBeanRegistration { 67 protected Log log = LogFactory.getLog(ManagerBase.class); 68 69 71 protected DataInputStream randomIS=null; 72 protected String devRandomSource="/dev/urandom"; 73 74 78 protected static final String DEFAULT_ALGORITHM = "MD5"; 79 80 81 86 protected String algorithm = DEFAULT_ALGORITHM; 87 88 89 92 protected Container container; 93 94 95 99 protected MessageDigest digest = null; 100 101 102 107 protected boolean distributable; 108 109 110 114 protected String entropy = null; 115 116 117 120 private static final String info = "ManagerBase/1.0"; 121 122 123 127 protected int maxInactiveInterval = 60; 128 129 130 133 protected int sessionIdLength = 16; 134 135 136 139 protected static String name = "ManagerBase"; 140 141 142 145 protected Random random = null; 146 147 148 152 protected String randomClass = "java.security.SecureRandom"; 153 154 155 158 protected int sessionMaxAliveTime; 159 160 161 164 protected int sessionAverageAliveTime; 165 166 167 170 protected int expiredSessions = 0; 171 172 173 177 protected Map sessions = new ConcurrentHashMap (); 178 179 protected int sessionCounter=0; 181 182 protected int maxActive=0; 183 184 protected int duplicates=0; 186 187 protected boolean initialized=false; 188 189 192 protected long processingTime = 0; 193 194 197 private int count = 0; 198 199 200 206 protected int processExpiresFrequency = 6; 207 208 211 protected static StringManager sm = 212 StringManager.getManager(Constants.Package); 213 214 217 protected PropertyChangeSupport support = new PropertyChangeSupport (this); 218 219 220 222 223 private class PrivilegedSetRandomFile implements PrivilegedAction { 224 225 public Object run(){ 226 try { 227 File f=new File ( devRandomSource ); 228 if( ! f.exists() ) return null; 229 randomIS= new DataInputStream ( new FileInputStream (f)); 230 randomIS.readLong(); 231 if( log.isDebugEnabled() ) 232 log.debug( "Opening " + devRandomSource ); 233 return randomIS; 234 } catch (IOException ex){ 235 return null; 236 } 237 } 238 } 239 240 241 243 246 public String getAlgorithm() { 247 248 return (this.algorithm); 249 250 } 251 252 253 258 public void setAlgorithm(String algorithm) { 259 260 String oldAlgorithm = this.algorithm; 261 this.algorithm = algorithm; 262 support.firePropertyChange("algorithm", oldAlgorithm, this.algorithm); 263 264 } 265 266 267 270 public Container getContainer() { 271 272 return (this.container); 273 274 } 275 276 277 282 public void setContainer(Container container) { 283 284 Container oldContainer = this.container; 285 this.container = container; 286 support.firePropertyChange("container", oldContainer, this.container); 287 } 288 289 290 292 public String getClassName() { 293 return this.getClass().getName(); 294 } 295 296 297 302 public synchronized MessageDigest getDigest() { 303 304 if (this.digest == null) { 305 long t1=System.currentTimeMillis(); 306 if (log.isDebugEnabled()) 307 log.debug(sm.getString("managerBase.getting", algorithm)); 308 try { 309 this.digest = MessageDigest.getInstance(algorithm); 310 } catch (NoSuchAlgorithmException e) { 311 log.error(sm.getString("managerBase.digest", algorithm), e); 312 try { 313 this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM); 314 } catch (NoSuchAlgorithmException f) { 315 log.error(sm.getString("managerBase.digest", 316 DEFAULT_ALGORITHM), e); 317 this.digest = null; 318 } 319 } 320 if (log.isDebugEnabled()) 321 log.debug(sm.getString("managerBase.gotten")); 322 long t2=System.currentTimeMillis(); 323 if( log.isDebugEnabled() ) 324 log.debug("getDigest() " + (t2-t1)); 325 } 326 327 return (this.digest); 328 329 } 330 331 332 336 public boolean getDistributable() { 337 338 return (this.distributable); 339 340 } 341 342 343 350 public void setDistributable(boolean distributable) { 351 352 boolean oldDistributable = this.distributable; 353 this.distributable = distributable; 354 support.firePropertyChange("distributable", 355 new Boolean (oldDistributable), 356 new Boolean (this.distributable)); 357 358 } 359 360 361 365 public String getEntropy() { 366 367 if (this.entropy == null) { 369 byte[] result = new byte[32]; 371 boolean apr = false; 372 try { 373 String methodName = "random"; 374 Class paramTypes[] = new Class [2]; 375 paramTypes[0] = result.getClass(); 376 paramTypes[1] = int.class; 377 Object paramValues[] = new Object [2]; 378 paramValues[0] = result; 379 paramValues[1] = new Integer (32); 380 Method method = Class.forName("org.apache.tomcat.jni.OS") 381 .getMethod(methodName, paramTypes); 382 method.invoke(null, paramValues); 383 apr = true; 384 } catch (Throwable t) { 385 } 387 if (apr) { 388 setEntropy(new String (result)); 389 } else { 390 setEntropy(this.toString()); 391 } 392 } 393 394 return (this.entropy); 395 396 } 397 398 399 404 public void setEntropy(String entropy) { 405 406 String oldEntropy = entropy; 407 this.entropy = entropy; 408 support.firePropertyChange("entropy", oldEntropy, this.entropy); 409 410 } 411 412 413 418 public String getInfo() { 419 420 return (info); 421 422 } 423 424 425 429 public int getMaxInactiveInterval() { 430 431 return (this.maxInactiveInterval); 432 433 } 434 435 436 442 public void setMaxInactiveInterval(int interval) { 443 444 int oldMaxInactiveInterval = this.maxInactiveInterval; 445 this.maxInactiveInterval = interval; 446 support.firePropertyChange("maxInactiveInterval", 447 new Integer (oldMaxInactiveInterval), 448 new Integer (this.maxInactiveInterval)); 449 450 } 451 452 453 459 public int getSessionIdLength() { 460 461 return (this.sessionIdLength); 462 463 } 464 465 466 472 public void setSessionIdLength(int idLength) { 473 474 int oldSessionIdLength = this.sessionIdLength; 475 this.sessionIdLength = idLength; 476 support.firePropertyChange("sessionIdLength", 477 new Integer (oldSessionIdLength), 478 new Integer (this.sessionIdLength)); 479 480 } 481 482 483 486 public String getName() { 487 488 return (name); 489 490 } 491 492 506 public void setRandomFile( String s ) { 507 if (System.getSecurityManager() != null){ 510 randomIS = (DataInputStream )AccessController.doPrivileged(new PrivilegedSetRandomFile()); 511 } else { 512 try{ 513 devRandomSource=s; 514 File f=new File ( devRandomSource ); 515 if( ! f.exists() ) return; 516 randomIS= new DataInputStream ( new FileInputStream (f)); 517 randomIS.readLong(); 518 if( log.isDebugEnabled() ) 519 log.debug( "Opening " + devRandomSource ); 520 } catch( IOException ex ) { 521 try { 522 randomIS.close(); 523 } catch (Exception e) { 524 log.warn("Failed to close randomIS."); 525 } 526 527 randomIS=null; 528 } 529 } 530 } 531 532 public String getRandomFile() { 533 return devRandomSource; 534 } 535 536 537 542 public Random getRandom() { 543 if (this.random == null) { 544 long seed = System.currentTimeMillis(); 546 long t1 = seed; 547 char entropy[] = getEntropy().toCharArray(); 548 for (int i = 0; i < entropy.length; i++) { 549 long update = ((byte) entropy[i]) << ((i % 8) * 8); 550 seed ^= update; 551 } 552 try { 553 Class clazz = Class.forName(randomClass); 555 this.random = (Random ) clazz.newInstance(); 556 this.random.setSeed(seed); 557 } catch (Exception e) { 558 log.error(sm.getString("managerBase.random", randomClass), 560 e); 561 this.random = new java.util.Random (); 562 this.random.setSeed(seed); 563 } 564 if(log.isDebugEnabled()) { 565 long t2=System.currentTimeMillis(); 566 if( (t2-t1) > 100 ) 567 log.debug(sm.getString("managerBase.seeding", randomClass) + " " + (t2-t1)); 568 } 569 } 570 571 return (this.random); 572 573 } 574 575 576 579 public String getRandomClass() { 580 581 return (this.randomClass); 582 583 } 584 585 586 591 public void setRandomClass(String randomClass) { 592 593 String oldRandomClass = this.randomClass; 594 this.randomClass = randomClass; 595 support.firePropertyChange("randomClass", oldRandomClass, 596 this.randomClass); 597 598 } 599 600 601 606 public int getExpiredSessions() { 607 return expiredSessions; 608 } 609 610 611 616 public void setExpiredSessions(int expiredSessions) { 617 this.expiredSessions = expiredSessions; 618 } 619 620 public long getProcessingTime() { 621 return processingTime; 622 } 623 624 625 public void setProcessingTime(long processingTime) { 626 this.processingTime = processingTime; 627 } 628 629 632 public int getProcessExpiresFrequency() { 633 634 return (this.processExpiresFrequency); 635 636 } 637 638 643 public void setProcessExpiresFrequency(int processExpiresFrequency) { 644 645 if (processExpiresFrequency <= 0) { 646 return; 647 } 648 649 int oldProcessExpiresFrequency = this.processExpiresFrequency; 650 this.processExpiresFrequency = processExpiresFrequency; 651 support.firePropertyChange("processExpiresFrequency", 652 new Integer (oldProcessExpiresFrequency), 653 new Integer (this.processExpiresFrequency)); 654 655 } 656 657 659 660 663 public void backgroundProcess() { 664 count = (count + 1) % processExpiresFrequency; 665 if (count == 0) 666 processExpires(); 667 } 668 669 672 public void processExpires() { 673 674 long timeNow = System.currentTimeMillis(); 675 Session sessions[] = findSessions(); 676 int expireHere = 0 ; 677 678 if(log.isDebugEnabled()) 679 log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); 680 for (int i = 0; i < sessions.length; i++) { 681 if (!sessions[i].isValid()) { 682 expireHere++; 683 } 684 } 685 long timeEnd = System.currentTimeMillis(); 686 if(log.isDebugEnabled()) 687 log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); 688 processingTime += ( timeEnd - timeNow ); 689 690 } 691 692 public void destroy() { 693 if( oname != null ) 694 Registry.getRegistry(null, null).unregisterComponent(oname); 695 initialized=false; 696 oname = null; 697 } 698 699 public void init() { 700 if( initialized ) return; 701 initialized=true; 702 703 if( oname==null ) { 704 try { 705 StandardContext ctx=(StandardContext)this.getContainer(); 706 Engine eng=(Engine)ctx.getParent().getParent(); 707 domain=ctx.getEngineName(); 708 distributable = ctx.getDistributable(); 709 StandardHost hst=(StandardHost)ctx.getParent(); 710 String path = ctx.getPath(); 711 if (path.equals("")) { 712 path = "/"; 713 } 714 oname=new ObjectName (domain + ":type=Manager,path=" 715 + path + ",host=" + hst.getName()); 716 Registry.getRegistry(null, null).registerComponent(this, oname, null ); 717 } catch (Exception e) { 718 log.error("Error registering ",e); 719 } 720 } 721 722 getRandomBytes(new byte[16]); 724 725 if(log.isDebugEnabled()) 726 log.debug("Registering " + oname ); 727 728 } 729 730 735 public void add(Session session) { 736 737 sessions.put(session.getIdInternal(), session); 738 int size = sessions.size(); 739 if( size > maxActive ) { 740 maxActive = size; 741 } 742 } 743 744 745 750 public void addPropertyChangeListener(PropertyChangeListener listener) { 751 752 support.addPropertyChangeListener(listener); 753 754 } 755 756 757 768 public Session createSession() { 769 return createSession(null); 770 } 771 772 773 786 public Session createSession(String sessionId) { 787 788 Session session = createEmptySession(); 790 791 session.setNew(true); 793 session.setValid(true); 794 session.setCreationTime(System.currentTimeMillis()); 795 session.setMaxInactiveInterval(this.maxInactiveInterval); 796 if (sessionId == null) { 797 sessionId = generateSessionId(); 798 808 809 825 } 826 session.setId(sessionId); 827 sessionCounter++; 828 829 return (session); 830 831 } 832 833 834 839 public Session createEmptySession() { 840 return (getNewSession()); 841 } 842 843 844 855 public Session findSession(String id) throws IOException { 856 857 if (id == null) 858 return (null); 859 return (Session) sessions.get(id); 860 861 } 862 863 864 868 public Session[] findSessions() { 869 870 Session results[] = null; 871 synchronized (sessions) { 872 results = new Session[sessions.size()]; 873 results = (Session[]) sessions.values().toArray(results); 874 } 875 return (results); 876 877 } 878 879 880 885 public void remove(Session session) { 886 887 sessions.remove(session.getIdInternal()); 888 889 } 890 891 892 897 public void removePropertyChangeListener(PropertyChangeListener listener) { 898 899 support.removePropertyChangeListener(listener); 900 901 } 902 903 904 906 907 910 protected StandardSession getNewSession() { 911 return new StandardSession(this); 912 } 913 914 915 protected void getRandomBytes(byte bytes[]) { 916 if (devRandomSource != null && randomIS == null) { 918 setRandomFile(devRandomSource); 919 } 920 if (randomIS != null) { 921 try { 922 int len = randomIS.read(bytes); 923 if (len == bytes.length) { 924 return; 925 } 926 if(log.isDebugEnabled()) 927 log.debug("Got " + len + " " + bytes.length ); 928 } catch (Exception ex) { 929 } 931 devRandomSource = null; 932 933 try { 934 randomIS.close(); 935 } catch (Exception e) { 936 log.warn("Failed to close randomIS."); 937 } 938 939 randomIS = null; 940 } 941 getRandom().nextBytes(bytes); 942 } 943 944 945 948 protected synchronized String generateSessionId() { 949 950 byte random[] = new byte[16]; 951 String jvmRoute = getJvmRoute(); 952 String result = null; 953 954 StringBuffer buffer = new StringBuffer (); 956 do { 957 int resultLenBytes = 0; 958 if (result != null) { 959 buffer = new StringBuffer (); 960 duplicates++; 961 } 962 963 while (resultLenBytes < this.sessionIdLength) { 964 getRandomBytes(random); 965 random = getDigest().digest(random); 966 for (int j = 0; 967 j < random.length && resultLenBytes < this.sessionIdLength; 968 j++) { 969 byte b1 = (byte) ((random[j] & 0xf0) >> 4); 970 byte b2 = (byte) (random[j] & 0x0f); 971 if (b1 < 10) 972 buffer.append((char) ('0' + b1)); 973 else 974 buffer.append((char) ('A' + (b1 - 10))); 975 if (b2 < 10) 976 buffer.append((char) ('0' + b2)); 977 else 978 buffer.append((char) ('A' + (b2 - 10))); 979 resultLenBytes++; 980 } 981 } 982 if (jvmRoute != null) { 983 buffer.append('.').append(jvmRoute); 984 } 985 result = buffer.toString(); 986 } while (sessions.containsKey(result)); 987 return (result); 988 989 } 990 991 992 994 995 1000 public Engine getEngine() { 1001 Engine e = null; 1002 for (Container c = getContainer(); e == null && c != null ; c = c.getParent()) { 1003 if (c != null && c instanceof Engine) { 1004 e = (Engine)c; 1005 } 1006 } 1007 return e; 1008 } 1009 1010 1011 1015 public String getJvmRoute() { 1016 Engine e = getEngine(); 1017 return e == null ? null : e.getJvmRoute(); 1018 } 1019 1020 1021 1023 1024 public void setSessionCounter(int sessionCounter) { 1025 this.sessionCounter = sessionCounter; 1026 } 1027 1028 1029 1034 public int getSessionCounter() { 1035 return sessionCounter; 1036 } 1037 1038 1039 1045 public int getDuplicates() { 1046 return duplicates; 1047 } 1048 1049 1050 public void setDuplicates(int duplicates) { 1051 this.duplicates = duplicates; 1052 } 1053 1054 1055 1060 public int getActiveSessions() { 1061 return sessions.size(); 1062 } 1063 1064 1065 1070 public int getMaxActive() { 1071 return maxActive; 1072 } 1073 1074 1075 public void setMaxActive(int maxActive) { 1076 this.maxActive = maxActive; 1077 } 1078 1079 1080 1087 public int getSessionMaxAliveTime() { 1088 return sessionMaxAliveTime; 1089 } 1090 1091 1092 1099 public void setSessionMaxAliveTime(int sessionMaxAliveTime) { 1100 this.sessionMaxAliveTime = sessionMaxAliveTime; 1101 } 1102 1103 1104 1111 public int getSessionAverageAliveTime() { 1112 return sessionAverageAliveTime; 1113 } 1114 1115 1116 1123 public void setSessionAverageAliveTime(int sessionAverageAliveTime) { 1124 this.sessionAverageAliveTime = sessionAverageAliveTime; 1125 } 1126 1127 1128 1132 public String listSessionIds() { 1133 StringBuffer sb=new StringBuffer (); 1134 Iterator keys = sessions.keySet().iterator(); 1135 while (keys.hasNext()) { 1136 sb.append(keys.next()).append(" "); 1137 } 1138 return sb.toString(); 1139 } 1140 1141 1142 1149 public String getSessionAttribute( String sessionId, String key ) { 1150 Session s = (Session) sessions.get(sessionId); 1151 if( s==null ) { 1152 if(log.isInfoEnabled()) 1153 log.info("Session not found " + sessionId); 1154 return null; 1155 } 1156 Object o=s.getSession().getAttribute(key); 1157 if( o==null ) return null; 1158 return o.toString(); 1159 } 1160 1161 1162 1174 public HashMap getSession(String sessionId) { 1175 Session s = (Session) sessions.get(sessionId); 1176 if (s == null) { 1177 if (log.isInfoEnabled()) { 1178 log.info("Session not found " + sessionId); 1179 } 1180 return null; 1181 } 1182 1183 Enumeration ee = s.getSession().getAttributeNames(); 1184 if (ee == null || !ee.hasMoreElements()) { 1185 return null; 1186 } 1187 1188 HashMap map = new HashMap (); 1189 while (ee.hasMoreElements()) { 1190 String attrName = (String ) ee.nextElement(); 1191 map.put(attrName, getSessionAttribute(sessionId, attrName)); 1192 } 1193 1194 return map; 1195 } 1196 1197 1198 public void expireSession( String sessionId ) { 1199 Session s=(Session)sessions.get(sessionId); 1200 if( s==null ) { 1201 if(log.isInfoEnabled()) 1202 log.info("Session not found " + sessionId); 1203 return; 1204 } 1205 s.expire(); 1206 } 1207 1208 1209 public String getLastAccessedTime( String sessionId ) { 1210 Session s=(Session)sessions.get(sessionId); 1211 if( s==null ) { 1212 log.info("Session not found " + sessionId); 1213 return ""; 1214 } 1215 return new Date (s.getLastAccessedTime()).toString(); 1216 } 1217 1218 1219 protected String domain; 1221 protected ObjectName oname; 1222 protected MBeanServer mserver; 1223 1224 public ObjectName getObjectName() { 1225 return oname; 1226 } 1227 1228 public String getDomain() { 1229 return domain; 1230 } 1231 1232 public ObjectName preRegister(MBeanServer server, 1233 ObjectName name) throws Exception { 1234 oname=name; 1235 mserver=server; 1236 domain=name.getDomain(); 1237 return name; 1238 } 1239 1240 public void postRegister(Boolean registrationDone) { 1241 } 1242 1243 public void preDeregister() throws Exception { 1244 } 1245 1246 public void postDeregister() { 1247 } 1248 1249} 1250 | Popular Tags |