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 [2/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...
Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java Thu May 18 22:18:18 2006
@@ -0,0 +1,480 @@
+/*
+ * 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.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+
+/**
+ * A group of modules and libraries.
+ *
+ * Modules can have one or more jars and class dirs. Classloaders are created
+ * from modules when the module is started are be disposed when the module is stopped.
+ *
+ * The module will delegate to the associated repository in addition to the
+ * normal delegation rules. The repository will search on all sibling modules.
+ * This mechanism is defined in the MLetClassLoader and is also used by JBoss and
+ * few other servers.
+ *
+ * TODO: explain more ( or point to the right jboss/mlet pages )
+ * TODO: explain how this can be used for webapps to support better partitioning
+ *
+ * @author Costin Manolache
+ */
+public class Repository {
+
+ private static final boolean DEBUG=Loader.getProperty("loader.debug.Repository") != null;
+
+ // Allows the (experimental) use of jar indexes
+ // Right now ( for small set of jars, incomplete build ) it's a tiny 3.5 -> 3.4 sec dif.
+ private static final boolean USE_IDX=Loader.getProperty("loader.Repository.noIndex") == null;
+
+ private Vector loaders=new Vector();
+ private String name;
+ private Vector grpModules=new Vector();
+ private transient Loader loader;
+
+ private transient RepositoryClassLoader groupClassLoader;
+ private Hashtable prefixes=new Hashtable();
+
+ // For delegation
+ private ClassLoader parentClassLoader;
+ private Repository parent;
+
+
+ private Repository() {
+ }
+
+ public Repository(Loader loader) {
+ if( loader== null ) throw new NullPointerException();
+ this.loader=loader;
+ }
+
+ public Loader getLoader() {
+ return loader;
+ }
+
+ void addModule( Module mod ) {
+ mod.setRepository( this );
+
+ grpModules.addElement(mod);
+ if( loader.listener!=null ) {
+ loader.listener.moduleAdd(mod);
+ }
+
+ if( parentClassLoader != null )
+ mod.setParentClassLoader( parentClassLoader );
+
+ if(! mod.isStarted()) {
+ mod.start();
+ //log("started " + mod);
+ } else {
+ //log("already started " + mod);
+ }
+
+ try {
+ if( USE_IDX ) {
+ processJarIndex(mod);
+ // TODO: if we are in the initial starting, write cache only once
+ // TODO: write it only if there is a change in the timestamp
+ writeCacheIdx();
+ }
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
+ public void newModule( String path ) {
+ Module m=new Module();
+ m.setPath( path );
+ addModule( m );
+ }
+
+ public Enumeration getModules() {
+ return grpModules.elements();
+ }
+
+ /** Reload any module that is modified
+ */
+ public void checkReload() {
+ try {
+ Enumeration mE=grpModules.elements();
+ while( mE.hasMoreElements() ) {
+ Module m=(Module)mE.nextElement();
+ boolean modif=m.modified();
+ log("Modified " + m + " " + modif);
+
+ if( modif ) {
+ m.stop();
+ m.start();
+ }
+ }
+ } catch( Throwable t ) {
+ t.printStackTrace();
+ }
+ }
+
+ /** Verify if any module is modified. This is a deep search, including dirs.
+ * Expensive operation.
+ *
+ * @return
+ */
+ public boolean isModified() {
+ try {
+ Enumeration mE=grpModules.elements();
+ while( mE.hasMoreElements() ) {
+ Module m=(Module)mE.nextElement();
+ boolean modif=m.modified();
+ log("Modified " + m + " " + modif);
+ if( modif ) return true;
+ }
+ } catch( Throwable t ) {
+ t.printStackTrace();
+ }
+ return false;
+ }
+
+ Repository getParent() {
+ return parent;
+ }
+
+ public String toString() {
+ return "Repository " + name + "(" + getClasspathString() + ")";
+ }
+
+ private String getClasspathString() {
+ StringBuffer sb=new StringBuffer();
+ Enumeration mE=grpModules.elements();
+ while( mE.hasMoreElements() ) {
+ Module m=(Module)mE.nextElement();
+ sb.append( m.getClasspathString() + ":");
+ }
+ return sb.toString();
+ }
+
+ /**
+ *
+ * @param parent The parent group
+ */
+ public void setParent(Repository parent) {
+ this.parent = parent;
+ }
+
+ /** 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
+ *
+ * @param myL
+ */
+ public void setParentClassLoader(ClassLoader myL) {
+ this.parentClassLoader=myL;
+ }
+
+
+ /** Add a class loder to the group.
+ *
+ * If this is a StandardClassLoader instance, it will be able to delegate
+ * to the group.
+ *
+ * If it's a regular ClassLoader - it'll be searched for classes, but
+ * it will not be able to delegate to peers.
+ *
+ * In future we may fine tune this by using manifests.
+ */
+ void addClassLoader(ClassLoader cl ) {
+ if( ( cl instanceof ModuleClassLoader )) {
+ ((ModuleClassLoader)cl).setRepository(this);
+ }
+ loaders.addElement(cl);
+ // log("Adding classloader " + cl);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void removeClassLoader(ClassLoader cl) {
+ int oldSize=loaders.size();
+ loaders.removeElement(cl);
+
+ if(DEBUG) log("removed " + loaders.size() + "/" + oldSize + ": " + cl);
+ // TODO: remove from index
+ }
+
+ /** Return a class loader associated with the group.
+ * This will delegate to all modules in the group, then to parent.
+ *
+ * @return
+ */
+ public ClassLoader getClassLoader() {
+ if( groupClassLoader==null ) {
+
+ ClassLoader pcl=parentClassLoader;
+ if( pcl==null && parent!=null ) {
+ pcl=parent.getClassLoader();
+ }
+ if( pcl==null ) {
+ pcl=Thread.currentThread().getContextClassLoader();
+ }
+
+ if( pcl == null ) {
+ // allow delegation to embedding app
+ groupClassLoader=new RepositoryClassLoader(new URL[0], this);
+ } else {
+ groupClassLoader=new RepositoryClassLoader(new URL[0], pcl, this);
+ }
+ if( DEBUG ) log("---------- Created repository loader " + pcl );
+ }
+ return groupClassLoader;
+ }
+
+ /**
+ * Find a class in the group. It'll iterate over each loader
+ * and try to find the class - using only the method that
+ * search locally or on parent ( i.e. not in group, to avoid
+ * recursivity ).
+ *
+ *
+ * @param classN
+ * @return
+ */
+ Class findClass(ClassLoader caller, String classN ) {
+ Class clazz=null;
+
+ // do we have it in index ?
+ if( USE_IDX ) {
+ int lastIdx=classN.lastIndexOf(".");
+ String prefix=(lastIdx>0) ? classN.substring(0, lastIdx) : classN;
+ Object mO=prefixes.get(prefix.replace('.', '/'));
+ if( mO!=null ) {
+ if( mO instanceof Module ) {
+ Module m=(Module)mO;
+ try {
+ Class c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
+ //log("Prefix: " +prefix + " " + classN + " " + m);
+ return c;
+ } catch (Exception e) {
+ //log("Prefix err: " +prefix + " " + classN + " " + m + " " + e);
+ //return null;
+ }
+ } else {
+ Module mA[]=(Module[])mO;
+ for( int i=0; i<mA.length; i++ ) {
+ Module m=mA[i];
+ try {
+ Class c=((ModuleClassLoader)m.getClassLoader()).findLocalClass(classN);
+ //log("Prefix: " +prefix + " " + classN + " " + m);
+ return c;
+ } catch (Exception e) {
+ //log("Prefix err: " +prefix + " " + classN + " " + m + " " + e);
+ //return null;
+ }
+ }
+ }
+ }
+ }
+
+ // TODO: move the vector to a []
+ for( int i=loaders.size()-1; i>=0; i-- ) {
+
+ // TODO: for regular CL, just use loadClass, they'll not recurse
+ // The behavior for non-SCL or not in the group loader is the same as for parent loader
+ ModuleClassLoader cl=(ModuleClassLoader)loaders.elementAt(i);
+ // TODO: move loaders with index in separate vector
+ //if( cl.getModule().hasIndex ) continue;
+ if( cl== caller ) continue;
+ //if( classN.indexOf("SmtpCoyoteProtocolHandler") > 0 ) {
+ //log("try " + cl.debugObj + " " + name + " " + classN + " " + loaders.size());
+ //}
+ try {
+ if( cl instanceof ModuleClassLoader ) {
+ clazz=((ModuleClassLoader)cl).findLocalClass(classN );
+ } else {
+ clazz=cl.findClass(classN);
+ }
+
+ //System.err.println("GRPLD: " + classN + " from " + info.get(cl));
+ return clazz;
+ } catch (ClassNotFoundException e) {
+ //System.err.println("CNF: " + classN + " " + info.get(cl) );
+ //if( classN.indexOf("smtp") > 0 ) e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param loader
+ * @param name2
+ * @return
+ */
+ URL findResource(ModuleClassLoader caller, String classN) {
+ URL url=null;
+ if( DEBUG ) log("Repository.findResource " + classN + " " + caller );
+ for( int i=loaders.size()-1; i>=0; i-- ) {
+ // TODO: for regular CL, just use loadClass, they'll not recurse
+ // The behavior for non-SCL or not in the group loader is the same as for parent loader
+ ModuleClassLoader cl=(ModuleClassLoader)loaders.elementAt(i);
+ if( cl== caller ) continue;
+ url=((ModuleClassLoader)cl).findResource(classN );
+ if( url!=null )
+ return url;
+ }
+ return null;
+ }
+
+ private void log(String s) {
+ System.err.println("Repository (" + name + "): " + s );
+ }
+
+ /**
+ * @param name2
+ */
+ public void setName(String name2) {
+ this.name=name2;
+ }
+
+ /*
+ * Work in progress:
+ *
+ * -use the INDEX.LIST to get prefixes to avoid linear
+ * search in repositories.
+ *
+ * - serialize the state ( including timestamps ) to improve startup time
+ * ( avoids the need to open all jars - if INDEX.LIST is ok)
+ */
+
+ /**
+ * Read the index. The index contain packages and top level resources
+ *
+ * @param cl
+ * @throws Exception
+ */
+ private void processJarIndex(Module m) throws Exception {
+ ModuleClassLoader cl=(ModuleClassLoader)m.createClassLoader();
+ // only support index for modules with a single jar in CP
+ String cp=m.getClasspathString();
+ if( ! cp.endsWith(".jar")) return;
+ URL urlIdx=cl.findResource("META-INF/INDEX.LIST");
+ if( urlIdx == null ) {
+ log("INDEX.LIST not found, run: jar -i " + m.getClasspathString());
+ return;
+ }
+ try {
+ InputStream is=urlIdx.openStream();
+ if( is==null ) {
+ log("Can't read " + urlIdx + " " + m.getClasspathString());
+ return;
+ }
+ BufferedReader br=new BufferedReader( new InputStreamReader(is) );
+ String line=br.readLine();
+ if( line==null ) return;
+ if( ! line.startsWith( "JarIndex-Version:") ||
+ ! line.endsWith("1.0")) {
+ log("Invalid signature " + line + " " + m.getClasspathString());
+ }
+ br.readLine(); // ""
+
+ while( readSection(br, m) ) {
+ }
+
+ m.hasIndex=true;
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private boolean readSection( BufferedReader br, Module m) throws IOException {
+ String jarName=br.readLine();
+ if( jarName==null ) return false; // done
+ if( "".equals( jarName )) {
+ log("Invalid jarName " + jarName + " " + m.getClasspathString() );
+ return false;
+ }
+ //log("Index " + jarName + " " + m.getClasspathString());
+ String prefix=null;
+ while( ((prefix=br.readLine()) != null ) &&
+ (! "".equals( prefix )) ) {
+ //log("found " + prefix + " " + m);
+ Object o=prefixes.get(prefix);
+ if( o == null ) {
+ prefixes.put(prefix, m);
+ } else {
+ Module mA[]=null;
+ if( o instanceof Module ) {
+ mA=new Module[2];
+ mA[0]=(Module)o;
+ mA[1]=m;
+ } else {
+ Object oldA[]=(Module[])o;
+ mA=new Module[oldA.length + 1];
+ System.arraycopy(oldA, 0, mA, 0, oldA.length);
+ mA[oldA.length]=m;
+ }
+ prefixes.put( prefix, mA);
+ //log("Multiple prefixes: " + prefix + " " + mA);
+
+ }
+ }
+
+ return prefix!=null;
+ }
+
+
+ /** Read loader.REPO.cache from work dir
+ *
+ * This file will hold timestamps for each module/jar and cache the INDEX -
+ * to avoid opening the jars/modules that are not used
+ *
+ * @throws IOException
+ */
+ private void readCachedIdx() throws IOException {
+
+ }
+
+ /** Check the index and verify that:
+ * - all jars are older than timestamp and still exist
+ * - there are no new jars
+ *
+ * @throws IOException
+ */
+ private void checkCacheIdx() throws IOException {
+
+ }
+
+
+ private void writeCacheIdx() throws IOException {
+ // For each module we write the timestamp, filename then the index
+ // The idea is to load this single file to avoid scanning many jars
+
+ // we'll use the cache
+
+
+ }
+
+}
Propchange: tomcat/sandbox/java/org/apache/tomcat/util/loader/Repository.java
------------------------------------------------------------------------------
svn:executable = *
Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/RepositoryClassLoader.java Thu May 18 22:18:18 2006
@@ -0,0 +1,253 @@
+/*
+ * 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;
+
+/**
+ * Class loader associated with a repository ( common, shared, server, etc ).
+ *
+ * This class loader will never load any class by itself ( since it has no repository ),
+ * it will just delegate to modules.
+ *
+ * Refactored as a separate class to make the code cleaner.
+ * Based on catalina loader.
+ *
+ * @author Costin Manolache
+ * @author Remy Maucherat
+ * @author Craig R. McClanahan
+ */
+public class RepositoryClassLoader
+ extends URLClassLoader
+{
+ 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 RepositoryClassLoader(URL repositories[], ClassLoader parent, Repository lg) {
+ super(repositories, parent);
+ this.repository=lg;
+ }
+
+
+ public RepositoryClassLoader(URL repositories[], Repository lg) {
+ super(repositories);
+ this.repository=lg;
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+ private Repository repository;
+
+ // ---------------------------------------------------- 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 {
+
+ Class clazz = null;
+
+ Enumeration modulesE=repository.getModules();
+ while( modulesE.hasMoreElements() ) {
+ try {
+ Module m=(Module)modulesE.nextElement();
+ return ((ModuleClassLoader)m.getClassLoader()).findClass2(name, false);
+ } catch( ClassNotFoundException ex ) {
+ // ignore
+ }
+ }
+ throw new ClassNotFoundException( name );
+
+ }
+
+ /** 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
+ {
+ Enumeration modulesE=repository.getModules();
+ while( modulesE.hasMoreElements() ) {
+ try {
+ Module m=(Module)modulesE.nextElement();
+ return ((ModuleClassLoader)m.getClassLoader()).findLocalClass(name);
+ } catch( ClassNotFoundException ex ) {
+ // ignore
+ }
+ }
+ throw new ClassNotFoundException( 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) {
+ URL url = null;
+ Enumeration modulesE=repository.getModules();
+ while( modulesE.hasMoreElements() ) {
+ Module m=(Module)modulesE.nextElement();
+ url=((ModuleClassLoader)m.getClassLoader()).findResource2(name, false);
+ if( url!= null ) {
+ return url;
+ }
+ }
+
+ if (url==null && DEBUG) {
+ if (DEBUGNF) log("findResource() NOTFOUND " + name );
+ }
+
+ return null;
+ }
+
+
+ /**
+ * 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 {
+ Vector result=new Vector();
+
+ Enumeration modulesE=repository.getModules();
+ while( modulesE.hasMoreElements() ) {
+ Module m=(Module)modulesE.nextElement();
+ Enumeration myRes=((ModuleClassLoader)m.getClassLoader()).findResources2(name,false);
+ if( myRes!=null ) {
+ while( myRes.hasMoreElements() ) {
+ result.addElement(myRes.nextElement());
+ }
+ }
+ }
+
+ return result.elements();
+
+ }
+
+ // Next methods implement the search alghoritm - parent, repo, delegation, etc
+
+ /** getResource() - modified to implement the search alghoritm
+ *
+ */
+ public URL getResource(String name) {
+ URL url = null;
+ Enumeration modulesE=repository.getModules();
+ while( modulesE.hasMoreElements() ) {
+ Module m=(Module)modulesE.nextElement();
+ url=((ModuleClassLoader)m.getClassLoader()).getResource2(name, null, false);
+ if( url!= null ) {
+ return url;
+ }
+ }
+
+ if (url==null && DEBUG) {
+ if (DEBUGNF) log("findResource() NOTFOUND " + name );
+ }
+
+ return null;
+ }
+
+ /**
+ * 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
+ {
+
+ Class clazz = null;
+ Enumeration modulesE=repository.getModules();
+ while( modulesE.hasMoreElements() ) {
+ try {
+ Module m=(Module)modulesE.nextElement();
+ return ((ModuleClassLoader)m.getClassLoader()).loadClass2(name, resolve, false);
+ } catch( ClassNotFoundException ex ) {
+ // ignore
+ }
+ }
+ throw new ClassNotFoundException( name );
+
+ }
+
+
+ // ------------------ Local methods ------------------------
+
+ private void log(String s ) {
+ System.err.println("RepositoryClassLoader: " + s);
+ }
+ private void log(String s, Throwable t ) {
+ System.err.println("RepositoryClassLoader: " + s);
+ t.printStackTrace();
+ }
+
+}
+
Added: tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html
URL: http://svn.apache.org/viewvc/tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html?rev=407715&view=auto
==============================================================================
--- tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html (added)
+++ tomcat/sandbox/java/org/apache/tomcat/util/loader/package.html Thu May 18 22:18:18 2006
@@ -0,0 +1,32 @@
+<html>
+<body>
+
+The goal of this package is to provide class loading functionality, similar in behavior with Jboss and MLET loaders. There
+is no specific policy, just a mechanism - how it is used depends on the application. It is based on the tomcat5.x class
+loader, with additional support for the 'repository' delegation.
+
+The main class is Loader - it controls a hierarchy of Repositories, each consisting of one or more Modules. Each Module corresponds to one jar file
+or directory - and will have a ModuleClassLoader that answers only for that file. The Repository is associated with a ModuleClassLoader that delegates to
+each Module. It is possible to add/remove/replace Modules at runtime - just like in JMX and JBoss. In normal tomcat, only webapps can be reloaded - this also allow connectors, valves, and any internal server jar to be reloaded.
+
+The package only deals with class loading, with minimal the dependencies. Currently there is no dependency except bare JDK1.3.
+
+The modules and loaders can be registered with JMX by a module using the ModuleListener, after jmx class loader is created. Note that JMX is not a dependency and doesn't have to be in the classpath - it can be loaded in a Repository, and then something like Modeler will do the mapping.
+
+Configuration uses a simple properties file describing the classpaths and the classes to launch - i.e. all a class loader needs to know, and similar with the old catalina.properties.
+
+To implement a good module system on top of this we need lifecycle ( already present in tomcat ) and discipline in making sure there are no stale references to objects in a module after its death.
+
+An OSGI-like system may seem to deal with the second problem - but it doesn't solve anything, it just makes
+the references more visible and requires major changes in how you code, as well as rewriting of most apis and implementations - and in the end it still
+doesn't solve the problem. JBoss and JMX are actually on the right track in this, as oposed to OSGI.
+
+The loader is also trying to stick to the minimal classloading-related functionality - unlike OSGI wich is reinventing all weels. I started working on the loader after trying to see how OSGI would fit, and realizing that it is a wrong design.
+
+
+<h2>Using loader for launching</h2>
+
+Loader has a main(), and will look up the loader.properties file, create the class loaders, and then launch any 'auto-startup' classes. The must important part of launching an app is setting the classpath, and using Loader allows the app to use more advanced features than using simple CLASSPATH.
+
+</body>
+</html>
\ 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