[Design of POJO Server] - Re: Classloader problem with NamingRestartUnitTestCase
by adrian@jboss.org
"adrian(a)jboss.org" wrote :
| And the test passes with the following output on redeploy
|
Just for clarification purposes, JBMICROCONT-234 is not required to fix the problem.
The fix is to use the deployment classloader as the initiating classloader.
But I've applied it anyway since it will resolve some other problems.
So a temporary workaround without updating the MC code in trunk would be
to replace the BeanMetaDataDeployer (configured in bootstrap-beans.xml)
with something like:
| package org.jboss.system.deployers;
|
| import org.jboss.beans.metadata.spi.BeanMetaData;
| import org.jboss.deployers.spi.DeploymentException;
| import org.jboss.deployers.structure.spi.DeploymentUnit;
| import org.jboss.deployers.vfs.deployer.kernel.BeanMetaDataDeployer;
| import org.jboss.kernel.Kernel;
|
| /**
| * A version of the POJO deployer that sets the context classloader to the deployment classloader
| *
| * @author <a href="adrian(a)jboss.com">Adrian Brock</a>
| * @version $Revision: 1.1 $
| */
| public class TempBeanMetaDataDeployer extends BeanMetaDataDeployer
| {
| public TempBeanMetaDataDeployer(Kernel kernel)
| {
| super(kernel);
| }
|
| public void deploy(DeploymentUnit unit, BeanMetaData deployment) throws DeploymentException
| {
| ClassLoader old = Thread.currentThread().getContextClassLoader();
| Thread.currentThread().setContextClassLoader(unit.getClassLoader());
| try
| {
| super.deploy(unit, deployment);
| }
| finally
| {
| Thread.currentThread().setContextClassLoader(old);
| }
| }
| }
|
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4126772#4126772
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4126772
18 years, 2 months
[Design of JBoss jBPM] - Re: Potential enhancement to jbpm
by brittm
anonymous wrote : alternatively users should be able to write their own parsers to extract the information from a process archive and put that information somewhere in the process definition.
While cutomizing the core jBPM libraries and data model is always an option for virtually any problem, its never the preferred solution for common problems. --the more frequently users must solve common problems in this way, the more likely they are to look elsewhere or to fork the project.
anonymous wrote : In jPDL 4 i want to add annotations. Basically, annotations are key-value pairs that you can associate to all process elements.
This does allow the user to solve the problem much more easily, and is a big improvement over what we have now. However, it falls short of providing a standard solution to the nearly universal problem of declaring an interface requirement. It's also not an option till version 4. :-)
Allowing the user a way to solve this problem is just a start, but providing a common solution is what is really needed. The user shouldn't have to look at an attribute tag and then invent a way to use it. At least for this particular problem which is such a common requirement, the jpdl should acknowledge the issue and provide the solution. At the same time, the jpdl should only solve it from the process definition side--in a way that does not tie the definition to a display technology.
The basic solution I presented earlier in the thread does all these things. The solution:
1) presents users with a common, defined jpdl solution for associating elements with UI requirements.
2) is not specific to any display technology, whether it be Swing, JSF, or any other tech that comes along.
3) does not require any knowledge of the display technology. So the display technology can be changed on top of existing definitions without impact.
4) can be added to jBPM 3.3 with minimal effort.
5) could likely be used in the jbpm web module to support robust UI versioning with minimal effort.
Items 2 and 3 are true so long as the user uses a reference to a UI requirement, rather than an actual view id; however, there is nothing stopping them from supplying a view id and using it directly if they don't mind tying the definition to their display technology.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4126767#4126767
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4126767
18 years, 2 months
[Design of POJO Server] - Re: Classloader problem with NamingRestartUnitTestCase
by adrian@jboss.org
"bstansberry(a)jboss.com" wrote : Ah, I'd missed your last post when I posted mine. Sounds like you've nailed it.
Actually, I haven't. The hack I mentioned above solves the problem
for ClassLoader.loadClass() but there is some internal caching going on with
Class.forName() where I can't intercept the behaviour fix the problem.
I added some debug to the BeanMetaDataDeployer
| public void deploy(DeploymentUnit unit, BeanMetaData deployment) throws DeploymentException
| {
| try
| {
| String bean = deployment.getBean();
| ClassLoader tcl = Thread.currentThread().getContextClassLoader();
| Class<?> fromClassLoader = tcl.loadClass(bean);
| Class<?> fromClassForName = Class.forName(bean, false, tcl);
| BeanInfo beanInfo = configurator.getBeanInfo(deployment);
| Class<?> fromBeanInfo = beanInfo.getClassInfo().getType();
|
| System.out.println("========> tcl=" + tcl + " fromClassLoader=" + printClass(fromClassLoader) + " fromClassForName=" + printClass(fromClassForName)+ " fromBeanInfo=" + printClass(fromBeanInfo)
|
which produces the following output on a redeploy
| 2008-02-05 21:27:25,189 INFO [STDOUT] ========> tcl=BaseClassLoader@73a5d3{vfsfile:/home/ejort/jboss-head/build/output/jboss-5.0.0.Beta4/server/all/conf/jboss-service
| .xml} fromClassLoader=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@26f7af{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar}
| fromClassForName=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@50567b{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} fro
| mBeanInfo=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@50567b{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar}
| 2008-02-05 21:27:25,191 TRACE [org.jboss.classloader.spi.base.BaseClassLoader] BaseClassLoader@50567b{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-
|
@26f7af is the correct version of the classloader
@50567b is the old (undeployed) version of the classloader
The Class.forName() invocation aboves never hits the classloader
(I've checked this by looking at the TRACE logging)
so it is obviously using some cache inside the JDK.
This problem will obviously be fixed when the TCL and BeanMetaData classloader
is set to the deployment classloader with the new code.
e.g. I can simulate this with
| public void deploy(DeploymentUnit unit, BeanMetaData deployment) throws DeploymentException
| {
| ClassLoader old = Thread.currentThread().getContextClassLoader();
| Thread.currentThread().setContextClassLoader(unit.getClassLoader());
| try
| {
| try
| {
| String bean = deployment.getBean();
| ClassLoader tcl = Thread.currentThread().getContextClassLoader();
| Class<?> fromClassLoader = tcl.loadClass(bean);
| Class<?> fromClassForName = Class.forName(bean, false, tcl);
| BeanInfo beanInfo = configurator.getBeanInfo(deployment);
| Class<?> fromBeanInfo = beanInfo.getClassInfo().getType();
|
| System.out.println("========> tcl=" + tcl + " fromClassLoader=" + printClass(fromClassLoader) + " fromClassForName=" + printClass(fromClassForName)+ " fromBeanInfo=" + printClass(fromBeanInfo));
| }
| catch (Throwable t)
| {
| throw DeploymentException.rethrowAsDeploymentException("Unexpected error", t);
| }
| ...
| }
| finally
| {
| Thread.currentThread().setContextClassLoader(old);
| }
| }
|
And the test passes with the following output on redeploy
| 21:40:29,591 INFO [STDOUT] ========> tcl=BaseClassLoader@f800e1{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} fromClassLoader=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@f800e1{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} fromClassForName=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@f800e1{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} fromBeanInfo=org.jboss.test.naming.restart.RestartNamingService.BaseClassLoader@f800e1{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar}
|
This is because the initiating classloader has changed so it avoids the
Class.forName() caching problem.
But this is still going to be an issue for usage of Class.forName() from
classloaders that don't get redeployed but have initiated classloading from
redeployed classloaders.
This must also have been issue with the old UnifiedClassLoader as well?
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4126757#4126757
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4126757
18 years, 2 months
[Design of POJO Server] - Re: Classloader problem with NamingRestartUnitTestCase
by adrian@jboss.org
"adrian(a)jboss.org" wrote :
| 3) There is some bad caching going on somewhere
| (the BeanInfo/ClassInfo caches are based on classloader so (1) would
| also appear as this problem).
Yep. This is the problem and it's in the JDK.
It's due to my lack of understanding of ClassLoader.findLoadedClass() actually works.
I thought this was just a cache of classes defined by this classloader
but the javadoc says it is something else
anonymous wrote :
| Returns the class with the given binary name if this loader has been recorded by the Java virtual machine as an initiating loader of a class with that binary name. Otherwise null is returned.
|
I think this is actually related to the change we made to use Class.forName()
to resolve the array class name problem in JDK6
Class.forName() does some additional caching inside the JDK.
This is what I'm seeing. The bootstrap classloader
created by conf/jboss-service.xml is remembering that it already the class
even though the classloader it loaded it from is dead:
| 2008-02-05 20:43:25,554 TRACE [org.jboss.classloader.spi.base.BaseClassLoader] BaseClassLoader@8be9ef{vfsfile:/home/ejort/jboss-head/build/output/jboss-5.0.0.Beta4/ser
| ver/all/conf/jboss-service.xml} loadClass org.jboss.test.naming.restart.RestartNamingService resolve=false
| 2008-02-05 20:43:25,554 TRACE [org.jboss.classloader.spi.base.BaseClassLoader] BaseClassLoader@8be9ef{vfsfile:/home/ejort/jboss-head/build/output/jboss-5.0.0.Beta4/ser
| ver/all/conf/jboss-service.xml} already loaded class org.jboss.test.naming.restart.RestartNamingService class org.jboss.test.naming.restart.RestartNamingService{cl=Bas
| eClassLoader@f834c8{vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-restart.sar} codeSource=(vfsfile:/home/ejort/jboss-head/testsuite/output/lib/naming-rest
| art.sar <no signer certificates>)}
|
This in this code in BaseClassLoader which is supposed to be an optimization :-)
| protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
| {
| boolean trace = log.isTraceEnabled();
| if (trace)
| log.trace(this + " loadClass " + name + " resolve=" + resolve);
|
| // Validate the class name makes sense
| ClassLoaderUtils.checkClassName(name);
|
| // Did we already load this class?
| Class<?> result = findLoadedClass(name);
| if (result != null && trace)
| log.trace(this + " already loaded class " + name + " " + ClassLoaderUtils.classToString(result));
|
So the obvious fix is to replace findLoadedClass() with a real cache
of just those classes we already loaded (like it already does for resources).
The findLoadedClass() still needs to be invoked as a last resort
because of things like IBM's proxy class handling, which is actually
kind of bad because it means it will still erronously continue to return
undeployed classes until the garbage collector runs.
Or alternatively, I could just hack the problem to ignore
classes the JVM caches that have gone away. e.g.
| Class<?> result = findLoadedClass(name);
| if (result != null)
| {
| ClassLoader cl = result.getClassLoader();
| // Not us, make sure the JDK isn't caching undeployed classes
| if (cl != null && cl != this && cl instanceof RealClassLoader)
| {
| RealClassLoader rcl = (RealClassLoader) cl;
| // Ignore when undeployed
| if (rcl.isValid() == false)
| result = null;
| }
| }
|
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4126743#4126743
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4126743
18 years, 2 months