Package Sinatra app into a single JAR file?

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

Answers


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

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!


Starting with a jruby-complete jar file; unzip the jar. You can then install your gems into the exploded jar.

jruby.home in the META-INF directory is where the "usual" jruby install is located. You can use the gem within that directory.

Next, in the jruby.home directory, make a directory, let's call it app and place your app in it.

Next you'll need to create a script to run in the bin directory which starts your application.

TEST and make sure everything is working.

Then zip everything back up, creating a file such as app.jar.

Finally, to run:

  java -jar app.jar -S YOUR_SCRIPT

-or- muck about with the manifest and create a java class which is functionally similar to the script.


Need Your Help

Button click sticks in active state and wont change until click function completes (workaround?)

jquery click jquery-events

I have this button making an ajax call using a click event. My goal is to make it so that the text inside the button changes from "submit" to "loading..." when I make that ajax call. The problem is...