views:

58

answers:

2

Hi everyone,
I've an apparently (silly) simple question:

With JRuby is it possible to deploy a single file Sinatra application?

I mean: I've my Sinatra app with all needed gems exploded into some ./vendor/lib directory and I'd like to deploy the whole app as a single jar file to run on a deployment machine:

$ java jar my_app.jar

where the only thing I have is Java.

Is that possible? And, if so, there is a simple way to accomplish that?

TIA

+1  A: 

It is quite easy in fact. Suppose you can run your application with everything frozen under some directory with a command:

ruby myapp.rb

Now you need to place this script into lib directory under your application and write an java wrapper which will load the script. Sample code which does this:

package livesync;

import org.jruby.Ruby;
import org.jruby.RubyRuntimeAdapter;
import org.jruby.javasupport.JavaEmbedUtils;  
import java.util.ArrayList;

public class LiveSyncRunner {
    public static void main(String[] args) {
        String[] jrubyArgs = new String[3 + args.length]; 
        jrubyArgs[0] = "-e";
        jrubyArgs[1] = "require 'livesync/livesync_wrapper'";
        jrubyArgs[2] = "livesync";
        for (int i = 0; i < args.length; ++i) {
            jrubyArgs[i + 3] = args[i];
        }
        org.jruby.Main.main(jrubyArgs);
    }
}

In case above the script I run is in lib/livesync_wrapper.rb

Now all you need is a proper build.xml file (placed in the root directory) My build.xml:

<?xml version="1.0" encoding="UTF-8"?>

<project basedir="." default="dist" name="Juggernaut">
  <description>Combine Ruby and Java source with the jruby-complete jar</description>
  <target name="dist" description="Create the deliverable jar">
    <taskdef name="jarjar" 
             classname="com.tonicsystems.jarjar.JarJarTask" 
             classpath="vendor/jarjar-1.0rc7.jar"/>
    <mkdir dir="pkg"/>
    <jarjar destfile="pkg/livesync.jar">
      <manifest>
        <attribute name="Main-Class" value="livesync.LiveSyncRunner"/>
      </manifest>
      <fileset dir="classes"/>
      <zipfileset dir="vendor/gems" prefix="vendor/gems"/>
      <zipfileset src="vendor/jruby-complete-1.1.2.jar" />
    </jarjar>
  </target>
</project>

Things you might have to change here are:

  • name of Main-Class - this have to much name of your java wrapper (loading ruby script)
  • add/remove some zipfilesets

You also need to include files jruby-complete-1.1.2.jar and jarjar-1.0rc7.jar in the vendor directory. You should google them out without any problem.

After doing this you just go to root directory and run ant. After this you can run your script with

java -jar pkg/livesync.jar args1 agrs2 ...

Hope this helps!

Marek Kowalski
+3  A: 

You can try using Warbler for this. As of version 1.1, Warbler supports making a war file "executable". See the documentation for details.

Basically, install warbler and try running it on your Sinatra application. If you have a config.ru, everything should pretty much work.

$ jruby -S gem install warbler
$ jruby -S warble executable war
$ java -jar my_app.war
Nick Sieger
TNX, I've already tried that... The only problem appears with some gem "installed" with Bundler (eg: nokogiri).
Carlo Pecchia