You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Essl Christian <ju...@esslchristian.de> on 2003/09/10 15:13:19 UTC

[HiveMind] Having problem with tomcat.

Tomcat throws an Exception when I try to get during Servlet init a simple 
Service implemented in the web-app.

I have written a simple web-app, which consits of a TestServlet that loads 
in the init a simple TestService:

	public void init(ServletConfig arg0) throws ServletException
	{
		super.init(arg0);

		ClassResolver resolver = new DefaultClassResolver();
		//alternatively
		//ClassResolver resolver = new DefaultClassResolver(this.getClass() 
.getClassLoader());
		RegistryBuilder builder = new RegistryBuilder();
		builder.processModules(resolver);
		Registry registry = builder.constructRegistry(Locale.getDefault());
		service = (TestService) registry.getService("org.test.TestService", 
TestService.class);
	}

The TestService has just one method public String getTestString() and the 
implementation just returns a static
String. The Web-app is build with maven war.

The servlet, the ServiceInterface (TestService) and the 
ServiceImplementation (TestServiceImpl) are are all in
/WEB-INF/classes. (Alternatively I have also jared them up and put them in 
the lib dir).

The hivemind.jar and all the runtime dependencies except of ant, xerces 
(which I see are only used for the ant tasks) and oro, saxon and log4j 
(which I read are only used for testing) are in the WEB-INF/lib dir.

Now when the servlet is initialized throgh Tomcat (both 4.0.2 and 4.1.27) 
tomcat shows the following Exception:

javax.servlet.ServletException: Servlet.init() for servlet test threw 
exception
..... (only catalina trace)

Root-Cause:
java.lang.NoClassDefFoundError: org/test/TestService
at java.lang.ClassLoader.defineClass0(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:502)
at java.lang.ClassLoader.defineClass(ClassLoader.java:431)
at javassist.ClassPool$LocalClassLoader.loadClass(ClassPool.java:365)
at javassist.ClassPool.writeAsClass(ClassPool.java:427)
at 
org.apache.commons.hivemind.service.impl.ClassFabImpl.createClass(ClassFabImpl.java:217)
at 
org.apache.commons.hivemind.impl.DeferredServiceExtensionPointImpl.createDeferredProxyClass(DeferredServiceExtensionPointImpl.java:190)
at 
org.apache.commons.hivemind.impl.DeferredServiceExtensionPointImpl.createServiceProxyClass(DeferredServiceExtensionPointImpl.java:146)
at 
org.apache.commons.hivemind.impl.DeferredServiceExtensionPointImpl.getServiceProxy(DeferredServiceExtensionPointImpl.java:130)
at 
org.apache.commons.hivemind.impl.DeferredServiceExtensionPointImpl.getService(DeferredServiceExtensionPointImpl.java:117)
at 
org.apache.commons.hivemind.impl.ServiceExtensionPointImpl.getService(ServiceExtensionPointImpl.java:317)
at 
org.apache.commons.hivemind.impl.ModuleImpl.getService(ModuleImpl.java:158)
at 
org.apache.commons.hivemind.impl.RegistryImpl.getService(RegistryImpl.java:125)
at org.test.TestServlet.init(TestServlet.java:59)
(... only catalina trace)

To run the Servlet I've used the lates CVS build with maven.

Originally I encountered the same problem in my Web-App. However the 
problem does not occur when I use jetty in my
eclipse-project and run jetty (directly) within the same project as the 
web-app.

A similar problem also occured when maven did the unit-tests on my project. 
In the unit tests everything (ServletContext, ServletRequest etc) where 
Mocks. Again the problem did not occur when I did the unit tests
in Eclipse.

This is obviously a ClassLoader thing. However I don't know do I have to 
change something in the init code or is there a bug in HiveMind or 
JavaAssist?




RE: [HiveMind] Having problem with tomcat.

Posted by "Howard M. Lewis Ship" <hl...@comcast.net>.
Obviously a class loader issue.

The ClassResolver you create (either way) should have visibility to the org.test.TestService
interface class.

Where was the HiveMind jar?  In WEB-INF/lib or elsewhere?  This could be a fault in HiveMind.  I'll
take a peek at the ClassFactory code.

