| 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 v
|