Issue Details (XML | Word | Printable)

Key: GLASSFISH-18082
Type: Bug Bug
Status: Resolved Resolved
Resolution: Works as designed
Priority: Major Major
Assignee: Jagadish
Reporter: orair
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
glassfish

Classloading problems using Resource Adapter (Jackrabbit-JCA), derived classloading policy and explicit JNDI lookups

Created: 23/Dec/11 05:50 PM   Updated: 24/Jan/12 10:31 AM   Resolved: 18/Jan/12 03:44 AM
Component/s: classloader
Affects Version/s: 3.1.1
Fix Version/s: None

Time Tracking:
Original Estimate: 3 days
Original Estimate - 3 days
Remaining Estimate: 3 days
Remaining Estimate - 3 days
Time Spent: Not Specified
Time Spent - Not Specified

File Attachments: 1. Text File server.derived.ejb-jar.log (90 kB) 05/Jan/12 04:41 PM - Jagadish
2. Text File server.derived.log (50 kB) 05/Jan/12 04:41 PM - Jagadish
3. Text File server.global.log (329 kB) 05/Jan/12 04:41 PM - Jagadish
4. GZip Archive useJackrabbitJCA-ROOT.modified.tar.gz (8 kB) 05/Jan/12 04:50 PM - Jagadish
5. GZip Archive useJackrabbitJCA-ROOT.tar.gz (8 kB) 23/Dec/11 05:50 PM - orair

Environment:

Linux Ubuntu


Tags: classloder resource-adapter jndi
Participants: Jagadish, orair and Sanjeeb Sahoo


 Description  « Hide

I am using the JackRabbit JCA Resource Adapter (http://jackrabbit.apache.org/jackrabbit-jca-resource-adapter.html) to access JCR repositories using explicit JNDI lookups, but I am facing some classloading problems on this environment.

I've created an Example Project to show the issues I am facing.

To Reproduce the issues you need to follow the step-by-step instructions:
Step 1 - Get JackRabbit JCA (version 2.3.3) on link http://www.apache.org/dyn/closer.cgi/jackrabbit/2.3.3/jackrabbit-jca-2.3.3.rar.

Step 2 - Deploy jackrabbit-jca on Glassfish.
2 - a) Specify the application name to jackrabbit-jca.
Application Name: jackrabbit-jca

Step 3 - Create a Connector Connection Pool, use the following configuration:
Pool Name: cp_jcr_repository
Resource Adapter: jackrabbit-jca
Connection Definition: javax.jcr.Repository
3 - a) As Additional Property, specify just the HomeDir parameter:
HomeDir: /tmp/jcr_repository

Step 4 - Create a new Connector Resource:
Jndi Name: jcr/Repository
Pool Name: cp_jcr_repository

Step 5 - Unzip the Example Project (attached) in a directory.
5 - a) Package the Example Project (Root module) using Maven.
mvn package

3 different EARs will be created:

  • EAR
    No Jackrabbit dependencies
    (It should be possible to get the jackrabbit repository from JackRabbit-JCA resource adapter using explicit JNDI)
  • EAR2
    jackrabbit-commons and jackrabbit-core dependences
    (this EAR has all jackrabbit dependences itself and it works but a "proxy" using Stateless session being is needed probably because of classloading issues when JMX invocations are used)
  • EAR3 (this is the most similar to the real world use case)
    It has jackrabbit-jcr-commons dependency
    (It should be possible to get the JCR repository using JCRUtils.getRepository(String uri) but it does not work)

Step 6 - Deploy one of the EARs modules on Glassfish.
All these 3 EARs packages just one EJB module.
The EJB module has one stateless ejb and one enabled JMX singleton ejb called JMXServiceActivator (The JMXServiceActivator is registered in managed bean server as app.JMXServiceActivator).
A jmx client may be used to launch the JMXServiceActivator methods:
a - getRepositoryUsingExplicitJNDI(String jndiName);
b - getRepositoryUsingJCRUtils(String jndiName);
c - getRepositoryUsingExplicitJNDIWithoutProxy(String jndiName);
d - getRepositoryUsingJCRUtilsWithoutProxy(String jndiName);

Step 7 - Call one of the JMXServiceActivator methods using a JMX client (such as jconsole).
jndiName: "jcr/Repository"

Step 8- Check the server.log the resulted behaviour.

After discussing with glassfish developers (Sahoo and Jagadish), I've created glassfish-application.xml and glassfish-resources.xml files to try to inform to Glassfish I need the Jackrabbit libraries/modules inside jackrabbit-jca available to my EAR. At least from my observations, inserting these files on EAR3 module didn't change anything.

