I couldn't understand all details to make JackRabbit work with JCA.
I sent my problems to Glassfish Users mailing list and didn't receive any answer yet.

Maybe, since it is all Jackrabbit related issue, I would like to know if someone here in JackRabbit Users may help me...


---------- Forwarded message ----------
From: Gustavo Henrique Orair <gustavo.orair@gmail.com>
Subject: JackRabbit JCA Classloading issues
To: users@glassfish.java.net, users@glassfish.dev.java.net


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?


Best regards,
---------------------------------------------------------------------------------------------------------------------
                               Gustavo Henrique Orair
------------------------------------------------------------------------------------------------------------------