To see it work with JBoss,
1- cut and paste the code below under
org.jboss.util.DependencyClassLoader.java
2- please replace in container Factory ...
(around line 319)
// create the _real_ classloader for this app
//cl = new URLClassLoader(urls, Thread.currentThread().getContextClassLoader
());
cl = new
DependencyClassLoader(url.toString(),urls,Thread.currentThread().getContextC
lassLoader ());
3- At's it!!! no XML nothing...
And see the CL caching statically and in instance variables. You will get
the feel for it from the messages.
And I THINK THIS SOLVES MOST OUR PROBLEMS. (we need to set these beasties as
parent in tomcat/jetty as well)
See below for the way it works. (below the code)
<code>
/*
* JBoss, the OpenSource EJB server
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.util;
import java.util.HashMap;
import java.util.Map;
import java.net.URLClassLoader;
import java.net.URL;
/**
* The Dependency Class Loader holds references on behalf of other Class
Loaders
*
* @author <a href="[EMAIL PROTECTED]"> Marc Fleury</a>
* @version
*/
public class DependencyClassLoader extends URLClassLoader
{
// A DependencyClassLoader operates within one application
private String application;
// A Map with all the dependencies of the underlying bean
private Map beanDependsOn = new HashMap();
// A Map with all the class in the DCL, this should be
// 1- a service, centralized
// 2- should be scoped by application (eventually)
// a static map map will do nicely for now (mf)
private static Map classes = new HashMap();
/**
* The DCL operates within the realm of an application, we pass the
application
* name in the constructor
*
* @param String application
* @param ClassLoader parent
*/
public DependencyClassLoader(String application, URL[] urls,
ClassLoader parent)
{
super(urls, parent);
this.application = application;
}
/**
* loadClass
*
* We intercept the load class to know exactly the dependencies
* of the underlying bean
*/
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
if (! name.startsWith("java.") &&! name.startsWith("javax.")) {
System.out.println("##MF## [Load] ("+this.hashCode()+")
loading class
"+name);
}
// Find locals
if (beanDependsOn.containsKey(name)) {
System.out.println("##MF## [Load] ("+this.hashCode()+")
returning class
from local instance maps "+name);
//Return the class in the local DCL map
return (Class) beanDependsOn.get(name);
}
//If not local then pass to super class
//Superclass will check system and call findClass if not found
Class loadedClass = super.loadClass(name, resolve);
if (! name.startsWith("java.") &&
! name.startsWith("javax.")) {
System.out.println("##MF## [Load] Caching locally
"+loadedClass.getName());
// Keep it in local maps
beanDependsOn.put(name, loadedClass);
}
return loadedClass;
}
/**
* findClass
*
* Find the class in the static maps (should move to a service)
*
* Also there is no need to ping dependent CL, it is all done with a static
map
* A Map with all the class in the DCL, this should be
* 1- a service, centralized
* 2- should be scoped by application (eventually)
* a static map map will do nicely for now (mf)
* private static Map classes = new HashMap();
*
*/
protected Class findClass(String name)
throws ClassNotFoundException
{
System.out.println("##MF## [Find] ("+this.hashCode()+") finding class
"+name);
Class foundClass;
// Do I have it in the static maps?
if (classes.containsKey(name)) {
System.out.println("##MF## [Find] ("+this.hashCode()+") found
in static
maps "+name);
// Ok that is our man
foundClass = (Class) classes.get(name);
}
else {
System.out.println("##MF## [Find] Going for super");
// if you don't go get it with the normal path (URL CL will
find it?)
foundClass = super.findClass(name);
// Keep it in static map
classes.put(name, foundClass);
System.out.println("##MF## [Find] ("+this.hashCode()+") found
it with
local URL and cached it "+name);
}
//we are done
return foundClass;
}
}
</code>
Ok the way it works is:
We intercept the load methods just because it enables us to build a
"dependency list" (not important for now but will be the key to management
in the future).
The real meat in this one is the fact that we intercept the findClass call
and delegate by super (URL find as in the normal JBoss) and then we keep the
reference in a static map the point of this being that now others can have
access to this uniquely defined class in the static.
The problem with this construction is that we keep the state in a static map
and therefore we need to clean that map when we delete one of the classes
(otherwise we are returning a false class). This is where "application
management" will come in the scope and also where the dependency list says
"if I have the class in my list then please cycle me" by the same token "if
I am cycled (just in the finalizer could work... don't know) then clean the
maps for the ones I found"...
So eventually we would need to move the list and static map to a service and
let the app manager be a event handler for the class changes inside the VM
so we can actually CYCLE TRANSPARENTLY the whole application but ONLY the
parts that "depend" on the cycled classes.
The indirection and interception of the "dependent" classes is the key.
Ok what else. oh yeah I started with a 2 level DCL structure but since the
map is static and we need to intercept the "ClassNotFound" I opted for a
"extension" that essentially make our level 2 structure a "one object
extended"... so we are down to 1 level (yes rickard we can beat 3 levels :).
The thing I like "philosophically" about it is that it is a purely "local"
construction, and only in the "application manager" that DrJung will write
;-) will we have global logical app knowledge...
oh and yes... I believe we will *not* need anything in XML
:)))
he he I am so fucking smart :)
(that is when you prove me wrong ;-)
marc
________________________________
"Gooooooooooooooooooooooooooool"
--South-American Soccer TV guy--
________________________________