Monday Feb 02, 2009

Rails/Merb and GlassFish at Super Happy Dev House 30


Supper Happy Dev House is "a premier monthly hackathon event that combines serious and not-so-serious productivity with a fun and exciting party atmosphere."

The 30th monthly event was hosted at Sun Microsystem's Executive Briefing Center (aka EBC) in Menlo Park. During my short stay at Dev House, all the key characteristics of "productivity" and "party atmosphere" were indeed evident. This was the biggest Dev House in it's history. My previous visits to EBC have been for formal customer presentations. And the Dev House gathering turned the EBC into a very lively environment :)

I gave a lightning talk (for 5 minutes) on Rails/Merb powered by GlassFish/NetBeans. The key messages were:
  • JRuby - "It's just Ruby!" with passing over 55,000 compliance tests and continuous performance improvements.
  • NetBeans - light-weight and intuitive IDE for Rails development/deployment
  • GlassFish - robust deployment environment for Rails/Merb applications
The demo showed in the talk is available as screencast #26 and TOTD #53. Sharat posted a recording of my talk and is included below:


Read the latest on GlassFish/JRuby/Rails/Merb on the GlassFish wiki.

Did you know Project Kenai is a massive Rails application deployed on GlassFish ? Host your project on kenai.com and get integrated support for Forums, Wikis, multiple source code reposisotry (including Subversion, Mercurial, and Git), bug tracking (including Bugzilla and JIRA) and much more. Empower your project on kenai.com - a complete Rails application running on GlassFish.

Here are some pictures:


And the complete album at:




Technorati: conf shdh shdh30 superhappydevhouse rubyonrails merb glassfish netbeans sun

Thursday Jan 08, 2009

TOTD #63: jmx4r gem - How to manage/monitor your Rails/Merb applications on JRuby/GlassFish ?


TOTD #61 and TOTD #62 shows how to use JMX APIs to locally/remotely manage/monitor your Rails/Merb applications. This Tip Of The Day extends TOTD #62 and shows how remote management can be done using jmx4r gem.

This gem provides a clean mapping between JMX APIs and Ruby. It allows to write pure Ruby code to manage/monitor any Rails application. As a result it removes all dependency on the Java code used in TOTD #62.

Lets first install the gem!

~ >gem install jmx4r
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Successfully installed jmx4r-0.0.6
1 gem installed
Installing ri documentation for jmx4r-0.0.6...
Installing RDoc documentation for jmx4r-0.0.6...