--
Howard M. Lewis Ship
Creator, Tapestry: Java Web Components
http://jakarta.apache.org/tapestry
http://jakarta.apache.org/commons/sandbox/hivemind/
http://javatapestry.blogspot.com

> -----Original Message-----
> From: Essl Christian [mailto:jucas@esslchristian.de] 
> Sent: Wednesday, September 10, 2003 9:13 AM
> To: commons-dev@jakarta.apache.org
> Subject: [HiveMind] Having problem with tomcat.
> 
> 
> Tomcat throws an Exception when I try to get during Servlet 
> init a simple 
> Service implemented in the web-app.
> 
> I have written a simple web-app, which consits of a 
> TestServlet that loads 
> in the init a simple TestService:
> 
> 	public void init(ServletConfig arg0) throws ServletException
> 	{
> 		super.init(arg0);
> 
> 		ClassResolver resolver = new DefaultClassResolver();
> 		//alternatively
> 		//ClassResolver resolver = new 
> DefaultClassResolver(this.getClass() 
> .getClassLoader());
> 		RegistryBuilder builder = new RegistryBuilder();
> 		builder.processModules(resolver);
> 		Registry registry = 
> builder.constructRegistry(Locale.getDefault());
> 		service = (TestService) 
> registry.getService("org.test.TestService", 
> TestService.class);
> 	}
> 
> The TestService has just one method public String 
> getTestString() and the 
> implementation just returns a static
> String. The Web-app is build with maven war.
> 
> The servlet, the ServiceInterface (TestService) and the 
> ServiceImplementation (TestServiceImpl) are are all in 
> /WEB-INF/classes. (Alternatively I have also jared them up 
> and put them in 
> the lib dir).
> 
> The hivemind.jar and all the runtime dependencies except of 
> ant, xerces 
> (which I see are only used for the ant tasks) and oro, saxon 
> and log4j 
> (which I read are only used for testing) are in the WEB-INF/lib dir.
> 
> Now when the servlet is initialized throgh Tomcat (both 4.0.2 
> and 4.1.27) 
> tomcat shows the following Exception:
> 
> javax.servlet.ServletException: Servlet.init() for servlet test threw 
> exception
> ..... (only catalina trace)
> 
> Root-Cause:
> java.lang.NoClassDefFoundError: org/test/TestService
> at java.lang.ClassLoader.defineClass0(Native Method)
> at java.lang.ClassLoader.defineClass(ClassLoader.java:502)
> at java.lang.ClassLoader.defineClass(ClassLoader.java:431)
> at javassist.ClassPool$LocalClassLoader.loadClass(ClassPool.java:365)
> at javassist.ClassPool.writeAsClass(ClassPool.java:427)
> at 
> org.apache.commons.hivemind.service.impl.ClassFabImpl.createCl
> ass(ClassFabImpl.java:217)
> at 
> org.apache.commons.hivemind.impl.DeferredServiceExtensionPoint
> Impl.createDeferredProxyClass(DeferredServiceExtensionPointImp
> l.java:190)
> at 
> org.apache.commons.hivemind.impl.DeferredServiceExtensionPoint
> Impl.createServiceProxyClass(DeferredServiceExtensionPointImpl
> .java:146)
> at 
> org.apache.commons.hivemind.impl.DeferredServiceExtensionPoint
> Impl.getServiceProxy(DeferredServiceExtensionPointImpl.java:130)
> at 
> org.apache.commons.hivemind.impl.DeferredServiceExtensionPoint
> Impl.getService(DeferredServiceExtensionPointImpl.java:117)
> at 
> org.apache.commons.hivemind.impl.ServiceExtensionPointImpl.get
> Service(ServiceExtensionPointImpl.java:317)
> at 
> org.apache.commons.hivemind.impl.ModuleImpl.getService(ModuleI
> mpl.java:158)
> at 
> org.apache.commons.hivemind.impl.RegistryImpl.getService(Regis
> tryImpl.java:125)
> at org.test.TestServlet.init(TestServlet.java:59)
> (... only catalina trace)
> 
> To run the Servlet I've used the lates CVS build with maven.
> 
> Originally I encountered the same problem in my Web-App. However the 
> problem does not occur when I use jetty in my
> eclipse-project and run jetty (directly) within the same 
> project as the 
> web-app.
> 
> A similar problem also occured when maven did the unit-tests 
> on my project. 
> In the unit tests everything (ServletContext, ServletRequest 
> etc) where 
> Mocks. Again the problem did not occur when I did the unit 
> tests in Eclipse.
> 
> This is obviously a ClassLoader thing. However I don't know 
> do I have to 
> change something in the init code or is there a bug in HiveMind or 
> JavaAssist?
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


