Thursday Apr 03, 2008

Rails and Java EE integration - Servlet co-bundled and invoked from Rails

One of the several advantages of deploying Rails applications on GlassFish is - co-hosting Rails and Java EE applications in the same container. The screencast #web9 shows how Rails applications can be easily deployed on GlassFish.

This blog takes the JRuby-on-Rails (jRoR) and Java EE integration to the next level. It show how a Java EE Servlet can be co-bundled within a jRoR application. And then it shows how such a servlet can be easily invoked from a Rails view. It uses WAR-based mode for deploying jRoR applications on GlassFish.

Here are the detailed steps:
  1. In an existing JRuby 1.1 RC3 installation (enabled with Rails), install the required gems:

    ~/testbed/jruby-1.1RC3 >bin/jruby -S gem install activerecord-jdbc-adapter   
    JRuby limited openssl loaded. gem install jruby-openssl for full support.
    http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
    Successfully installed activerecord-jdbc-adapter-0.8
    1 gem installed
    Installing ri documentation for activerecord-jdbc-adapter-0.8...
    Installing RDoc documentation for activerecord-jdbc-adapter-0.8...
  2. Create a Rails app as:

    ~/testbed/jruby-1.1RC3/samples/rails >../../bin/jruby -S rails railsee1
          create 
          create  app/controllers
          create  app/helpers
          create  app/models
          create  app/views/layouts
          create  config/environments
          create  config/initializers
          create  db
          create  doc
          create  lib
          create  lib/tasks
          create  log
          create  public/images
          create  public/javascripts
          create  public/stylesheets
          create  script/performance
          create  script/process
          create  test/fixtures
          create  test/functional
          create  test/integration
          create  test/mocks/development
          create  test/mocks/test
          create  test/unit
          create  vendor
          create  vendor/plugins
          create  tmp/sessions
          create  tmp/sockets
          create  tmp/cache
          create  tmp/pids
          create  Rakefile
          create  README
          create  app/controllers/application.rb
          create  app/helpers/application_helper.rb
          create  test/test_helper.rb
          create  config/database.yml
          create  config/routes.rb
          create  public/.htaccess
          create  config/initializers/inflections.rb
          create  config/initializers/mime_types.rb
          create  config/boot.rb
          create  config/environment.rb
          create  config/environments/production.rb
          create  config/environments/development.rb
          create  config/environments/test.rb
          create  script/about
          create  script/console
          create  script/destroy
          create  script/generate
          create  script/performance/benchmarker
          create  script/performance/profiler
          create  script/performance/request
          create  script/process/reaper
          create  script/process/spawner
          create  script/process/inspector
          create  script/runner
          create  script/server
          create  script/plugin
          create  public/dispatch.rb
          create  public/dispatch.cgi
          create  public/dispatch.fcgi
          create  public/404.html
          create  public/422.html
          create  public/500.html
          create  public/index.html
          create  public/favicon.ico
          create  public/robots.txt
          create  public/images/rails.png
          create  public/javascripts/prototype.js
          create  public/javascripts/effects.js
          create  public/javascripts/dragdrop.js
          create  public/javascripts/controls.js
          create  public/javascripts/application.js
          create  doc/README_FOR_APP
          create  log/server.log
          create  log/production.log
          create  log/development.log
          create  log/test.log

    In order to keep it simple, this application will not be using any database so uncomment the following line from "config/environment.rb" (remove "#" at  beginning of the line):

    config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
  3. Install Goldspike plugin in the application as:

    ~/testbed/jruby-1.1RC3/samples/rails/railsee1 >../../../bin/jruby script/plugin install svn://rubyforge.org/var/svn/jruby-extras/trunk/rails-integration/plugins/goldspike
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/test
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/test/war_config_test_config.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/test/test_java_library.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/test/test_maven_library.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/test/test_create_war.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/Rakefile
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/init.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/tasks
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/tasks/war.rake
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/lib
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/lib/util.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/lib/war_config.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/lib/run.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/lib/java_library.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/lib/packer.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/lib/create_war.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/install.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/generators
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/generators/goldspike
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/generators/goldspike/goldspike_generator.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/generators/goldspike/templates
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/generators/goldspike/templates/web.xml.erb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/generators/goldspike/templates/war.rb
    A    /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1/vendor/plugins/goldspike/README
    Exported revision 960.
          exists  config
          create  config/war.rb
          create  WEB-INF
          create  WEB-INF/web.xml.erb

    Optionally Warbler may be used for packaging and Goldspike for dispatching.
  4. Create a Java library with Servlet code
    1. Using NetBeans IDE, create a project of type "Java Class Library" and specify the name "HelloServlet".
    2. Right-click on the project, select "New" and "Servlet...". Enter the class name as "HelloServlet" and package as "server" as shown below:

    3. Right-click on the project, select Properties and in "Libraries", "Compile Tab Libraries" add "javaee.jar" from GlassFish v2 UR1 "lib" directory.
    4. Change the "try" block in "processRequest" method to following:

      String name = request.getParameter("name");
      if (name == null || name.equals(""))
          name = "Duke";
                 
      out.println("<h1>Servlet HelloServlet at " + request.getContextPath () + " says Hello " + name + "!</h1>");
    5. Right-click on the project and select "Clean and Build".
  5. Configure Rails app for Servlet
    1. In your Rails application directory, add the following fragments to "WEB-INF/web.xml.erb":

      <servlet>
                      <servlet-name>hello</servlet-name>
                      <servlet-class>server.HelloServlet</servlet-class>
      </servlet>

      <servlet-mapping>
                      <servlet-name>hello</servlet-name>
                      <url-pattern>/hello</url-pattern>
      </servlet-mapping>
    2. Create "WEB-INF/lib" directory and copy "HelloServlet.jar" from the "dist" directory of NetBeans project here.
  6. Create & Deploy the WAR
    1. Create a WAR file as:

      ~/testbed/jruby-1.1RC3/samples/rails/railsee1 >../../../bin/jruby -S rake war:standalone:create
      (in /Users/arungupta/testbed/jruby-1.1RC3/samples/rails/railsee1)
      info: Assembling web application
      info: Packing needed Java libraries ...
      info:   adding Java library jruby-complete-1.1RC3
      info:   adding Java library goldspike-1.6
      info:   adding Java library activation-1.1
      info:   adding Java library commons-pool-1.3
      info:   adding Java library bcprov-jdk14-124
      info: Packing needed Ruby gems ...
      info:   adding Ruby gem rails version 2.0.2
      info:   adding Ruby gem rake version 0.8.1
      info:   adding Ruby gem activesupport version 2.0.2
      info:   adding Ruby gem activerecord version 2.0.2
      info:   adding Ruby gem actionpack version 2.0.2
      info:   adding Ruby gem actionmailer version 2.0.2
      info:   adding Ruby gem activeresource version 2.0.2
      info:   adding Ruby gem activerecord-jdbc-adapter version 0.8
      info: Packing needed files ...
      info: Creating web archive
    2. Deploy the WAR to GlassFish v2 UR1 as:

      ~/testbed/jruby-1.1RC3/samples/rails/railsee1 >~/testbed/glassfish/v2ur1/glassfish/bin/asadmin deploy railsee1.war
      Command deploy executed successfully.
  7. The bundled Servlet is now accessible at "http://localhost:8080/railsee1/hello". The default browser output looks like:



    And passing a parameter to the URL as "http://localhost:8080/railsee1/hello?name=Arun" shows the output as:

  8. With this, your Java EE Servlet is now bundled with your Rails application deployed on GlassFish v2 UR1.

    Now, lets add Controller and View to Rails application and invoke this servlet from there to show complete integration with Rails.
  1. Create a new Controller and View as

    ~/testbed/jruby-1.1RC3/samples/rails/railsee1 >../../../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 generated controller in "app/controllers/home_controller.rb" to:

    class HomeController < ApplicationController

    include Java

      def index
            url = java.net.URL.new("http://localhost:8080/railsee1/hello");
            conn = url.open_connection;
            reader = java.io.BufferedReader.new(java.io.InputStreamReader.new(conn.get_input_stream));
            @servlet_output = "";
            input_line = reader.read_line;
            while input_line != nil
                    @servlet_output << input_line;
                    input_line = reader.read_line;
            end
            reader.close;
      end
    end
  3. Change the generated view in "app/views/home/index.rhtml.erb" to:

    <h1>Home#index</h1>
    <p>Find me in app/views/home/index.html.erb</p>

    <%= @servlet_output %>
  4. Re-create & re-deploy the WAR as describd in bullet # 6 above. And now "http://localhost:8080/railsee1/home/index" shows the output as shown:

