Thursday Jul 30, 2009

TOTD #87: How to fix the error undefined method `new' for "Rack::Lock":String caused by Warbler/JRuby-Rack ?


If you are using Warbler to create a WAR file of your application and deploying on GlassFish or any other Servlet container, then you are likely seeing the following error during deployment:

[#|2009-07-30T15:29:50.788-0700|SEVERE|sun-appserver2.1|javax.enterprise.system.container.web|_ThreadID=17;
_ThreadName=httpWorkerThread-4848-0;_RequestID=1d7e8f18-1c9a-4924-bd0b-6a07eba425ba;|WebModule
[/session]unable to create shared application instance
org.jruby.rack.RackInitializationException: undefined method `new' for "Rack::Lock":String
        from /Users/arungupta/tools/glassfish/v2.1/glassfish/domains/domain1/applications/j2ee-modules/session/WEB-INF/gems/gems/actionpack-2.3.2/lib/
action_controller/middleware_stack.rb:116:in `inject'
        from /Users/arungupta/tools/glassfish/v2.1/glassfish/domains/domain1/applications/j2ee-modules/session/WEB-INF/gems/gems/actionpack-2.3.2/lib/
action_controller/middleware_stack.rb:116:in `build'
        from /Users/arungupta/tools/glassfish/v2.1/glassfish/domains/domain1/applications/j2ee-modules/session/WEB-INF/gems/gems/actionpack-2.3.2/lib/
action_controller/dispatcher.rb:82:in `initialize'

. . .

This is a known issue as reported at JRUBY-3789 and JRUBY_RACK-18.

As the bug report indicates, this is actually an issue with jruby-rack-0.9.4 and is fixed in jruby-rack-0.9.5. The 3-step workaround is described here and explained below for convenience:
  1. Do "warble war:clean" to clean up the .war file and staging area. This basically removes previous version of jruby-rack.jar.
  2. Download the latest jruby-rack-0.9.5 snapshot (complete list) and copy in the "lib" directory of your application.
  3. If "config/warble.rb" does not exist then generate it using "jruby -S config warble". Edit "config/warble.rb" such that it looks like:

      # Additional Java .jar files to include. Note that if .jar files are placed
      # in lib (and not otherwise excluded) then they need not be mentioned here.
      # JRuby and JRuby-Rack are pre-loaded in this list. Be sure to include your
      # own versions if you directly set the value
      # config.java_libs += FileList["lib/java/\*.jar"]
      config.java_libs.delete_if {|f| f =~ /jruby-rack/ }
      config.java_libs += FileList["lib/jruby-rack\*.jar"]

    This will pack jruby-rack-0.9.5 snapshot instead of the one bundled with Warbler.

    Now warbler 1.0.0 bundles "jruby-complete-1.3.0RC1.jar". Optionally, you can also download the latest jruby-complete (jruby-complete-1.3.1.jar as of this writing) and copy in the "lib" directory of your application. In that case, modify the above fragment to:

      # Additional Java .jar files to include. Note that if .jar files are placed
      # in lib (and not otherwise excluded) then they need not be mentioned here.
      # JRuby and JRuby-Rack are pre-loaded in this list. Be sure to include your
      # own versions if you directly set the value
      # config.java_libs += FileList["lib/java/\*.jar"]
      config.java_libs.delete_if {|f| f =~ /jruby-rack/ || f =~ /jruby-complete/ }
      config.java_libs += FileList["lib/jruby-complete\*.jar"]
      config.java_libs += FileList["lib/jruby-rack\*.jar"]

    This packs the "jruby-complete-1.3.1.jar" in your .war file.
And now follow your regular procedure of creating the .war file using "jruby -S warble" and happily deploy your Rails/Sintara/Merb applications on GlassFish.

There are several users who are already using Rails on GlassFish in production environment and they are listed at rubyonrails+glassfish+stories. Drop a comment on this blog if you are using it too :)

Technorati: jruby rack glassfish war servlet rubyonrails

Monday May 04, 2009

Rails Conf 2009 - Day 1 Trip Report


