I have some issues with Glassfish ClassLoader.
I am using JackRabbit JCA (Resource Adapter for JCR Repositories) to
provide JCR repositories (JSR-283).
I have many problems and all looks like related to classloading.
It looks like that Glassfish ClassLoader do not find the libraries inside
the jackrabbit JCA rar.
JackRabbit JCA is shipped with JackRabbit Core inside that provides the
"server implementation". But the class with this implementation is not
found by the classloader.
I will try to explain what I found trying to solve this problem and the
workarounds I've used and see if someone may help me to understand better
the problems and how to solve them (or file a bug).
JackRabbit JCA is a Resource Adapter. You may create connection pool for a
specific JCR Repository providing some parameters such as HomeDir (the
directory where the repository is found).
JackRabbit JCA based on these parameters specified uses
org.apache.jackrabbit.client.RepositoryFactoryImpl class. This
RepositoryFactoryImpl class just get the parameters specified and check the
existence of the HomeDir parameter. When this HomeDir parameter is found,
it try to load the class org.apache.jackrabbit.core.RepositoryFactoryImpl
dynamically (provided in jackrabbit-core inside the jackrabbit-jca). The
code used to load org.apache.jackrabbit.core.RepositoryFactoryImpl is
similar to:
Class<?> repositoryFactoryClass =
Class.forName("org.apache.jackrabbit.core.RepositoryFactoryImpl",
true,Thread.currentThread().getContextClassLoader());
repositoryFactory = repositoryFactoryClass.newInstance();
If the clients perform explicit JNDI lookups, the
org.apache.jackrabbit.client.RepositoryFactoryImpl is not being found.
Another very common option for the clients to access the JCR repository is
to use JcrUtils.getRepository(String uri) provided in
jackrabbit-jcr-commons (specifying a "jndi:jcr/Repository" uri) . This
utility basically search using ServiceRegistry.lookupProviders for
RepositoryFactory providers that accepts the parameters specified. Code:
Iterator<RepositoryFactory> iterator =
ServiceRegistry.lookupProviders(RepositoryFactory.class);
Using this utility, the code fails again (it really make an explicit JNDI
lookup inside JndiRepositoryFactory class).
Since these classes were not being found inside JackRabbit JCA, I tried as
a workaround to add jackrabbit-core and jackrabbit-commons modules inside
the EAR.
I was able to get the repository but I needed another workaround.
I added JMX methods to a singleton EJB to make the tests easier (and study
JMX classloader issues).
If I invoke JCRUtils.getRepository directly from this singleton EJB, the
RepositoryFactory implementations are not found.
So, I did a following workaround: Created a Stateless Session bean. The
Singleton EJB works like a "proxy" and just delegate the methods from
Singleton ejb to the stateless ejb. Using this workround, finally I could
successfully get a JCR repository using JNDI. Additional note: if the
delegation is done to static methods defined in the stateless ejb, the
workaround doesn't work.
To make easier to reproduce these problems,
I have created a small EJB module with the stateless and the singleton ejb
as discussed.
This EJB module has a Singleton JMXServiceActivator. The
JMXServiceActivator is registered in managed bean server as
app.JMXServiceActivator and you can use jmx client (such as jconsole) to
launch the following methos:
1 - getRepositoryUsingExplicitJNDI(String jndiName);
2 - getRepositoryUsingJCRUtils(String jndiName);
3 - getRepositoryUsingExplicitJNDIWithoutProxy(String jndiName);
4 - getRepositoryUsingJCRUtilsWithoutProxy(String jndiName);
After, I created 3 different client EARs to check all these issues
(attached in this e-mail):
1 - EAR
No Jackrabbit dependencies
(It should be possible to get the jackrabbit repository using explicit
JNDI)
2 - EAR2
jackrabbit-commons and jackrabbit-core dependences
(it really can get the JCR repository but a "proxy" using Stateless
session being is needed to make it work)
3 - EAR3
Just jackrabbit-commons dependency
(It should be possible to get the JCR repository using
JCRUtils.getRepository(String uri) but it does not work)
I am doing something wrong?
Are these really Classloading bugs?
Is this just an unique bug or there are multiple bugs involved?
---------------------------------------------------------------------------------------------------------------------
Gustavo Henrique Orair
Mestre em Ciência da Computação - MSc in Computer Science
Universidade Federal de Minas Gerais
Celular/Cell phone: 55-31-85157887
------------------------------------------------------------------------------------------------------------------