This shows how a Java EE 5 Servlet can be easily invoked from a Rails application deployed on GlassFish. JRuby-on-Rails and GlassFish allows you to leverage business knowledge that exists in Java EE applications very easily and still providing Rails agility.


Technorati: rubyonrails netbeans glassfish javaee5 servlets jruby ruby goldspike

Sunday Dec 16, 2007

JRuby-on-GlassFish Update Center Module - Now Updated with JRuby 1.0.2

Pramod updated the JRuby-on-GlassFish module on the GlassFish Update Center with JRuby 1.0.2, Rails 1.2.6 and Goldspike revision 808.

I created a standalone (self-contained with all the libraries, gems & plug-ins) and shared (contains only web.xml and libraries are loaded from the Application Server instance) WAR image for the bundled Hello World sample. The screencast #web9 provide detail instructions on how to create standalone and shared images. The difference in the image size is pretty significant:

Shared Image 226, 977 bytes
Standalone Image 11,039,883 bytes (48 x)

If you have multiple such applications and each application has one or more plug-ins then this size grows up pretty fast. The war:shared:create rake target in Goldspike is buggy and serves the same purpose as war:standalone:create (#13265).

Loading shared libraries from GlassFish Application Server instance to keep your Rails application size to a minimum is another reason to consider using GlassFish for deploying your JRuby-on-Rails application.

Technorati: glassfish ruby jruby rails goldspike

Monday Aug 20, 2007

Ruby/JRuby Process Models Explained

In the JRuby Hackday, Nick Sieger described the process models of a Rails application deployed using

In this blog entry I'm capturing a brain dump from him after the event. The images below shows process models in each of the above mentioned approaches. The containment of boxes in each image is shown in terms of the application logic instead of the process. The legend followed in the images is as follows:

In the first approach, a C-based Ruby on Rails application is front-ended by an HTTP library - Mongrel. The typical app will be deployed on a cluster of Mongrel servers - provided by Mongrel_cluster plug-in.

This plug-in configure and control the several Mongrel servers. Mongrel is largely written in Ruby and uses native C for HTTP request parsing. Each instance of Mongrel starts a Ruby interpreter that listens on a server socket. The Ruby script has a Mongrel handler that queues up multiple requests from the client and passes the state, one at a time, to a Rails instance (that is by design single threaded).

For a Mongrel cluster, multiple Ruby interpreters are started as an OS process.

The second approach shows how a Rails application may be deployed using JRuby. This is a transition approach between traditional C-based Ruby on Mongrel deployment and JRuby-based deployment on GlassFish.

Mongrel JCluster is an update to Mongrel_cluster that only runs in JRuby. The biggest difference is that it starts only one Java Virtual Machine (JVM) that starts several Mongrels in the same JVM by spawning multiple JRuby processes, one in each thread. As in traditional approach, each Mongrel listens to the request on a server socket and passes the request state to Rails.

For a Mongrel JCluster, only one JVM is started as an OS process.

The last approach shows how a JRuby application may be deployed on GlassFish. With this approach, there are two modes to deploy an application.

In the first case, Goldspike plug-in is installed in a standard Rails application. This plug-in adds the "war:\*" rake targets to a Rails project. Invoking "war:standalone:create" rake target creates a WAR file containing all the dependent JRuby and Rails libraries. This WAR file can then be deployed in GlassFish. The "web.xml" in this WAR file contains a Servlet (org.jruby.webapp.RailsServlet) that translates data from Servlet request to Rails dispatcher.
In the second case, the Grizzly connector understands the request format and dispatch it directly to a pre-configured JRuby installation (updated with the Rails gem). In both the cases, there is only one JVM running as the OS process for GlassFish. The main advantage of the second approach is that it by-passes the web application processing and delegate the request directly to the Rails framework.

A detailed screencast of the first GlassFish case (Goldspike/JRuby) is available here and for the second case (Grizzly/JRuby) is documented here.

Technorati: ruby jruby jrubyonglassfish glassfish grizzly goldspike rubyonrails ror

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
« September 2015
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