I am getting the following results:
EAR1: Methods 1 and 3 should work (2 and 4 would work if the jackrabbit-jcr-commons module inside jackrabbit-jca was accessible), but none of the methods works.
EAR2: All 4 methods should work on EAR2, but only 1 and 2 works (probably problems related to JMX avoid these methods to work correctly, but it is not the focus of this issue).
EAR3 (this use case is the most similar to my real world project): All methods should work, but none works.

As I said, the focus on this issue is to make the classloader finds the libraries inside the resource adapter, the problem related to JMX is not the big problem (at least for now since I've used a "workaround" proxy).

So, I am really interested to make the method getRepositoryUsingJCRUtils(String jndiName) (method b) from EAR3 application work.

To understand the problem, I explain the behavior I observed and why it fails:
When JcrUtils.getRepository is called, the EJB pass the uri parameter with jndi scheme (jndi:jcr/Repository), "JcrUtils" search for providers and it finds JndiRepositoryFactory provider (inside jackrabbit-jcr-commons dependency that exists in EAR3 lib's directory). The JndiRepositoryFactory performs an explicit JNDI lookup to jcr/Repository.
The JCARepositoryManager invokes JcrUtils.getRepository again but it pass a Map of parameters containing the parameters found in the Connection pool configuration (cp_jcr_repository). Then, ServiceRegistry.lookupProviders(RepositoryFactory.class) is called, but the classloader used doesn't find the org.apache.jackrabbit.client.RepositoryFactoryImpl (this class belongs to jackrabbit-jcr-client module shipped inside jackrabbit-jca resource adapter).

Note: JackRabbit source code may be checked out from a subversion repository in https://svn.apache.org/repos/asf/jackrabbit/tags/2.3.3 .



orair added a comment - 27/Dec/11 12:27 PM

I asked for experiences using JackRabbit-JCA on Glassfish and some users confirmed that jackrabbit-jca worked using injection. So, seems no need to change any code on Jackrabbbit-jca side.


Sanjeeb Sahoo added a comment - 03/Jan/12 06:43 AM

Assigning to JCA team to investigate.


Jagadish added a comment - 05/Jan/12 04:37 PM

I have tried to reproduce the issue w.r.t EAR3.

1) All the four methods (called via Jconsole) fail. The reason being, .ear does not refer the connector-resource created for jackrabbit RAR.
Though glassfish-resources.xml is present, the resource need to be referred via <resource-ref> element in ejb-jar.xml.
Attached server.log for this use-case : server.derived.log

2) I changed the connector classloading policy to "global", restarted GlassFish.
First 3 methods (called via jconsole) pass and fourth one failed with the following exception :
---------------------------------------------------------------------------------------------------------------------------------------
[#|2012-01-05T20:07:45.489+0530|INFO|44.0|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=13;_ThreadName=Thread-2;|2012-01-05 20:07:45.488 ERROR [RMI TCP Connection(3)-127.0.0.1] App.java:85 Failed access the repository.
javax.jcr.RepositoryException: Unable to access a repository with the following settings:
org.apache.jackrabbit.repository.uri: jndi:jcr/Repository
The following RepositoryFactory classes were consulted:
Perhaps the repository you are trying to access is not available at the moment.
at org.apache.jackrabbit.commons.JcrUtils.getRepository(JcrUtils.java:215) ~[jackrabbit-jcr-commons-2.3.3.jar:na]
at org.apache.jackrabbit.commons.JcrUtils.getRepository(JcrUtils.java:255) ~[jackrabbit-jcr-commons-2.3.3.jar:na]
at app.App.getRepositoryUsingJCRUtils(App.java:80) ~[useJackrabbitJCA-ejb-0.0.1-SNAPSHOT_jar/:na]
at app.JMXServiceActivator.getRepositoryUsingJCRUtilsWithoutProxy(JMXServiceActivator.java:70) [useJackrabbitJCA-ejb-0.0.1-SNAPSHOT_jar/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.6.0_27]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) ~[na:1.6.0_27]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) ~[na:1.6.0_27]
at java.lang.reflect.Method.invoke(Method.java:597) ~[na:1.6.0_27]
---------------------------------------------------------------------------------------------------------------------------------------
Attached the server.log for this use-case : server.global.log

