You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2006/05/19 07:18:20 UTC
svn commit: r407715 [1/2] - in /tomcat/sandbox: ./
java/org/apache/coyote/adapters/ java/org/apache/coyote/http11/
java/org/apache/coyote/http11/apr/ java/org/apache/coyote/standalone/
java/org/apache/tomcat/util/loader/ java/org/apache/tomcat/util/net...
Author: costin
Date: Thu May 18 22:18:18 2006
New Revision: 407715
URL: http://svn.apache.org/viewvc?rev=407715&view=rev
Log:
Cleaning up, this time I hope in the right place.
- The APR stuff is not going anywhere, and probably doesn't matter, people using it probably won't care nothing
is shared with the other connectors ( and viceversa )
- The adapters were just examples - I'm keeping the 2 that may matter for coyote standalone use.
- adding loader from util, so the only dep will be tomcat6
Added:
tomcat/sandbox/java/org/apache/tomcat/util/loader/
tomcat/sandbox/java/org/apache/tomcat/util/loader/Loader.java (with props)
tomcat/sandbox/java/org/apache/tomcat/util/loader/Module.java (with props)
tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleClassLoader.java (with props)
tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleListener.java
tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java (with props)
tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java
tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html
Removed:
tomcat/sandbox/java/org/apache/coyote/adapters/Counters.java
tomcat/sandbox/java/org/apache/coyote/adapters/HelloWorldAdapter.java
tomcat/sandbox/java/org/apache/coyote/adapters/JsAdapter.java
tomcat/sandbox/java/org/apache/coyote/adapters/Mapper.java
tomcat/sandbox/java/org/apache/coyote/http11/apr/Http11AprBaseProtocol.java
tomcat/sandbox/java/org/apache/coyote/http11/apr/Http11AprProcessor.java
tomcat/sandbox/java/org/apache/coyote/http11/apr/Http11AprProtocol.java
tomcat/sandbox/java/org/apache/coyote/http11/apr/InternalAprInputBuffer.java
tomcat/sandbox/java/org/apache/coyote/http11/apr/InternalAprOutputBuffer.java
tomcat/sandbox/java/org/apache/tomcat/util/net/apr/AprByteChannel.java
tomcat/sandbox/java/org/apache/tomcat/util/net/apr/AprEndpoint.java
tomcat/sandbox/java/org/apache/tomcat/util/net/apr/AprFileChannel.java
tomcat/sandbox/java/org/apache/tomcat/util/net/apr/AprSocket.java
Modified:
tomcat/sandbox/.classpath
tomcat/sandbox/java/org/apache/coyote/adapters/FileAdapter.java
tomcat/sandbox/java/org/apache/coyote/adapters/MapperAdapter.java
tomcat/sandbox/java/org/apache/coyote/http11/Http11Protocol.java
tomcat/sandbox/java/org/apache/coyote/standalone/Main.java
Modified: tomcat/sandbox/.classpath
URL: http://svn.apache.org/viewvc/tomcat/sandbox/.classpath?rev=407715&r1=407714&r2=407715&view=diff
==============================================================================
--- tomcat/sandbox/.classpath (original)
+++ tomcat/sandbox/.classpath Thu May 18 22:18:18 2006
@@ -1,14 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="java"/>
- <classpathentry kind="src" path="test"/>
- <classpathentry combineaccessrules="false" kind="src" path="/container"/>
- <classpathentry combineaccessrules="false" kind="src" path="/connectors"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="var" path="TOMCAT_LIBS_BASE/rhino1_6R2/js.jar"/>
- <classpathentry kind="var" path="TOMCAT_LIBS_BASE/junit3.8.1/junit.jar"/>
- <classpathentry kind="var" path="TOMCAT_LIBS_BASE/servlet-api-2.4/lib/servlet-api.jar"/>
- <classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-modeler-1.1/commons-modeler.jar"/>
- <classpathentry kind="var" path="TOMCAT_LIBS_BASE/commons-el-1.0/commons-el.jar"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/tomcat6"/>
<classpathentry kind="output" path="classes"/>
</classpath>
Modified: tomcat/sandbox/java/org/apache/coyote/adapters/FileAdapter.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/adapters/FileAdapter.java?rev=407715&r1=407714&r2=407715&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/adapters/FileAdapter.java (original)
+++ tomcat/sandbox/java/org/apache/coyote/adapters/FileAdapter.java Thu May 18 22:18:18 2006
@@ -10,9 +10,7 @@
import org.apache.coyote.Adapter;
import org.apache.coyote.Request;
import org.apache.coyote.Response;
-import org.apache.coyote.standalone.MessageWriter;
import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.C2BConverter;
/**
* Serve a static file. This is the traditional method, a separate adapter could
@@ -122,6 +120,11 @@
public String getContentType( String ext ) {
return contentTypes.getProperty( ext, "text/plain" );
+ }
+
+ public boolean event(Request req, Response res, boolean error) throws Exception {
+ // TODO Auto-generated method stub
+ return false;
}
}
Modified: tomcat/sandbox/java/org/apache/coyote/adapters/MapperAdapter.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/adapters/MapperAdapter.java?rev=407715&r1=407714&r2=407715&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/adapters/MapperAdapter.java (original)
+++ tomcat/sandbox/java/org/apache/coyote/adapters/MapperAdapter.java Thu May 18 22:18:18 2006
@@ -1,16 +1,12 @@
package org.apache.coyote.adapters;
-import java.util.Enumeration;
import java.util.Hashtable;
import org.apache.coyote.Adapter;
import org.apache.coyote.Request;
import org.apache.coyote.Response;
-import org.apache.coyote.http11.Http11BaseProtocol;
import org.apache.coyote.standalone.MessageWriter;
import org.apache.tomcat.util.http.mapper.Mapper;
-import org.apache.tomcat.util.loader.Loader;
-import org.apache.tomcat.util.loader.Repository;
/**
*
@@ -76,6 +72,11 @@
public Adapter getDefaultAdapter() {
return defaultAdapter;
+ }
+
+ public boolean event(Request req, Response res, boolean error) throws Exception {
+ // TODO Auto-generated method stub
+ return false;
}
}
Modified: tomcat/sandbox/java/org/apache/coyote/http11/Http11Protocol.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/http11/Http11Protocol.java?rev=407715&r1=407714&r2=407715&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/http11/Http11Protocol.java (original)
+++ tomcat/sandbox/java/org/apache/coyote/http11/Http11Protocol.java Thu May 18 22:18:18 2006
@@ -16,35 +16,14 @@
package org.apache.coyote.http11;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.URLEncoder;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Iterator;
-
import javax.management.MBeanRegistration;
import javax.management.MBeanServer;
import javax.management.ObjectName;
-import org.apache.commons.modeler.Registry;
-import org.apache.coyote.ActionCode;
-import org.apache.coyote.ActionHook;
-import org.apache.coyote.Adapter;
-import org.apache.coyote.ProtocolHandler;
import org.apache.coyote.RequestGroupInfo;
import org.apache.coyote.RequestInfo;
+import org.apache.tomcat.util.modeler.Registry;
import org.apache.tomcat.util.net.PoolTcpEndpoint;
-import org.apache.tomcat.util.net.TcpConnection;
-import org.apache.tomcat.util.net.TcpConnectionHandler;
-import org.apache.tomcat.util.net.javaio.SSLImplementation;
-import org.apache.tomcat.util.net.javaio.SSLSupport;
-import org.apache.tomcat.util.net.javaio.ServerSocketFactory;
-import org.apache.tomcat.util.res.StringManager;
-import org.apache.tomcat.util.threads.ThreadPool;
import org.apache.tomcat.util.threads.ThreadWithAttributes;
Modified: tomcat/sandbox/java/org/apache/coyote/standalone/Main.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/coyote/standalone/Main.java?rev=407715&r1=407714&r2=407715&view=diff
==============================================================================
--- tomcat/sandbox/java/org/apache/coyote/standalone/Main.java (original)
+++ tomcat/sandbox/java/org/apache/coyote/standalone/Main.java Thu May 18 22:18:18 2006
@@ -4,11 +4,8 @@
import java.util.Hashtable;
import org.apache.coyote.Adapter;
-import org.apache.coyote.adapters.Counters;
-import org.apache.coyote.adapters.HelloWorldAdapter;
import org.apache.coyote.adapters.MapperAdapter;
import org.apache.coyote.http11.Http11BaseProtocol;
-import org.apache.tomcat.util.http.mapper.Mapper;
import org.apache.tomcat.util.loader.Loader;
import org.apache.tomcat.util.loader.Repository;
@@ -40,13 +37,8 @@
proto = new Http11BaseProtocol();
mainAdapter = new MapperAdapter();
- mainAdapter.addAdapter("/hello", new HelloWorldAdapter());
- Counters cnt=new Counters();
- cnt.setNext( mainAdapter );
-
- //proto.setAdapter(mainAdapter);
- proto.setAdapter(cnt);
+ proto.setAdapter(mainAdapter);
}
public MapperAdapter getMapper() {
Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/Loader.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/Loader.java?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/Loader.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/Loader.java Thu May 18 22:18:18 2006
@@ -0,0 +1,881 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.FileInputStream;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+
+/**
+ * Boostrap loader for Catalina or other java apps.
+ *
+ * This application constructs a class loader
+ * for use in loading the Catalina internal classes (by accumulating all of the
+ * JAR files found in the "server" directory under "catalina.home"), and
+ * starts the regular execution of the container. The purpose of this
+ * roundabout approach is to keep the Catalina internal classes (and any
+ * other classes they depend on, such as an XML parser) out of the system
+ * class path and therefore not visible to application level classes.
+ *
+ *
+ * Merged with CatalinaProperties:
+ * Load a properties file describing the modules and startup sequence.
+ * This is responsible for configuration of the loader.
+ * TODO: support jmx-style configuration, including persistence.
+ * TODO: better separate legacy config and the new style
+ *
+ * The properties file will be named "loader.properties" or
+ * "catalina.properties" ( for backwad compatibility ) and
+ * will be searched in:
+ * - TODO
+ *
+ * Properties used:
+ * - TODO
+ *
+ * loader.* and *.loader properties are used internally by the loader (
+ * *.loader is for backward compat with catalina ).
+ * All other properties in the config file are set as System properties.
+ *
+ * Based on o.a.catalina.bootstrap.CatalinaProperties - utility class to read
+ * the bootstrap Catalina configuration.
+
+ *
+ * @author Craig R. McClanahan
+ * @author Remy Maucherat
+ * @author Costin Manolache
+ */
+public final class Loader {
+
+ private static final boolean DEBUG=true; //LoaderProperties.getProperty("loader.debug.Loader") != null;
+ // If flat, only one loader is created. If false - one loader per jar/dir
+ private static final boolean FLAT=false;//LoaderProperties.getProperty("loader.Loader.flat") != null;
+
+ // -------------------------------------------------------------- Constants
+
+
+ private static final String CATALINA_HOME_TOKEN = "${catalina.home}";
+ private static final String CATALINA_BASE_TOKEN = "${catalina.base}";
+
+
+ // ------------------------------------------------------- Static Variables
+
+
+ /**
+ * Daemon object used by main.
+ */
+ private static Loader daemon = null;
+
+ // one should be enough
+ ModuleListener listener;
+
+
+ // -------------------------------------------------------------- Variables
+
+ protected Repository commonRepository = null;
+ protected Repository catalinaRepository = null;
+ protected Repository sharedRepository = null;
+
+ protected ClassLoader catalinaLoader = null;
+ private String[] args;
+ private Hashtable repositories=new Hashtable();
+ private ClassLoader parentClassLoader;
+
+ private static Properties properties = null;
+
+
+ private static String propFile;
+
+ // -------------------------------------------------------- Private Methods
+
+ /** Set the parent class loader - can be used instead of setParent,
+ * in case this is the top loader and needs to delagate to embedding app.
+ * The common loader will delegate to this loader
+ *
+ * @param myL
+ */
+ public void setParentClassLoader(ClassLoader myL) {
+ this.parentClassLoader=myL;
+ }
+
+
+
+ /** Initialize the loader, creating all repositories.
+ * Will create common, server, shared.
+ *
+ * TODO: create additional repos.
+ *
+ */
+ public void init() {
+ try {
+ commonRepository = initRepository("common", null, parentClassLoader);
+ catalinaRepository = initRepository("server", commonRepository,null);
+ catalinaLoader = catalinaRepository.getClassLoader();
+ sharedRepository = initRepository("shared", commonRepository,null);
+ } catch (Throwable t) {
+ log("Class loader creation threw exception", t);
+ System.exit(1);
+ }
+ }
+
+ /** Create a new repository.
+ * No Module is added ( currently )
+ * TODO: use props to prepopulate, if any is present.
+ *
+ * @param name
+ * @param parent
+ * @return
+ */
+ public Repository createRepository(String name, Repository parent) {
+ Repository lg=new Repository(this);
+
+ lg.setName(name);
+
+ lg.setParent( parent );
+
+ repositories.put(name, lg);
+
+ if( listener != null ) {
+ listener.repositoryAdd(lg);
+ }
+ return lg;
+ }
+
+ public Enumeration getRepositoryNames() {
+ return repositories.keys();
+ }
+
+ /** Create a module using the NAME.loader property to construct the
+ * classpath.
+ *
+ * @param name
+ * @param parent
+ * @return
+ * @throws Exception
+ */
+ private Repository initRepository(String name, Repository parent, ClassLoader pcl)
+ throws Exception
+ {
+ String value = getProperty(name + ".loader");
+
+ Repository lg=createRepository(name, parent );
+ if( pcl != null )
+ lg.setParentClassLoader( pcl );
+ if( DEBUG ) log( "Creating loading group " + name + " - " + value + " " + pcl);
+
+ if ((value == null) || (value.equals("")))
+ return lg;
+
+ ArrayList unpackedList = new ArrayList();
+ ArrayList packedList = new ArrayList();
+ ArrayList urlList = new ArrayList();
+
+ Vector repo=split( value );
+ Enumeration elems=repo.elements();
+ while (elems.hasMoreElements()) {
+ String repository = (String)elems.nextElement();
+
+ // Local repository
+ boolean packed = false;
+
+ if (repository.startsWith(CATALINA_HOME_TOKEN)) {
+ repository = getCatalinaHome()
+ + repository.substring(CATALINA_HOME_TOKEN.length());
+ } else if (repository.startsWith(CATALINA_BASE_TOKEN)) {
+ repository = getCatalinaBase()
+ + repository.substring(CATALINA_BASE_TOKEN.length());
+ }
+
+ // Check for a JAR URL repository
+ try {
+ urlList.add(new URL(repository));
+ continue;
+ } catch (MalformedURLException e) {
+ // Ignore
+ }
+
+ if (repository.endsWith("*.jar")) {
+ packed = true;
+ repository = repository.substring
+ (0, repository.length() - "*.jar".length());
+ }
+ if (packed) {
+ packedList.add(new File(repository));
+ } else {
+ unpackedList.add(new File(repository));
+ }
+ }
+
+ File[] unpacked = (File[]) unpackedList.toArray(new File[0]);
+ File[] packed = (File[]) packedList.toArray(new File[0]);
+ URL[] urls = (URL[]) urlList.toArray(new URL[0]);
+
+ // previously: ClassLoaderFactory.createClassLoader
+ initRepository(lg, unpacked, packed, urls, parent); //new ModuleGroup();
+
+
+ // TODO: JMX registration for the group loader
+ /*
+ // Register the server classloader
+ ObjectName objectName =
+ new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
+ mBeanServer.registerMBean(classLoader, objectName);
+ */
+
+ return lg; // classLoader;
+
+ }
+
+ /** Small hack to allow a loader.properties file to be passed in CLI, to
+ * allow a more convenient method to start with different params from
+ * explorer/kde/etc.
+ *
+ * If the first arg ends with ".loader", it is used as loader.properties
+ * file and removed from args[].
+ */
+ private void processCLI() {
+ if( args!=null && args.length > 0 &&
+ (args[0].toLowerCase().endsWith(".tomcat") ||
+ args[0].toLowerCase().endsWith(".loader") ||
+ args[0].toLowerCase().endsWith("loader.properties") )) {
+ String props=args[0];
+ String args2[]=new String[args.length-1];
+ System.arraycopy(args, 1, args2, 0, args2.length);
+ args=args2;
+ setPropertiesFile(props);
+ } else {
+ loadProperties();
+ }
+ }
+
+ /**
+ * Initialize:
+ * - detect the home/base directories
+ * - init the loaders / modules
+ * - instantiate the "startup" class(es)
+ *
+ */
+ public void main()
+ throws Exception
+ {
+ processCLI();
+
+ // Set Catalina path
+ setCatalinaHome();
+ setCatalinaBase();
+
+ init();
+
+ Thread.currentThread().setContextClassLoader(catalinaLoader);
+
+ securityPreload(catalinaLoader);
+
+ autostart();
+ }
+
+ private void autostart() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
+ // Load our startup classes and call its process() method
+ /* Why multiple classes ?
+ * - maybe you want to start more "servers" ( tomcat ,something else )
+ * - easy hook for other load on startup modules ( like a jmx hook )
+ * - maybe split the loader-specific code from catalina
+ */
+ String startupClasses=getProperty("loader.auto-startup",
+ "org.apache.catalina.startup.CatalinaModuleListener");
+ Vector v=split( startupClasses );
+
+ for( int i=0; i<v.size(); i++ ) {
+ String startupCls=(String)v.elementAt(i);
+
+ if (DEBUG)
+ log("Loading startup class " + startupCls);
+
+ Class startupClass =
+ catalinaLoader.loadClass(startupCls);
+
+ Object startupInstance = startupClass.newInstance();
+
+ if( startupInstance instanceof ModuleListener ) {
+ addModuleListener((ModuleListener)startupInstance);
+
+ // it can get args[] and properties from Loader
+ listener.setLoader(this);
+
+ // all arg processing moved there. Maybe we can make it consistent
+ // for all startup schemes
+ listener.start();
+ } else if ( startupInstance instanceof Runnable ) {
+ ((Runnable)startupInstance).run();
+ } else {
+ Class paramTypes[] = new Class[0];
+ Object paramValues[] = new Object[0];
+ Method method =
+ startupInstance.getClass().getMethod("execute", paramTypes);
+ if( method==null )
+ method = startupInstance.getClass().getMethod("start", paramTypes);
+ if( method!=null )
+ method.invoke(startupInstance, paramValues);
+ }
+
+ }
+ }
+
+ /** Returns one of the repositories.
+ *
+ * Typically at startup we create at least: "common", "shared" and "server", with
+ * same meaning as in tomcat.
+ *
+ * @param name
+ * @return
+ */
+ public Repository getRepository( String name ) {
+ return (Repository)repositories.get(name);
+ }
+
+ private static void securityPreload(ClassLoader loader)
+ throws Exception {
+
+ if( System.getSecurityManager() == null ){
+ return;
+ }
+
+ String value=getProperty("security.preload");
+ Vector repo=split( value );
+ Enumeration elems=repo.elements();
+ while (elems.hasMoreElements()) {
+ String classN = (String)elems.nextElement();
+ try {
+ loader.loadClass( classN);
+ } catch( Throwable t ) {
+ // ignore
+ }
+ }
+ }
+
+
+ // ----------------------------------------------------------- Main Program
+
+ /** Access to the command line arguments, when Loader is used to launc an app.
+ */
+ public String[] getArgs() {
+ return args;
+ }
+
+ /**
+ * Main method.
+ *
+ * @param args Command line arguments to be processed
+ */
+ public static void main(String args[]) {
+
+ try {
+ if (daemon == null) {
+ daemon = new Loader();
+ daemon.args=args;
+
+ try {
+ daemon.main();
+ } catch (Throwable t) {
+ t.printStackTrace();
+ return;
+ }
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ }
+
+ }
+
+
+ /**
+ * Initialize the loader properties explicitely.
+ *
+ * TODO: add setPropertiesRes
+ *
+ * @param props
+ */
+ public void setPropertiesFile(String props) {
+ propFile=props;
+ loadProperties();
+ }
+
+ /**
+ * Return specified property value.
+ */
+ static String getProperty(String name) {
+ if( properties==null ) loadProperties();
+ return properties.getProperty(name);
+ }
+
+
+ /**
+ * Return specified property value.
+ */
+ static String getProperty(String name, String defaultValue) {
+ if( properties==null ) loadProperties();
+ return properties.getProperty(name, defaultValue);
+ }
+
+ /**
+ * Load properties.
+ * Will try:
+ * - "catalina.config" system property ( a URL )
+ * - "catalina.base", "catalina.home", "user.dir" system properties +
+ * "/conf/" "../conf" "/" + "loader.properties" or "catalina.properties"
+ * - /org/apache/catalina/startup/catalina.properties
+ *
+ * Properties will be loaded as system properties.
+ *
+ * loader.properties was added to allow coexistence with bootstrap.jar ( the
+ * current scheme ), since the classpaths are slightly different.
+ */
+ static void loadProperties() {
+ properties = new Properties();
+
+ InputStream is = null;
+ Throwable error = null;
+
+ // TODO: paste the code to do ${} substitution
+ // TODO: add the code to detect where tomcat-properties is loaded from
+ if( propFile != null ) {
+ try {
+ File properties = new File(propFile);
+ is = new FileInputStream(properties);
+ if( is!=null && DEBUG ) {
+ log("Loaded from loader.properties " + properties );
+ }
+ } catch( Throwable t) {
+ System.err.println("Can't find " + propFile);
+ return;
+ }
+ }
+
+ if( is == null ) {
+ try {
+ // "catalina.config" system property
+ String configUrl = System.getProperty("catalina.config");
+ if (configUrl != null) {
+ is = (new URL(configUrl)).openStream();
+ if( is!=null && DEBUG ) {
+ log("Loaded from catalina.config " + configUrl );
+ }
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+
+ if( is == null ) {
+ try {
+ // "loader.config" system property
+ String configUrl = System.getProperty("loader.config");
+ if (configUrl != null) {
+ is = (new URL(configUrl)).openStream();
+ if( is!=null && DEBUG ) {
+ log("Loaded from catalina.config " + configUrl );
+ }
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+
+ if (is == null) {
+ try {
+ setCatalinaBase(); // use system properties, then user.dir
+ File home = new File(getCatalinaBase());
+ File conf = new File(home, "conf");
+
+ // use conf if exists, or the base directory otherwise
+ if( ! conf.exists() ) conf = new File(home, "../conf");
+ if( ! conf.exists() ) conf = home;
+ File propertiesF=null;
+ if( conf.exists() )
+ propertiesF= new File(conf, "loader.properties");
+ if( ! propertiesF.exists() ) {
+ propertiesF= new File( home, "loader.properties");
+ }
+ if( propertiesF.exists() )
+ is = new FileInputStream(propertiesF);
+ if( is!=null && DEBUG ) {
+ log("Loaded from loader.properties " + properties );
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+
+ if (is == null) {
+ try {
+ File home = new File(getCatalinaBase());
+ File conf = new File(home, "conf");
+ File properties = new File(conf, "catalina.properties");
+ is = new FileInputStream(properties);
+ if( is!=null && DEBUG ) {
+ log("Loaded from catalina.properties " + properties );
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+
+ if (is == null) {
+ try {
+ is = Loader.class.getResourceAsStream
+ ("/org/apache/catalina/startup/catalina.properties");
+ if( is!=null && DEBUG ) {
+ log("Loaded from o/a/c/startup/catalina.properties " );
+ }
+
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+
+ if (is == null) {
+ try {
+ is = Loader.class.getResourceAsStream
+ ("loader.properties");
+ if( is!=null && DEBUG ) {
+ log("Loaded from res loader.properties " );
+ }
+ } catch (Throwable t) {
+ // Ignore
+ }
+ }
+
+ if (is != null) {
+ try {
+ properties.load(is);
+ is.close();
+ } catch (Throwable t) {
+ error = t;
+ }
+ }
+
+// if ((is == null) || (error != null)) {
+// // Do something
+// log("Error: no properties found !!!");
+// }
+
+ // Register the _unused_ properties as system properties
+ if( properties != null ) {
+ Enumeration enumeration = properties.propertyNames();
+ while (enumeration.hasMoreElements()) {
+ String name = (String) enumeration.nextElement();
+ String value = properties.getProperty(name);
+ if( "security.preload".equals( name )) continue;
+ if( "package.access".equals( name )) continue;
+ if( "package.definition".equals( name )) continue;
+ if( name.endsWith(".loader")) continue;
+ if( name.startsWith("loader.")) continue;
+ if (value != null) {
+ System.setProperty(name, value);
+ }
+ }
+ }
+
+ }
+
+ static void setCatalinaHome(String s) {
+ System.setProperty( "catalina.home", s );
+ }
+
+ static void setCatalinaBase(String s) {
+ System.setProperty( "catalina.base", s );
+ }
+
+
+ /**
+ * Get the value of the catalina.home environment variable.
+ *
+ * @deprecated
+ */
+ static String getCatalinaHome() {
+ if( properties==null ) loadProperties();
+ return System.getProperty("catalina.home",
+ System.getProperty("user.dir"));
+ }
+
+
+ /**
+ * Get the value of the catalina.base environment variable.
+ *
+ * @deprecated
+ */
+ static String getCatalinaBase() {
+ if( properties==null ) loadProperties();
+ return System.getProperty("catalina.base", getCatalinaHome());
+ }
+
+
+ /**
+ * Set the <code>catalina.base</code> System property to the current
+ * working directory if it has not been set.
+ */
+ static void setCatalinaBase() {
+ if( properties==null ) loadProperties();
+
+ if (System.getProperty("catalina.base") != null)
+ return;
+ if (System.getProperty("catalina.home") != null)
+ System.setProperty("catalina.base",
+ System.getProperty("catalina.home"));
+ else
+ System.setProperty("catalina.base",
+ System.getProperty("user.dir"));
+
+ }
+
+
+ /**
+ * Set the <code>catalina.home</code> System property to the current
+ * working directory if it has not been set.
+ */
+ static void setCatalinaHome() {
+
+ if (System.getProperty("catalina.home") != null)
+ return;
+ File bootstrapJar =
+ new File(System.getProperty("user.dir"), "bootstrap.jar");
+ File tloaderJar =
+ new File(System.getProperty("user.dir"), "tomcat-loader.jar");
+ if (bootstrapJar.exists() || tloaderJar.exists()) {
+ try {
+ System.setProperty
+ ("catalina.home",
+ (new File(System.getProperty("user.dir"), ".."))
+ .getCanonicalPath());
+ } catch (Exception e) {
+ // Ignore
+ System.setProperty("catalina.home",
+ System.getProperty("user.dir"));
+ }
+ } else {
+ System.setProperty("catalina.home",
+ System.getProperty("user.dir"));
+ }
+
+ }
+
+
+
+ /**
+ * Get the module from the classloader. Works only for classloaders created by
+ * this package - or extending ModuleClassLoader.
+ *
+ * This shold be the only public method that allows this - Loader acts as a
+ * guard, only if you have the loader instance you can access the internals.
+ *
+ *
+ * @param cl
+ * @return
+ */
+ public Module getModule(ClassLoader cl ) {
+ if( cl instanceof ModuleClassLoader ) {
+ return ((ModuleClassLoader)cl).getModule();
+ }
+ return null;
+ }
+
+ /**
+ * Create and return a new class loader, based on the configuration
+ * defaults and the specified directory paths:
+ *
+ * @param unpacked Array of pathnames to unpacked directories that should
+ * be added to the repositories of the class loader, or <code>null</code>
+ * for no unpacked directories to be considered
+ * @param packed Array of pathnames to directories containing JAR files
+ * that should be added to the repositories of the class loader,
+ * or <code>null</code> for no directories of JAR files to be considered
+ * @param urls Array of URLs to remote repositories, designing either JAR
+ * resources or uncompressed directories that should be added to
+ * the repositories of the class loader, or <code>null</code> for no
+ * directories of JAR files to be considered
+ * @param parent Parent class loader for the new class loader, or
+ * <code>null</code> for the system class loader.
+ *
+ * @exception Exception if an error occurs constructing the class loader
+ */
+ private void initRepository(Repository lg, File unpacked[],
+ File packed[], URL urls[], Repository parent)
+ throws Exception
+ {
+ StringBuffer sb=new StringBuffer();
+
+ // Construct the "class path" for this class loader
+ ArrayList list = new ArrayList();
+
+ // Add unpacked directories
+ if (unpacked != null) {
+ for (int i = 0; i < unpacked.length; i++) {
+ File file = unpacked[i];
+ if (!file.exists() || !file.canRead()) {
+ if (DEBUG)
+ log(" Not found: "+ file.getAbsolutePath());
+ continue;
+ }
+// String cPath=file.getCanonicalPath();
+// URL url=null;
+//
+// if( cPath.toLowerCase().endsWith(".jar") ||
+// cPath.toLowerCase().endsWith(".zip") ) {
+// url = new URL("file", null, cPath);
+// } else {
+// url = new URL("file", null, cPath + File.separator);
+// }
+ URL url=file.toURL();
+ if (DEBUG)
+ sb.append(" : "+ url);
+ if( ! FLAT ) {
+ addLoader(lg, parent, new URL[] { url });
+ } else {
+ list.add(url);
+ }
+ }
+ }
+
+ // Add packed directory JAR files
+ if (packed != null) {
+ for (int i = 0; i < packed.length; i++) {
+ File directory = packed[i];
+ if (!directory.isDirectory() || !directory.exists() ||
+ !directory.canRead()) {
+ if (DEBUG)
+ log(" Not found: "+ directory.getAbsolutePath());
+ continue;
+ }
+ String filenames[] = directory.list();
+ for (int j = 0; j < filenames.length; j++) {
+ String filename = filenames[j].toLowerCase();
+ if (!filename.endsWith(".jar"))
+ continue;
+ File file = new File(directory, filenames[j]);
+// if (DEBUG)
+// sb.append(" [pak]="+ file.getCanonicalPath());
+// URL url = new URL("file", null,
+// file.getCanonicalPath());
+ URL url=file.toURL();
+ if (DEBUG)
+ sb.append(" pk="+ url);
+
+ if( ! FLAT ) {
+ addLoader(lg, parent, new URL[] { url });
+ } else {
+ list.add(url);
+ }
+ }
+ }
+ }
+
+ // Add URLs
+ if (urls != null) {
+ for (int i = 0; i < urls.length; i++) {
+ if( ! FLAT ) {
+ addLoader(lg, parent, new URL[] { urls[i] });
+ } else {
+ list.add(urls[i]);
+ }
+ if (DEBUG)
+ sb.append(" "+ urls[i]);
+ }
+ }
+
+ // Construct the class loader itself
+
+ // TODO: experiment with loading each jar in a separate loader.
+ if (DEBUG)
+ log("Creating new class loader " + lg.getName() + " " + sb.toString());
+
+
+ URL[] array = (URL[]) list.toArray(new URL[list.size()]);
+ if( array.length > 0 ) {
+ addLoader(lg, parent, array);
+ }
+ }
+
+ /**
+ * @param lg
+ * @param parent
+ * @param list
+ */
+ private void addLoader(Repository lg, Repository parent, URL array[])
+ throws Exception
+ {
+ Module module=new Module();
+
+ module.setParent( parent );
+ module.setClasspath( array );
+
+ lg.addModule(module);
+
+ }
+
+ private static Vector split( String value ) {
+ Vector result=new Vector();
+ StringTokenizer tokenizer = new StringTokenizer(value, ",");
+ while (tokenizer.hasMoreElements()) {
+ String repository = tokenizer.nextToken();
+ repository.trim();
+ if( ! "".equals(repository) )
+ result.addElement(repository);
+ }
+ return result;
+ }
+
+ void notifyModuleStart(Module module) {
+ if(listener!=null) listener.moduleStart(module);
+ }
+
+ void notifyModuleStop(Module module) {
+ if( listener!=null ) listener.moduleStop(module);
+ }
+
+ /** Add a module listener.
+ *
+ * To keep the dependencies minimal, the loader package only implements the
+ * basic class loading mechanism - but any advanced feature ( management,
+ * policy, etc ) should be implemented by a module.
+ *
+ * @param listener
+ */
+ public void addModuleListener(ModuleListener listener) {
+ this.listener=listener;
+ }
+
+ private static void log(String s) {
+ System.err.println("Main: " + s);
+ }
+
+ private static void log( String msg, Throwable t ) {
+ System.err.println("Main: " + msg);
+ t.printStackTrace();
+ }
+
+}
Propchange: tomcat/sandbox/java/org/apache/tomcat/util/loader/Loader.java
------------------------------------------------------------------------------
svn:executable = *
Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/Module.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/Module.java?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/Module.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/Module.java Thu May 18 22:18:18 2006
@@ -0,0 +1,370 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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;
+ }
+
+
+}
Propchange: tomcat/sandbox/java/org/apache/tomcat/util/loader/Module.java
------------------------------------------------------------------------------
svn:executable = *
Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleClassLoader.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleClassLoader.java?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleClassLoader.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleClassLoader.java Thu May 18 22:18:18 2006
@@ -0,0 +1,692 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Enumeration;
+import java.util.Vector;
+
+/*
+ * Initially, I started with WebappClassLoader attempting to clean up and
+ * refactor it. Because of complexity and very weird ( and likely buggy )
+ * behavior, I moved the other way, starting with URLClassLoader and adding
+ * the functionality from WebappClassLoader.
+ *
+ * The current version has a lot of unimplemented WebappClassLoader features and
+ * TODOs - all of them are needed in order to support a single/consistent loader
+ * for webapps and server/modules.
+ *
+ * - all ordering options and tricks
+ * - local loading - in case it can be made more efficient than URLCL
+ * - hook to plugin JNDI finder
+ * - ability to add extra permissions to loaded classes
+ * - ability to use work dir for anti-jar locking and generated classes ( incl getURLs)
+ *
+ *
+ * Things better kept out:
+ * - negative cache - it'll waste space with little benefit, most not found classes
+ * will not be asked multiple times, and most will be in other loaders
+ * - binaryContent cache - it's unlikely same resource will be loaded multiple
+ * times, and some may be large
+ *
+ */
+
+/**
+ * Simple module class loader. Will search the repository if the class is not
+ * found locally.
+ *
+ * TODO: findResources() - merge all responses from the repo and parent.
+ *
+ * Based on StandardClassLoader and WebappClassLoader.
+ *
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ */
+public class ModuleClassLoader
+ extends URLClassLoader
+{
+ // Don't use commons logging or configs to debug loading - logging is dependent
+ // on loaders and drags a lot of stuff in the classpath
+ //
+ private static final boolean DEBUG=false; //LoaderProperties.getProperty("loader.debug.ModuleClassLoader") != null;
+ private static final boolean DEBUGNF=false;//LoaderProperties.getProperty("loader.debug.ModuleClassLoaderNF") != null;
+
+ // ----------------------------------------------------------- Constructors
+
+
+ public ModuleClassLoader(URL repositories[], ClassLoader parent) {
+ super(repositories, parent);
+ if(DEBUG) log( "NEW ModuleClassLoader " + parent + " " + repositories.length);
+ updateStamp();
+ }
+
+
+ public ModuleClassLoader(URL repositories[]) {
+ super(repositories);
+ if(DEBUG) log( "NEW ModuleClassLoader -null-"+ " " + repositories.length);
+ updateStamp();
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+ protected Repository repository;
+
+ /**
+ * Should this class loader delegate to the parent class loader
+ * <strong>before</strong> searching its own repositories (i.e. the
+ * usual Java2 delegation model)? If set to <code>false</code>,
+ * this class loader will search its own repositories first, and
+ * delegate to the parent only if the class or resource is not
+ * found locally.
+ */
+ protected boolean delegate = false;
+
+ /**
+ * Last time a JAR was accessed.
+ * TODO: change to last time the loader was accessed
+ */
+ protected long lastJarAccessed = 0L;
+
+ protected long lastModified=0L;
+
+ /**
+ * Has this component been started?
+ */
+ protected boolean started = false;
+
+ protected Module module;
+
+ // ------------------------------------------------------------- Properties
+
+ /**
+ * Set the "delegate first" flag for this class loader.
+ *
+ * @param delegate The new "delegate first" flag
+ */
+ void setDelegate(boolean delegate) {
+ this.delegate = delegate;
+ }
+
+ void setRepository(Repository lg ) {
+ this.repository=lg;
+ }
+
+ void setModule(Module webappLoader) {
+ this.module=webappLoader;
+ }
+
+ /** Not public - his can only be called from package.
+ * To get the module from a ClassLoader you need access to the Loader
+ * instance.
+ *
+ * @return
+ */
+ Module getModule() {
+ return module;
+ }
+
+ void setWorkDir(File s) {
+ // TODO
+ }
+
+ /**
+ * Add a new repository to the set of places this ClassLoader can look for
+ * classes to be loaded.
+ *
+ * @param repository Name of a source of classes to be loaded, such as a
+ * directory pathname, a JAR file pathname, or a ZIP file pathname
+ *
+ * @exception IllegalArgumentException if the specified repository is
+ * invalid or does not exist
+ */
+ void addRepository(String repository) {
+ // Add this repository to our underlying class loader
+ try {
+ boolean mod=modified();
+ URL url = new URL(repository);
+ super.addURL(url);
+ if( ! mod ) {
+ // don't check if it is modified, so it works
+ updateStamp();
+ }
+ } catch (MalformedURLException e) {
+ IllegalArgumentException iae = new IllegalArgumentException
+ ("Invalid repository: " + repository);
+ iae.initCause(e);
+ //jdkCompat.chainException(iae, e);
+ throw iae;
+ }
+ }
+
+ void updateStamp() {
+ URL cp[]=super.getURLs();
+ if (cp != null ) {
+ for (int i = 0; i <cp.length; i++) {
+ File f=new File(cp[i].getFile());
+ long lm=f.lastModified();
+ if( lm > lastModified ) lastModified=lm;
+ }
+ }
+ }
+
+ private boolean dirCheck(File dir ) {
+ //log("Checking " + dir );
+ File subd[]=dir.listFiles();
+ for( int i=0; i< subd.length; i++ ) {
+ long lm=subd[i].lastModified();
+ if( lm > lastModified ) {
+ log("Modified file: " + dir + " " + subd[i] + " " + lm + " " + lastModified);
+ return true;
+ }
+ if( subd[i].isDirectory() ) {
+ return dirCheck(subd[i]);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Have one or more classes or resources been modified so that a reload
+ * is appropriate?
+ *
+ * Not public - call it via Module
+ */
+ boolean modified() {
+ URL cp[]=super.getURLs();
+ if (cp != null ) {
+ for (int i = 0; i <cp.length; i++) {
+ File f=new File(cp[i].getFile());
+ long lm=f.lastModified();
+ if( lm > lastModified ) {
+ log( "Modified file: " + f + " " + lm + " " + lastModified);
+ return true;
+ }
+ // assume dirs are used only for debug and small
+ if( f.isDirectory() ) {
+ return dirCheck(f);
+ }
+ }
+ }
+
+ if (DEBUG)
+ log("modified() false");
+
+ // TODO - check at least the jars
+ return (false);
+ }
+
+ // ---------------------------------------------------- ClassLoader Methods
+
+
+ /**
+ * Find the specified class in our local repositories, if possible. If
+ * not found, throw <code>ClassNotFoundException</code>.
+ *
+ * @param name Name of the class to be loaded
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class findClass(String name) throws ClassNotFoundException {
+ return findClass2(name, true);
+ }
+
+ public Class findClass2(String name, boolean del2repo) throws ClassNotFoundException {
+ if( del2repo ) {
+ return ((RepositoryClassLoader)repository.getClassLoader()).findClass(name);
+ } // else
+
+ Class clazz = null;
+
+ try {
+ clazz = super.findClass(name);
+ } catch (RuntimeException e) {
+ if (DEBUG)
+ log("findClass() -->RuntimeException " + name, e);
+ throw e;
+ } catch( ClassNotFoundException ex ) {
+ URL cp[]=this.getURLs();
+ if (DEBUGNF)
+ log("findClass() NOTFOUND " + name + " " + (( cp.length > 0 ) ? cp[0].toString() : "") );
+ throw ex;
+ }
+
+ if (clazz == null) { // does it ever happen ?
+ if (DEBUGNF)
+ log("findClass() NOTFOUND throw CNFE " + name);
+ throw new ClassNotFoundException(name);
+ }
+
+ // Return the class we have located
+ if (DEBUG) {
+ if( clazz.getClassLoader() != this )
+ log("findClass() FOUND " + clazz + " Loaded by " + clazz.getClassLoader());
+ else
+ log("findClass() FOUND " + clazz );
+ }
+ return (clazz);
+ }
+
+ /** Same as findClass, but also checks if the class has been previously
+ * loaded.
+ *
+ * In most implementations, findClass() doesn't check with findLoadedClass().
+ * In order to implement repository, we need to ask each loader in the group
+ * to load only from it's local resources - however this will lead to errors
+ * ( duplicated definition ) if findClass() is used.
+ *
+ * @param name
+ * @return
+ * @throws ClassNotFoundException
+ */
+ public Class findLocalClass(String name) throws ClassNotFoundException
+ {
+ Class clazz = findLoadedClass(name);
+ if (clazz != null) {
+ if (DEBUG)
+ log("findLocalClass() - FOUND " + name);
+ return (clazz);
+ }
+
+ return findClass(name);
+ }
+
+
+
+
+ /**
+ * Find the specified resource in our local repository, and return a
+ * <code>URL</code> refering to it, or <code>null</code> if this resource
+ * cannot be found.
+ *
+ * @param name Name of the resource to be found
+ */
+ public URL findResource(final String name) {
+ return findResource2( name, true);
+ }
+
+ public URL findResource2(final String name, boolean del2repo ) {
+ if( del2repo ) {
+ return ((RepositoryClassLoader)repository.getClassLoader()).findResource(name);
+ } // else:
+
+ URL url = null;
+
+ url = super.findResource(name);
+
+ if(url==null) {
+ // try the repository
+ // TODO
+ }
+
+ if (url==null && DEBUG) {
+ if (DEBUGNF) log("findResource() NOTFOUND " + name );
+ return null;
+ }
+
+ if (DEBUG) log("findResource() found " + name + " " + url );
+ return (url);
+ }
+
+
+ /**
+ * Return an enumeration of <code>URLs</code> representing all of the
+ * resources with the given name. If no resources with this name are
+ * found, return an empty enumeration.
+ *
+ * @param name Name of the resources to be found
+ *
+ * @exception IOException if an input/output error occurs
+ */
+ public Enumeration findResources(String name) throws IOException {
+ return findResources2(name, true);
+ }
+
+ Enumeration findResources2(String name, boolean del2repo) throws IOException {
+ if( del2repo ) {
+ return ((RepositoryClassLoader)repository.getClassLoader()).findResources(name);
+ } else {
+ return super.findResources(name);
+ }
+ }
+
+ // Next methods implement the search alghoritm - parent, repo, delegation, etc
+
+ /** getResource() - modified to implement the search alghoritm
+ *
+ */
+ public URL getResource(String name) {
+ return getResource2( name, null, true);
+ }
+
+ /** getResource() - same thing, but don't delegate to repo if called
+ * from repo
+ *
+ */
+ URL getResource2(String name, ClassLoader originator, boolean delegate2repo ) {
+
+ URL url = null;
+
+ // (1) Delegate to parent if requested
+ if (delegate) {
+ url=getResourceParentDelegate(name);
+ if(url!=null ) return url;
+ }
+
+ // (2) Search local repositories
+ url = findResource(name);
+ if (url != null) {
+ // TODO: antijar locking - WebappClassLoader is making a copy ( is it ??)
+ if (DEBUG)
+ log("getResource() found locally " + delegate + " " + name + " " + url);
+ return (url);
+ }
+
+ // Finally, try the group loaders ( via super() in StandardClassLoader ).
+ // not found using normal loading mechanism. load from one of the classes in the group
+ if( delegate2repo && repository!=null ) {
+ url=repository.findResource(this, name);
+ if(url!=null ) {
+ if( DEBUG )
+ log("getResource() FOUND from group " + repository.getName() + " " + name + " " + url);
+ return url;
+ }
+ }
+
+ // (3) Delegate to parent unconditionally if not already attempted
+ if( !delegate ) {
+ url=getResourceParentDelegate(name);
+ if(url!=null ) return url;
+ }
+
+
+ // (4) Resource was not found
+ if (DEBUGNF)
+ log("getResource() NOTFOUND " + delegate + " " + name + " " + url);
+ return (null);
+
+ }
+
+
+ // to avoid duplication - get resource from parent, when delegating
+ private URL getResourceParentDelegate(String name) {
+ URL url=null;
+ ClassLoader loader = getParent();
+
+ if (loader == null) {
+ loader = getSystemClassLoader();
+ if (url != null) {
+ if (DEBUG)
+ log("getResource() found by system " + delegate + " " + name + " " + url);
+ return (url);
+ }
+ } else {
+ url = loader.getResource(name);
+ if (url != null) {
+ if (DEBUG)
+ log("getResource() found by parent " + delegate + " " + name + " " + url);
+ return (url);
+ }
+ }
+ if( DEBUG ) log("getResource not found by parent " + loader);
+
+ return url;
+ }
+
+ /**
+ * Load the class with the specified name, searching using the following
+ * algorithm until it finds and returns the class. If the class cannot
+ * be found, returns <code>ClassNotFoundException</code>.
+ * <ul>
+ * <li>Call <code>findLoadedClass(String)</code> to check if the
+ * class has already been loaded. If it has, the same
+ * <code>Class</code> object is returned.</li>
+ * <li>If the <code>delegate</code> property is set to <code>true</code>,
+ * call the <code>loadClass()</code> method of the parent class
+ * loader, if any.</li>
+ * <li>Call <code>findClass()</code> to find this class in our locally
+ * defined repositories.</li>
+ * <li>Call the <code>loadClass()</code> method of our parent
+ * class loader, if any.</li>
+ * </ul>
+ * If the class was found using the above steps, and the
+ * <code>resolve</code> flag is <code>true</code>, this method will then
+ * call <code>resolveClass(Class)</code> on the resulting Class object.
+ *
+ * @param name Name of the class to be loaded
+ * @param resolve If <code>true</code> then resolve the class
+ *
+ * @exception ClassNotFoundException if the class was not found
+ */
+ public Class loadClass(String name, boolean resolve)
+ throws ClassNotFoundException
+ {
+ return loadClass2( name, resolve, true );
+ }
+
+ public Class loadClass2(String name, boolean resolve, boolean del2repo)
+ throws ClassNotFoundException
+ {
+
+ Class clazz = null;
+
+ // Don't load classes if class loader is stopped
+ if (!started) {
+ log("Not started " + this + " " + module);
+ //throw new ThreadDeath();
+ start();
+ }
+
+ // (0) Check our previously loaded local class cache
+ clazz = findLoadedClass(name);
+ if (clazz != null) {
+ if (DEBUG)
+ log("loadClass() FOUND findLoadedClass " + name + " , " + resolve);
+ if (resolve) resolveClass(clazz);
+ return (clazz);
+ }
+
+ // (0.2) Try loading the class with the system class loader, to prevent
+ // the webapp from overriding J2SE classes
+ try {
+ clazz = getSystemClassLoader().loadClass(name);
+ if (clazz != null) {
+ // enabling this can result in ClassCircularityException
+// if (DEBUG)
+// log("loadClass() FOUND system " + name + " , " + resolve);
+ if (resolve) resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ // Ignore
+ }
+
+ // TODO: delegate based on filter
+ boolean delegateLoad = delegate;// || filter(name);
+
+ // (1) Delegate to our parent if requested
+ if (delegateLoad) {
+
+ ClassLoader loader = getParent();
+ if( loader != null ) {
+ try {
+ clazz = loader.loadClass(name);
+ if (clazz != null) {
+ if (DEBUG)
+ log("loadClass() FOUND by parent " + delegate + " " + name + " , " + resolve);
+ if (resolve)
+ resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+ }
+ }
+
+ // (2) Search local repositories
+ try {
+ clazz = findClass(name);
+ if (clazz != null) {
+ if (DEBUG)
+ log("loadClass - FOUND findClass " + delegate + " " + name + " , " + resolve);
+ if (resolve) resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+
+ // Finally, try the group loaders ( via super() in StandardClassLoader ).
+ // not found using normal loading mechanism. load from one of the classes in the group
+ if( del2repo && repository!=null ) {
+ Class cls=repository.findClass(this, name);
+ if(cls!=null ) {
+ if( DEBUG )
+ log("loadClass(): FOUND from group " + repository.getName() + " " + name);
+ if (resolve) resolveClass(clazz);
+ return cls;
+ }
+ }
+
+ // (3) Delegate to parent unconditionally
+ if (!delegateLoad) {
+ ClassLoader loader = getParent();
+ if( loader != null ) {
+ try {
+ clazz = loader.loadClass(name);
+ if (clazz != null) {
+ if (DEBUG)
+ log("loadClass() FOUND parent " + delegate + " " + name + " , " + resolve);
+ if (resolve) resolveClass(clazz);
+ return (clazz);
+ }
+ } catch (ClassNotFoundException e) {
+ ;
+ }
+ }
+ }
+
+ if( DEBUGNF ) log("loadClass(): NOTFOUND " + name + " xxx " + getParent() + " " + repository.getName() );
+ throw new ClassNotFoundException(name);
+ }
+
+
+ // ------------------------------------------------------ Lifecycle Methods
+
+
+
+ /**
+ * Start the class loader.
+ *
+ * @exception LifecycleException if a lifecycle error occurs
+ */
+ void start() {
+
+ started = true;
+
+ }
+
+ /** Support for "disabled" state.
+ *
+ * @return
+ */
+ boolean isStarted() {
+ return started;
+ }
+
+
+ /**
+ * Stop the class loader.
+ *
+ * @exception LifecycleException if a lifecycle error occurs
+ */
+ void stop() {
+
+ started = false;
+
+ }
+
+
+
+
+ /**
+ * Validate a classname. As per SRV.9.7.2, we must restict loading of
+ * classes from J2SE (java.*) and classes of the servlet API
+ * (javax.servlet.*). That should enhance robustness and prevent a number
+ * of user error (where an older version of servlet.jar would be present
+ * in /WEB-INF/lib).
+ *
+ * @param name class name
+ * @return true if the name is valid
+ */
+ protected boolean validate(String name) {
+
+ if (name == null)
+ return false;
+ if (name.startsWith("java."))
+ return false;
+
+ return true;
+
+ }
+
+
+ // ------------------ Local methods ------------------------
+
+ private void log(String s ) {
+ System.err.println("ModuleClassLoader: " + s);
+ }
+ private void log(String s, Throwable t ) {
+ System.err.println("ModuleClassLoader: " + s);
+ t.printStackTrace();
+ }
+
+ Object debugObj=new Object();
+
+ /**
+ * Render a String representation of this object.
+ */
+ public String toString() {
+
+ StringBuffer sb = new StringBuffer("ModuleCL ");
+ sb.append(debugObj).append(" delegate: ");
+ sb.append(delegate);
+ //sb.append("\r\n");
+ sb.append(" cp: ");
+ URL cp[]=super.getURLs();
+ if (cp != null ) {
+ for (int i = 0; i <cp.length; i++) {
+ sb.append(" ");
+ sb.append(cp[i].getFile());
+ }
+ }
+ if (getParent() != null) {
+ sb.append("\r\n----------> Parent: ");
+ sb.append(getParent().toString());
+ sb.append("\r\n");
+ }
+ return (sb.toString());
+ }
+}
+
Propchange: tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleClassLoader.java
------------------------------------------------------------------------------
svn:executable = *
Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleListener.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleListener.java?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleListener.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/ModuleListener.java Thu May 18 22:18:18 2006
@@ -0,0 +1,105 @@
+/*
+ * Copyright 1999,2004 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * Interface providing notifications on Module events.
+ *
+ * @author Costin Manolache
+ */
+public interface ModuleListener {
+
+ /** Called when a module group is created. This is only called when a new group
+ * is added to a running engine - we may cache a the list of groups and reuse
+ * it on restarts.
+ *
+ * @param manager
+ */
+ public void repositoryAdd( Repository manager );
+
+ /** Notification that a module has been added. You can get the group
+ * with getGroup().
+ *
+ * Adding a module doesn't imply that the module is started or the class loader
+ * created - this happens only on start() ( TODO: or when a class is accessed ? ).
+ *
+ * This callback is only called for new modules, deployed while the engine is
+ * running, or in some cases when the module engine is reseting the cache. For
+ * old modules - you need to get a list from the ModuleGroup.
+ *
+ *
+ * @param module
+ */
+ public void moduleAdd( Module module );
+
+ /** Notification that a module has been removed.
+ *
+ * @param module
+ */
+ public void moduleRemove( Module module );
+
+ /** Module reload - whenever reload happens, a reload notification will be generated.
+ * Sometimes a remove/add will do the same.
+ *
+ * @param module
+ */
+ public void moduleReload( Module module );
+
+ /** Called when a module is started.
+ *
+ * This is called after the class loader is created, to allow listeners to use classes
+ * from the module to initialize.
+ *
+ * I think it would be good to have the module 'started' on first class loaded
+ * and 'stopped' explicitely.
+ *
+ * @param module
+ */
+ public void moduleStart(Module module);
+
+ /**
+ * Called when a module is stopped. Stoping a module will stop the class
+ * loader and remove all references to it. When a module is stopped, all attempts
+ * to load classes will result in exceptions.
+ *
+ * The callback is called before the class loader is stopped - this allows listeners
+ * to use classes from the module to deinitialize.
+ *
+ * @param module
+ */
+ public void moduleStop(Module module);
+
+ /** Pass a reference to the loader.
+ *
+ * This is the only supported way to get it - no static methods are
+ * provided. From loader you can control all repositories and modules.
+ *
+ * Note that ModuleClassLoader does not provide a way to retrieve the Module -
+ * you need to have a reference to the Loader to get the Module for a
+ * ClassLoader.
+ * @param main
+ */
+ public void setLoader(Loader main);
+
+ /** Start the listener.
+ * TODO: this is only used by Loader to pass control to the listener -
+ * instead of introspection for main()
+ */
+ public void start();
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org