blob: 9656d29535cb5a10a5c898681dcfad91222c80a9 [file] [log] [blame]
/*
* 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;
}
}