3) Set the classloading policy to "derived" (the default one) and restarted GlassFish
Removed glassfish-resources.xml, created connector-resource and pool as indicated the pool.
Updated ejb-jar.xml to have ejb related information and <resource-ref> to the connector-resource.
First 3 JMX calls succeeded. last call failed with same exception :
---------------------------------------------------------------------------------------------------------------------------------------
[#|2012-01-05T21:44:41.855+0530|INFO|44.0|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=23;_ThreadName=Thread-2;|2012-01-05 21:44:41.855 ERROR [RMI TCP Connection(15)-127.0.0.1] App.java:85 Failed access the repository.
javax.jcr.RepositoryException: Unable to access a repository with the following settings:
org.apache.jackrabbit.repository.uri: jndi:jcr/Repository
The following RepositoryFactory classes were consulted:
Perhaps the repository you are trying to access is not available at the moment.
at org.apache.jackrabbit.commons.JcrUtils.getRepository(JcrUtils.java:215) ~[jackrabbit-jcr-commons-2.3.3.jar:na]
at org.apache.jackrabbit.commons.JcrUtils.getRepository(JcrUtils.java:255) ~[jackrabbit-jcr-commons-2.3.3.jar:na]
at app.App.getRepositoryUsingJCRUtils(App.java:80) ~[useJackrabbitJCA-ejb-0.0.1-SNAPSHOT_jar/:na]
at app.JMXServiceActivator.getRepositoryUsingJCRUtilsWithoutProxy(JMXServiceActivator.java:70) [useJackrabbitJCA-ejb-0.0.1-SNAPSHOT_jar/:na]
---------------------------------------------------------------------------------------------------------------------------------------
Attached the server.log for this use-case : server.derived.ejb-jar.log

So, having appropriate <resource-ref> in ejb-jar.xml seems to make it work. I am not sure whether 4th JMX call is related to class-loading/connectors.

Also, attached the modified source bundle that does not have glassfish-resources.xml and has modified ejb-jar.xml (with resource-ref).

ENVIRONMENT :
JackRabbit RA from :http://archive.apache.org/dist/jackrabbit/2.3.3/
JCR API from :http://mirrors.ibiblio.org/pub/mirrors/maven2/javax/jcr/jcr/2.0/jcr-2.0.jar (Copied to GlassFish's lib directory).


Jagadish added a comment - 05/Jan/12 04:41 PM

1) server.log for connector's class-loading-policy as "global" : server.global.log
2) connector's class-loading-policy : derived with ejb-jar.xml that has <resource-ref> for connector-resource : server.derived.ejb-jar.log
3) server.log for connector's class-loading-policy as "derived" : server.derived.log


Jagadish added a comment - 05/Jan/12 04:50 PM

modified test-case (no glassfish-resources.xml, updated ejb-jar.xml to have <resource-ref> for connector-resource)


Sanjeeb Sahoo added a comment - 06/Jan/12 01:02 AM

In server.log, I see following messages that might affect the outcome:

