| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| |
| package org.apache.tomcat.util.loader; |
| |
| |
| import java.io.File; |
| import java.io.Serializable; |
| import java.lang.reflect.Constructor; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| |
| // Based on org.apache.catalina.Loader - removed most of the catalina-specific |
| |
| /** |
| * Represent one unit of code - jar, webapp, etc. Modules can be reloaded independently, |
| * and may be part of a flat structure or a hierarchy. |
| * |
| * @author Costin Manolache |
| * @author Craig R. McClanahan |
| * @author Remy Maucherat |
| */ |
| public class Module implements Serializable { |
| |
| // ----------------------------------------------------------- Constructors |
| |
| |
| /** |
| * |
| */ |
| public Module() { |
| } |
| |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| private static final boolean DEBUG=false; //LoaderProperties.getProperty("loader.Module.debug") != null; |
| |
| /** |
| * The class loader being managed by this Loader component. |
| */ |
| private transient ModuleClassLoader classLoader = null; |
| |
| /** |
| * The "follow standard delegation model" flag that will be used to |
| * configure our ClassLoader. |
| */ |
| private boolean delegate = false; |
| |
| private Class classLoaderClass; |
| |
| /** |
| * The Java class name of the ClassLoader implementation to be used. |
| * This class should extend ModuleClassLoader, otherwise, a different |
| * loader implementation must be used. |
| */ |
| private String loaderClass = null; |
| // "org.apache.catalina.loader.WebappClassLoader"; |
| |
| /** |
| * The parent class loader of the class loader we will create. |
| * Use Repository if the parent is also a repository, otherwise set |
| * the ClassLoader |
| */ |
| private transient ClassLoader parentClassLoader = null; |
| private Repository parent; |
| |
| private Repository repository; |
| |
| /** |
| * The set of repositories associated with this class loader. |
| */ |
| private String repositories[] = new String[0]; |
| private URL classpath[] ; |
| |
| private File workDir; |
| |
| /** |
| * Has this component been started? |
| */ |
| private boolean started = false; |
| |
| boolean hasIndex=false; |
| |
| // ------------------------------------------------------------- Properties |
| |
| |
| /** |
| * Return the Java class loader to be used by this Container. |
| */ |
| public ClassLoader getClassLoader() { |
| return classLoader; |
| } |
| |
| |
| /** |
| * Return the "follow standard delegation model" flag used to configure |
| * our ClassLoader. |
| */ |
| public boolean getDelegate() { |
| return (this.delegate); |
| } |
| |
| |
| /** |
| * Set the "follow standard delegation model" flag used to configure |
| * our ClassLoader. |
| * |
| * @param delegate The new flag |
| */ |
| public void setDelegate(boolean delegate) { |
| boolean oldDelegate = this.delegate; |
| this.delegate = delegate; |
| if( classLoader != null ) classLoader.setDelegate(delegate); |
| } |
| |
| |
| // --------------------------------------------------------- Public Methods |
| |
| /** |
| * Has the internal repository associated with this Loader been modified, |
| * such that the loaded classes should be reloaded? |
| */ |
| public boolean modified() { |
| return (classLoader.modified()); |
| } |
| |
| public boolean isStarted() { |
| return started; |
| } |
| |
| public String getClasspathString() { |
| if(classpath==null ) { |
| return null; |
| } |
| StringBuffer sb=new StringBuffer(); |
| for( int i=0; i<classpath.length; i++ ) { |
| if( i>0 ) sb.append(":"); |
| sb.append( classpath[i].getFile() ); |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Start this component, initializing our associated class loader. |
| * |
| * @exception LifecycleException if a lifecycle error occurs |
| */ |
| public void start() { |
| // Validate and update our current component state |
| if (started) |
| throw new RuntimeException |
| ("Already started"); |
| started = true; |
| |
| log("start()"); |
| |
| // Construct a class loader based on our current repositories list |
| try { |
| |
| classLoader = createClassLoader(); |
| |
| //classLoader.setResources(container.getResources()); |
| classLoader.setDelegate(this.delegate); |
| |
| for (int i = 0; i < repositories.length; i++) { |
| classLoader.addRepository(repositories[i]); |
| } |
| |
| classLoader.start(); |
| |
| getRepository().getLoader().notifyModuleStart(this); |
| |
| } catch (Throwable t) { |
| log( "LifecycleException ", t ); |
| throw new RuntimeException("start: ", t); |
| } |
| |
| } |
| |
| |
| /** |
| * Stop this component, finalizing our associated class loader. |
| * |
| * @exception LifecycleException if a lifecycle error occurs |
| */ |
| public void stop() { |
| if (!started) |
| throw new RuntimeException("stop: started=false"); |
| |
| //if (DEBUG) |
| log("stop()", null); |
| |
| getRepository().getLoader().notifyModuleStop(this); |
| |
| started = false; |
| |
| // unregister this classloader in the server group |
| if( repository != null ) repository.removeClassLoader(classLoader); |
| |
| // Throw away our current class loader |
| classLoader.stop(); |
| |
| classLoader = null; |
| |
| } |
| |
| // ------------------------------------------------------- Private Methods |
| |
| /** |
| * Experiment for basic lifecycle driven by higher layer. |
| * start() and stop() methods will be called on the class when the |
| * module is stopped and started. |
| * |
| */ |
| //public void addModuleClass(String s) { |
| |
| //} |
| |
| /** Set the class used to construct the class loader. |
| * |
| * The alternative is to set the context class loader to allow loaderClass |
| * to be created. |
| * |
| * @param c |
| */ |
| public void setClassLoaderClass( Class c ) { |
| classLoaderClass=c; |
| } |
| |
| /** |
| * Create associated classLoader. |
| */ |
| ModuleClassLoader createClassLoader() |
| throws Exception |
| { |
| |
| if( classLoader != null ) return classLoader; |
| if( classLoaderClass==null && loaderClass!=null) { |
| classLoaderClass = Class.forName(loaderClass); |
| } |
| |
| ModuleClassLoader classLoader = null; |
| |
| if (parentClassLoader == null) { |
| if( parent != null ) { |
| parentClassLoader = parent.getClassLoader(); |
| } |
| } |
| if (parentClassLoader == null) { |
| parentClassLoader = Thread.currentThread().getContextClassLoader(); |
| } |
| |
| if( classLoaderClass != null ) { |
| Class[] argTypes = { URL[].class, ClassLoader.class }; |
| Object[] args = { classpath, parentClassLoader }; |
| Constructor constr = classLoaderClass.getConstructor(argTypes); |
| classLoader = (ModuleClassLoader) constr.newInstance(args); |
| } else { |
| classLoader=new ModuleClassLoader( classpath, parentClassLoader); |
| } |
| System.err.println("---- Created class loader " + classpath + " " + parentClassLoader + " repo=" + repository.getName() + " " + parent); |
| |
| classLoader.setModule(this); |
| classLoader.setDelegate( delegate ); |
| |
| classLoader.start(); |
| repository.addClassLoader(classLoader); |
| |
| return classLoader; |
| } |
| |
| |
| /** |
| * @param parent |
| */ |
| public void setParent(Repository parent) { |
| this.parent=parent; |
| } |
| |
| /** |
| * @param array |
| */ |
| public void setClasspath(URL[] array) { |
| this.classpath=array; |
| } |
| |
| /** Set the path to the module. |
| * In normal use, each module will be associated with one jar or |
| * classpath dir. |
| * |
| * @param name |
| */ |
| public void setPath(String name) { |
| this.classpath=new URL[1]; |
| try { |
| classpath[0]=new URL(name); |
| } catch (MalformedURLException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| |
| |
| /** |
| * @param lg |
| */ |
| public void setRepository(Repository lg) { |
| this.repository=lg; |
| } |
| |
| /** |
| * Return a String representation of this component. |
| */ |
| public String toString() { |
| |
| StringBuffer sb = new StringBuffer("ModuleLoader["); |
| sb.append(getClasspathString()); |
| sb.append("]"); |
| return (sb.toString()); |
| |
| } |
| |
| private void log( String s ) { |
| log(s,null); |
| } |
| |
| private void log(String s, Throwable t ) { |
| System.err.println("Module: " + s ); |
| if( t!=null) |
| t.printStackTrace(); |
| } |
| |
| |
| /** |
| * @return |
| */ |
| public Repository getRepository() { |
| return repository; |
| } |
| |
| |
| /** |
| * @return |
| */ |
| public String getName() { |
| return classpath[0].getFile(); // this.toString(); |
| } |
| |
| |
| public void setParentClassLoader(ClassLoader parentClassLoader2) { |
| this.parentClassLoader=parentClassLoader2; |
| } |
| |
| |
| } |