June 8, 2012

Jackrabbit with PostgreSQL on JBoss AS 7.1

Posted in Jackrabbit, Java, JCR at 10:56 by theBlackDragon

Getting Jackrabbit (2.4.1 and/or 2.6-SVN) to work on JBoss AS 7.1  has been a long and arduous journey. Most of the information is out there, but it’s fragmented at best so I’ll describe the steps I had  to take to get Jackrabbit to work with JBoss using a PostgreSQL database.

1 Setting up the database

1.2 Registering the JDBC driver

The first order of business is to register the PostgreSQL driver, recent drivers don’t require any entries in the modules directory anymore, just specifying putting the driver jar in the deployments folder and putting the filename in the <driver> element in the JBoss configuration file (standalone/configuration/standalone.xml) suffices (see next section about setting up the datasource).

Alternatively you can create a new folder structure in the modules directory “org/postgres/main” and put the driver jar in there. Then you need to create a module.xml file with the following contents:

  <?xml version="1.0" encoding="UTF-8"?>
  <module xmlns="urn:jboss:module:1.0" name="org.postgresql">
    <resources>
      <resource-root path="postgresql-9.1-901-1.jdbc4.jar"/>
    </resources>
    <dependencies>
      <module name="javax.api"/>
      <module name="javax.transaction.api"/>
    </dependencies>
  </module>

We also need to add a <driver> element to standalone.xml under drivers in the datasource section (just search the file for “drivers”, there’s only one such element in the default configuration) like this:

  <driver name="postgres-jdbc4" module="org.postgresql">
      <xa-datasource-class>org.postgresql.xa.PGXADataSource</xa-datasource-class>
  </driver>

Here it is important that the module name is the same as the name in module.xml, the driver name can be anything.

This second method makes it easier to update the driver if it is used by multipe projects.

1.2 Setting up the datasource

Next we need to set up a new datasource under the datasource subsystem element:

  <subsystem xmlns="urn:jboss:domain:datasources:1.0">
    <datasources>
      <datasource jta="true" jndi-name="java:/jdbc/DocumentStoreDS" 
                  pool-name="DocumentStoreDS" enabled="true" 
                  use-java-context="true" use-ccm="true">
        <connection-url>jdbc:postgresql://localhost/documentstore</connection-url>
        <driver-class>org.postgresql.Driver</driver-class>
        <driver>postgresql-9.1-901-1.jdbc4.jar</driver>
        <pool>
          <min-pool-size>1</min-pool-size>
          <max-pool-size>4</max-pool-size>
          <prefill>false</prefill>
        </pool>
        <security>
          <user-name>documentstore</user-name>
          <password>password</password>
        </security>
        <validation>
          <check-valid-connection-sql>SELECT 1</check-valid-connection-sql>
        </validation>
      </datasource>
    </datasources>
  </subsystem>

If using the module way of registering the JDBC driver change the <driver> element in the above snipped to refer to the chosen driver name (“postgres-jdbc4” in the example)

If you start JBoss now it should say the driver is available under the chosen JNDI name.

  11:33:55,231 INFO  [org.jboss.as.connector.subsystems.datasources] 
    (MSC service thread 1-1) JBAS010400: Bound data source [java:/jdbc/DocumentStoreDS]

2 Registering the JCR API

Next we have to register the JCR API jar as module. The steps are basically the same as for the PostgreSQL driver (if you chose to go that route).

Create a subdirectory javax/jcr/main under modules, put the jcr-2.0.jar in it and create a module.xml file like this:

  <?xml version="1.0" encoding="UTF-8"?>
  <module xmlns="urn:jboss:module:1.0" name="javax.jcr">
    <dependencies>
      <module name="javax.transaction.api" export="true"/>
    </dependencies>

    <resources>
      <resource-root path="jcr-2.0.jar"/>
    </resources>
  </module>

3 Setting up Jackrabbit

3.1 Working around a Jackrabbit issue

JCA requires certain classes to implement the equals and hascode methods, unfortunately current Jackrabbit versions don’t do so (see this JIRA issue)

The easiest solution is to turn off failure upon JCA validation errors in the JBoss configuration (or just turn off validation entirely):

  <subsystem xmlns="urn:jboss:domain:jca:1.1">
      <archive-validation enabled="true" fail-on-error="false"
      fail-on-warn="false"/>
      ...
  </subsystem>

3.2 Specifying Jackrabbit dependencies

Next we need to be able to tell JBoss that Jackrabbit depends on the JCR API. For this we need to unpack the jackrabbit-jca-<version>.rar and change it’s MANIFEST.MF by adding the following line:

  Dependencies: javax.jcr

Then repackage it.

Note that any projects you want to deploy to JBoss that require Jackrabbit *must* also specify this dependency in their manifest.

3.3 Configure Jackrabbit

Now we’re ready to add Jackrabbit to the JBoss configuration as a resource adapter:

  <subsystem xmlns="urn:jboss:domain:resource-adapters:1.0">
    <resource-adapters>
      <resource-adapter>
        <archive>
          jackrabbit-jca-2.4.1.rar
        </archive>
        <transaction-support>XATransaction</transaction-support>
        <connection-definitions>
          <connection-definition 
              class-name="org.apache.jackrabbit.jca.JCAManagedConnectionFactory" 
              jndi-name="java:/jackrabbit" enabled="true" 
              use-java-context="true" 
              pool-name="jackrabbit-jca-2_4_1_rar-Pool" use-ccm="true">
            <config-property name="HomeDir">
              ${jboss.server.data.dir}/jcr-repository
            </config-property>
            <config-property name="ConfigFile">
              ${jboss.server.data.dir}/jcr-repository/repository.xml
            </config-property>
            <xa-pool>
              <min-pool-size>3</min-pool-size>
              <max-pool-size>15</max-pool-size>
              <prefill>true</prefill>
              <use-strict-min>true</use-strict-min>
            </xa-pool>
          </connection-definition>
        </connection-definitions>
      </resource-adapter>
    </resource-adapters>
  </subsystem>

If you update the repository configuration appropriately you should now be able to start JBoss AS and access Jackrabbit over JNDI.