Rails Conf 2009 started this morning. The first day consists of morning and afternoon tutorials.

I attended Nick Sieger's JRuby on Rails tutorial, the slides are available. A survey in the room showed:
  • 95% comfortable with Ruby/Rails
  • 80% have used JRuby
  • 10% use JRuby actively
Here are some of the key points highlighted in the tutorial:

Why JRuby ?
  • JRuby is "Less Bitter Java", after all Java is a great platform.
  • Concurrency (Native threading)
  • Reliability (well-behaved because of Hotspot compiler, no process monitoring, etc)
  • Encapsulation (take a Rails application, bundle it as a single deployable artifact that is fully contained)
  • Choice (Any Java application server, huge breadth of Java libraries, and can write thin Ruby wrappers around Java libraries)
Download JDK 5 minimum, JDK 6 preferred, MySQL 5.x, JRuby 1.2 (1.3.0 RC1 OK too), GlassFish v2.1 b60e

Common options
  • --server: Run with server VM, better performance
  • --headless: No UI
  • --properties: Show tweaks for compiler, JIT compiling,  thread pooling etc
  • -J<java-opt>: Pass any Java properties
  • -J-Xmx1G: Increase memory to 1G
Drawbacks: No fork(), No native extensions (for example ParseTree, EventMachine, RMagic cannot be used), No tty for subprocesses, Startup time slow for short scripts

Advantages: Improved versions of some Ruby APIs (tempfile, mutex, thread, timeout), 1.8 and 1.9 in a single install (jruby --1.9), Wrap Java libraries and APIs in Ruby

The slides have much more details in terms of deployment options (WAR-based, GlassFish Gem), and many other interesting details Scroll to slide #68 to understand all the guts of kenai.com - a real life application running using JRuby, Rails, and GlassFish.

The afternoon tutorial for me was A Hat Full of Tricks with Sinatra. The tutorial was completely code driven with no slides, just love that format!

The tutorial started with a brief introduction to Rack. A basic Rack application can be "config.ru" or "app.rb", lets start with "config.ru" Hello World:

run lambda { |env|
  [
    200,
    {
    'Content-Length' => '2',
    'Content-Type' => 'text/html',
    },
    ["hi"]
  ]
}

Run it as ...

~/samples/railsconf/sinatra/basic-rack >~/tools/jruby/bin/jruby -S rackup
[2009-05-04 13:40:18] INFO  WEBrick 1.3.1
[2009-05-04 13:40:18] INFO  ruby 1.8.6 (2009-03-16) [java]
[2009-05-04 13:40:18] INFO  WEBrick::HTTPServer#start: pid=90964 port=9292
127.0.0.1 - - [04/May/2009 13:40:27] "GET / HTTP/1.1" 200 2 0.0160
127.0.0.1 - - [04/May/2009 13:40:27] "GET /favicon.ico HTTP/1.1" 200 2 0.0060
127.0.0.1 - - [04/May/2009 13:40:30] "GET /favicon.ico HTTP/1.1" 200 2 0.0100

"config.ru" is the default Rackup script, otherwise need to specify the name. And now "app.rb" ..

App = lambda { |env|
  [
    200,
    {
    'Content-Length' => '2',
    'Content-Type' => 'text/html',
    },
    ["hi"]
  ]
}

And run it as ...

~/samples/railsconf/sinatra/basic-rack >~/tools/jruby/bin/jruby -S rackup app.rb
[2009-05-04 13:43:57] INFO  WEBrick 1.3.1
[2009-05-04 13:43:57] INFO  ruby 1.8.6 (2009-03-16) [java]
[2009-05-04 13:43:57] INFO  WEBrick::HTTPServer#start: pid=90990 port=9292
127.0.0.1 - - [04/May/2009 13:44:09] "GET / HTTP/1.1" 200 2 0.0110

In both cases, the application is accessible at "http://localhost:9292".

Change the basic "config.ru" to convert into a class as ...

class BasicRack
     def call(env)
      body = "Hello from a class"
      [
        200,
        {
        'Content-Length' => body.size.to_s,
        'Content-Type' => 'text/html',
        },
        [body]
      ]
    end
