I'm still not sure what this is supposed to do, that can't be done much easier using the standard J2EE-style ClassLoaders that Tomcat 3.3 and higher provide.
In any case, your life will be made much easier if you use: Thread.currentThread().getContextClassLoader() as the parent of your CL (assuming that your code is being called from a Servlet). In Tomcat 3.3 and higher, this is always set to be the Web-app ClassLoader while a Servlet is executing. It should make a lot of the weird errors go away, since you will be using the same ClassLoader as Tomcat to load stuff like HttpServlet. "Kurt Heston" <[EMAIL PROTECTED]> wrote in message [EMAIL PROTECTED]">news:[EMAIL PROTECTED]... > Have a look. Let me know what you think. > --------------------------------------------------- > > import java.io.*; > import java.lang.reflect.Method; > import java.net.*; > import java.util.*; > > import javax.servlet.http.*; > import javax.servlet.*; > > public class ServletCaller > { > public static void callServlet( > String servletName, > ServletConfig config, > HttpServletRequest req, > HttpServletResponse resp) > throws Exception > { > Class[] doGetArgTypes = > { HttpServletRequest.class, HttpServletResponse.class }; > Class[] initArgType = { ServletConfig.class }; > Object[] doGetArgs = { req, resp }; > Object[] initArg = { config }; > > ServletClassLoader ldr = new ServletClassLoader(getParentLoader()); > Class clz = ldr.loadClass(servletName, true); > Object servlet = clz.newInstance(); // Blows up here > > Method initMethod = clz.getMethod("init",initArgType); > Method doGetMethod = clz.getMethod("doGet",doGetArgTypes); > initMethod.invoke(servlet, initArg); > doGetMethod.invoke(servlet, doGetArgs); > // RequestDispatcher won't work!!! > // Using a custom HttpResponse object to read servlet output > } > > public static Class getServletClass(String servletName) throws Exception > { > ServletClassLoader ldr = new ServletClassLoader(); > Class clz = ldr.loadClass(servletName); > > return clz; > } > > private static class ServletClassLoader extends ClassLoader > { > > private Hashtable classes = new Hashtable(); > private String root; > > public ServletClassLoader(ClassLoader parent) > { > super(parent); > String rootDir = System.getProperty("SERVLETDIR"); > if (rootDir == null) > throw new IllegalArgumentException("Null root directory"); > root = rootDir; > } > > public ServletClassLoader() > { > super(ClassLoader.getSystemClassLoader()); > String rootDir = System.getProperty("SERVLETDIR"); > if (rootDir == null) > throw new IllegalArgumentException("Null root directory"); > root = rootDir; > } > > protected Class loadClass(String name, boolean resolve) > throws ClassNotFoundException > { > Class clas = null; > System.out.println("\nAttempting to load class: " + name); > > clas = findClass(name); > if (clas != null) { > if (resolve) > resolveClass(clas); > return clas; > } > > if (clas == null) > { > try { > byte[] buff = loadClassData(name); > clas = defineClass(name, buff, 0, buff.length); > if (resolve) > resolveClass(clas); > > } > catch (IOException e) > { > throw new ClassNotFoundException( > "Error reading file: " + name); > } > } > classes.put(name, clas); > return clas; > } > > private byte[] loadClassData(String filename) throws IOException > { > File f = new File(root, filename + ".class"); > int size = (int) f.length(); > byte buff[] = new byte[size]; > FileInputStream fis = new FileInputStream(f); > DataInputStream dis = new DataInputStream(fis); > dis.readFully(buff); > dis.close(); > > return buff; > } > > protected Class findClass(String name) throws ClassNotFoundException > { > Class clas = (Class) classes.get(name); > > System.out.println("\nClass name: " + name); > > try > { > if (clas == null) > clas = super.findLoadedClass(name); > if (clas == null) > { > ClassLoader parent = getParent(); > clas = parent.loadClass(name); > } > if (clas == null) > clas = super.findSystemClass(name); > } > catch (ClassNotFoundException e) > {} > if (clas != null) > { > if (clas.getClassLoader() != null) > System.out.println( > "\tClassloader: " + clas.getClassLoader().toString()); > > // Store for future use > if (classes.get(name) == null) > classes.put(name, clas); > } > > return clas; > } > > public InputStream getResourceAsStream(String name) > { > return getParent().getResourceAsStream(name); > } > > public URL getResource(String name) > { > return getParent().getResource(name); > } > > public Class loadClass(String name) throws ClassNotFoundException > { > return loadClass(name, false); > } > > public URL findResource(String name) > { > return super.findResource(name); > } > > protected Enumeration findResources(String name) throws IOException > { > return super.findResources(name); > } > > } > > private static ClassLoader getParentLoader() throws Exception > { > // Vector classUrls = new Vector(); > // String tcPath = ""+System.getProperty("tc_path_add"); > // > // // Get tomcat classpath for 3.3 and later > // StringTokenizer tknzr = new StringTokenizer( > // tcPath,File.pathSeparator); > // while( tknzr.hasMoreTokens() ) { > // String tkn = tknzr.nextToken(); > // System.out.println(tkn); > // classUrls.add( new URL("file:"+tkn) ); > // } > // > // tknzr = new StringTokenizer( > // System.getProperty("java.class.path"),File.pathSeparator); > // while( tknzr.hasMoreTokens() ) > // classUrls.add( new URL("file:"+tknzr.nextToken()) ); > // > // URL [] classPathArray = new URL[classUrls.size()]; > // classUrls.copyInto( classPathArray ); > > URL[] classPathArray = new URL[] { > new URL("file://D:/apache/tomcat331/lib/common/servlet.jar"), > new URL("file://D:/apache/tomcat331/lib/common/connector_util.jar"), > new URL("file://D:/apache/tomcat331/lib/common/core_util.jar"), > new URL("file://D:/apache/tomcat331/lib/common/etomcat.jar"), > new URL("file://D:/apache/tomcat331/lib/common/jasper-runtime.jar"), > new URL("file://D:/apache/tomcat331/lib/common/tomcat_core.jar"), > new URL("file://D:/apache/tomcat331/lib/apps/xalan.jar"), > new URL("file://D:/apache/tomcat331/lib/apps/xerces.jar"), > new URL("file://D:/apache/tomcat331/lib/apps/xml4j.jar"), > new URL("file://D:/apache/tomcat331/lib/apps/xsltc.jar"), > new URL("file://D:/apache/tomcat331/lib/stop-tomcat.jar"), > new URL("file://D:/apache/tomcat331/lib/tomcat.jar"), > new URL("file://D:/apache/tomcat331/lib/container/crimson.jar"), > new URL("file://D:/apache/tomcat331/lib/container/facade22.jar"), > new URL("file://D:/apache/tomcat331/lib/container/jasper.jar"), > new URL("file://D:/apache/tomcat331/lib/container/tomcat_modules.jar"), > new URL("file://D:/apache/tomcat331/lib/container/tomcat_util.jar"), > }; > > // URL other_CP = new URL( System.getProperty("java.class.path") ); > ClassLoader loader = new URLClassLoader(classPathArray); > > // String classPathStr = System.getProperty("java.class.path") > // + File.pathSeparatorChar > // + System.getProperty("tc_path_add"); > // System.setProperty("java.class.path", classPathStr); > // System.out.println("\n\njava.class.path= " > // +System.getProperty("java.class.path") + "\n\n"); > > return loader; > } > } > > --------------------------------------------------- > > > -----Original Message----- > From: Jacob Kjome [mailto:[EMAIL PROTECTED]] > Sent: Monday, December 16, 2002 4:55 AM > To: Tomcat Users List > Subject: Re: custom ClassLoader Purgatory in Tomcat 3.3.1 > > > > The classloader behavior for webapps is specified in the servlet spec to be > exactly opposite that of the normal Java2 classloading behavior. So, > classes in the WebappClassLoader will *not* as the parent to load classes > for it unless it can't find the class to load there first. That's one > thing to remember. The other thing is that parent classloaders can't see > their children, but children can see their parents. If you have a class in > a parent classloader which is trying to load classes or other resources in > the child classloader, you will have problems....unless you use the thread > context classloader. If you use Class.forName(String) you are asking for > trouble. The other version of Class.forName() which takes 3 parameters is > your ticket out of this situation since you can pass it the thread context > classloader to load the resource. > > Anyway, I'm pretty sure you will be able to do what you are attempting to > do, but without sample code, no one can help you. > > Jake > > 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 > 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 > 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 > 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 > the > >process can check with it to see whether it's created a certain class > 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 > 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: > 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: > <mailto:[EMAIL PROTECTED]> > >For additional commands, e-mail: > <mailto:[EMAIL PROTECTED]> -- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
