| 1 16 18 package org.apache.catalina.loader; 19 20 21 import java.beans.PropertyChangeEvent ; 22 import java.beans.PropertyChangeListener ; 23 import java.beans.PropertyChangeSupport ; 24 import java.io.File ; 25 import java.io.FileOutputStream ; 26 import java.io.FilePermission ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.io.OutputStream ; 30 import java.lang.reflect.Constructor ; 31 import java.lang.reflect.Method ; 32 import java.net.MalformedURLException ; 33 import java.net.URL ; 34 import java.net.URLClassLoader ; 35 import java.net.URLStreamHandlerFactory ; 36 import java.util.ArrayList ; 37 import java.util.jar.JarFile ; 38 39 import javax.management.MBeanRegistration ; 40 import javax.management.MBeanServer ; 41 import javax.management.ObjectName ; 42 import javax.naming.Binding ; 43 import javax.naming.NameClassPair ; 44 import javax.naming.NamingEnumeration ; 45 import javax.naming.NamingException ; 46 import javax.naming.directory.DirContext ; 47 import javax.servlet.ServletContext ; 48 49 import org.apache.catalina.Container; 50 import org.apache.catalina.Context; 51 import org.apache.catalina.DefaultContext; 52 import org.apache.catalina.Engine; 53 import org.apache.catalina.Globals; 54 import org.apache.catalina.Lifecycle; 55 import org.apache.catalina.LifecycleException; 56 import org.apache.catalina.LifecycleListener; 57 import org.apache.catalina.Loader; 58 import org.apache.catalina.Logger; 59 import org.apache.catalina.core.StandardContext; 60 import org.apache.catalina.util.LifecycleSupport; 61 import org.apache.catalina.util.StringManager; 62 import org.apache.commons.modeler.Registry; 63 import org.apache.naming.resources.DirContextURLStreamHandler; 64 import org.apache.naming.resources.DirContextURLStreamHandlerFactory; 65 import org.apache.naming.resources.Resource; 66 67 68 85 86 public class WebappLoader 87 implements Lifecycle, Loader , PropertyChangeListener , MBeanRegistration { 88 89 91 92 96 public WebappLoader() { 97 98 this(null); 99 100 } 101 102 103 109 public WebappLoader(ClassLoader parent) { 110 super(); 111 this.parentClassLoader = parent; 112 } 113 114 115 117 118 121 private static boolean first = true; 122 123 124 127 private WebappClassLoader classLoader = null; 128 129 130 133 private Container container = null; 134 135 136 139 private int debug = 0; 140 141 142 145 protected DefaultContext defaultContext = null; 146 147 148 152 private boolean delegate = false; 153 154 155 158 private static final String info = 159 "org.apache.catalina.loader.WebappLoader/1.0"; 160 161 162 165 protected LifecycleSupport lifecycle = new LifecycleSupport(this); 166 167 168 173 private String loaderClass = 174 "org.apache.catalina.loader.WebappClassLoader"; 175 176 177 180 private ClassLoader parentClassLoader = null; 181 182 183 186 private boolean reloadable = false; 187 188 189 192 private String repositories[] = new String [0]; 193 194 195 198 protected static final StringManager sm = 199 StringManager.getManager(Constants.Package); 200 201 202 205 private boolean started = false; 206 207 208 211 protected PropertyChangeSupport support = new PropertyChangeSupport (this); 212 213 214 217 private String classpath = null; 218 219 220 223 private ArrayList loaderRepositories = null; 224 225 226 228 229 232 public ClassLoader getClassLoader() { 233 234 239 if (classLoader != null) { 240 return classLoader; 241 } else { 242 return parentClassLoader; 243 } 244 245 } 246 247 248 251 public Container getContainer() { 252 253 return (container); 254 255 } 256 257 258 263 public void setContainer(Container container) { 264 265 if ((this.container != null) && (this.container instanceof Context )) 267 ((Context ) this.container).removePropertyChangeListener(this); 268 269 Container oldContainer = this.container; 271 this.container = container; 272 support.firePropertyChange("container", oldContainer, this.container); 273 274 if ((this.container != null) && (this.container instanceof Context )) { 276 setReloadable( ((Context ) this.container).getReloadable() ); 277 ((Context ) this.container).addPropertyChangeListener(this); 278 } 279 280 } 281 282 283 287 public DefaultContext getDefaultContext() { 288 289 return (this.defaultContext); 290 291 } 292 293 294 299 public void setDefaultContext(DefaultContext defaultContext) { 300 301 DefaultContext oldDefaultContext = this.defaultContext; 302 this.defaultContext = defaultContext; 303 support.firePropertyChange("defaultContext", oldDefaultContext, this.defaultContext); 304 305 } 306 307 308 311 public int getDebug() { 312 313 return (this.debug); 314 315 } 316 317 318 323 public void setDebug(int debug) { 324 325 int oldDebug = this.debug; 326 this.debug = debug; 327 support.firePropertyChange("debug", new Integer (oldDebug), 328 new Integer (this.debug)); 329 330 } 331 332 333 337 public boolean getDelegate() { 338 339 return (this.delegate); 340 341 } 342 343 344 350 public void setDelegate(boolean delegate) { 351 352 boolean oldDelegate = this.delegate; 353 this.delegate = delegate; 354 support.firePropertyChange("delegate", new Boolean (oldDelegate), 355 new Boolean (this.delegate)); 356 357 } 358 359 360 365 public String getInfo() { 366 367 return (info); 368 369 } 370 371 372 375 public String getLoaderClass() { 376 377 return (this.loaderClass); 378 379 } 380 381 382 387 public void setLoaderClass(String loaderClass) { 388 389 this.loaderClass = loaderClass; 390 391 } 392 393 394 397 public boolean getReloadable() { 398 399 return (this.reloadable); 400 401 } 402 403 404 409 public void setReloadable(boolean reloadable) { 410 411 boolean oldReloadable = this.reloadable; 413 this.reloadable = reloadable; 414 support.firePropertyChange("reloadable", 415 new Boolean (oldReloadable), 416 new Boolean (this.reloadable)); 417 418 } 419 420 421 423 424 429 public void addPropertyChangeListener(PropertyChangeListener listener) { 430 431 support.addPropertyChangeListener(listener); 432 433 } 434 435 436 441 public void addRepository(String repository) { 442 443 if (log.isDebugEnabled()) 444 log.debug(sm.getString("webappLoader.addRepository", repository)); 445 446 for (int i = 0; i < repositories.length; i++) { 447 if (repository.equals(repositories[i])) 448 return; 449 } 450 String results[] = new String [repositories.length + 1]; 451 for (int i = 0; i < repositories.length; i++) 452 results[i] = repositories[i]; 453 results[repositories.length] = repository; 454 repositories = results; 455 456 if (started && (classLoader != null)) { 457 classLoader.addRepository(repository); 458 if( loaderRepositories != null ) loaderRepositories.add(repository); 459 setClassPath(); 460 } 461 462 } 463 464 465 471 public String [] findRepositories() { 472 473 return ((String [])repositories.clone()); 474 475 } 476 477 public String [] getRepositories() { 478 return ((String [])repositories.clone()); 479 } 480 481 483 public String getRepositoriesString() { 484 StringBuffer sb=new StringBuffer (); 485 for( int i=0; i<repositories.length ; i++ ) { 486 sb.append( repositories[i]).append(":"); 487 } 488 return sb.toString(); 489 } 490 491 public String [] getLoaderRepositories() { 492 if( loaderRepositories==null ) return null; 493 String res[]=new String [ loaderRepositories.size()]; 494 loaderRepositories.toArray(res); 495 return res; 496 } 497 498 public String getLoaderRepositoriesString() { 499 String repositories[]=getLoaderRepositories(); 500 StringBuffer sb=new StringBuffer (); 501 for( int i=0; i<repositories.length ; i++ ) { 502 sb.append( repositories[i]).append(":"); 503 } 504 return sb.toString(); 505 } 506 507 508 514 public String getClasspath() { 515 return classpath; 516 } 517 518 519 523 public boolean modified() { 524 525 return (classLoader.modified()); 526 527 } 528 529 530 533 public void closeJARs(boolean force) { 534 if (classLoader !=null){ 535 classLoader.closeJARs(force); 536 } 537 } 538 539 540 545 public void removePropertyChangeListener(PropertyChangeListener listener) { 546 547 support.removePropertyChangeListener(listener); 548 549 } 550 551 552 555 public String toString() { 556 557 StringBuffer sb = new StringBuffer ("WebappLoader["); 558 if (container != null) 559 sb.append(container.getName()); 560 sb.append("]"); 561 return (sb.toString()); 562 563 } 564 565 566 568 569 574 public void addLifecycleListener(LifecycleListener listener) { 575 576 lifecycle.addLifecycleListener(listener); 577 578 } 579 580 581 585 public LifecycleListener[] findLifecycleListeners() { 586 587 return lifecycle.findLifecycleListeners(); 588 589 } 590 591 592 597 public void removeLifecycleListener(LifecycleListener listener) { 598 599 lifecycle.removeLifecycleListener(listener); 600 601 } 602 603 private boolean initialized=false; 604 605 public void init() { 606 initialized=true; 607 608 if( oname==null ) { 609 if( container instanceof StandardContext) { 611 try { 613 StandardContext ctx=(StandardContext)container; 614 Engine eng=(Engine)ctx.getParent().getParent(); 615 String path = ctx.getPath(); 616 if (path.equals("")) { 617 path = "/"; 618 } 619 oname=new ObjectName (ctx.getEngineName() + ":type=Loader,path=" + 620 path + ",host=" + ctx.getParent().getName()); 621 Registry.getRegistry(null, null).registerComponent(this, oname, null); 622 controller=oname; 623 } catch (Exception e) { 624 log.error("Error registering loader", e ); 625 } 626 } 627 } 628 629 if( container == null ) { 630 633 } 634 } 635 636 public void destroy() { 637 if( controller==oname ) { 638 Registry.getRegistry(null, null).unregisterComponent(oname); 640 oname = null; 641 } 642 initialized = false; 643 644 } 645 646 651 public void start() throws LifecycleException { 652 if( ! initialized ) init(); 654 if (started) 655 throw new LifecycleException 656 (sm.getString("webappLoader.alreadyStarted")); 657 if (log.isDebugEnabled()) 658 log.debug(sm.getString("webappLoader.starting")); 659 lifecycle.fireLifecycleEvent(START_EVENT, null); 660 started = true; 661 662 if (container.getResources() == null) { 663 log.info("No resources for " + container); 664 return; 665 } 666 URLStreamHandlerFactory streamHandlerFactory = 668 new DirContextURLStreamHandlerFactory(); 669 if (first) { 670 first = false; 671 try { 672 URL.setURLStreamHandlerFactory(streamHandlerFactory); 673 } catch (Exception e) { 674 log.error("Error registering jndi stream handler", e); 676 } catch (Throwable t) { 677 log.info("Dual registration of jndi stream handler: " 679 + t.getMessage()); 680 } 681 } 682 683 try { 685 686 classLoader = createClassLoader(); 687 classLoader.setResources(container.getResources()); 688 classLoader.setDebug(this.debug); 689 classLoader.setDelegate(this.delegate); 690 691 for (int i = 0; i < repositories.length; i++) { 692 classLoader.addRepository(repositories[i]); 693 } 694 695 setRepositories(); 697 setClassPath(); 698 699 setPermissions(); 700 701 if (classLoader instanceof Lifecycle) 702 ((Lifecycle) classLoader).start(); 703 704 DirContextURLStreamHandler.bind 706 ((ClassLoader ) classLoader, this.container.getResources()); 707 708 StandardContext ctx=(StandardContext)container; 709 Engine eng=(Engine)ctx.getParent().getParent(); 710 String path = ctx.getPath(); 711 if (path.equals("")) { 712 path = "/"; 713 } 714 ObjectName cloname = new ObjectName  715 (ctx.getEngineName() + ":type=WebappClassLoader,path=" 716 + path + ",host=" + ctx.getParent().getName()); 717 Registry.getRegistry(null, null) 718 .registerComponent(classLoader, cloname, null); 719 720 } catch (Throwable t) { 721 log.error( "LifecycleException ", t ); 722 throw new LifecycleException("start: ", t); 723 } 724 725 } 726 727 728 733 public void stop() throws LifecycleException { 734 735 if (!started) 737 throw new LifecycleException 738 (sm.getString("webappLoader.notStarted")); 739 if (log.isDebugEnabled()) 740 log.debug(sm.getString("webappLoader.stopping")); 741 lifecycle.fireLifecycleEvent(STOP_EVENT, null); 742 started = false; 743 744 if (container instanceof Context ) { 746 ServletContext servletContext = 747 ((Context ) container).getServletContext(); 748 servletContext.removeAttribute(Globals.CLASS_PATH_ATTR); 749 } 750 751 if (classLoader instanceof Lifecycle) 753 ((Lifecycle) classLoader).stop(); 754 DirContextURLStreamHandler.unbind((ClassLoader ) classLoader); 755 756 try { 757 StandardContext ctx=(StandardContext)container; 758 Engine eng=(Engine)ctx.getParent().getParent(); 759 String path = ctx.getPath(); 760 if (path.equals("")) { 761 path = "/"; 762 } 763 ObjectName cloname = new ObjectName  764 (ctx.getEngineName() + ":type=WebappClassLoader,path=" 765 + path + ",host=" + ctx.getParent().getName()); 766 Registry.getRegistry(null, null).unregisterComponent(cloname); 767 } catch (Throwable t) { 768 log.error( "LifecycleException ", t ); 769 } 770 771 classLoader = null; 772 773 destroy(); 774 775 } 776 777 778 780 781 786 public void propertyChange(PropertyChangeEvent event) { 787 788 if (!(event.getSource() instanceof Context )) 790 return; 791 Context context = (Context ) event.getSource(); 792 793 if (event.getPropertyName().equals("reloadable")) { 795 try { 796 setReloadable 797 ( ((Boolean ) event.getNewValue()).booleanValue() ); 798 } catch (NumberFormatException e) { 799 log.error(sm.getString("webappLoader.reloadable", 800 event.getNewValue().toString())); 801 } 802 } 803 804 } 805 806 807 809 810 813 private WebappClassLoader createClassLoader() 814 throws Exception { 815 816 Class clazz = Class.forName(loaderClass); 817 WebappClassLoader classLoader = null; 818 819 if (parentClassLoader == null) { 820 parentClassLoader = Thread.currentThread().getContextClassLoader(); 821 } 822 Class [] argTypes = { ClassLoader .class }; 823 Object [] args = { parentClassLoader }; 824 Constructor constr = clazz.getConstructor(argTypes); 825 classLoader = (WebappClassLoader) constr.newInstance(args); 826 827 return classLoader; 828 829 } 830 831 832 837 private void log(String message) { 838 839 Logger logger = null; 840 if (container != null) 841 logger = container.getLogger(); 842 if (logger != null) 843 logger.log("WebappLoader[" + container.getName() + "]: " 844 + message); 845 else { 846 String containerName = null; 847 if (container != null) 848 containerName = container.getName(); 849 System.out.println("WebappLoader[" + containerName 850 + "]: " + message); 851 } 852 853 } 854 855 856 862 private void log(String message, Throwable throwable) { 863 864 Logger logger = null; 865 if (container != null) 866 logger = container.getLogger(); 867 if (logger != null) { 868 logger.log("WebappLoader[" + container.getName() + "] " 869 + message, throwable); 870 } else { 871 String containerName = null; 872 if (container != null) 873 containerName = container.getName(); 874 System.out.println("WebappLoader[" + containerName 875 + "]: " + message); 876 System.out.println("" + throwable); 877 throwable.printStackTrace(System.out); 878 } 879 880 } 881 882 883 886 private void setPermissions() { 887 888 if (System.getSecurityManager() == null) 889 return; 890 if (!(container instanceof Context )) 891 return; 892 893 ServletContext servletContext = 895 ((Context ) container).getServletContext(); 896 897 File workDir = 899 (File ) servletContext.getAttribute(Globals.WORK_DIR_ATTR); 900 if (workDir != null) { 901 try { 902 String workDirPath = workDir.getCanonicalPath(); 903 classLoader.addPermission 904 (new FilePermission (workDirPath, "read,write")); 905 &
|