end

run BasicRack.new

and run the same way as earlier.

Change body to "env.inspect" to see an output as:



Sinatra allows reloading of application but that "feature" will be removed soon. Instead install shotgun (which does not work with JRuby yet!). Anyway, install the gem:

~/samples/railsconf/sinatra/basic-rack >~/tools/jruby/bin/jruby -S gem install shotgun
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Successfully installed configuration-0.0.5
Successfully installed launchy-0.3.3
Successfully installed shotgun-0.2
3 gems installed
Installing ri documentation for launchy-0.3.3...
Installing RDoc documentation for launchy-0.3.3...

And run as:

~/samples/railsconf/sinatra/basic-rack >~/tools/jruby/bin/jruby -J-Djruby.fork.enabled=true -S shotgun
[2009-05-04 13:55:46] INFO  WEBrick 1.3.1
[2009-05-04 13:55:46] INFO  ruby 1.8.6 (2009-03-16) [java]
== Shotgun starting Rack::Handler::WEBrick on localhost:9393
[2009-05-04 13:55:46] INFO  WEBrick::HTTPServer#start: pid=91089 port=9393

Process separate bodies depending upon the info:

class BasicRack
     def call(env)
      body = if env["PATH_INFO"] == "/foo"
        "in foo"
      else
       "in other"
      end
      [
        200,
        {
        'Content-Length' => body.size.to_s,
        'Content-Type' => 'text/html',
        },
        [body]
      ]
    end
end

run BasicRack.new

Accessing "http://localhost:9292/foo" shows "in foo" and accessing "http://localhost:9393" shows "in other".

Target application is the last application specified by "run".

Rack supports middleware which are like filters, they can applied before/after a message is processed.

Rack will initialize middleware at load, so hold on to that application as shown:

class BasicRackApp
     def call(env)
      body = "hello from app"
      [
        200,
        {
        'Content-Length' => body.size.to_s,
        'Content-Type' => 'text/html',
        },
        [body]
      ]
    end
end

class MyMiddleware
    def initialize(app)
        @app = app
    end
   
    def call(env)
        @app.call(env)
    end
end

use MyMiddleware

run BasicRackApp.new

@app.call calls the next middleware in the chain.

Rack comes with couple of standard middleware, e.g.:

use Rack::CommonLogger

Example of an after filter:

    def call(env)
        status, headers, body = @app.call(env)
        body.map! { |part| part.upcase}
        [status, headers, body]
    end

Lots of other filters available.

With a basic Rack understanding, lets build a Sinatra app:

require 'sinatra'

is the simplest Sinatra application. Save it in a file "basic-sinatra.rb" and run it as:

~/samples/railsconf/sinatra/basic-sinatra >~/tools/jruby/bin/jruby -rubygems basic-sinatra.rb
== Sinatra/0.9.1.1 has taken the stage on 4567 for development with backup from WEBrick
[2009-05-04 14:40:14] INFO  WEBrick 1.3.1
[2009-05-04 14:40:14] INFO  ruby 1.8.6 (2009-03-16) [java]
[2009-05-04 14:40:14] INFO  WEBrick::HTTPServer#start: pid=91396 port=4567

The application is now available at "http://localhost:4567". BTW, this app can easily be run using GlassFish Gem as explained  in TOTD #79. Add a simple GET method and "not_found" handler as:

require 'rubygems'
require 'sinatra'

not_found do
  'hi from other'
end

get '/foo' do
    'hi from foo'
end

Every time a request comes in, it builds a request context, instance evals lambda and finds the one that hits.

Sinatra takes care of status and headers, the application needs to process the body.

Another one ...

require 'rubygems'
require 'sinatra'

get '/env' do
    env.inspect
end

And it shows Rack environment hash at 'http://localhost:4567".

Another one ...

require 'rubygems'
require 'sinatra'

get '/' do
end

post '/' do
end 

put '/' do
end

delete '/' do
end

This adds 4 HTTP methods with different routes.