Here is the equivalent Ruby code to flush the class cache (as in TOTD #62):

require 'rubygems'
require 'jmx4r'

JMX::MBean.establish_connection :host => "129.145.133.163", :port => 8686

beans = JMX::MBean.find_all_by_name "org.jruby:\*"
beans.each { |bean|
  service = bean.object_name["service"]
  case service
  when "ClassCache"
    @cc_mbean = bean
  when "Config"
    @c_mbean = bean
  end
}

# clear the cache if it's full
if @cc_mbean.full
  printf "JIT Max: %d, JIT Threshold: %d, Class load count: %d\\n", @c_mbean.jit_max,
    @c_mbean.jit_threshold, @cc_mbean.class_load_count
    @cc_mbean.flush
else
  puts "Class Cache is not full"
  printf "Loaded: %d, Reused: %d, Live: %d\\n", @cc_mbean.class_load_count,
    @cc_mbean.class_reuse_count, @cc_mbean.live_class_count
end

As with all Ruby code, really clean and simple!

The key parts of the code are highlighted in bold. "JMX::MBean.establish_connection" establishes a connection with a JMX agent running on a remote machine identified by the IP address and port number specified. "JMX::MBean.find_all_by_name" queries the agent for all the MBeans in "org.jruby" domain. And then the code is self explanatory.

Just dump this code in a file and run it as:

jruby main.rb

to see the output similar to:

Class Cache is not full
Loaded: 76, Reused: 0, Live: 76

Make sure Rails/Merb application is running after setting JAVA_OPTS as described in TOTD #62. For this blog, the JMX agent/Rails application ran on a Mac and the JMX client on a Solaris box.

The jmxr examples provides some more ways to use the gem.

There is also jmx gem that provides similar functionality. It even allows to create MBeans and provides a simple server where they can be registered. Tom's blog provide more details on usage and there is even a sample included.

Subsequent blogs in this series will discuss:
  • How to remotely manage your Rails/Merb applications using JMX API ?
  • How to publish your own metrics that can be managed using JMX API ?
  • How to use jmx gem to manage/monitor ?
  • How to use VisualVM to get more information about the underlying VM ?
  • How to use NewRelic/FiveRuns to manage/monitor an application ?
Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive of all tips is available here.

Technorati: totd glassfish jruby rubyonrails merb jmx jmx4r manage monitor

Wednesday Jan 07, 2009

TOTD #62: How to remotely manage/monitor your Rails/Merb applications on JRuby/GlassFish using JMX API ?


TOTD #61 showed how to manage/monitor a Rails/Merb application running using JRuby/GlassFish using standard Java tools. Both the application and the management tools are running on the same machine. But that's never the case in a production environment. Instead remote management of an application is required when running in production mode. Fortunately, similar set of tools can be used for remote management as well.

However the underlying Java Virtual Machine needs to be configured to enable remote monitoring. This is achieved by setting JAVA_OPTS environment variables as shown below:

Set up the following envinronment variable before running the Rails/Merb application:

export JAVA_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8686 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"

The first property enables the JMX remote agent (aka MBeans server) and local monitoring. The second property configures the port number for remote management using JMX/RMI connections. The third and fourth properties, for simplicity only, disable access control and SSL for remote monitoring. It is highly recommended to use them in a production environment. Using Password Authentication provide more details about configuring passwords for access control. Using SSL provide more details about configuring SSL.

Now for a Rails/Merb application running on GlassFish all the MBeans are also available on the JMX agent running on port 8686. This agent can be accessed using the standard URL as shown below:

service:jmx:rmi:///jndi/rmi://192.168.124.1:8686/jmxrmi

"192.168.124.1" is the host's IP address on which the Rails/Merb application is running and "8686" is the port configured in JAVA_OPTS. More details about the URL are available here.

First, lets use jconsole on a different machine to monitor this application. Start jconsole by typing the command in a shell as:

jconsole

In the "New Connection" window, select "Remote Process" and enter the URL defined above as shown below:



And then the management data snapshot is captured as shown below:



And here is a snapshot from a remote Solaris machine:



Notice the URL, as opposed to "pid", is shown on the jconsole window. This indicates that remote connection is being used instead of local process id. TOTD #61 further explains how jconsole can be used to manage/monitor your Rails/Merb applications.

As mentioned in TOTD #61, JRuby runtime exposes 4 different MBeans - ClassCache, Config, JITCompiler and ParserStats - all in "org.jruby" domain. Lets write a client application that query these MBeans to monitor the state of JRuby runtime and perform some management actions based upon the returned results.

Here is the Ruby client code using Java Management Extensions (JMX) APIs. 

include Java

import java.io.IOException
import java.util.HashSet
import java.util.Set
import javax.management.JMRuntimeException
import javax.management.MBeanServerConnection
import javax.management.MalformedObjectNameException
import javax.management.ObjectName
import javax.management.JMX
import javax.management.remote.JMXConnector
import javax.management.remote.JMXConnectorFactory
import javax.management.remote.JMXServiceURL
import org.jruby.management.ClassCacheMBean
import org.jruby.management.ConfigMBean

url = JMXServiceURL.new "service:jmx:rmi:///jndi/rmi://192.168.124.1:8686/jmxrmi"
mbsc = JMXConnectorFactory.connect(url, nil).get_mbean_server_connection

names = HashSet.new(mbsc.query_names(ObjectName.new("org.jruby:\*"), nil))
names.each { |name|
     service = name.get_key_property "service"
     if service == "ClassCache"
           @cc_mbean = JMX.new_mbean_proxy(mbsc, name, Java::org.jruby.management.ClassCacheMBean.java_class)
     elsif service == "Config"
           @c_mbean = JMX.newMBeanProxy(mbsc, name, Java::org.jruby.management.ConfigMBean.java_class)
     end
}

# clear the cache if it's full
if @cc_mbean.is_full
    puts @c_mbean.get_jit_max
    puts @c_mbean.get_jit_threshold
    puts @cc_mbean.get_class_load_count
    @cc_mbean.flush
else
    puts "Class Cache is not full"
    printf "Loaded: %d, Reused: %d, Live: %d\\n", @cc_mbean.get_class_load_count,
      @cc_mbean.get_class_reuse_count, @cc_mbean.get_live_class_count
end

Here are the main tasks achieved by this code:
  • Do include/import for Java classes
  • Connect with the JMX Agent where JRuby MBeans are registered and obtain a MBean Server Connection (explained here)
  • Query for all the MBeans in "org.jruby" domain
  • Create proxies for ClassCache and Config MBeans
  • Flush the ClassCache if its full and print some debugging information
These MBeans are part of JRuby runtime so provide relevant management/montoring information corresponding to that. But as you can see it's fairly trivial to write a client to query MBeans and achieve dynamism using standard Ruby code.

Each JRuby-exposed MBean has multiple attributes that can be utilized to monitor your application and take appropriate actions. For example, an application could detect low memory and stop accepting new connections.

And you can continue to use GlassFish for running your Rails and Merb applications (now Sinatra as well)!

Subsequent blogs in this series will discuss:
  • How to remotely manage your Rails/Merb applications using JMX API ?
  • How to publish your own metrics that can be managed using JMX API ?
  • How to use jmx gem to manage/monitor ?
  • How to use VisualVM to get more information about the underlying VM ?
  • How to use NewRelic/FiveRuns to manage/monitor an application ?
Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive of all tips is available here.

Technorati: totd glassfish jruby rubyonrails merb jmx manage monitor

Tuesday Jan 06, 2009

TOTD #61: How to locally manage/monitor your Rails/Merb applications on JRuby/GlassFish using JMX ?


GlassFish Gem can easily run both Rails and Merb application. Using JRuby, as opposed to MRI, allows you to use standard Java monitoring framework and tools. Java Management Extensions (JMX) is a standard management and monitoring solution for Java platform. This Tip Of The Day shows how to apply JMX techniques to monitor Rails/Merb applications.

The blog uses a trivial Rails/Merb application to demonstrate monitoring but the techniques can be applied to any Rails or Merb application. FYI TOTD #52 shows to create a simple Merb application and TOTD #28 shows how to create a simple Rails scaffold.

This blog will focus on local monitoring, i.e. monitor a Rails/Merb application running on the same machine as monitoring tool. A subsequent blog will demonstrate remote monitoring, i.e. monitor a Rails/Merb application from a different machine.

There is no extra configuration required to enable monitoring if your Rails/Merb application is running on GlassFish gem. You just need to launch an additional tool to monitor the already running application.

jconsole is a CLI bundled with JDK and launches a graphical tool to monitor and manage Java applications on a local or remote machine. jconsole can be used to monitor local application (those running on the same systems as jconsole) and remote applications (systems other than running jconsole).

Invoke "jconsole" in a shell as:

jconsole

It shows the following window:



The window shows different Java process that can be managed/monitored by jconsole. "org.jruby.Main -S glassfish" is the process corresponding to our Rails/Merb application running using GlassFish Gem. Click on that process (6179 in this case) and click "Connect".

The jconsole interface explains the different tabs and meaning of information displayed on each tab. Here is a snapshot of different tabs captured for a trivial Rails application.



It shows heap memory usage, threads, classes loaded, and CPU usage over a period of time. The "Memory" tab tracks different GC pools and shows their dynamic growth. Clicking on "Perform GC" on top-right corner performs a garbage collection (more on this later).



The "Threads" tab shows the highest number of threads since JVM started and current number of live daemon and non-daemon threads. Clicking on a particular thread shows it's current state and stack trace if it's waiting.



MBeans tab shows different managed beans registered with the platform MBean server, i.e. MBean server available in the JDK. As you can see there are several standard MBeans displayed on the left-hand side from java.lang and java.util.logging domains.



JRuby runtime also exposes 4 different MBeans - ClassCache, Config, JITCompiler and ParserStats - all in "org.jruby" domain. Clicking on each MBean shows detailed information collected by that MBean as shown below:



Clicking on "Attributes" node shows the current snapshot of all the attributes exposed by the MBean as shown below:



Clicking on "Refresh" button will read the fresh values from the MBean.

Some MBeans expose functions as well. Such MBeans have "Operations" node and clicking on them show the functions exposed as shown below:



These functions can be invoked by clicking on the button in right-hand panel.

These snapshots are captured without even a single invocation of the application. Accessing "http://localhost:3000/" in a browser updates heap usage screenshot as shown below:



And permgen is increased because new classes are JITed by JRuby as shown below:




After a Garbage Collection is performed (by clicking on "Perform GC" button in "Memory" tab), the updated screenshot looks like:



As the snapshot indicates the "Heap Memory Usage" is back to normal (which indicates no memory leak) and there is a spike in "CPU Usage" because CPU cycles are used to perform GC.

Monitoring a Merb application is no different at all. The "Overview" tab for a trivial Merb app looks like:



The wide range of JMX-compatible tools is another advantage of using JRuby over MRI :)

