Hello Kurt,
I can see why you might want to do this to create your own sort of
mini-container running outside another running Tomcat's JVM, but It
appears that you are running this within a currently running Tomcat
container. Why do you need to do this? To be honest, I know how to
deal with some common classloading issues, but I don't know so much
about using a custom classloader. This might be a Tomcat-Dev list
question.
Jake
Monday, December 16, 2002, 9:35:07 AM, you wrote:
KH> Have a look. Let me know what you think.
KH> ---------------------------------------------------
KH> import java.io.*;
KH> import java.lang.reflect.Method;
KH> import java.net.*;
KH> import java.util.*;
KH> import javax.servlet.http.*;
KH> import javax.servlet.*;
KH> public class ServletCaller
KH> {
KH> public static void callServlet(
KH> String servletName,
KH> ServletConfig config,
KH> HttpServletRequest req,
KH> HttpServletResponse resp)
KH> throws Exception
KH> {
KH> Class[] doGetArgTypes =
KH> { HttpServletRequest.class, HttpServletResponse.class };
KH> Class[] initArgType = { ServletConfig.class };
KH> Object[] doGetArgs = { req, resp };
KH> Object[] initArg = { config };
KH> ServletClassLoader ldr = new ServletClassLoader(getParentLoader());
KH> Class clz = ldr.loadClass(servletName, true);
KH> Object servlet = clz.newInstance(); // Blows up here
KH> Method initMethod = clz.getMethod("init",initArgType);
KH> Method doGetMethod = clz.getMethod("doGet",doGetArgTypes);
KH> initMethod.invoke(servlet, initArg);
KH> doGetMethod.invoke(servlet, doGetArgs);
KH> // RequestDispatcher won't work!!!
KH> // Using a custom HttpResponse object to read servlet output
KH> }
KH> public static Class getServletClass(String servletName) throws Exception
KH> {
KH> ServletClassLoader ldr = new ServletClassLoader();
KH> Class clz = ldr.loadClass(servletName);
KH> return clz;
KH> }
KH> private static class ServletClassLoader extends ClassLoader
KH> {
KH> private Hashtable classes = new Hashtable();
KH> private String root;
KH> public ServletClassLoader(ClassLoader parent)
KH> {
KH> super(parent);
KH> String rootDir = System.getProperty("SERVLETDIR");
KH> if (rootDir == null)
KH> throw new IllegalArgumentException("Null root
directory");
KH> root = rootDir;
KH> }
KH> public ServletClassLoader()
KH> {
KH> super(ClassLoader.getSystemClassLoader());
KH> String rootDir = System.getProperty("SERVLETDIR");
KH> if (rootDir == null)
KH> throw new IllegalArgumentException("Null root
directory");
KH> root = rootDir;
KH> }
KH> protected Class loadClass(String name, boolean resolve)
KH> throws ClassNotFoundException
KH> {
KH> Class clas = null;
KH> System.out.println("\nAttempting to load class: " + name);
KH> clas = findClass(name);
KH> if (clas != null) {
KH> if (resolve)
KH> resolveClass(clas);
KH> return clas;
KH> }
KH> if (clas == null)
KH> {
KH> try {
KH> byte[] buff = loadClassData(name);
KH> clas = defineClass(name, buff, 0,
buff.length);
KH> if (resolve)
KH> resolveClass(clas);
KH> }
KH> catch (IOException e)
KH> {
KH> throw new ClassNotFoundException(
KH> "Error reading file: " + name);
KH> }
KH> }
KH> classes.put(name, clas);
KH> return clas;
KH> }
KH> private byte[] loadClassData(String filename) throws IOException
KH> {
KH> File f = new File(root, filename + ".class");
KH> int size = (int) f.length();
KH> byte buff[] = new byte[size];
KH> FileInputStream fis = new FileInputStream(f);
KH> DataInputStream dis = new DataInputStream(fis);
KH> dis.readFully(buff);
KH> dis.close();
KH> return buff;
KH> }
KH> protected Class findClass(String name) throws
ClassNotFoundException
KH> {
KH> Class clas = (Class) classes.get(name);
KH> System.out.println("\nClass name: " + name);
KH> try
KH> {
KH> if (clas == null)
KH> clas = super.findLoadedClass(name);
KH> if (clas == null)
KH> {
KH> ClassLoader parent = getParent();
KH> clas = parent.loadClass(name);
KH> }
KH> if (clas == null)
KH> clas = super.findSystemClass(name);
KH> }
KH> catch (ClassNotFoundException e)
KH> {}
KH> if (clas != null)
KH> {
KH> if (clas.getClassLoader() != null)
KH> System.out.println(
KH> "\tClassloader: " +
clas.getClassLoader().toString());
KH> // Store for future use
KH> if (classes.get(name) == null)
KH> classes.put(name, clas);
KH> }
KH> return clas;
KH> }
KH> public InputStream getResourceAsStream(String name)
KH> {
KH> return getParent().getResourceAsStream(name);
KH> }
KH> public URL getResource(String name)
KH> {
KH> return getParent().getResource(name);
KH> }
KH> public Class loadClass(String name) throws ClassNotFoundException
KH> {
KH> return loadClass(name, false);
KH> }
KH> public URL findResource(String name)
KH> {
KH> return super.findResource(name);
KH> }
KH> protected Enumeration findResources(String name) throws IOException
KH> {
KH> return super.findResources(name);
KH> }
KH> }
KH> private static ClassLoader getParentLoader() throws Exception
KH> {
KH> // Vector classUrls = new Vector();
KH> // String tcPath =
""+System.getProperty("tc_path_add");
KH> //
KH> // // Get tomcat classpath for 3.3 and later
KH> // StringTokenizer tknzr = new StringTokenizer(
KH> // tcPath,File.pathSeparator);
KH> // while( tknzr.hasMoreTokens() ) {
KH> // String tkn = tknzr.nextToken();
KH> // System.out.println(tkn);
KH> // classUrls.add( new URL("file:"+tkn) );
KH> // }
KH> //
KH> // tknzr = new StringTokenizer(
KH> //
System.getProperty("java.class.path"),File.pathSeparator);
KH> // while( tknzr.hasMoreTokens() )
KH> // classUrls.add( new
URL("file:"+tknzr.nextToken()) );
KH> //
KH> // URL [] classPathArray = new URL[classUrls.size()];
KH> // classUrls.copyInto( classPathArray );
KH> URL[] classPathArray = new URL[] {
KH> new
URL("file://D:/apache/tomcat331/lib/common/servlet.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/common/connector_util.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/common/core_util.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/common/etomcat.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/common/jasper-runtime.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/common/tomcat_core.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/apps/xalan.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/apps/xerces.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/apps/xml4j.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/apps/xsltc.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/stop-tomcat.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/tomcat.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/container/crimson.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/container/facade22.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/container/jasper.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/container/tomcat_modules.jar"),
KH> new
URL("file://D:/apache/tomcat331/lib/container/tomcat_util.jar"),
KH> };
KH> // URL other_CP = new URL(
System.getProperty("java.class.path") );
KH> ClassLoader loader = new URLClassLoader(classPathArray);
KH> // String classPathStr =
System.getProperty("java.class.path")
KH> // + File.pathSeparatorChar
KH> // + System.getProperty("tc_path_add");
KH> // System.setProperty("java.class.path",
classPathStr);
KH> // System.out.println("\n\njava.class.path= "
KH> // +System.getProperty("java.class.path") +
"\n\n");
KH> return loader;
KH> }
KH> }
KH> ---------------------------------------------------
KH> -----Original Message-----
KH> From: Jacob Kjome [mailto:[EMAIL PROTECTED]]
KH> Sent: Monday, December 16, 2002 4:55 AM
KH> To: Tomcat Users List
KH> Subject: Re: custom ClassLoader Purgatory in Tomcat 3.3.1
KH> The classloader behavior for webapps is specified in the servlet spec to be
KH> exactly opposite that of the normal Java2 classloading behavior. So,
KH> classes in the WebappClassLoader will *not* as the parent to load classes
KH> for it unless it can't find the class to load there first. That's one
KH> thing to remember. The other thing is that parent classloaders can't see
KH> their children, but children can see their parents. If you have a class in
KH> a parent classloader which is trying to load classes or other resources in
KH> the child classloader, you will have problems....unless you use the thread
KH> context classloader. If you use Class.forName(String) you are asking for
KH> trouble. The other version of Class.forName() which takes 3 parameters is
KH> your ticket out of this situation since you can pass it the thread context
KH> classloader to load the resource.
KH> Anyway, I'm pretty sure you will be able to do what you are attempting to
KH> do, but without sample code, no one can help you.
KH> Jake
KH> At 12:59 AM 12/16/2002 -0800, you wrote:
>>Hello,
>>
>>I'm having issues with using a custom classloader in Tomcat 3.3.1. I have
KH> a
>>need to load servlets from a runtime-determined classpath. The solution
>>worked fine in 3.2.x. Here's what I think the problem is (let me know
KH> where
>>my understanding is flawed):
>>
>>I'm pretty confident any custom classloader that tries to load servlets is
>>doomed on newer versions of Tomcat. By this I mean, TC4x and TC5x won't
>>work either as they employ a similar classpath paradigm as that of TC3.3x.
>>
>>It seems that the classloader alchemy the Jakarta people are doing to allow
>>web application classpaths to be independent of each other and that used by
>>the core Tomcat components is going to prevent me from instantiating a
>>servlet via a runtime-determined classpath. A JVM process will only allow
KH> a
>>single instance of any class type within its process space. Every JVM
>>process has a SystemClassLoader that manages loading the core java stuff,
>>like the String class. Any other classLoader in the process space that
>>tries to load a String.class object after the SystemClassLoader has done so
>>will throw a NoClassDefFoundException or some other instantiation error.
>>
>>What's nice about the SystemClassLoader is that any other ClassLoader in
KH> the
>>process can check with it to see whether it's created a certain class
KH> before
>>trying to do so, and use the one it has. A ClassLoader can also do this if
>>it is chained with other class loaders. It needs only traverse the chain
>>via the getParent() method and query each for the class in question. The
>>problem with Tomcat creating its own class loaders is that my custom class
>>loader has no way of knowing what classes they've loaded nor can I use any
>>of those instances. So, when I try to create my servlet object, its super
>>class, HttpServlet is also instantiated and pow, the JVM dumps a stack
KH> trace
>>claiming it can't find resources.
>>
>>(sample Stack trace)
>>-----------------------
>>Attempting to load class: java.lang.NoClassDefFoundError
>>
>>Class name: java.lang.NoClassDefFoundError
>>2002-12-15 23:51:07 - Ctx() : Exception in R( + /servlet/MyServlet +
>>null) - java.lang.ExceptionInInitializerError:
>>java.util.MissingResourceException: Can't find bundle for base name
>>javax.servlet.http.LocalStrings, locale en_US
>> at
>>java.util.ResourceBundle.throwMissingResourceException(ResourceBundle.java:
KH> 7
>>07)
>> at java.util.ResourceBundle.getBundleImpl(ResourceBundle.java:678)
>> at java.util.ResourceBundle.getBundle(ResourceBundle.java:541)
>> at javax.servlet.http.HttpServlet.<clinit>(HttpServlet.java)
>>-----------------------
>>
>>I'm guessing this is a nonsense error because the ResourceBundle it's
>>looking for is in the same jar that HttpServlet is in. So, it's definitely
>>on the classpath.
>>
>>Anyway, what else might I try to remedy this?
>>
>>Thanks.
>>
>>
>>--
>>To unsubscribe, e-mail:
KH> <mailto:[EMAIL PROTECTED]>
>>For additional commands, e-mail:
KH> <mailto:[EMAIL PROTECTED]>
KH> --
KH> To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
KH> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
--
Best regards,
Jacob mailto:[EMAIL PROTECTED]
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>