Apache Jackrabbit : JackrabbitOnJBoss

This document describes how to

  • Deploy Jackrabbit on JBoss with JCA.
  • Expose the local repository through JNDI and WEBDAV to remote clients.
  • Access the repository from session beans
  • Access the repository remotely from a java program, or from a command line tool (contrib/jcr-commands).

Feel free to make changes to this document.

Security

A separate document for security is located under JackrabbitOnJbossSecurity

Custom access manager when using Jboss for security is referenced at SimpleJbossAccessManager

Deploy Jackrabbit with JCA

  1. If you have not done so already, download the JCR 2.0 specification.
  2. Copy the jcr-2.0.jar from the specification package to $JBOSS_HOME/common/lib (or $JBOSS_HOME/server/default/lib in JBoss 4.x). Remember that you must not include the jcr jar in any local client application at the risk of getting ClassCastExceptions when trying to access the repository through JNDI.
  3. Download the latest Jackrabbit JCA archive and deploy it either through the JBoss console or by placing it in the deploy folder.
  4. Download the latest jcr-ds.xml template file
  5. Edit the template to match your environment:
    • Change the rar-name setting to match the actual name of the jackrabbit-jca RAR file you downloaded and deployed above
    • Change the homeDir property to match the folder where you want Jackrabbit to store its files
      (warning) If you change the HomeDir property, you should not use repositoryURI property.
  6. Deploy the resulting jcr-ds.xml file to JBoss

Now, jackrabbit is running and available through JNDI at java:jcr/local (or whatever other JNDI name you specified).

Code snippet to lookup the local repository:

Repository repo = (Repository) new InitialContext().lookup("java:jcr/local");

(warning) For more detailed explanations on JBOSS AS 6 and JBOSS AS 7 you may access JBoss Wiki on http://community.jboss.org/wiki/JackrabbitDeploymentInAS6AndAS7

Expose the local repository through RMI

Now a JCR RMI server is running at jnp://localhost:1099/jcrServer

Expose the local repository through JNDI and Webdav

To expose a local repository through JNDI (local) and WebDav (remote) simultaneously, you will need a Jackrabbit WebApp.

By default, JackRabbit WebApp register the JNDI name using a dummy class (org.apache.jackrabbit.core.jndi.provider.DummyInitialContextFactory) and the repository will be available just to the app.

Follow these steps to expose JNDI globally and use the repository according to Model 2 - Shared J2EE Resource:

  • configure jcr-webapp to connect to the local repository. see web.xml
    • disable repository startup servlet in web.xml.
    • Change the JNDI Name.
      It must match the jndi-name set in jcr-ds.xml. default is "java:jcr/local"
    • disable JNDI environment variables for creating the initial context.
      So, the webapp use the default properties received from the application server.
  • copy jackrabbit-webapp-2.0.0.war to the deploy folder in jboss as jackrabbit-server.war

Notice that by default JackRabbit WebApp expose the WebDav server. Now the webdav server is running at http://localhost:8080/jackrabbit-server

Access the repository from a session bean

EJB3 example

Container managed transactions

@Stateless
public class TestCMT implements TestCMTBean {
	
	public void test() throws Exception {
		InitialContext ctx = new InitialContext() ;
		Repository repo = (Repository) ctx.lookup("java:jcr/local") ;
		Credentials cred = new SimpleCredentials("user",new char[]{'´p','w','d'}) ;
		Session s = repo.login(cred) ;
		s.getRootNode().addNode("foo") ;
		s.save();
	}

}

Bean managed transactions

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class TestBMT implements TestBMTBean {
	
	
	@Resource
	UserTransaction utx ;

	public void test() throws Exception {
		utx.begin() ;
		InitialContext ctx = new InitialContext();
		Repository repo = (Repository) ctx.lookup("java:jcr/local");
		Credentials cred = new SimpleCredentials("user",new char[]{'´p','w','d'}) ;
		Session s = repo.login(cred);
		s.getRootNode().addNode("foo");
		s.save();
		utx.commit() ;
	}

}

Access the repository remotely from the command line interface

