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.

Advertisements

October 24, 2011

Making NetBeans 7.0 work with Subversion 1.7

Posted in Java, Netbeans, RCS, Subversion at 13:55 by theBlackDragon

As you might know the newly released Subversion 1.7 uses a different local repository format, no more do you need an .svn folder per directory in your project instead it uses one .svn folder in the root of your project.

The drawback is that new clients don’t support the old format and vice versa. Netbeans 7.0 still ships with an old built-in Subversion client so after upgrading TortoiseSVN and upgrading my repositories to the new format I could no longer use SVN functionality in Netbeans which was a bit annoying.

Theoretically the solution to this is simple: just tell NetBeans to use the TortoiseSVN provided svn binary (or the one that came with your distribution, if using GNU/Linux) in Tools -> Options -> Versioning -> Subversion -> Path to the SVN executable File.

Unfortunately that doesn’t seem to quite work, I’m assuming that due to a bug NetBeans is still trying to use the built in SVN client. The solution to this I found on the NetBeans forums (here) is that you need start NetBeans with the “-J-DsvnClientAdapterFactory=commandline” argument to force it to use the command line client instead of it’s built in one.

I hope this bug gets fixed in the upcoming 7.1 release, in the meantime this workaround seems to be working fine for me.

July 5, 2011

Move line to end of file and comment

Posted in Emacs, Java at 15:40 by theBlackDragon

I had to work on a bunch of translation Java property files in an ancient J2EE project that had old translations in between the new ones resulting in a hardly readable mess that confused the hell out of Netbeans’ property file editor plugin, so I decided to just move all those old lines to the bottom of the file and comment them out.
For this I quickly hacked up two elisp functions

(defun move-line-to-end-of-file ()
  "Move the current line to the end of the file."
  (interactive)
  (save-excursion
    (beginning-of-line)
    (kill-whole-line)
    (end-of-buffer)
    (yank-as-comment)))

(defun yank-as-comment ()
  "Yank the last killed selection as a comment, but leave text 
  alone that is already a comment according to the current mode."
  (interactive)
  (save-excursion
    (yank)
    (if (not (comment-only-p (mark) (point)))
        (comment-region (mark) (point)))))

There probably is a much more idiomatic way to do this (which I’d love to hear about), but this seems to work just fine for my use. Note however that move-line-to-end-of-file will just append to the last line if the file doesn’t end with a newline (which isn’t an issue in my case).

March 18, 2011

Dynamic class loading in Java, using constructors

Posted in Java at 15:10 by theBlackDragon

This is a followup to my previous post on this subject. Recently I needed to load some modules (which all implement the “Plugin” interface in my example) in a project using constructor arguments, this is how to go about it. Most of the previous post stays valid, you still need a ClassLoader that “knows” the jars you want to load.

        URL[] jarFiles = findAllJars();
        if(jarFiles != null)
            classLoader = URLClassLoader.newInstance(jarFiles);

Then you need to load the Class (without instantiating it, of course) and create a Constructor object, then pass the appropriate arguments to the Constructor object and instantiate the class using this object and the actual arguments.

This is how the previous article’s example looks like when using arguments:

    public static void load(String p)
    throws ClassNotFoundException, InstantiationException,
    IllegalAccessException{
        Class cl = classLoader.loadClass(p);
        Constructor c = cl.getConstructor(String.class);
        Plugin plug = (Plugin) c.newInstance("myArgument");
    }

The argument p is the class to be loaded (for example be.lair.plugins.MyPlugin). The argument(s) to the getConstructor call are the types of parameters the constructor expects and the last line actually provide these arguments and instantiates the class.

On a related note, maybe I should look into unloading these classes after they have been loaded, if at all possible. I’ve never had a use case for trying to do this but it might be an interesting exercise.

September 15, 2010

Spring Framework missing in Netbeans 6.9

Posted in Java, Netbeans at 19:43 by theBlackDragon

Or is it?

When I tried to follow the Netbeans Spring tutorial I couldn’t for the life of me find the Spring framework where it was supposed to be, only Hibernate showed up.

Apparently you have to explicitly enable the Java Web and EE Plugin as described here. Finding this took me quite a while, I would honestly have expected this question to come up more often, especially from new Netbeans users or people that don’t usually use the Web technologies plugins (like me).

March 11, 2008

Dynamic class loading in Java

Posted in Java at 12:03 by theBlackDragon

This is a repost of an older article I wrote back in 2006 (yes, I had to use the wayback machine to get it back ;))

I was looking for a way to dynamically load plugins from (at development time) unknown jars the other day and after some searching (nowadays they call that Googling I guess?) I found the solution in Java’s ClassLoader class, in URLClassLoader to be precise. This task turned out to be amazingly simple.

I just defined an interface called Plugin that all the Plugins should implement so that I can cast whatever I get from the ClassLoader to this interface.

So without further ado, here’s the code (yes, only 6 lines of actual code):

        URL[] jarFiles = findAllJars();
        if(jarFiles != null)
            classLoader = URLClassLoader.newInstance(jarFiles);

This gets me a new ClassLoader with all the plugins in a given directory. findAllJars() is a oneliner grabbing all jars from my projects “plugin” directory using a FilenameFilter to filter the Jars from the cruft 😉

I can then load a plugin like this:

    public static void load(String p)
    throws ClassNotFoundException, InstantiationException, 
    IllegalAccessException{
        Class c = classLoader.loadClass(p);
        Plugin plug = (Plugin) c.newInstance();
    }

This uses the ClassLoader to load an instance of the dot-notated classname I pass in (eg. be.lair.remes.plugin.ircplugin.IRCPlugin), I then use this Class to create an instance which I then cast to the correct type.

Notwithstanding the fact that I didn’t find a great deal of example of this on the net it was amazingly simple to get working. Makes me wonder why people always need to pick on Java.