No explicit render method, e.g.

require 'rubygems'
require 'sinatra'

get '/' do
  content_type "application/json"
  { "foo" => "goo" }.to_json
end

No ".rhtml.erb" or ".json.erb", instead it's just ".erb". Add "views/index.erb" as:

<html>
  <body>
  Hello form Sinatra + ERB
  </body>
  </html>

And change GET method to:

require 'rubygems'
require 'sinatra'

get '/' do
  erb :index
end

And the application now uses ERB templating.

Using HAML templates is simple, change to:

require 'rubygems'
require 'sinatra'
require 'haml'

get '/' do
  haml :index
end

And add "views/index.haml" as:

%html
  %body
    %h1 Hello from HAML

And now the application is using HAML templates.

__END__ is the end of Ruby, can be anything after that and it'll not barf. Sinatra uses it for in file templates:

require 'rubygems'
require 'sinatra'
require 'haml'

get '/' do
  erb :index
end

use_in_file_templates!

__END__

@@ index

<html>
  <body>
  Hello form Sinatra + ERB in file
  </body>
  </html>

Start with in-file templates, and then move out to separate directory ("views") once grows big. But no syntax highlighting etc.

Add your custom template as:

require 'rubygems'
require 'sinatra'
require 'haml'

get '/' do
  erb :index
end

get '/foo' do
  erb :foo
end

use_in_file_templates!

__END__

@@ index

<html>
  <body>
  Hello form Sinatra + ERB in file
  </body>
  </html>
 
@@ foo
<h1>FOO!</h1>

With this file "http://localhost:4567/" uses ERB template, and "http://localhost:4567/foo" uses "foo" template.

Sinatra defines on Main. The before filters work before every single request, executed in the same context as lambda. Can be used if every request needs to do some setup.

Helpers can be defined as:

require 'rubygems'
require 'sinatra'
require 'haml'

helpers do
 
end

without defining on Main. Or ...

require 'rubygems'
require 'sinatra'
require 'haml'

module helpers
    def self.dosomething(arg)
    end
end

get '/' do
    Helpers.dosomething
end

Don't define something on Main, it's a bad practice.

Extension is a nice package that can be shared for other Sinatra developers to use, like Rails plugins but does not have boilerplate, much easier to do.

Rest of tutorial was quite fast paced so the code samples could not be captured. But there is boatload of information available at sinatrarb.com.

Check out the pictures from Day 1:


The evening concluded with dinner at Burger Bar at Mandalay Bay along with Project Kenai team.

And check the evolving album at:



On to GlassFish talk tomorrow, and running with @railsConfRunner in the morning before that :)

Technorati: conf railsconf lasvegas jruby rubyonrails sinatra glassfish

Friday Nov 14, 2008

TOTD #52: Getting Started with Merb using GlassFish Gem

GlassFish Gem 0.9.0 was recently released. It can run any Rack-compatible framework such as Rails and Merb. Support for another Rack-based framework Sinatra will be released in the near future. The gem is even extensible and allows to plug any of your favorite Ruby framework using -apptype switch (more on this in a future blog). This blog shows how to install the gem and use it for running a Merb application.



Lets install the gem first:

~/tools/jruby-1.1.5 >gem install glassfish rack
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Successfully installed glassfish-0.9.0-universal-java
Successfully installed rack-0.4.0
2 gems installed
Installing ri documentation for glassfish-0.9.0-universal-java...
Installing ri documentation for rack-0.4.0...
Installing RDoc documentation for glassfish-0.9.0-universal-java...
Installing RDoc documentation for rack-0.4.0...

The Rack dependency will be fixed as part of the next gem update and for now we have to install it explicitly. The different options supported by the gem can be seen using "-h" switch as:

~/tools/jruby-1.1.5 >glassfish -h

Synopsis
--------
glassfish: GlassFish v3 server for rails, merb, sintra applications


Usage:
------
glassfish [OPTION] APPLICATION_PATH

-h, --help:             show help

-c, --contextroot PATH: change the context root (default: '/')

-p, --port PORT:        change server port (default: 3000)