Some other alternatives are using a combination of jps and jstat.

The JMX Home Page provides all details about JMX framework.  Subsequent blogs in this series will discuss:
  • How to remotely manage your Rails/Merb applications using JMX API ?
  • How to publish your own metrics that can be managed using JMX API ?
  • How to use VisualVM to get more information about the underlying VM ?
  • How to use NewRelic/FiveRuns to manage/monitor an application ?
How do you monitor your Rails or Merb applications ?

Please leave suggestions on other TOTD (Tip Of The Day) that you'd like to see. A complete archive of all tips is available here.

Technorati: totd glassfish jruby rubyonrails merb jmx manage monitor

Wednesday Dec 03, 2008

LOTD #15: Deploying Merb application on GlassFish v3 using Warbler


GlassFish v3 with Merb and Warbler explains how to use Warbler to deploy a Merb application on GlassFish v3. Here is a quote from the blog:

this lovely server had a gem which you can use to fire up a Glassfish server. Easy as pie and within no time at all we were developing our Merb app on Glassfish.

The blog requires some workaround for Warbler and Nick is planning to fix them in the next rev. And other workaround is required because of Webrat's recently introduced dependency on Nokogiri which does not run on JRuby yet.

In addition, TOTD #52 explains how to deploy a Merb application using GlassFish gem and TOTD #53 explains how to create a scaffold in Merb.