Since version 2.1, jcr-commands has been integrated to JackRabbit Standalone (https://issues.apache.org/jira/browse/JCR-2457?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel).

It may be executed by parameter -i or --cli.

For example:

java -Xmx256m -jar jackrabbit-standalone-2.2.4.jar --cli file:///scratch/jcr/repository

Notice that the parameter --cli accepts a valid URI to access the repository. It invokes JcrUtils.getRepository(URI) from jackrabbit-commons to get the access to the repository. See the documentation of this method in jackrabbit-commons for more detail.

See the documentation of the repository implementation you want to use for whether it supports this repository URI convention and for what the repository URI should look like. For example, Jackrabbit 2.0 supports the following types of repository URIs:

http(s)://...
A remote repository connection using SPI2DAVex with the given URL. See the jackrabbit-jcr2dav component for more details. file://...
An embedded Jackrabbit repository located in the given directory. See the jackrabbit-core component for more details. jndi:...
JNDI lookup for the named repository. See the JndiRepositoryFactory class for more details.

The next examples are valid:

java -Xmx256m -jar jackrabbit-standalone-2.2.4.jar --cli jndi:jcr/Repository

After executing standalone with --cli parameter, you may execute jcr commands in an interactive mode. Execute

  ``help''

to list the available commands and

  help [command]

for details in a specific command.

For example, you may execute the following commands:

Login using the user and password in the repository:

login user password

create an additional workspace1 workspace:

createWorkspace workspace1

DEPRECATED

  • checkout jcr-commands from subversion
  • build with "maven jar:jar"
  • unzip the generated zip file at ./target into a folder of your choice
  • copy jboss client libraries into the lib folder.
    e.g. copy the file [jboss]/client/jbossall-client.jar to [jcr-commands]/lib

  • run the command line with the script at bin/run.bat
  • connect to the remote server. command: "jndi jcrServer".
  • login to the remote repository. command: "login [user] [password]".

  • type "help" to view the available commands.
  • type "help [command name]" for a detailed description of the given command.

Common problems faced while configuring jackrabbit on jboss

  1. I get following exception when configured jca on jboss
    Reason: org.jboss.deployment.DeploymentException: couldn't get oldRarDeployment!
    jboss.jca:service=RARDeployment,name='jackrabbit-jca-1.0-SNAPSHOT.rar'; - nested throwable:
    (org.jboss.deployment.DeploymentException: ConnectionDefinition 'javax.jcr.Session' not found
    in rar .....
    Solution: Most probably your jboss doesnt support old rar deployment, you better take the latest source code from svn and build the rar your own and try it. Above mentioned instructions work well with jackrabbit-jca-1.1-SNAPSHOT.rar.

2. I get following exception when trying to connect remote jackrabbit repository using jnp port
javax.naming.CommunicationException [Root exception is java.rmi.ConnectException: Connection refused to host: 127.0.0.1; nested exception is:...........

Solution: Try running your jboss server with following arguments
-Djava.rmi.server.hostname=<server name or ip address>

3. I am using jackrabbit on jboss 4.x and am getting following exception when jackrabbit-server.war gets deployed.
log4j:ERROR "org.jboss.logging.util.OnlyOnceErrorHandler" was loaded by [org.jboss.system.server.NoAnnotationURLClassLoader@1888759].
ERROR [STDERR] log4j:ERROR Could not create an Appender. Reported error follows.
ERROR [STDERR] java.lang.ClassCastException
ERROR [STDERR] at org.apache.log4j.xml.DOMConfigurator.parseAppender(DOMConfigurator.java:165)

Solution: There are some classloader issues with jboss, try modifying following attribute value in jbossweb-tomcat55.sar/META-INF/jboss-service.xml
<attribute name="UseJBossWebLoader">true</attribute>
Set it 'to true', default is 'false'.

You can also try adding the parameter -Dorg.jboss.logging.Log4jService.catchSystemOut=false to the JBoss startup parameters.

4. In JBoss 4.0.5, I've got the Jackrabbit 1.3 repository configured and I can look it up in the JNDI using a test app, but my WebDav app cannot find the repository eventhough I've followed the instructions and my configuration looks ok...
If you're trying to get the jackrabbit-server.war (WebDAV) to deploy against a Model-2 shared JCA-based repository as per the instructions above on JBoss 4.0.5, you might run into the problem where the servlet complains about an "invalid config". The servlet will dump you're current config to the console/log file:

12:07:31,087 INFO  [AbstractConfig] Configuration of BootstrapConfig
12:07:31,087 INFO  [AbstractConfig] ----------------------------------------------
12:07:31,090 INFO  [AbstractConfig]   jndiConfig: org.apache.jackrabbit.j2ee.JNDIConfig@9d2834
12:07:31,090 INFO  [AbstractConfig]   rmiConfig: org.apache.jackrabbit.j2ee.RMIConfig@baae59
12:07:31,090 INFO  [AbstractConfig]   repositoryHome: null
12:07:31,090 INFO  [AbstractConfig]   repositoryConfig: null
12:07:31,091 INFO  [AbstractConfig]   class: class org.apache.jackrabbit.j2ee.BootstrapConfig
12:07:31,091 INFO  [AbstractConfig]   valid: true
12:07:31,091 INFO  [AbstractConfig]   repositoryName: java:jcr/local
12:07:31,091 INFO  [AbstractConfig] ----------------------------------------------
12:07:31,091 INFO  [AbstractConfig] Configuration of JNDIConfig
12:07:31,091 INFO  [AbstractConfig] ----------------------------------------------
12:07:31,091 INFO  [AbstractConfig]   jndiName: java:jcr/local
12:07:31,091 INFO  [AbstractConfig]   class: class org.apache.jackrabbit.j2ee.JNDIConfig
12:07:31,091 INFO  [AbstractConfig]   jndiEnv: {}
12:07:31,091 INFO  [AbstractConfig]   valid: true
12:07:31,091 INFO  [AbstractConfig]   jndiEnabled: false
12:07:31,091 INFO  [AbstractConfig] ----------------------------------------------

The big hint is "jndiEnabled: false", which in the source code is set to true/false whether or not java.naming.provider.url is specified in your web.xml <init-param> section. So the solution for me was to set the following <init-param> section in the web.xml:

    <servlet>
        <servlet-name>Repository</servlet-name>
        <description>
            This servlet provides other servlets and jsps a common way to access
            the repository. The repository can be accessed via JNDI, RMI or Webdav.
        </description>
        <servlet-class>org.apache.jackrabbit.j2ee.RepositoryAccessServlet</servlet-class>
        <init-param>
            <param-name>repository-name</param-name>
            <param-value>java:jcr/local</param-value>
            <description>Repository Name that is used to retrieve it via JNDI</description>
        </init-param>
        <init-param>
            <param-name>java.naming.provider.url</param-name>
            <param-value>jnp://localhost:1099</param-value>
        </init-param>
        <init-param>
            <param-name>java.naming.factory.initial</param-name>
            <param-value>org.jnp.interfaces.NamingContextFactory</param-value>
        </init-param> 
        <load-on-startup>3</load-on-startup>
    </servlet>

It's a hack, because the code shouldn't need the JNDI environment details when deployed inside JBoss, but that's all it took to get the WebDAV servlets working in JBoss 4.0.5.

5. In JBoss 5, there's a conflict between xml-apis and xercesImpl bundled with Jackrabbit and Jboss libraries. This problem affects Jackrabbit versions <= 2.1 (see JCR-2344)

Caused by: java.lang.ClassCastException: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl cannot be cast to javax.xml.parsers.DocumentBuilderFactory
	at javax.xml.parsers.DocumentBuilderFactory.newInstance(Unknown Source)
	at org.apache.jackrabbit.webdav.xml.DomUtil.<clinit>(DomUtil.java:46)
	... 74 more
2009-10-14 13:22:36,301 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[localhost].[/jackrabbit-webapp-1.6.0]] (main) El Servlet /jackrabbit-webapp-1.6.0 lanzó excepción de load()
java.lang.ClassCastException: org.apache.xerces.jaxp.DocumentBuilderFactoryImpl cannot be cast to javax.xml.parsers.DocumentBuilderFactory
	at javax.xml.parsers.DocumentBuilderFactory.newInstance(Unknown Source)
	at org.apache.jackrabbit.webdav.xml.DomUtil.<clinit>(DomUtil.java:46)
	at org.apache.jackrabbit.webdav.simple.ResourceConfig.parse(ResourceConfig.java:95)
	at org.apache.jackrabbit.webdav.simple.SimpleWebdavServlet.init(SimpleWebdavServlet.java:157)

Only Jboss libraries must remain. xml-apis-1.3.03.jar and xercesImpl-2.8.1.jar must be removed from Jackrabbit JCA and WAR.

Attachments:

web.xml (text/xml)