-e, --environment ENV:  change rails environment (default: development)

-n --runtimes NUMBER:   Number of JRuby runtimes to crete initially

--runtimes-min NUMBER:  Minimum JRuby runtimes to crete

--runtimes-max NUMBER:  Maximum number of JRuby runtimes to crete

APPLICATION_PATH (optional): Path to the application to be run (default:
current).

And complete rdocs are available here.

Lets create and run a Merb application!
  1. Install Merb: Merb 1.0 has some native dependencies in DataMapper and so cannot be installed as is with JRuby. However since Merb is ORM-agnostic, ActiveRecord can be installed as ORM layer. "gem install merb" uses DataMapper as the default ORM so a Merb installation in JRuby (for now) is:

    ~/tools/jruby-1.1.5 >gem install merb-core merb-more merb_activerecord
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Successfully installed extlib-0.9.8
    Successfully installed abstract-1.0.0
    Successfully installed erubis-2.6.2
    Successfully installed json_pure-1.1.3
    Successfully installed rack-0.4.0
    Successfully installed mime-types-1.15
    Successfully installed thor-0.9.8
    Successfully installed merb-core-1.0
    Successfully installed ZenTest-3.11.0
    Successfully installed RubyInline-3.8.1
    Successfully installed sexp_processor-3.0.0
    Successfully installed ParseTree-3.0.2
    Successfully installed ruby2ruby-1.2.1
    Successfully installed merb-action-args-1.0
    Successfully installed merb-assets-1.0
    Successfully installed merb-slices-1.0
    Successfully installed merb-auth-core-1.0
    Successfully installed merb-auth-more-1.0
    Successfully installed merb-auth-slice-password-1.0
    Successfully installed merb-auth-1.0
    Successfully installed merb-cache-1.0
    Successfully installed merb-exceptions-1.0
    Successfully installed highline-1.5.0
    Successfully installed diff-lcs-1.1.2
    Successfully installed templater-0.4.0
    Successfully installed merb-gen-1.0
    Successfully installed haml-2.0.4
    Successfully installed merb-haml-1.0
    Successfully installed merb-helpers-1.0
    Successfully installed mailfactory-1.4.0
    Successfully installed merb-mailer-1.0
    Successfully installed merb-param-protection-1.0
    Successfully installed addressable-1.0.4
    Successfully installed data_objects-0.9.6
    Successfully installed dm-core-0.9.6
    Successfully installed dm-migrations-0.9.6
    Successfully installed merb_datamapper-1.0
    Successfully installed merb-more-1.0
    Successfully installed merb_activerecord-0.9.13
    39 gems installed
    Installing ri documentation for json_pure-1.1.3...
    Installing ri documentation for rack-0.4.0...
    Installing ri documentation for mime-types-1.15...
    . . .
    Installing RDoc documentation for dm-migrations-0.9.6...
    Installing RDoc documentation for merb_datamapper-1.0...
    Installing RDoc documentation for merb_activerecord-0.9.13...

    It would be nice if this can be further simplified to "gem install merb --orm activerecord" or something similar.
  2. Create a Merb application:  A "jump start" Merb application created using "merb-gen app" uses ERB templating and DataMapper for ORM. But as mentioned earlier DataMapper does not work with JRuby (at least for now) so a Merb application needs to be created using "merb-gen core". This command creates a Merb application with Ruby-on-Rails like structure and allows to plugin templating engine and ORM frameworks.

    Lets create our first Merb application with no ORM and default templating engine as:

    ~/samples/jruby/merb >merb-gen core hello
    Generating with core generator:
         [ADDED]  gems
         [ADDED]  merb.thor
         [ADDED]  .gitignore
         [ADDED]  public/.htaccess
         [ADDED]  doc/rdoc/generators/merb_generator.rb
         [ADDED]  doc/rdoc/generators/template/merb/api_grease.js
         [ADDED]  doc/rdoc/generators/template/merb/index.html.erb
         [ADDED]  doc/rdoc/generators/template/merb/merb.css
         [ADDED]  doc/rdoc/generators/template/merb/merb.rb
         [ADDED]  doc/rdoc/generators/template/merb/merb_doc_styles.css
         [ADDED]  doc/rdoc/generators/template/merb/prototype.js
         [ADDED]  public/favicon.ico
         [ADDED]  public/merb.fcgi
         [ADDED]  public/robots.txt
         [ADDED]  public/images/merb.jpg
         [ADDED]  Rakefile
         [ADDED]  app/controllers/application.rb
         [ADDED]  app/controllers/exceptions.rb
         [ADDED]  app/helpers/global_helpers.rb
         [ADDED]  app/views/exceptions/not_acceptable.html.erb
         [ADDED]  app/views/exceptions/not_found.html.erb
         [ADDED]  autotest/discover.rb
         [ADDED]  autotest/merb.rb
         [ADDED]  autotest/merb_rspec.rb
         [ADDED]  config/init.rb
         [ADDED]  config/rack.rb
         [ADDED]  config/router.rb
         [ADDED]  config/environments/development.rb
         [ADDED]  config/environments/production.rb
         [ADDED]  config/environments/rake.rb
         [ADDED]  config/environments/staging.rb
         [ADDED]  config/environments/test.rb
         [ADDED]  public/javascripts/application.js
         [ADDED]  public/stylesheets/master.css
         [ADDED]  spec
         [ADDED]  app/views/layout/application.html.erb

    ActiveRecord can be used as pluggable ORM by using the command "merb-gen core --orm activerecord hello". A future blog will cover creating a Merb scaffold using ActiveRecord.
  3. Create a new controller as:

    ~/samples/jruby/merb/hello >merb-gen controller Runners
    Loading init file from /Users/arungupta/samples/jruby/merb/jruby-1.1.5/samples/merb/hello/config/init.rb
    Loading /Users/arungupta/samples/jruby/merb/jruby-1.1.5/samples/merb/hello/config/environments/development.rb
    Generating with controller generator:
    Loading init file from /Users/arungupta/samples/jruby/merb/jruby-1.1.5/samples/merb/hello/config/init.rb
    Loading /Users/arungupta/samples/jruby/merb/jruby-1.1.5/samples/merb/hello/config/environments/development.rb
         [ADDED]  app/controllers/runners.rb
         [ADDED]  app/views/runners/index.html.erb
         [ADDED]  spec/requests/runners_spec.rb
         [ADDED]  app/helpers/runners_helper.rb

    Notice the convention of controller name is a plural word and starting with a capital letter.
  4. Edit application
    1. Edit "app/controllers/runners.rb" and change the "index" action such that it looks like:

        def index
          @message = "Miles to go ..."
          render
        end
    2. Edit "app/views/runners/index.html.erb" and add "<br><%= @message %>" as the last line.
  5. Run application:  Running a Merb application using the Gem is pretty straight forward. If JRUBY_HOME/bin is in PATH, just type the command "glassfish" in the application directory and now you are running a Merb application using GlassFish. The application is accessible at "http://localhost:3000" and the output looks like:



    The controller is accessible at "http://localhost:3000/runners" and the output is:

