You did know that you can write Ruby scripts, even those that use popular frameworks like Ruby on Rails or Sinatra and deploy them to the Java Application Server’s JVM of your portal environment? Right?
Well, you can. And this blog details how, with a simple example for an “Hello World” Sinatra/Rack application.
So, follow along with all the steps and do it yourself. Or cheat, and download my WAR archive to be found at the end of this post and deploy it directly to your SAP JVM (and then go and hack the WAR archive)!
We will use a wonderful technology called Jruby:
As it self-describes itself at http://jruby.org/, with JRuby you get the best of the JVM, but at the same time it is ‘just Ruby’. Basically JRuby is an implementation of Ruby, written mostly in Java. Wikipedia has a good page that describes it well. The important thing is that, for JRuby support, you’re going to need a modern version of Java. I can confirm that a SAP NetWeaver AS Java 7.30 system using SAP JVM 6 serves as a suitable host for deployment with Jruby 1.7.2.
So, how to begin? Firstly we will need to get JRuby itself and then certain ruby gems (sinatra/warbler/rack/bundler). In ruby parlace, a gem is a packaged ruby application or library. You can do this in the environment you prefer: Windows, Mac, *BSD or Linux. I’m going to assume that you’ll be able to follow along with the documentation and that you’ll be able to set this up for yourself because depending on which operating system you select the process will be slightly different. So the steps that I will be describing here may not match what you need to do to get started.
In my case my system is Linux (Debian 6.0.6 squeeze) and I make use of the RVM (ruby version management) system. I’ve already installed JRuby 1.7.2 as a ruby using RVM, and then these are the steps that I performed to create a gemset that contains the gems that are required:
$ rvm use jruby-1.7.2 Using /home/jgroll/.rvm/gems/jruby-1.7.2 $ rvm gemset create jrubydemo gemset created jrubydemo => /home/jgroll/.rvm/gems/jruby-1.7.2@jrubydemo $ rvm use jruby@jrubydemo Using /home/jgroll/.rvm/gems/jruby-1.7.2 with gemset jrubydemo $ gem install sinatra rack rubygems-bundler warbler Fetching: rack-1.5.2.gem (100%) Fetching: rack-protection-1.3.2.gem (100%) Fetching: tilt-1.3.3.gem (100%) Fetching: sinatra-1.3.4.gem (100%) Successfully installed rack-1.5.2 Successfully installed rack-protection-1.3.2 Successfully installed tilt-1.3.3 Successfully installed sinatra-1.3.4 Successfully installed rack-1.5.2 Fetching: rubygems-bundler-1.1.0.gem (100%) Successfully installed rubygems-bundler-1.1.0 Fetching: jruby-jars-1.7.2.gem (100%) Fetching: jruby-rack-220.127.116.11.gem (100%) Fetching: rubyzip-0.9.9.gem (100%) Fetching: warbler-1.3.6.gem (100%) Successfully installed jruby-jars-1.7.2 Successfully installed jruby-rack-18.104.22.168 Successfully installed rubyzip-0.9.9 Successfully installed warbler-1.3.6 10 gems installed
So, the gems we’ve installed are the following (plus their dependancies):
sinatra – a light web framework
rack – provides a consistent minimal and modular interface for web applications
bundler – assists with bundling and tracking the ruby gems needed
warbler – a gem to make a Java JAR or WAR file out of your application
We’ll now create a folder for our application (call it jrubydemo), and into that folder create a file called jrubydemo.rb containing the actual code for our application:
require 'sinatra/base' class JrubyDemo < Sinatra::Base get '/' do 'Hello world!' end end
Yes, it is as simple as that. We have a handler that responds to a GET request of the root url (‘/’) by sending the plain text response of Hello World!
Then, inside your jrubydemo folder create another folder called ‘config’ and in that folder create a file called ‘warble.rb’ which looks like this:
Warbler::Config.new do |config| # Application directories to be included in the webapp. config.dirs = %w() # Additional files/directories to include, above those in config.dirs config.includes = FileList["jrubydemo.rb"] # Set JRuby to run in 1.9 mode. config.webxml.jruby.compat.version = "1.9" end
This file tells warbler what to put into the WAR archive.
Following this, we create a rackup file which tells rack how to start the application. So, inside the main jrubydemo folder create a file called config.ru that contains:
require 'rubygems' require 'bundler' Bundler.require require './jrubydemo' run JrubyDemo
Next, we will need to tell bundler which gems are required by our app (sinatra in our case). So inside the main jrubydemo folder create a file called Gemfile which contains:
source "https://rubygems.org" gem "sinatra", :require => "sinatra/base"
Bundler tracks an application’s code and the rubygems it needs by creating a file called Gemfile.lock. Let’s create it now:
$ bundle install Fetching gem metadata from https://rubygems.org/........... Fetching gem metadata from https://rubygems.org/.. Using rack (1.5.2) Using rack-protection (1.3.2) Using tilt (1.3.3) Installing sinatra (1.3.5) Using bundler (1.2.3) Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
At last we are in a position where we can create the WAR archive which we’ll be deploying which is done as follows at the command line:
$ warble pluginize $ warble war:clean rm -f jrubydemo.war $ warble war rm -f jrubydemo.war Creating jrubydemo.war
The jrubydemo.war archive that it has created is actually quite large when you consider that it only contains a seven line Sinatra app. On my system it was 18M in size. It is this size because it contains three large JAR archives for the JRuby interpreter (if you’re interested, open up the .war archive in a zip tool, like 7-zip and look inside the WEB-INF/lib folder). The WAR archive also contains some of the ruby gems which our app requires.
Now that we have our WAR archive we are in a position where we can deploy it. You can try and deploy it directly to your SAP Java Application Server, or like me you can play it safe and deploy it to a Tomcat server first as a test to see that deployment is possible. To be clear then you can skip this step altogether if it is too much work to first try a test deploy or to install Tomcat or a similar server.
So, to deploy to Tomcat I simply move the .war archive to my Tomcat’s webapps folder:
$ sudo cp jrubydemo.war /var/lib/tomcat6/webapps/
Then in my case I accessed the app from Tomcat, by visiting
And it worked!
To deploy to the SAP Java Application Server, the easiest method is to use the deployment perspective of Netweaver Developer Studio (NWDS). Alternatively, you could ask your friendly basis admin 😉
Note that it was necessary to set the option to ignore the version number – I have no idea why it decides that the version number of the app is 42 (it could be the answer to life, the universe and everything if you find out). The thing is the version always stays at 42, even if you rebuild your WAR archive, and this could prevent further deployments after you’ve made any changes to your app. So, the setting “update deployed archives with any version” needs to be selected.
It deployed perfectly to my SAP Java Application Server:
How to cheat:
I thoroughly endorse cheating here, except it isn’t really cheating. If you’re struggling to build your own WAR archive using the above steps simply use mine (for the security savvy the md5sum of this file is b8d9bceefcc13805f0326c28b4b458a5). And, if deploying the WAR works for you, feel free to also hack my WAR archive. In order to hack it, open it up in a tool like 7-zip and edit the jrubydemo.rb file. Then redeploy it – you may not need to remake the entire WAR archive if your changes do not need extra ruby gems.
Where to from here? You could make the sinatra app do more things, and make it into a useful application that does more than render Hello World. Or, you change it into a program that uses one of the standard ruby libraries to do something powerful. The world is your oyster: you could write your own mashup, scrape web pages with style, parse JSON, or create your own REST API. And, of course, you can create an app that uses the powerful and popular ruby on rails framework and it is even possible to do so with an app that references java JAR archives.