Rails on JRuby - different behavior in console and server?

I’m using JRuby 1.7.1 with a Rails 3.2.9 application. The application
uses
Java code in a JAR file which is loaded via a ‘require’ statement.

When I execute some JRuby code that uses the Java classes in the rails
console things work fine. However, when I execute that same JRuby code
via
a Rails controller action running with “rails s” I get an error related
to
trying to dynamically load an HSQLDB JDBC driver.

The relevant portion of the stacktrace:

Cannot create JDBC driver of class ‘’ for connect URL
‘jdbc:hsqldb:file:/private/var/folders/ww/__zw8nvj6blfn0tfgvs1gs240000gq/T/1357181247259-0/data/’
java.sql.SQLException: No suitable driver
at java.sql.DriverManager.getDriver(DriverManager.java:264)
at
org.apache.commons.dbcp.BasicDataSource.createConnectionFactory(BasicDataSource.java:1437)
at
org.apache.commons.dbcp.BasicDataSource.createDataSource(BasicDataSource.java:1371)
at
org.apache.commons.dbcp.BasicDataSource.getConnection(BasicDataSource.java:1044)

Looking at the DriverManager.java source it seems that this could be a
ClassLoader issue, but I’m unsure as to what the differences are in the
Java environment when executing this code in the rails console versus
the
rails server (which is using the Puma webserver) which might cause this
behavior.

Can anyone enlighten me on this or point me to some docs that describe
the
differences between console and server? Any suggestions for
troubleshooting would be much appreciated as well.

Thanks,

Chris

What version of AR-JDBC (activerecord-jdbc-adapter and jdbc-hsqldb) are
you
using? We’ve had some “noise” in the recent releases, which may be the
culprit.

Anthony,

I’m not doing any ActiveRecord stuff in the JRuby code presently, so I
don’t have either of those gems installed. The HSQLDB stuff is
happening
way down in the Java code that I’m loading from the JAR.

Do you think adding the AR-JDBC and HSQLDB gems would make a difference
when I run under the server process? As I said, the code works
perfectly
when I invoke it from the console.

Cheers,

Chris

Generally you can’t rely on DriverManager to find driver classes in a
server process. The problem is an issue related to dynamic classloaders
and DriverManager, where DriverManager can’t find any SQL drivers that
aren’t present on the JVM’s boot classpath. It’s best to just directly
instantiate the relevant driver class versus using DriverManager to find
things. This is how all the major JRuby database libraries do things as
well - some first attempt to use DriverManager and fall back on direct
instantiation and some just skip DriverManager entirely.

If you really want to use DriverManager, you’ll have to ensure that the
HSQLDB driver is on the JVM’s classpath when it boots.

Ben

Ben,

I think you’re spot on with this analysis. There is some code that
dynamically loads a “legacy” version of the HSQLDB driver as part of a
data-migration process. I don’t think that driver is on the boot
classpath
and is only loaded if needed to do the migration.

So is there a difference between the JVM’s boot classpath between
running
“rails console” and running “rails server”? I would love to test this
theory somehow.

I very much appreciate your help!

Chris

Ben,

One other thought. I saw this SO post:

I thought I’d try the same, but looking into it I found, I think, that
the
HSQLDB driver is actually called org.hsqldb.jdbcDriver

And with the driver name starting in lowercase I couldn’t use
java_import
to try to add it to the classpath. This isn’t an inner class name, so
is
there a workaround to get JRuby to gracefully handle jdbcDriver?

Chris

I was able to actually get the driver loaded by using the technique in
the
Stack Overflow post listed below. The trick was using the Java for_name
call since JRuby wasn’t happy with the lowercase jdbcDriver name that
HSQLDB uses.

The code executes properly in both rails server and console now.

Thanks for your help!

Chris

Great - glad you it working. I don’t really know the details of Puma to
know why this specific trick works, but if you were to deploy this
application to a Java-based server such as Tomcat, Trinidad, or
TorqueBox you’d still hit a classloading issue with DriverManager and
need to instantiate the drivers directly or add them to the JVM’s boot
classpath.

Ben