Re: [HiveMind] Having problem with tomcat.

Posted by Essl Christian <ju...@esslchristian.de>.
On Wed, 10 Sep 2003 20:01:36 -0400, Howard M. Lewis Ship 
<hl...@comcast.net> wrote:


> Why do you think the committed solution is faster?

Because it just uses one map lookup.

However I was thinking about the multiple (unneeded) ClassLoaders. I have 
my problems with that. A minor problem is that a ClassLoader is quite a big 
class (Maps, Sets etc). My actual problem is that it of course integrates 
tightly with the VM (native-methods) and I don't know how different VMs 
behave when there are many class loaders (Do you have an idea?). Therefore 
I thought its better to prevent it when it is not realy needed.

I also saw that a javassist class-pool is constructed for each module 
(which is I think as well not needed).

Because you don't like the IdentityHashMap with ClassLoaders as keys (Why?) 
. I took a compromise and used as a key in the (normal) _moduleData Map 
just the ClassResolver of the module instead of the id (I think they 
shouldn't be equal if they use different ClassLoaders). This way there is 
only one ClassFactoryClassLoader and one ClassPool per ClassResolver.

The code change is minimal. The hivemind tests work and also the tomcat- 
stuff works.

Here is the diff:

Index: 
src/java/org/apache/commons/hivemind/service/impl/ClassFactoryImpl.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons- 
sandbox/hivemind/src/java/org/apache/commons/hivemind/service/impl/ClassFactoryImpl.java,v
retrieving revision 1.9
diff -u -r1.9 ClassFactoryImpl.java
--- 
src/java/org/apache/commons/hivemind/service/impl/ClassFactoryImpl.java	10 
Sep 2003 20:38:03 -0000	1.9
+++ 
src/java/org/apache/commons/hivemind/service/impl/ClassFactoryImpl.java	11 
Sep 2003 12:20:33 -0000
@@ -67,6 +67,7 @@
 import javassist.NotFoundException;
 import org.apache.commons.hivemind.ApplicationRuntimeException;
+import org.apache.commons.hivemind.ClassResolver;
 import org.apache.commons.hivemind.HiveMind;
 import org.apache.commons.hivemind.Module;
 import org.apache.commons.hivemind.service.ClassFab;
@@ -142,15 +143,15 @@
 private synchronized ModuleData findModuleData(Module module)
     {
-        String id = module.getModuleId();
+        ClassResolver resolver = module.getClassResolver();
 -        ModuleData result = (ModuleData) _moduleDataMap.get(id);
+        ModuleData result = (ModuleData) _moduleDataMap.get(resolver);
 if (result == null)
         {
             ClassPool pool = new ClassPool(null);
 -            ClassLoader moduleLoader = module.getClassResolver() 
.getClassLoader();
+            ClassLoader moduleLoader = resolver.getClassLoader();
             ClassPath path = new LoaderClassPath(moduleLoader);
 pool.appendClassPath(path);
@@ -162,7 +163,7 @@
             result._pool = pool;
             result._loader = loader;
 -            _moduleDataMap.put(id, result);
+            _moduleDataMap.put(resolver, result);
         }
 return result;
 

RE: [HiveMind] Having problem with tomcat.

Posted by "Howard M. Lewis Ship" <hl...@comcast.net>.
Building a community is partly giving credit where credit is due.

Why do you think the committed solution is faster?

--
Howard M. Lewis Ship
Creator, Tapestry: Java Web Components
http://jakarta.apache.org/tapestry
http://jakarta.apache.org/commons/sandbox/hivemind/
http://javatapestry.blogspot.com

> -----Original Message-----
> From: Essl Christian [mailto:jucas@esslchristian.de] 
> Sent: Wednesday, September 10, 2003 6:09 PM
> To: Jakarta Commons Developers List
> Subject: Re: [HiveMind] Having problem with tomcat.
> 
> 
> On Wed, 10 Sep 2003 16:39:40 -0400, Howard M. Lewis Ship 
> <hl...@comcast.net> wrote:
> 
> > I just adapted your patch and checked in the result; I made minor 
> > changes
> > (each module will get its
> > own ClassFactoryClassLoader, which is overkill when 
> multiple modules 
> > share the same class loader ...
> > I just wasn't comfortable using IdentityHashMap keyed on 
> ClassLoader).  
> > All my tests pass.  Please
> > retry using your environment, thanks!
> >
> 
> Yes it works in my enviroment. Thank you that you mentioned 
> my name in this 
> cool project. Actually also my maven unit-tests work now (I 
> don't now why 
> the original hivemind tests worked but when hivemind was used 
> in my project 
> my test didn't work with it).
> 
> I also think that your aproach with one ClassLoader per 
> module is better 
> (it's at least faster).
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


Re: [HiveMind] Having problem with tomcat.

Posted by Essl Christian <ju...@esslchristian.de>.
On Wed, 10 Sep 2003 16:39:40 -0400, Howard M. Lewis Ship 
<hl...@comcast.net> wrote:

> I just adapted your patch and checked in the result; I made minor changes 
> (each module will get its
> own ClassFactoryClassLoader, which is overkill when multiple modules 
> share the same class loader ...
> I just wasn't comfortable using IdentityHashMap keyed on ClassLoader).  
> All my tests pass.  Please
> retry using your environment, thanks!
>

Yes it works in my enviroment. Thank you that you mentioned my name in this 
cool project. Actually also my maven unit-tests work now (I don't now why 
the original hivemind tests worked but when hivemind was used in my project 
my test didn't work with it).

I also think that your aproach with one ClassLoader per module is better 
(it's at least faster).



RE: [HiveMind] Having problem with tomcat.

Posted by "Howard M. Lewis Ship" <hl...@comcast.net>.
I just adapted your patch and checked in the result; I made minor changes (each module will get its
own ClassFactoryClassLoader, which is overkill when multiple modules share the same class loader ...
I just wasn't comfortable using IdentityHashMap keyed on ClassLoader).  All my tests pass.  Please
retry using your environment, thanks!

--
Howard M. Lewis Ship
Creator, Tapestry: Java Web Components
http://jakarta.apache.org/tapestry
http://jakarta.apache.org/commons/sandbox/hivemind/
http://javatapestry.blogspot.com

> -----Original Message-----
> From: Essl Christian [mailto:jucas@esslchristian.de] 
> Sent: Wednesday, September 10, 2003 2:22 PM
> To: Jakarta Commons Developers List
> Subject: Re: [HiveMind] Having problem with tomcat.
> 
> 
> On Wed, 10 Sep 2003 11:01:12 -0400, Howard M. Lewis Ship 
> <hl...@comcast.net> wrote:
> 
> > I just checked in a tiny change to ClassFactoryImpl that may (but
> > probably won't) fix your problem.
> > Please give it a try.
> >
> 
> Unfortunately this didn't work either.
> 
> However I found a way. I think the problem is that HiveMind uses 
> ClassPool.writeAsClass() to obtain the Class.
> This inturn uses an internal ClassLoader which is a child of the 
> SystemClassLoader only. The internal classloader
> is needed to load classes on which the new Class depends (in Hivemind 
> typically interfaces). As in any Servelt-Container the 
> ServicesInterfaces 
> are not contained in the SystemClassLoader the Interfaces can 
> not be found.
> 
> Therefore I make a new ClassLoader for each used ClassLoader 
> in the Modules 
> and give this to the ClassFabImpl. The
> ClassFabImpl than creates with this classLoader the class [ 
> _classLoader.loadClass(_ctClass.getName(), 
> _pool.write(_ctClass.getName())) 
> ; ]
> 
> This works fine now.
> 
> The diff is:
> 
> 
> Index: 
> src/java/org/apache/commons/hivemind/service/impl/ClassFabImpl.java
> ===================================================================
> RCS file: /home/cvspublic/jakarta-commons- 
> sandbox/hivemind/src/java/org/apache/commons/hivemind/service/
> impl/ClassFabImpl.java,v
> retrieving revision 1.8
> diff -u -r1.8 ClassFabImpl.java
> --- 
> src/java/org/apache/commons/hivemind/service/impl/ClassFabIm
> pl.java	30 
> Aug 2003 14:29:54 -0000	1.8
> +++ 
> src/java/org/apache/commons/hivemind/service/impl/ClassFabIm
> pl.java	10 
> Sep 2003 18:16:24 -0000
> @@ -86,14 +86,17 @@
>      private ClassFactoryImpl _factory;
>      private CtClass _ctClass;
>      private ClassPool _pool;
> +    //used in create Class
> +    private ClassFactoryImpl.LocalClassLoader _classLoader;
>  private static final boolean WRITE_CLASS = 
> Boolean.getBoolean("hivemind.write-class");
>  -    public ClassFabImpl(ClassFactoryImpl factory, CtClass ctClass)
> +    public ClassFabImpl(ClassFactoryImpl factory, CtClass ctClass, 
> ClassFactoryImpl.LocalClassLoader cL)
>      {
>          _factory = factory;
>          _ctClass = ctClass;
>          _pool = ctClass.getClassPool();
> +        _classLoader = cL;
>      }
>  public void addInterface(Class interfaceClass)
> @@ -213,8 +216,12 @@
>          {
>              if (WRITE_CLASS)
>                  _ctClass.writeFile();
> -
> -            return _pool.writeAsClass(_ctClass.getName());
> +			
> +			//use now our classLoader which is a 
> child of the module ClassLoader
> +			//instead of (implicitly) the 
> ClassPool.LocalClassLoader, (which is 
> always a child of +			//the 
> SystemClassLoader) through _pool.writeAsClass() 
> .
> +            Class ret = _classLoader.loadClass(_ctClass.getName(), 
> _pool.write(_ctClass.getName()));
> +            return ret;
>          }
>          catch (Exception ex)
>          {
> @@ -226,5 +233,6 @@
>                  ex);
>          }
>      }
> -
> +	
> +	
>  }
> Index: 
> src/java/org/apache/commons/hivemind/service/impl/ClassFactory
> Impl.java
> ===================================================================
> RCS file: /home/cvspublic/jakarta-commons- 
> sandbox/hivemind/src/java/org/apache/commons/hivemind/service/
> impl/ClassFactoryImpl.java,v
> retrieving revision 1.8
> diff -u -r1.8 ClassFactoryImpl.java
> --- 
> src/java/org/apache/commons/hivemind/service/impl/ClassFactory
> Impl.java	10 
> Sep 2003 15:00:47 -0000	1.8
> +++ 
> src/java/org/apache/commons/hivemind/service/impl/ClassFactory
> Impl.java	10 
> Sep 2003 18:16:26 -0000
> @@ -58,6 +58,7 @@
>  package org.apache.commons.hivemind.service.impl;
>  import java.util.HashMap;
> +import java.util.IdentityHashMap;
>  import java.util.Map;
>  import javassist.ClassPath;
> @@ -87,6 +88,12 @@
>       * Map of ClassPool, keyed on module id.
>       */
>      private Map _poolMap = new HashMap();
> +    +    /**
> +     * maps ClassLoaders of ClassResolvers (key) to 
> LocalClassLoaders (JRE 
> 1.4)
> +     */
> +    private IdentityHashMap _localClassLoaders = new 
> IdentityHashMap();
> +
>  public ClassFab newClass(String name, Class superClass, 
> Module module)
>      {
> @@ -94,11 +101,13 @@
>  CtClass ctSuperClass = getClass(pool, superClass);
>  +		LocalClassLoader classLoader = 
> findLocalClassLoader(module);
> +		
>          try
>          {
>              CtClass ctNewClass = pool.makeClass(name, ctSuperClass);
>  -            return new ClassFabImpl(this, ctNewClass);
> +            return new ClassFabImpl(this, ctNewClass,classLoader);
>          }
>          catch (Exception ex)
>          {
> @@ -149,5 +158,48 @@
>  return result;
>      }
> +    +	/**
> +	 * finds and creates LocalClassLoader for each 
> ClassLoader used in 
> ClassResolver
> +	 * @param module
> +	 * @return LocalClassLoader
> +	 */
> +	private synchronized LocalClassLoader 
> findLocalClassLoader(Module module)
> +	{
> +		
> +		ClassLoader resCL = 
> module.getClassResolver().getClassLoader();
> +		LocalClassLoader ret = (LocalClassLoader) 
> this._localClassLoaders.get(resCL);
> +		if(ret == null){
> +			ret = new LocalClassLoader(resCL);
> +			this._localClassLoaders.put(resCL,ret);
> +		}
> +		
> +		return ret;
> +	}
> +    +	/**
> +	 * ClassLoader which does not directly go into the 
> SystemClassLoader as 
> the one
> +	 * used by ClassPool internally. Rather it uses to 
> lookup dependend 
> classes the
> +	 * ClassLoader from the ClassResolver. (Only the 
> constructor is changed 
> from
> +	 * ClassPool.LocalClassLoader)
> +	 * +	 * Created 10.09.2003
> +	 * @author chris
> +	 *
> +	 */
> +	static class LocalClassLoader extends ClassLoader {
> +		public LocalClassLoader(ClassLoader parent){
> +			super(parent);
> +		}
> +		
> +		public Class loadClass(String name, byte[] classfile)
> +			throws ClassFormatError
> +		{
> +			Class c = defineClass(name, classfile, 
> 0, classfile.length);
> +			resolveClass(c);
> +			return c;
> +		}
> +	}
> +	
>  }
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 


Re: [HiveMind] Having problem with tomcat.

Posted by Essl Christian <ju...@esslchristian.de>.
On Wed, 10 Sep 2003 11:01:12 -0400, Howard M. Lewis Ship 
<hl...@comcast.net> wrote:

> I just checked in a tiny change to ClassFactoryImpl that may (but 
> probably won't) fix your problem.
> Please give it a try.
>

Unfortunately this didn't work either.

However I found a way. I think the problem is that HiveMind uses 
ClassPool.writeAsClass() to obtain the Class.
This inturn uses an internal ClassLoader which is a child of the 
SystemClassLoader only. The internal classloader
is needed to load classes on which the new Class depends (in Hivemind 
typically interfaces). As in any Servelt-Container the ServicesInterfaces 
are not contained in the SystemClassLoader the Interfaces can not be found.

Therefore I make a new ClassLoader for each used ClassLoader in the Modules 
and give this to the ClassFabImpl. The
ClassFabImpl than creates with this classLoader the class [ 
_classLoader.loadClass(_ctClass.getName(), _pool.write(_ctClass.getName())) 
; ]

This works fine now.

The diff is:


Index: src/java/org/apache/commons/hivemind/service/impl/ClassFabImpl.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons- 
sandbox/hivemind/src/java/org/apache/commons/hivemind/service/impl/ClassFabImpl.java,v
retrieving revision 1.8
diff -u -r1.8 ClassFabImpl.java
--- src/java/org/apache/commons/hivemind/service/impl/ClassFabImpl.java	30 
Aug 2003 14:29:54 -0000	1.8
+++ src/java/org/apache/commons/hivemind/service/impl/ClassFabImpl.java	10 
Sep 2003 18:16:24 -0000
@@ -86,14 +86,17 @@
     private ClassFactoryImpl _factory;
     private CtClass _ctClass;
     private ClassPool _pool;
+    //used in create Class
+    private ClassFactoryImpl.LocalClassLoader _classLoader;
 private static final boolean WRITE_CLASS = 
Boolean.getBoolean("hivemind.write-class");
 -    public ClassFabImpl(ClassFactoryImpl factory, CtClass ctClass)
+    public ClassFabImpl(ClassFactoryImpl factory, CtClass ctClass, 
ClassFactoryImpl.LocalClassLoader cL)
     {
         _factory = factory;
         _ctClass = ctClass;
         _pool = ctClass.getClassPool();
+        _classLoader = cL;
     }
 public void addInterface(Class interfaceClass)
@@ -213,8 +216,12 @@
         {
             if (WRITE_CLASS)
                 _ctClass.writeFile();
-
-            return _pool.writeAsClass(_ctClass.getName());
+			
+			//use now our classLoader which is a child of the module ClassLoader
+			//instead of (implicitly) the ClassPool.LocalClassLoader, (which is 
always a child of +			//the SystemClassLoader) through _pool.writeAsClass() 
.
+            Class ret = _classLoader.loadClass(_ctClass.getName(), 
_pool.write(_ctClass.getName()));
+            return ret;
         }
         catch (Exception ex)
         {
@@ -226,5 +233,6 @@
                 ex);
         }
     }
-
+	
+	
 }
Index: 
src/java/org/apache/commons/hivemind/service/impl/ClassFactoryImpl.java
===================================================================
RCS file: /home/cvspublic/jakarta-commons- 
sandbox/hivemind/src/java/org/apache/commons/hivemind/service/impl/ClassFactoryImpl.java,v
retrieving revision 1.8
diff -u -r1.8 ClassFactoryImpl.java
--- 
src/java/org/apache/commons/hivemind/service/impl/ClassFactoryImpl.java	10 
Sep 2003 15:00:47 -0000	1.8
+++ 
src/java/org/apache/commons/hivemind/service/impl/ClassFactoryImpl.java	10 
Sep 2003 18:16:26 -0000
@@ -58,6 +58,7 @@
 package org.apache.commons.hivemind.service.impl;
 import java.util.HashMap;
+import java.util.IdentityHashMap;
 import java.util.Map;
 import javassist.ClassPath;
@@ -87,6 +88,12 @@
      * Map of ClassPool, keyed on module id.
      */
     private Map _poolMap = new HashMap();
+    +    /**
+     * maps ClassLoaders of ClassResolvers (key) to LocalClassLoaders (JRE 
1.4)
+     */
+    private IdentityHashMap _localClassLoaders = new IdentityHashMap();
+
 public ClassFab newClass(String name, Class superClass, Module module)
     {
@@ -94,11 +101,13 @@
 CtClass ctSuperClass = getClass(pool, superClass);
 +		LocalClassLoader classLoader = findLocalClassLoader(module);
+		
         try
         {
             CtClass ctNewClass = pool.makeClass(name, ctSuperClass);
 -            return new ClassFabImpl(this, ctNewClass);
+            return new ClassFabImpl(this, ctNewClass,classLoader);
         }
         catch (Exception ex)
         {
@@ -149,5 +158,48 @@
 return result;
     }
+    +	/**
+	 * finds and creates LocalClassLoader for each ClassLoader used in 
ClassResolver
+	 * @param module
+	 * @return LocalClassLoader
+	 */
+	private synchronized LocalClassLoader findLocalClassLoader(Module module)
+	{
+		
+		ClassLoader resCL = module.getClassResolver().getClassLoader();
+		LocalClassLoader ret = (LocalClassLoader) 
this._localClassLoaders.get(resCL);
+		if(ret == null){
+			ret = new LocalClassLoader(resCL);
+			this._localClassLoaders.put(resCL,ret);
+		}
+		
+		return ret;
+	}
+    +	/**
+	 * ClassLoader which does not directly go into the SystemClassLoader as 
the one
+	 * used by ClassPool internally. Rather it uses to lookup dependend 
classes the
+	 * ClassLoader from the ClassResolver. (Only the constructor is changed 
from
+	 * ClassPool.LocalClassLoader)
+	 * +	 * Created 10.09.2003
+	 * @author chris
+	 *
+	 */
+	static class LocalClassLoader extends ClassLoader {
+		public LocalClassLoader(ClassLoader parent){
+			super(parent);
+		}
+		
+		public Class loadClass(String name, byte[] classfile)
+			throws ClassFormatError
+		{
+			Class c = defineClass(name, classfile, 0, classfile.length);
+			resolveClass(c);
+			return c;
+		}
+	}
+	
 }



RE: [HiveMind] Having problem with tomcat.

Posted by "Howard M. Lewis Ship" <hl...@comcast.net>.
I just checked in a tiny change to ClassFactoryImpl that may (but probably won't) fix your problem.
Please give it a try.

--
Howard M. Lewis Ship
Creator, Tapestry: Java Web Components
http://jakarta.apache.org/tapestry
http://jakarta.apache.org/commons/sandbox/hivemind/
http://javatapestry.blogspot.com

> -----Original Message-----
> From: Essl Christian [mailto:jucas@esslchristian.de] 
> Sent: Wednesday, September 10, 2003 9:13 AM
> To: commons-dev@jakarta.apache.org
> Subject: [HiveMind] Having problem with tomcat.
> 
> 
> Tomcat throws an Exception when I try to get during Servlet 
> init a simple 
> Service implemented in the web-app.
> 
> I have written a simple web-app, which consits of a 
> TestServlet that loads 
> in the init a simple TestService:
> 
> 	public void init(ServletConfig arg0) throws ServletException
> 	{
> 		super.init(arg0);
> 
> 		ClassResolver resolver = new DefaultClassResolver();
> 		//alternatively
> 		//ClassResolver resolver = new 
> DefaultClassResolver(this.getClass() 
> .getClassLoader());
> 		RegistryBuilder builder = new RegistryBuilder();
> 		builder.processModules(resolver);
> 		Registry registry = 
> builder.constructRegistry(Locale.getDefault());
> 		service = (TestService) 
> registry.getService("org.test.TestService", 
> TestService.class);
> 	}
> 
> The TestService has just one method public String 
> getTestString() and the 
> implementation just returns a static
> String. The Web-app is build with maven war.
> 
> The servlet, the ServiceInterface (TestService) and the 
> ServiceImplementation (TestServiceImpl) are are all in 
> /WEB-INF/classes. (Alternatively I have also jared them up 
> and put them in 
> the lib dir).
> 
> The hivemind.jar and all the runtime dependencies except of 
> ant, xerces 
> (which I see are only used for the ant tasks) and oro, saxon 
> and log4j 
> (which I read are only used for testing) are in the WEB-INF/lib dir.
> 
> Now when the servlet is initialized throgh Tomcat (both 4.0.2 
> and 4.1.27) 
> tomcat shows the following Exception:
> 
> javax.servlet.ServletException: Servlet.init() for servlet test threw 
> exception
> ..... (only catalina trace)
> 
> Root-Cause:
> java.lang.NoClassDefFoundError: org/test/TestService
> at java.lang.ClassLoader.defineClass0(Native Method)
> at java.lang.ClassLoader.defineClass(ClassLoader.java:502)
> at java.lang.ClassLoader.defineClass(ClassLoader.java:431)
> at javassist.ClassPool$LocalClassLoader.loadClass(ClassPool.java:365)
> at javassist.ClassPool.writeAsClass(ClassPool.java:427)
> at 
> org.apache.commons.hivemind.service.impl.ClassFabImpl.createCl
> ass(ClassFabImpl.java:217)
> at 
> org.apache.commons.hivemind.impl.DeferredServiceExtensionPoint
> Impl.createDeferredProxyClass(DeferredServiceExtensionPointImp
> l.java:190)
> at 
> org.apache.commons.hivemind.impl.DeferredServiceExtensionPoint
> Impl.createServiceProxyClass(DeferredServiceExtensionPointImpl
> .java:146)
> at 
> org.apache.commons.hivemind.impl.DeferredServiceExtensionPoint
> Impl.getServiceProxy(DeferredServiceExtensionPointImpl.java:130)
> at 
> org.apache.commons.hivemind.impl.DeferredServiceExtensionPoint
> Impl.getService(DeferredServiceExtensionPointImpl.java:117)
> at 
> org.apache.commons.hivemind.impl.ServiceExtensionPointImpl.get
> Service(ServiceExtensionPointImpl.java:317)
> at 
> org.apache.commons.hivemind.impl.ModuleImpl.getService(ModuleI
> mpl.java:158)
> at 
> org.apache.commons.hivemind.impl.RegistryImpl.getService(Regis
> tryImpl.java:125)
> at org.test.TestServlet.init(TestServlet.java:59)
> (... only catalina trace)
> 
> To run the Servlet I've used the lates CVS build with maven.
> 
> Originally I encountered the same problem in my Web-App. However the 
> problem does not occur when I use jetty in my
> eclipse-project and run jetty (directly) within the same 
> project as the 
> web-app.
> 
> A similar problem also occured when maven did the unit-tests 
> on my project. 
> In the unit tests everything (ServletContext, ServletRequest 
> etc) where 
> Mocks. Again the problem did not occur when I did the unit 
> tests in Eclipse.
> 
> This is obviously a ClassLoader thing. However I don't know 
> do I have to 
> change something in the init code or is there a bug in HiveMind or 
> JavaAssist?
> 
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
>