Hit Ctrl+C to stop the application.

A Merb app generated using MRI can also be run using GlassFish, provided it does not have any native dependencies. On my MacBook, I had to update gems (gem update --system) and install XCode.

This same gem can be used to run Rails application, and guess what? That is pretty straight forward too. Just type "glassfish" in the application directory and now you are running a Rails application on GlassFish. These applications can very well be created using MRI but they must be using pure-Ruby gems/plugins. Alternatively Foreign Function Interface can be used to port your native gems to Ruby.

Lets make it more real by running Substruct - an open source E-Commerce project. Install it as explained here, type "glassfish" in the application directory and your application is now accessible at "http://localhost:3000" as shown below:



Really simple, easy and powerful!

Rails powered by GlassFish
explains the benefits of running Rails application on GlassFish. And now GlassFish v3 Prelude allows you to even buy production support for your Rails applications! Screencast #26 how to develop/run/debug your Rails application using NetBeans and GlassFish.

Open Source Rails has a gallery of open source Rails projects, have you tried any of them ?

Is there any Merb equivalent of www.opensourcerails.com ?

Technorati: totd glassfish v3 gem rubyonrails merb rack

Wednesday May 14, 2008

WAR-based Packaging and Deployment of Rails on GlassFish - Goldspike, RailServlet, Warbler, Rack, ...