During deploymemnt:
[#|2012-01-05T20:06:44.279+0530|WARNING|44.0|javax.enterprise.system.tools.deployment.org.glassfish.deployment.common|_ThreadID=10;_ThreadName=Thread-2;|This app [useJackrabbitJCA3-ear] has no resource reference by the name of [jcr/Repository]|#]

[#|2012-01-05T20:06:44.279+0530|WARNING|44.0|javax.enterprise.system.tools.deployment.org.glassfish.deployment.common|_ThreadID=10;_ThreadName=Thread-2;|DPL8007: Unsupported deployment descriptors element jndi-name value jcr/Repository|#]

Just before the exception:
[#|2012-01-05T20:07:32.994+0530|INFO|44.0|javax.enterprise.resource.resourceadapter.com.sun.enterprise.connectors|_ThreadID=12;_ThreadName=Thread-2;|The log message is empty or null. Please log an issue against the component in the logger field.|#]

The last one may not be relevant, but the first two looks suspicious to me.


orair added a comment - 16/Jan/12 11:57 AM

Are there any updates on this issue?

In my case, I really would like a way to allow any jcr resources (jndi name) using the Jackrabbit resource adapter being accessed by the module. My ear projects access many JCR resources and I would like to change the JCR resources to be accessed without the need to redeploy my EAR.

At least for me, looks like JMS resources works exactly the way I expected for JCR resources. I don't need to specify/inject a JMS resource to be able to get the specific resource from JNDI server using explicit JNDI lookup.

Are the JMS resources considered "first-class" resources?

Anyway, is there any workaround available to specify that I want to access using explicit JNDI lookup any resources from the resource adapter?

Br,
Orair.


Jagadish added a comment - 16/Jan/12 03:35 PM

Please refer my evaluation dated 5th Jan ( option (3) ). I have also attached the modified application (added ejb-jar.xml to the application) which will get deployed successfully without any change to application server.

Query-1 :
"In my case, I really would like a way to allow any jcr resources (jndi name) using the Jackrabbit resource adapter being accessed by the module. My ear projects access many JCR resources and I would like to change the JCR resources to be accessed without the need to redeploy my EAR."

Response :
If you would like to access the resource by jndi-name without bundling descriptors with <resource-ref> / @Resource annotations, then you need to set the class-loading policy to "global".

Query-2 :
"At least for me, looks like JMS resources works exactly the way I expected for JCR resources. I don't need to specify/inject a JMS resource to be able to get the specific resource from JNDI server using explicit JNDI lookup.

Are the JMS resources considered "first-class" resources?"

Response :
Yes, JMS (and JDBC) resources are first-class resources as those resource-types need to be supported by application-server (mandatory requirement)

Query-3 :
"Anyway, is there any workaround available to specify that I want to access using explicit JNDI lookup any resources from the resource adapter?"

Response :
This query is same as Query-1. Changing class-loading-policy to "global" is the solution.


Jagadish added a comment - 18/Jan/12 03:44 AM

Marking the issue as "working as designed" and the use-case works fine for me with :
a) Change to class-loading policy
or
b) Change to application's descriptor to refer a resource of the resource-adapter.


orair added a comment - 18/Jan/12 12:24 PM

The resolution proposed cannot satisfy my needs.

This resolution make impossible the use of explicit JNDI lookups in dynamic environments.
Since it proposed I create the resource-ref for each EJB.
In my case, as I've explained, I have a Crawler object that makes explicit JNDI lookups.
These Crawler objects may be instantiated inside an EJB Timer Service, a MDB Service Activator, or a Singleton EJB.

The resolution proposed need that I preregister all the JCR repositories in all my EJBs.
Since I have tens of JCR repositories, and tens of ejbs, it is really dificulty to create and manage all these deployment descriptors.

If the approach using a dummy resource-ref in glassfish-application.xml or glassfish-resources.xml was available, at least, I wouldn't need to create a lot of unnecessary ejb-jar.xml for all my EJBs (Timer Services and Singleton) and MDBs.

I've created the glassfish-application.xml and glassfish-resources.xml based on the documentation available, but no explainations were provided why these XMLs failed. As Sahoo noted, the resulting log was:

[#|2012-01-05T20:06:44.279+0530|WARNING|44.0|javax.enterprise.system.tools.deployment.org.glassfish.deployment.common|_ThreadID=10;_ThreadName=Thread-2;|This app [useJackrabbitJCA3-ear] has no resource reference by the name of [jcr/Repository]|#]

[#|2012-01-05T20:06:44.279+0530|WARNING|44.0|javax.enterprise.system.tools.deployment.org.glassfish.deployment.common|_ThreadID=10;_ThreadName=Thread-2;|DPL8007: Unsupported deployment descriptors element jndi-name value jcr/Repository|#]


orair added a comment - 18/Jan/12 01:30 PM

I tested the approach of creating a dummy EJB with the ejb-jar.xml deployment descriptor proposed by Jagadish.
I tested if the other EJB would be able to make explicit JNDI lookups and it worked.
So I concluded creating a dummy EJB can already change the classloading rules of all other components of the EAR.

So a workaround would be to create a dummy EJB with the ejb-jar.xml proposed by Jagadish and package them to my EAR.
However, I prefer to create a workaround that used only specific deployment descriptors Glassfish inside the EAR as other servers such as JBoss deployment does not require this workaround.

Once creating the dummy EJB solves the problem, it seems possible that just creating/configuring the xml files (glassfish-resources.xml and/or glassfish-application.xml) inside the EAR could solve the problem.
But I do not know yet how to do this.
The approach of change only these specific Glassfish deployment descriptors within the EAR looks like much more portable than create the EJB dummy or create/configure dozens of ejb-jar.xml files.


Jagadish added a comment - 24/Jan/12 10:31 AM

Query :
"So a workaround would be to create a dummy EJB with the ejb-jar.xml proposed by Jagadish and package them to my EAR.
However, I prefer to create a workaround that used only specific deployment descriptors Glassfish inside the EAR as other servers such as JBoss deployment does not require this workaround."

Response :
One <resource-ref> in any of the Deployment Descriptor of web.xml/ejb-jar.xml (or @Resource annotation in Servlet/EJB) is suffcient to make the RAR available to the archive. This is a new implementation in GlassFish (3.0 and above) as per the guidelines of Connector Architecture 1.6 specification in order to avoid class duplication related issues when multiple RARs export same set of classes. The standard way of using a resource is via <resource-ref> (or its @Resource annotation equivalent) and hence this is not actually a workaround. [Doing lookup via "jndi-name" of the resource is actually called as physical lookup and is defined as non-portable]

Query :
"Once creating the dummy EJB solves the problem, it seems possible that just creating/configuring the xml files (glassfish-resources.xml and/or glassfish-application.xml) inside the EAR could solve the problem. But I do not know yet how to do this."

Response :
You can bundle resource configurations via glassfish-resources.xml, but still need to refer them via <resource-ref>/@Resource as stated in the above response.