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
| Method from org.apache.tomcat.util.loader.Repository Detail: |
void addClassLoader(ClassLoader cl) {
if( ( cl instanceof ModuleClassLoader )) {
((ModuleClassLoader)cl).setRepository(this);
}
loaders.addElement(cl);
// log("Adding classloader " + cl);
}
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 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 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();
}
}
Reload any module that is modified |
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;
}
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 ). |
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;
}
|
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;
}
Return a class loader associated with the group.
This will delegate to all modules in the group, then to parent. |
public Loader getLoader() {
return loader;
}
|
public Enumeration getModules() {
return grpModules.elements();
}
|
public String getName() {
return name;
}
|
Repository getParent() {
return parent;
}
|
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;
}
Verify if any module is modified. This is a deep search, including dirs.
Expensive operation. |
public void newModule(String path) {
Module m=new Module();
m.setPath( path );
addModule( m );
}
|
public void removeClassLoader(ClassLoader cl) {
int oldSize=loaders.size();
loaders.removeElement(cl);
if(DEBUG) log("removed " + loaders.size() + "/" + oldSize + ": " + cl);
// TODO: remove from index
}
|
public void setName(String name2) {
this.name=name2;
}
|
public void setParent(Repository parent) {
this.parent = parent;
}
|
public void setParentClassLoader(ClassLoader myL) {
this.parentClassLoader=myL;
}
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 |
public String toString() {
return "Repository " + name + "(" + getClasspathString() + ")";
}
|