Submit your Merb/GlassFish bugs here, talk to us using GlassFish Forum, and get the latest information on JRuby wiki.

All previous entries in this series are archived at LOTD.

Technorati: lotd glassfish v3 gem warbler merb

Monday Nov 17, 2008

TOTD #53: Scaffold in Merb using JRuby/GlassFish


GlassFish Gem 0.9.0 can be used to run Rails and Merb applications. Support another Rack-based framework Sinatra is coming up in the near future. This blog shows how to create a scaffold in Merb and run it using the GlassFish gem.



Merb allows pluggable ORM and comes with DataMapper as the default one. However DataMapper has native dependencies and so cannot be used with JRuby. There is discussion about creating a DataMapper adapter over JDBC but in the meanwhile ActiveRecord is the only ORM that can be used with JRuby.

Merb wiki has extensive documentation but lacks clearly defined steps for generating scaffold when using ActiveRecord. This blog fulfills those gaps and provides a comprehensive tutorial to build a Merb scaffold.
  1. Lets create a Merb application using ActiveRecord ORM as:

    ~/samples/jruby/merb >~/tools/jruby-1.1.5/bin/jruby -S merb-gen core --orm activerecord 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
  2. Generate a Merb resource (model, controller and associated things):

    ~/samples/jruby/merb/hello >merb-gen resource Runner distance:float,minutes:integer
    Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
    Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
    Generating with resource generator:
    Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
    Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
    Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
    Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
    Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
    Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
    Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
    Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
         [ADDED]  spec/models/runner_spec.rb
         [ADDED]  app/models/runner.rb
         [ADDED]  schema/migrations/001_runner_migration.rb
         [ADDED]  spec/requests/runners_spec.rb
         [ADDED]  app/controllers/runners.rb
         [ADDED]  app/views/runners/index.html.erb
         [ADDED]  app/views/runners/show.html.erb
         [ADDED]  app/views/runners/edit.html.erb
         [ADDED]  app/views/runners/new.html.erb
         [ADDED]  app/helpers/runners_helper.rb
    resources :runners route added to config/router.rb

    As evident from the generated files Model, Controller, Helper and Views are generated. The Views are only template files with no code because this code end up getting changed anyway most of the times. Instead template Views can be written as explained in CRUD View Examples (more on this later).
  3. Configure Database
    1. Merb applications do not have a pre-generated "database.yml" so create one as:

      ~/samples/jruby/merb/hello >rake db:create
      (in /Users/arungupta/samples/jruby/merb/hello)
      JRuby limited openssl loaded. gem install jruby-openssl for full support.
      http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
      Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
      Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
      Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
      Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
       ~ It took: 0
       ~ Loading: Merb::BootLoader::MixinSession
       ~ It took: 0
       ~ Loading: Merb::BootLoader::BeforeAppLoads
       ~ It took: 0
       ~ Loading: Merb::Orms::ActiveRecord::Connect
       ~ No database.yml file found in /Users/arungupta/samples/jruby/merb/hello/config.
       ~ A sample file was created called database.yml.sample for you to copy and edit.
    2. Copy "config/database.yml.sample" to "config/database.yml". Wonder why this step is explicitly required ?
    3. Edit database configuration such that it looks like:

      :development: &defaults
        :adapter: mysql
        :database: hello_development
        :username: root
        :password:
        :host: localhost
        :socket: /tmp/mysql.sock
        :encoding: utf8

      The changed lines are shown in bold.
    4. Create the database as:

      ~/samples/jruby/merb/hello >rake db:create
      (in /Users/arungupta/samples/jruby/merb/hello)
      JRuby limited openssl loaded. gem install jruby-openssl for full support.
      http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
      Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
      Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
      Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
      Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
       ~ It took: 0
       ~ Loading: Merb::BootLoader::MixinSession
       ~ It took: 0
       ~ Loading: Merb::BootLoader::BeforeAppLoads
       ~ It took: 0
       ~ Loading: Merb::Orms::ActiveRecord::Connect
       ~ Connecting to database...
       ~ It took: 0
       ~ Loading: Merb::BootLoader::LoadClasses
       ~ It took: 0
       ~ Loading: Merb::BootLoader::Router
       ~ Compiling routes...
       ~ It took: 0
       ~ Loading: Merb::BootLoader::Templates
       ~ It took: 0
       ~ Loading: Merb::BootLoader::MimeTypes
       ~ It took: 0
       ~ Loading: Merb::BootLoader::Cookies
       ~ It took: 0
       ~ Loading: Merb::BootLoader::SetupSession
       ~ It took: 1
       ~ Loading: Merb::BootLoader::SetupStubClasses
       ~ It took: 0
       ~ Loading: Merb::BootLoader::AfterAppLoads
       ~ It took: 0
       ~ Loading: Merb::BootLoader::ChooseAdapter
       ~ It took: 0
       ~ Loading: Merb::BootLoader::RackUpApplication
       ~ It took: 0
       ~ Loading: Merb::BootLoader::ReloadClasses
       ~ It took: 0
      DEPRECATION WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library will be REMOVED FROM RAILS 2.2. Please switch to the offical mysql gem: `gem install mysql`  See http://www.rubyonrails.org/deprecation for details. (called from mysql_connection at /Users/arungupta/tools/jruby-1.1.5/lib/ruby/gems/1.8/gems/activerecord-2.1.2/lib/active_record/connection_adapters/mysql_adapter.rb:81)
       ~   SQL (0.000581)   SET NAMES 'utf8'
       ~   SQL (0.000581)   SET SQL_AUTO_IS_NULL=0
       ~   SQL (0.000894)   CREATE DATABASE `hello_development` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_general_ci`
      MySQL hello_development database successfully created
    5. Migrate the database as:

      ~/samples/jruby/merb/hello >rake db:migrate
      (in /Users/arungupta/samples/jruby/merb/hello)
      JRuby limited openssl loaded. gem install jruby-openssl for full support.
      http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
      Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
      Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
      Loading init file from /Users/arungupta/samples/jruby/merb/hello/config/init.rb
      Loading /Users/arungupta/samples/jruby/merb/hello/config/environments/development.rb
       ~ It took: 0
       ~ Loading: Merb::BootLoader::MixinSession
       ~ It took: 0
       ~ Loading: Merb::BootLoader::BeforeAppLoads
       ~ It took: 0
       ~ Loading: Merb::Orms::ActiveRecord::Connect
       ~ Connecting to database...
       ~ It took: 0
       ~ Loading: Merb::BootLoader::LoadClasses
       ~ It took: 1
       ~ Loading: Merb::BootLoader::Router
       ~ Compiling routes...
       ~ It took: 0
       ~ Loading: Merb::BootLoader::Templates
       ~ It took: 0
       ~ Loading: Merb::BootLoader::MimeTypes
       ~ It took: 0
       ~ Loading: Merb::BootLoader::Cookies
       ~ It took: 0
       ~ Loading: Merb::BootLoader::SetupSession
       ~ It took: 0
       ~ Loading: Merb::BootLoader::SetupStubClasses
       ~ It took: 0
       ~ Loading: Merb::BootLoader::AfterAppLoads
       ~ It took: 0
       ~ Loading: Merb::BootLoader::ChooseAdapter
       ~ It took: 0
       ~ Loading: Merb::BootLoader::RackUpApplication
       ~ It took: 0
       ~ Loading: Merb::BootLoader::ReloadClasses
       ~ It took: 0
      DEPRECATION WARNING: You're using the Ruby-based MySQL library that ships with Rails. This library will be REMOVED FROM RAILS 2.2. Please switch to the offical mysql gem: `gem install mysql`  See http://www.rubyonrails.org/deprecation for details. (called from mysql_connection at /Users/arungupta/tools/jruby-1.1.5/lib/ruby/gems/1.8/gems/activerecord-2.1.2/lib/active_record/connection_adapters/mysql_adapter.rb:81)
       ~   SQL (0.000769)   SET NAMES 'utf8'
       ~   SQL (0.000610)   SET SQL_AUTO_IS_NULL=0
       ~   SQL (0.001609)   SHOW TABLES
       ~   SQL (0.003952)   CREATE TABLE `schema_migrations` (`version` varchar(255) NOT NULL) ENGINE=InnoDB
       ~   SQL (0.054355)   CREATE UNIQUE INDEX `unique_schema_migrations` ON `schema_migrations` (`version`)
       ~   SQL (0.001691)   SHOW TABLES
       ~   SQL (0.001643)   SELECT version FROM schema_migrations
       ~ Migrating to RunnerMigration (1)
      == 1 RunnerMigration: migrating ===============================================
      -- create_table(:runners)
       ~   SQL (0.005301)   CREATE TABLE `runners` (`id` int(11) DEFAULT NULL auto_increment PRIMARY KEY, `distance` float, `minutes` int(11), `created_at` datetime, `updated_at` datetime) ENGINE=InnoDB
         -> 0.0107s
      == 1 RunnerMigration: migrated (0.0114s) ======================================

       ~   SQL (0.014063)   INSERT INTO schema_migrations (version) VALUES ('1')
       ~   SQL (0.003585)   SHOW TABLES
       ~   SQL (0.001324)   SELECT version FROM schema_migrations
       ~   SQL (0.001451)   SHOW TABLES
       ~   SQL (0.017054)   SHOW FIELDS FROM `runners`
       ~   SQL (0.018503)   describe `runners`
       ~   SQL (0.009372)   SHOW KEYS FROM `runners`
  4. Create the CRUD views
    1. Add dependencies
      1. Edit "config/init.rb" and add the following line:

        require 'config/dependencies.rb'

        as the first uncommented line.
      2. Create "config/dependencies.rb" and add the following dependency (explained here):

        dependency "merb-assets", "1.0"
        dependency "merb-helpers", "1.0"
    2. Add the resource routes by editing "config/router.rb" and adding:

      resources :runners

      insider "Merb::Router.prepare do" block.
    3. Edit the "index" view in "app/views/runners/index.html.erb" as:

      <h1>Runner controller, index action</h1>

      <table>
        <tr>
          <th>Distance (in miles)</th>
          <th>Time (in mins)</th>

          <th colspan="3">Actions</th>
        </tr>

      <% @runners.each do |runner| %>
        <tr>
          <td><%=h runner.distance %></td>
          <td><%=h runner.minutes %></td>

          <td><%= link_to 'Show', resource(runner) %></td>
          <td><%= link_to 'Edit', resource(runner, :edit) %></td>
          <td><%= delete_button(runner, "Delete #{runner.distance}") %></td>
        </tr>
      <% end %>
      </table>

      <%= link_to 'New', resource(:runners, :new) %>
    4. Edit the "new" in "app/views/runners/new.html.erb" view as:

      <h1>Runners controller, new action</h1>

      <%= form_for(@runner, :action => resource(:runners) ) do %>
       
        <p>
          <%= text_field :distance, :label => "Distance (in miles)" %>
        </p>
       
        <p>
          <%= text_field :minutes, :label => "Time (in mins)"  %>
        </p>
       
        <p>
          <%= submit "Create" %>
        </p>
      <% end =%>
       
      <%= link_to 'Back', resource(:runners) %>
    5. Edit the "show" view in "app/views/runners/show.html.erb" as:

      <h1>Runners controller, show action</h1>

      <p>Distance (in miles): <%=h @runner.distance %></p>
      <p>Time (in mins): <%=h @runner.minutes %></p>
       
      <%= link_to 'Back', resource(:runners) %>
    6. Edit the "edit" in "app/views/runners/edit.html.erb" view as:

      <h1>Runners controller, edit action</h1>

      <%= form_for(@runner, :action => resource(@runner)) do %>
       
        <p>
          <%= text_field :distance, :label => "Distance (in miles)"  %>
        </p>
       
        <p>
          <%= text_field :minutes, :label => "Time (in mins)"  %>
        </p>
       
        <p>
          <%= submit "Update" %>
        </p>
      <% end =%>
       
      <%= link_to 'Show', resource(@runner) %> | <%= link_to 'Back', resource(:runners) %>
That's it!

And now here are some of the captured outputs.

The default output at "http://localhost:3000/runners"



Creating a new Runner at "http://localhost:3000/runners/new" as:



"Show" view of a runner at "http://localhost:3000/runners/<id>" as :



"Index" view with one runner at "http://localhost:3000/runners" as:



And now "index" view with 2 runners at "http://localhost:3000/runners" as:



A Merb app generated using MRI can also be run using GlassFish, provided it does not have any native dependencies.

And another useful piece of information is difference between Rails and Merb provide comparative syntax between Rails and Merb.

And thanks to all the discussion on merb@googlegroups where all my questions were answered very promptly!

Submit your bugs here, talk to us using GlassFish Forum, and get the latest information on JRuby wiki.

Technorati: totd glassfish v3 gem jruby rubyonrails merb

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

Wednesday Apr 02, 2008

Merb on JRuby 1.1 RC3


This blog provides how you can get started with Merb on JRuby 1.1 RC3.

Merb is another MVC framework (just like Rails) but with a pluggable ORM, JavaScript library and Template language. Rails has built-in support for these using ActiveRecord, Script.aculo.us and ERB templates. Making it pluggable keeps the core very lightweight and still providing support for a particular feature using plugins. Another big advantage of Merb is that unlike Rails it's thread-safe.

There are already third party supports for ActiveRecord, DataMapper and Sequel ORMs. I will hopefully be able to build support for Java Persistence API ORM in Merb. Until then, here is how you install and get started with Merb on JRuby 1.1 RC3.

Install Merb on JRuby as:
Macintosh-187:jruby-1.1RC3 arungupta$ bin/jruby -S gem install merb mongrel
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Updating metadata for 339 gems from http://gems.rubyforge.org
.........................................................................................................
.........................................................................................................
.........................................................................................................
........................
complete
Successfully installed abstract-1.0.0
Successfully installed erubis-2.5.0
Successfully installed json_pure-1.1.2
Successfully installed rack-0.3.0
Successfully installed hpricot-0.6-java
Successfully installed mime-types-1.15
Successfully installed merb-core-0.9.2
Successfully installed merb-action-args-0.9.2
Successfully installed merb-assets-0.9.2
Successfully installed activesupport-2.0.2
Successfully installed rubigen-1.2.4
Successfully installed merb-gen-0.9.2
Successfully installed merb-haml-0.9.2
Successfully installed merb-builder-0.9.2
Successfully installed mailfactory-1.2.3
Successfully installed merb-mailer-0.9.2
Successfully installed merb-parts-0.9.2
Successfully installed merb-cache-0.9.2
Successfully installed merb-more-0.9.2
Successfully installed merb-0.9.2
Successfully installed gem_plugin-0.2.3
Successfully installed mongrel-1.1.4-java
22 gems installed
Installing ri documentation for json_pure-1.1.2...
Installing ri documentation for rack-0.3.0...
Installing ri documentation for hpricot-0.6-java...
Installing ri documentation for mime-types-1.15...
Installing ri documentation for merb-core-0.9.2...
Installing ri documentation for merb-action-args-0.9.2...
Installing ri documentation for merb-assets-0.9.2...
Installing ri documentation for activesupport-2.0.2...
Installing ri documentation for rubigen-1.2.4...
Installing ri documentation for merb-gen-0.9.2...
Installing ri documentation for merb-haml-0.9.2...
Installing ri documentation for merb-builder-0.9.2...
Installing ri documentation for mailfactory-1.2.3...
Installing ri documentation for merb-mailer-0.9.2...
Installing ri documentation for merb-parts-0.9.2...
Installing ri documentation for merb-cache-0.9.2...
Installing ri documentation for gem_plugin-0.2.3...
Installing ri documentation for mongrel-1.1.4-java...
Installing RDoc documentation for json_pure-1.1.2...
Installing RDoc documentation for rack-0.3.0...
Installing RDoc documentation for hpricot-0.6-java...
Installing RDoc documentation for mime-types-1.15...
Installing RDoc documentation for merb-core-0.9.2...
Installing RDoc documentation for merb-action-args-0.9.2...
Installing RDoc documentation for merb-assets-0.9.2...
Installing RDoc documentation for activesupport-2.0.2...
Installing RDoc documentation for rubigen-1.2.4...
Installing RDoc documentation for merb-gen-0.9.2...
Installing RDoc documentation for merb-haml-0.9.2...
Installing RDoc documentation for merb-builder-0.9.2...
Installing RDoc documentation for mailfactory-1.2.3...
Installing RDoc documentation for merb-mailer-0.9.2...
Installing RDoc documentation for merb-parts-0.9.2...
Installing RDoc documentation for merb-cache-0.9.2...
Installing RDoc documentation for gem_plugin-0.2.3...
Installing RDoc documentation for mongrel-1.1.4-java...
This is so much simpler than couple of weeks ago where all the dependencies had to be explicitly installed. Now create a sample application as:

Macintosh-187:jruby-1.1RC3 arungupta$ cd samples/
Macintosh-187:samples arungupta$ mkdir merb
Macintosh-187:samples arungupta$ cd merb/
Macintosh-187:merb arungupta$ ../../bin/jruby -S merb-gen app hello
RubiGen::Scripts::Generate
      create  app
      create  autotest
      create  config
      create  public
      create  spec
      create  app/controllers
      create  app/helpers
      create  app/views
      create  app/views/exceptions
      create  app/views/layout
      create  config/environments
      create  public/images
      create  public/stylesheets
      create  autotest/discover.rb
      create  autotest/merb.rb
      create  autotest/merb_rspec.rb
      create  config/rack.rb
      create  config/router.rb
      create  config/init.rb
      create  public/merb.fcgi
      create  spec/spec.opts
      create  spec/spec_helper.rb
      create  app/controllers/application.rb
      create  app/controllers/exceptions.rb
      create  app/helpers/global_helpers.rb
      create  app/views/exceptions/internal_server_error.html.erb
      create  app/views/exceptions/not_acceptable.html.erb
      create  app/views/exceptions/not_found.html.erb
      create  app/views/layout/application.html.erb
      create  config/environments/development.rb
      create  config/environments/production.rb
      create  config/environments/rake.rb
      create  config/environments/test.rb
      create  public/images/merb.jpg
      create  public/stylesheets/master.css
      create  /Rakefile

The top-level directory looks like:

Macintosh-187:hello arungupta$ ls -la
total 8
drwxr-xr-x  8 arungupta  arungupta   272 Apr  1 22:20 .
drwxr-xr-x  3 arungupta  arungupta   102 Apr  1 22:20 ..
-rw-r--r--  1 arungupta  arungupta  3334 Apr  1 22:20 Rakefile
drwxr-xr-x  5 arungupta  arungupta   170 Apr  1 22:20 app
drwxr-xr-x  5 arungupta  arungupta   170 Apr  1 22:20 autotest
drwxr-xr-x  6 arungupta  arungupta   204 Apr  1 22:20 config
drwxr-xr-x  5 arungupta  arungupta   170 Apr  1 22:20 public
drwxr-xr-x  4 arungupta  arungupta   136 Apr  1 22:20 spec

And finally start the app as:

Macintosh-187:hello arungupta$ ../../../bin/jruby -S merb
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
 ~ Loaded DEVELOPMENT Environment...
 ~ Compiling routes...
 ~ Using 'share-nothing' cookie sessions (4kb limit per client)
 ~ Using Mongrel adapter

And the default app is hosted at "http://localhost:4000/" and shown in the browser as:

There is a wealth of information available to get you going after this. Here are couple of things to try:
  • If possible, use WARbler to package Merb app and deploy on GlassFish.
  • Try Java Persistence API as the pluggable ORM.

Technorati: rubyonrails merb jruby ruby jpa glassfish
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