Leonardo Borges

the not so usual geeky stuff

JRuby on Rails and Legacy Java Apps: Managing Dependencies

The motivation for this post came from a couple of messages I’ve seen on the jruby’s google group and because I think it’s pretty cool to share how we tackled this problem.

- A little bit of context

We, as a vast amount of people out there, have legacy Java code. A lot. In our case this legacy is pretty much crucial to our business. We can’t just trash it and start from scratch. Bad idea.

On the other hand we do have new features to be built on top of it. But we wanted an easier way to develop this new stuff and decided for a JRuby on Rails solution, using it as a front-end to our existing services.

- What we decided to do

Our final rails project would make use of a specially created jar file containing our Java application. This Jar would also contain a public interface of the services we’d have to interact with from rails.

As any Java application, ours depend on a number of external jar files that correspond to the various framewoks we usually have in place. e.g.: Hibernate, Spring, apache-commons …

Which means we need to make our app’s jar and all it’s dependencies available in the JRuby classpath in order to use it.

Given we’re using warbler to package our application as a war file, we just need to place all jars needed into our rails app’s lib folder. Warbler then takes care of copying any jar files located in there into the war.

- The problem

So we needed a smart way to include all these dependencies into the project, and copy/paste isn’t an option.

In the Java world we use Maven to manage our projects dependencies - and you should too. Because of that our approach involved turning our rails application into a Maven aware project.

Basically we needed a pom file that would declaratively list our java project as a dependency. From there on, Maven knows what the dependencies are and downloads them to your local repository.

Which leaves us with one more task. We need to put all these dependencies into our lib folder after maven has downloaded them.

Below you’ll find the pom.xml file that we use to achieve this with inline comments explaining each bit:


xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0

com.company

war
1.0-SNAPSHOT
railsApp
railsApp


com.company
java-legacy-app
1.0-SNAPSHOT
compile



railsApp


org.codehaus.mojo
exec-maven-plugin



create-mock-web-descriptor
compile

/bin/sh
.

-c

mkdir -p src/main/webapp/WEB-INF
touch src/main/webapp/WEB-INF/web.xml




exec




copy-needed-jars-into-lib
package

/bin/sh
.

-c

rm -f lib/*.jar
cp target/railsApp/WEB-INF/lib/*.jar lib
rm -rf target/railsApp*
rm -rf src




exec




create-final-war
package

/bin/sh
.

-c

rm -rf *.war tmp/war
jruby -S warble && \
mv *.war target/railsApp.war




exec









Now from the command line we can just run mvn package and we’re good to go.

Maven will start to package the application as a war file. Since it’s not a Java application we create the empty web.xml file in the compile phase, to fool maven.


After it has copied all the dependencies into WEB-INF/lib the next packaging goals will make sure we copy them to our rails’ lib folder, also creating the final war file, ready for deployment.


Note that once done, you can use a simple code snippet similar to this one as an initializer and load all dependencies:

Dir.entries("#{RAILS_ROOT}/lib").sort.each do |entry|
if entry =~ /.jar$/
require entry
end
end


Then we can just use script/console, script/server and so on, as we normally would.

Sorry for the long post, I tried to pack in as much as I could and I certainly hope it’s useful to someone. Any doubts, comments and etc… just drop me a line. :)

Comments