JRuby-Rack is a lightweight adapter for the Java servlet environment that allows any Rack-based application to run unmodified in a Java servlet container. JRuby-Rack supports Rails, Merb, as well as any Rack-compatible Ruby web framework.
For more information on Rack, visit http://rack.rubyforge.org.
The easiest way to use JRuby-Rack is to get Warbler. Warbler depends on the latest version of JRuby-Rack and ensures it gets placed in your WAR file when it gets built.
If you're assembling your own WAR using other means, you can install the
jruby-rack gem. It provides a method to located the jruby-rack jar file:
require 'fileutils' require 'jruby-rack' FileUtils.cp JRubyJars.jruby_rack_jar_path, '.'
Otherwise you'll need to download the latest JRuby-Rack jar, drop it into the WEB-INF/lib directory and configure the RackFilter in your application's web.xml. Example web.xml snippets are as follows.
Here's sample web.xml configuration for Rails. Note the environment and min/max runtime parameters. For multi-threaded Rails with a single runtime, set min/max both to 1. Otherwise, define the size of the runtime pool as you wish.
<context-param> <param-name>rails.env</param-name> <param-value>production</param-value> </context-param> <context-param> <param-name>jruby.min.runtimes</param-name> <param-value>1</param-value> </context-param> <context-param> <param-name>jruby.max.runtimes</param-name> <param-value>1</param-value> </context-param> <filter> <filter-name>RackFilter</filter-name> <filter-class>org.jruby.rack.RackFilter</filter-class> </filter> <filter-mapping> <filter-name>RackFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.jruby.rack.rails.RailsServletContextListener</listener-class> </listener>
Here's a sample web.xml configuration for a Sinatra application. The main difference is to place the rackup script for assembling the Rack-based application in the 'rackup' parameter. Be sure to escape angle-brackets for XML.
<context-param> <param-name>rackup</param-name> <param-value> require 'rubygems' gem 'sinatra', '~> 0.9' require './lib/demo' set :run, false set :environment, :production run Sinatra::Application </param-value> </context-param> <filter> <filter-name>RackFilter</filter-name> <filter-class>org.jruby.rack.RackFilter</filter-class> </filter> <filter-mapping> <filter-name>RackFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.jruby.rack.RackServletContextListener</listener-class> </listener>
JRuby-Rack's main mode of operation is as a servlet filter. This allows requests for static content to pass through and be served by the application server. Dynamic requests only happen for URLs that don't have a corresponding file, much like many Ruby applications expect. The application can also be configured to dispatch through a servlet instead of a filter if it suits your environment better.
- Servlet context is accessible to any application both through the global variable $servlet_context and the Rack environment variable java.servlet_context.
- Servlet request object is available in the Rack environment via the key java.servlet_request.
- Servlet request attributes are passed through to the Rack environment.
- Rack environment variables and headers can be overridden by servlet request attributes.
- Java servlet sessions are available as a session store for both Rails and Merb. Session attributes with String keys and String, numeric, boolean, or java object values are automatically copied to the servlet session for you.
Several aspects of Rails are automatically set up for you.
- The Rails controller setting ActionController::Base.relative_url_root is set for you automatically according to the context root where your webapp is deployed.
- Rails logging output is redirected to the application server log.
- Page caching and asset directories are configured appropriately.
JRuby runtime management and pooling is done automatically by the framework. In the case of Rails, runtimes are pooled. For Merb and other Rack applications, a single runtime is created and shared for every request.
JRuby-Rack can be configured by setting context init parameters in web.xml.
rackup: Rackup script for configuring how the Rack application is mounted. Required for Rack-based applications other than Rails or Merb. Can be omitted if a
config.ruis included in the application root.
jruby.min.runtimes: For non-threadsafe Rails applications using a runtime pool, specify an integer minimum number of runtimes to hold in the pool.
jruby.max.runtimes: For non-threadsafe Rails applications, an integer maximum number of runtimes to keep in the pool.
jruby.init.serial: When using runtime pooling, indicate that the runtime pool should be created serially in the foreground rather than spawning background threads. For environments where creating threads is not permitted.
public.root: Relative path to the location of your application's static assets. Defaults to
gem.path: Relative path to the bundled gem repository. Defaults to
merb.root: Root path to the location of the Rails or Merb application files. Defaults to
rails.env: Specify the Rails environment to run. Defaults to 'production'.
rails.relative_url_append: Specify a path to be appended to the ActionController::Base.relative_url_root after the context path. Useful for running a rails app from the same war as an existing app, under a sub-path of the main servlet context root.
merb.environment: Specify the merb environment to run. Defaults to
jruby.rack.logging: Specify the logging device to use. Defaults to
servlet_context. See below.
jruby.rack.slash.index: Force rewriting of requests that end in '/' to be passed through to the container as '/index.html'. Default is false, but is turned on for Jetty by default to avoid triggering directory index pages.
JRuby-Rack sets up a delegate logger for Rails that sends logging
javax.servlet.ServletContext#log by default. If you wish
to use a different logging system, set the
context parameter as follows:
servlet_context(default): Sends log messages to the servlet context.
stdout: Sends log messages to the standard output stream
commons_logging: Sends log messages to Apache commons-logging. You still need to configure commons-logging with additional details.
slf4j: Sends log messages to SLF4J. Again, SLF4J configuration is left up to you.
For those loggers that require a specific named logger, set it in the
jruby.rack.logging.name context parameter.
Checkout the JRuby Rack code and cd to that directory.
git clone git://kenai.com/jruby-rack~main jruby-rack cd jruby-rack
You can choose to build with either Maven or Rake. Either of the following two will suffice (but see the NOTE below).
mvn install jruby -S rake
The generated jar should be located here: target/jruby-rack-*.jar.
This example shows how to create and deploy a simple Rails app using the embedded Java database H2 to a WAR using Warble and JRuby Rack. JRuby Rack is now included in the latest release of Warbler (0.9.9), but you can build your own jar from source and substitute it if you like.
Install Rails and the driver and ActiveRecord adapters for the H2 database:
jruby -S gem install rails activerecord-jdbch2-adapter
jruby -S gem install warbler
Make the "Blog" application
jruby -S rails blog cd blog
Copy this configuration into config/database.yml:
development: adapter: jdbch2 database: db/development_h2_database test: adapter: jdbch2 database: db/test_h2_database production: adapter: jdbch2 database: db/production_h2_database
Generate a scaffold for a simple model of blog comments.
jruby script/generate scaffold comment name:string body:text
Run the database migration that was just created as part of the scaffold.
jruby -S rake db:migrate
Start your application on the Rails default port 3000 using Mongrel/ and make sure it works:
Generate a custom Warbler WAR configuration for the blog application
jruby -S warble config
Generate a production version of the H2 database for the blog application:
RAILS_ENV=production jruby -S rake db:migrate
Edit this file: config/warble.rb and add the following line after these comments:
# Additional files/directories to include, above those in config.dirs # config.includes = FileList["db"] config.includes = FileList["db/production_h2*"]
This will tell Warble to include the just initialized production H2 database in the WAR.
Continue editing config/warble.rb and add the following line after these comments:
# Gems to be packaged in the webapp. Note that Rails gems are added to this # list if vendor/rails is not present, so be sure to include rails if you # overwrite the value # config.gems = ["activerecord-jdbc-adapter", "jruby-openssl"] # config.gems << "tzinfo" # config.gems["rails"] = "1.2.3" config.gems << "activerecord-jdbch2-adapter"
This will tell Warble to add the JDBC driver for H2 as well as the ActiveRecord JDBC and JDBC-H2 adapter Gems.
Now generate the WAR file:
jruby -S warble war
This task generates the file: blog.war at the top level of the application as well as an exploded version of the war located here: tmp/war.
The war should be ready to deploy to your Java application server.
- All contributors! But also:
- Dudley Flanders, for the Merb support
- Robert Egglestone, for the original JRuby servlet integration project, Goldspike
- Chris Neukirchen, for Rack
- Sun Microsystems, for early project support