WAR-based packaging and dispatching of Rails application on Java Application Servers is going through third iteration based what is used for packaging and dispatching:
  • Goldspike + RailsServlet: The first iteration was WAR-packaging of Rails app as defined by Goldspike plugin (nee Rails-integration) and using RailsServlet (part of Goldspike) for dispatching.
  • Warbler + RailsServlet: The second iteration (slightly short lived) overcame the shortcomings of Goldspike (packaging with sane defaults, fast, light-weight, and flexible configuration) by using Warbler for packaging. It decoupled packaging and dispatching by doing only packaging and allowing for pluggable dispatching mechanism. RailsServlet continues to be the default Servlet binding mechanism. This is the version currently supported by GlassFish v2 Update Center.
  • Warbler + Rack:  Nick released JRuby-Rack (JRuby version of Rack, also see Introducing Rack and Docs) last week. And so the third iteration is using Warbler packaging and Rack-based dispatching. JRuby-Rack provides a more seamless connection between the Servlet environment and Rack.

The JRuby-Rack wiki says "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.".

This means that, other than Rails, conceptually Merb applications (which also use Rack for deployment) can now also be deployed on GlassFish. This blog entry explains how to deploy a simple Rack-based Rails application.
  1. Install Rails and JRuby-Rack (as part of Warbler) as:

    ~/testbed/jruby-1.1.1 >bin/jruby -S gem install rails warbler --no-ri --no-rdoc
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Updating metadata for 289 gems from http://gems.rubyforge.org/
    ..............................................................................................................................
    ..............................................................................................................................
    .....................................
    complete
    Successfully installed activesupport-2.0.2
    Successfully installed activerecord-2.0.2
    Successfully installed actionpack-2.0.2
    Successfully installed actionmailer-2.0.2
    Successfully installed activeresource-2.0.2
    Successfully installed rails-2.0.2
    Successfully installed warbler-0.9.9
    7 gems installed
  2. Create a template Rails app as:

    ~/testbed/jruby-1.1.1/samples/rails >../../bin/jruby -S rails hello -d mysql
          create 
          create  app/controllers
          create  app/helpers
          create  app/models
          create  app/views/layouts
          create  config/environments
          . . .
          create  doc/README_FOR_APP
          create  log/server.log
          create  log/production.log
          create  log/development.log
          create  log/test.log
  3. Disable database access from the application by uncommenting line 21 (remove "#" at the beginning) from "config/environment.rb" as:

       config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
  4. Create a WAR file as:

    ~/testbed/jruby-1.1.1/samples/rails/hello >../../../bin/jruby -S warble
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    jar cf hello.war -C tmp/war .

  5. A new file "hello.war" is generated in the current directory.
  6. The generated WAR file can be easily deployed on GlassFish.
    1. Download and Install GlassFish v2 UR2 from here.
    2. Start GlassFish Application Server as:

      ~/testbed/glassfish/v2ur2/glassfish >bin/asadmin start-domain --verbose
      Starting Domain domain1, please wait.
      May 13, 2008 11:23:44 AM com.sun.enterprise.admin.servermgmt.launch.ASLauncher buildCommand
      INFO:
      /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home/bin/java
      . . .

      [#|2008-05-13T11:34:13.252-0700|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=10;_ThreadName=main;4848;|WEB0712: Starting Sun-Java-System/Application-Server HTTP/1.1 on 4848|#]

      [#|2008-05-13T11:34:13.691-0700|INFO|sun-appserver9.1|javax.enterprise.system.core.selfmanagement|_ThreadID=10;_ThreadName=main;|SMGT0007: Self Management Rules service is enabled|#]

      [#|2008-05-13T11:34:13.718-0700|INFO|sun-appserver9.1|javax.enterprise.system.core|_ThreadID=10;_ThreadName=main;|Application server startup complete.|#]
    3. Deploy the WAR on GlassFish as:

      ~/testbed/jruby-1.1.1/samples/rails/hello >~/testbed/glassfish/v2ur2/glassfish/bin/asadmin deploy hello.war
      Command deploy executed successfully.

      The output in the GlassFish console looks like:

      [#|2008-05-13T11:34:23.330-0700|INFO|sun-appserver9.1|javax.enterprise.system.tools.admin|_ThreadID=14;_ThreadName=httpWorkerThread-4848-0;/private/tmp/s1astempdomain1server1547440193/hello.war;|ADM1006:Uploading the file to:[/private/tmp/s1astempdomain1server1547440193/hello.war]|#]

      [#|2008-05-13T11:34:26.019-0700|INFO|sun-appserver9.1|javax.enterprise.system.tools.deployment|_ThreadID=15;_ThreadName=Thread-30;|deployed with moduleid = hello|#]

      [#|2008-05-13T11:34:30.626-0700|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=16;_ThreadName=httpWorkerThread-4848-1;|PWC1412: WebModule[/hello] ServletContext.log():Info: using runtime pool timeout of 30 seconds|#]

      [#|2008-05-13T11:34:30.626-0700|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=16;_ThreadName=httpWorkerThread-4848-1;|PWC1412: WebModule[/hello] ServletContext.log():Warning: no initial runtimes specified.|#]

      [#|2008-05-13T11:34:30.627-0700|INFO|sun-appserver9.1|javax.enterprise.system.container.web|_ThreadID=16;_ThreadName=httpWorkerThread-4848-1;|PWC1412: WebModule[/hello] ServletContext.log():Warning: no max runtimes specified.|#]
    4. The default Rails page is now visible at "http://localhost:8080/hello" as shown below:

  7. Add some functionality to the application to show Servlet and Rack integration
    1. Add a Controller and View as

      ~/testbed/jruby-1.1.1/samples/rails/hello >../../../bin/jruby script/generate controller home index
      JRuby limited openssl loaded. gem install jruby-openssl for full support.
      http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
            exists  app/controllers/
            exists  app/helpers/
            create  app/views/home
            exists  test/functional/
            create  app/controllers/home_controller.rb
            create  test/functional/home_controller_test.rb
            create  app/helpers/home_helper.rb
            create  app/views/home/index.html.erb
    2. Change the "index" helper method in "app/controllers/home_controller.rb" as:

      def index
              @greeting = "Hello from Rack!!"

              # access Servlet Context
              @server_info = $servlet_context.get_server_info
              # alternative way to get Servlet Context
              #@server_info2 = request.env['java.servlet_context'].get_server_info

              # access Servlet Request
              @method = request.env['java.servlet_request'].get_method
              @request_uri = request.env['java.servlet_request'].get_request_uri
              @protocol = request.env['java.servlet_request'].get_protocol
              @port = request.env['java.servlet_request'].get_server_port
      end
    3. Add the following fragment as the last line in "app/views/home/index.html.erb":

      <%= @greeting %><br><br>
      Hosted on "<%= @server_info %>" on port "<%= @port %>"<br>
      <%= @method %> <%= @request_uri %> <%= @protocol %>
  8. Re-create and deploy the WAR file
    1. Re-create the WAR file as explained in step 4.
    2. Re-deploy the WAR file as explained in step 5.3.
    3. Now "http://localhost:8080/hello/home/index" shows the output as:

The magic fragment in "tmp/war/WEB-INF/web.xml" is:

  <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>

And also "WEB-INF/lib/jruby-rack-0.9.jar" is bundled in the WAR.
Let us know if you try Rack-based deployment of Merb applications on GlassFish.

Technorati: rubyonrails jruby ruby rack merb glassfish web2.0
About

profile image
Arun Gupta is a technology enthusiast, a passionate runner, author, and a community guy who works for Oracle Corp.


Java EE 7 Samples

Stay Connected

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today