SlideShare a Scribd company logo
a jar-nORM-ous task
                   simple data-backed web app in a single jar

                                    Ian Dees
                          www.ian.dees.name ● @undees
                                JRubyConf 2009




Hi. I’m Ian, a JRuby user. This talk is about deploying a Ruby app in a single .jar file. When you’re
leaning on big frameworks like ActiveRecord, there are a few things to remember when you package
your app.
CRUD - CUD



Imagine you’re handed some database credentials, and you want to whip up a web front end in
Sinatra to browse around the data. Let’s say the schema is simple and fairly normalized: the sweet
spot for ActiveRecord.

Photo (cc) flickr.com/photos/treehouse1977/1425246464
define “success”
                                     images and stylesheets
                        A
                        B            single .jar

                        C            app.jar + jruby.jar

                        D            “Install Ruby....”

                        F            “Install....”


MRI and MySQL present some deployment challenges, even when everyone is on the same platform.
With JRuby, you can just hand out a couple of .jar files and have people run “java -jar
app.jar” (assuming everyone has a recent JVM). For bigger deployments, you can use Warbler to
make a .war file—but that requires configuring an application server: definitely overkill for small
projects.
1-2-3-4

             1. vendor everything
             2. extract jars from your binary gems
             3. let rawr do the heavy lifting
             4. combine your jar with jruby-complete




The “rawr” project provides some recipes for packing Ruby code into a .jar, with a small Java
bootstrapper. Here are the four basic steps involved.
1. vendor everything
   # This file is auto-generated;
   # use 'rake gems:vendor' to update it.

                                                              TE
   %w(activerecord-2.3.4

                                  L
       activerecord-jdbc-adapter-0.9.2                      E
       activesupport-2.3.4
                                SO
       activerecord-jdbcsqlite3-adapter-0.9.2

       haml-2.2.13

                      O
       jdbc-sqlite3-3.6.3.054
       rack-1.0.1
                              B
       sinatra-0.9.4).each do |dir|
     $: << File.dirname(__FILE__) + "/#{dir}/lib"
   end

Trying to disentangle the notion of a GEM_HOME from the weird file paths inside .jars is... nontrivial.
You can avoid the fuss by just putting your dependencies into the .jar as plain old Ruby libraries, a
bit like Rails’ vendored gems.
1 (revised). use Bundler
              bundle_path 'lib/ruby'
              bin_path    'lib/ruby/bin'

              gem     'activerecord'
              gem     'activerecord-jdbc-adapter'
              gem     'activerecord-jdbcsqlite3-adapter'
              gem     'activesupport'
              gem     'haml'
              gem     'jdbc-sqlite3'
              gem     'rack'
              gem     'sinatra'



The Bundler library can automate this step for you.
2. binary gems
  desc 'Extract jars from our gems into staging area'

  task :unjar => 'package/classes' do
    Dir['lib/ruby/**/*.jar'].each do |jar|
      path = File.expand_path(jar)

      Dir.chdir 'package/classes' do
        sh "jar -xf #{path}"
      end
    end
  end



Some gems, notably including ActiveRecord database adapters, contain .jars. Java can’t load these
from within another .jar. One workaround is to extract the .class files out of the sub-.jars for
inclusion in your project. (Another approach is to use something like JarJar.)
3. rawr
  # build_configuration.rb
  configuration do |c|
    # ...

     c.source_dirs = ['src', 'lib/ruby']
     c.source_exclude_filter = Dir['lib/ruby/**/*.java'].map do
       |file|

       Regexp.new(
         File.basename(file).gsub(".", ".") + "$")
     end

    # ...
  end



The default configuration of rawr gets confused by gems that include .java files. The easiest thing to
do is tell it to skip these files. It would be nice if rawr’s configuration file took a glob-style file
pattern, but for now, you can make do with an array of regular expressions.
4a. unjar
desc 'Extract app and jruby-complete 
for later combining'

task :stage => 'package/bigjar/contents' do
  Dir.chdir('package/bigjar/contents') do
    sh 'jar -xf ../../jar/appapp.jar'
    sh 'jar -xf ../../jar/lib/java/jruby-complete.jar'
  end
end




At this point, you’ve got your app.jar and a stock jruby-complete.jar. That fits the “C” grade on our
success criteria, so we could stop here. But it’s not too big of an extra step to combine those into a
single .jar. That should earn us at least a “B.” First, extract them into the same directory.
4b. manifest
desc 'Point the big jar manifest at our app'

task :manifest do
  manifest = IO.read 
    'package/bigjar/contents/META-INF/MANIFEST.MF'

   manifest.gsub! /^Main-Class: .+$/,
                  'Main-Class: org.rubyforge.rawr.Main'

  File.open('package/bigjar/manifest', 'w') do
    |f| f.write manifest
  end
end

Then, change the main class in the manifest from the JRuby interpreter to the rawr-generated
bootstrapper.
4c. combine

 desc 'Combine staged app and 
 jruby-complete files into one jar'

 task :package do
   Dir.chdir('package/bigjar') do
     sh 'jar -cfm appapp.jar manifest -C contents/ .'
   end
 end




Finally, combine them all into one jar.
5-6-7-8

             task :default => %w(
               gems:bundle
               gems:unjar
               rawr:jar
               app:stage app:manifest app:package)




Just to run this idea into the ground, here are those four basic steps again, expressed as Rake
tasks.
}            /undees/appapp



An example of this technique is available on GitHub and Bitbucket. The demo app is a silly web front
end around some iPhone app store data. To run it, you’ll need to download the app store CSV data
provided by busted-loop.com and run a couple of Rake tasks to populate your database first. See
the Rakefile for details.
overall grade:



                                    B-
A single .jar, with no embedded stylesheets or images, is nearly enough to earn a solid B according
to our success criteria. All that’s left to do is fix one minor quirk (the app currently has to be run
from a subfolder of the working directory).

More Related Content

PDF
"Mobage DBA Fight against Big Data" - NHN TE
PDF
When Ruby Meets Java - The Power of Torquebox
PPTX
Dmp hadoop getting_start
PDF
TorqueBox - When Java meets Ruby
PDF
PuppetConf. 2016: Puppet Best Practices: Roles & Profiles – Gary Larizza, Puppet
PDF
Kickin' Ass with Cache-Fu (without notes)
 
PDF
Kickin' Ass with Cache-Fu (with notes)
 
PDF
Hong Qiangning in QConBeijing
"Mobage DBA Fight against Big Data" - NHN TE
When Ruby Meets Java - The Power of Torquebox
Dmp hadoop getting_start
TorqueBox - When Java meets Ruby
PuppetConf. 2016: Puppet Best Practices: Roles & Profiles – Gary Larizza, Puppet
Kickin' Ass with Cache-Fu (without notes)
 
Kickin' Ass with Cache-Fu (with notes)
 
Hong Qiangning in QConBeijing

What's hot (20)

PDF
[Spring Camp 2013] Java Configuration 없인 못살아!
PDF
FOSDEM 2012: MySQL synchronous replication in practice with Galera
PDF
Ecos基础应用介绍
PDF
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
PDF
Drupal Pilipinas Apprentice: LAMP Administration, CSS, and Vagrant
PDF
JRuby @ Boulder Ruby
PDF
Puppet Camp Boston 2014: Greenfield Puppet: Getting it right from the start (...
PDF
RubyEnRails2007 - Dr Nic Williams - DIY Syntax
PDF
RubyEnRails2007 - Dr Nic Williams - Keynote
PDF
RubyGems 3 & 4
PDF
MySQLドライバの改良と軽量O/Rマッパーの紹介
PDF
Practical Testing of Ruby Core
PDF
High Performance tDiary
PDF
Perl Stored Procedures for MySQL (2009)
PDF
RubyGems 3 & 4
PPTX
Harmonious Development: Standardizing The Deployment Process via Vagrant and ...
DOC
Apache hadoop 2_installation
PPTX
Herd your chickens: Ansible for DB2 configuration management
PDF
Php on Windows
PDF
Macruby& Hotcocoa presentation by Rich Kilmer
[Spring Camp 2013] Java Configuration 없인 못살아!
FOSDEM 2012: MySQL synchronous replication in practice with Galera
Ecos基础应用介绍
RestfulX “The RESTful Way to develop Adobe Flex and AIR applications”
Drupal Pilipinas Apprentice: LAMP Administration, CSS, and Vagrant
JRuby @ Boulder Ruby
Puppet Camp Boston 2014: Greenfield Puppet: Getting it right from the start (...
RubyEnRails2007 - Dr Nic Williams - DIY Syntax
RubyEnRails2007 - Dr Nic Williams - Keynote
RubyGems 3 & 4
MySQLドライバの改良と軽量O/Rマッパーの紹介
Practical Testing of Ruby Core
High Performance tDiary
Perl Stored Procedures for MySQL (2009)
RubyGems 3 & 4
Harmonious Development: Standardizing The Deployment Process via Vagrant and ...
Apache hadoop 2_installation
Herd your chickens: Ansible for DB2 configuration management
Php on Windows
Macruby& Hotcocoa presentation by Rich Kilmer
Ad

Viewers also liked (8)

PPTX
A World of Playfulness
PPTX
We are playful
PDF
Playfulness at Work
KEY
Logic Lessons That Last Generations
PDF
JRuby, Not Just For Hard-Headed Pragmatists Anymore
KEY
Your Own Metric System
PDF
Thnad's Revenge
PDF
Write Your Own JVM Compiler
A World of Playfulness
We are playful
Playfulness at Work
Logic Lessons That Last Generations
JRuby, Not Just For Hard-Headed Pragmatists Anymore
Your Own Metric System
Thnad's Revenge
Write Your Own JVM Compiler
Ad

Similar to A jar-nORM-ous Task (20)

PDF
Buildr In Action @devoxx france 2012
PDF
Gradle talk, Javarsovia 2010
PDF
JRuby on Rails Deployment: What They Didn't Tell You
PDF
Crank Up Your Apps With TorqueBox
PDF
Jaoo Michael Neale 09
KEY
Ruby on Rails survival guide of an aged Java developer
PDF
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
PPT
Practical JRuby
KEY
Практики применения JRuby
PPTX
Leaner microservices with Java 10
PDF
The Future of Dependency Management for Ruby
PDF
JRuby, Ruby, Rails and You on the Cloud
KEY
Jruby synergy-of-ruby-and-java
PDF
Monkeybars in the Manor
KEY
把鐵路開進視窗裡
PDF
Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010
PPT
Gradle: The Build system you have been waiting for
PDF
PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...
PDF
Challenges of container configuration
PPTX
How to build your query engine in spark
Buildr In Action @devoxx france 2012
Gradle talk, Javarsovia 2010
JRuby on Rails Deployment: What They Didn't Tell You
Crank Up Your Apps With TorqueBox
Jaoo Michael Neale 09
Ruby on Rails survival guide of an aged Java developer
JRuby + Rails = Awesome Java Web Framework at Jfokus 2011
Practical JRuby
Практики применения JRuby
Leaner microservices with Java 10
The Future of Dependency Management for Ruby
JRuby, Ruby, Rails and You on the Cloud
Jruby synergy-of-ruby-and-java
Monkeybars in the Manor
把鐵路開進視窗裡
Getting Started with Rails on GlassFish (Hands-on Lab) - Spark IT 2010
Gradle: The Build system you have been waiting for
PuppetConf 2016: The Challenges with Container Configuration – David Lutterko...
Challenges of container configuration
How to build your query engine in spark

Recently uploaded (20)

PDF
2021 HotChips TSMC Packaging Technologies for Chiplets and 3D_0819 publish_pu...
PPTX
OMC Textile Division Presentation 2021.pptx
PDF
STKI Israel Market Study 2025 version august
PDF
TrustArc Webinar - Click, Consent, Trust: Winning the Privacy Game
PDF
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PPTX
TLE Review Electricity (Electricity).pptx
PDF
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
PDF
A contest of sentiment analysis: k-nearest neighbor versus neural network
PDF
Univ-Connecticut-ChatGPT-Presentaion.pdf
PDF
Hindi spoken digit analysis for native and non-native speakers
PPTX
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
PPT
Module 1.ppt Iot fundamentals and Architecture
PPTX
Chapter 5: Probability Theory and Statistics
PPTX
Final SEM Unit 1 for mit wpu at pune .pptx
PDF
project resource management chapter-09.pdf
PDF
NewMind AI Weekly Chronicles - August'25-Week II
PDF
Architecture types and enterprise applications.pdf
PDF
Enhancing emotion recognition model for a student engagement use case through...
PPT
What is a Computer? Input Devices /output devices
2021 HotChips TSMC Packaging Technologies for Chiplets and 3D_0819 publish_pu...
OMC Textile Division Presentation 2021.pptx
STKI Israel Market Study 2025 version august
TrustArc Webinar - Click, Consent, Trust: Winning the Privacy Game
ENT215_Completing-a-large-scale-migration-and-modernization-with-AWS.pdf
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
TLE Review Electricity (Electricity).pptx
Video forgery: An extensive analysis of inter-and intra-frame manipulation al...
A contest of sentiment analysis: k-nearest neighbor versus neural network
Univ-Connecticut-ChatGPT-Presentaion.pdf
Hindi spoken digit analysis for native and non-native speakers
MicrosoftCybserSecurityReferenceArchitecture-April-2025.pptx
Module 1.ppt Iot fundamentals and Architecture
Chapter 5: Probability Theory and Statistics
Final SEM Unit 1 for mit wpu at pune .pptx
project resource management chapter-09.pdf
NewMind AI Weekly Chronicles - August'25-Week II
Architecture types and enterprise applications.pdf
Enhancing emotion recognition model for a student engagement use case through...
What is a Computer? Input Devices /output devices

A jar-nORM-ous Task

  • 1. a jar-nORM-ous task simple data-backed web app in a single jar Ian Dees www.ian.dees.name ● @undees JRubyConf 2009 Hi. I’m Ian, a JRuby user. This talk is about deploying a Ruby app in a single .jar file. When you’re leaning on big frameworks like ActiveRecord, there are a few things to remember when you package your app.
  • 2. CRUD - CUD Imagine you’re handed some database credentials, and you want to whip up a web front end in Sinatra to browse around the data. Let’s say the schema is simple and fairly normalized: the sweet spot for ActiveRecord. Photo (cc) flickr.com/photos/treehouse1977/1425246464
  • 3. define “success” images and stylesheets A B single .jar C app.jar + jruby.jar D “Install Ruby....” F “Install....” MRI and MySQL present some deployment challenges, even when everyone is on the same platform. With JRuby, you can just hand out a couple of .jar files and have people run “java -jar app.jar” (assuming everyone has a recent JVM). For bigger deployments, you can use Warbler to make a .war file—but that requires configuring an application server: definitely overkill for small projects.
  • 4. 1-2-3-4 1. vendor everything 2. extract jars from your binary gems 3. let rawr do the heavy lifting 4. combine your jar with jruby-complete The “rawr” project provides some recipes for packing Ruby code into a .jar, with a small Java bootstrapper. Here are the four basic steps involved.
  • 5. 1. vendor everything # This file is auto-generated; # use 'rake gems:vendor' to update it. TE %w(activerecord-2.3.4 L activerecord-jdbc-adapter-0.9.2 E activesupport-2.3.4 SO activerecord-jdbcsqlite3-adapter-0.9.2 haml-2.2.13 O jdbc-sqlite3-3.6.3.054 rack-1.0.1 B sinatra-0.9.4).each do |dir| $: << File.dirname(__FILE__) + "/#{dir}/lib" end Trying to disentangle the notion of a GEM_HOME from the weird file paths inside .jars is... nontrivial. You can avoid the fuss by just putting your dependencies into the .jar as plain old Ruby libraries, a bit like Rails’ vendored gems.
  • 6. 1 (revised). use Bundler bundle_path 'lib/ruby' bin_path 'lib/ruby/bin' gem 'activerecord' gem 'activerecord-jdbc-adapter' gem 'activerecord-jdbcsqlite3-adapter' gem 'activesupport' gem 'haml' gem 'jdbc-sqlite3' gem 'rack' gem 'sinatra' The Bundler library can automate this step for you.
  • 7. 2. binary gems desc 'Extract jars from our gems into staging area' task :unjar => 'package/classes' do Dir['lib/ruby/**/*.jar'].each do |jar| path = File.expand_path(jar) Dir.chdir 'package/classes' do sh "jar -xf #{path}" end end end Some gems, notably including ActiveRecord database adapters, contain .jars. Java can’t load these from within another .jar. One workaround is to extract the .class files out of the sub-.jars for inclusion in your project. (Another approach is to use something like JarJar.)
  • 8. 3. rawr # build_configuration.rb configuration do |c| # ... c.source_dirs = ['src', 'lib/ruby'] c.source_exclude_filter = Dir['lib/ruby/**/*.java'].map do |file| Regexp.new( File.basename(file).gsub(".", ".") + "$") end # ... end The default configuration of rawr gets confused by gems that include .java files. The easiest thing to do is tell it to skip these files. It would be nice if rawr’s configuration file took a glob-style file pattern, but for now, you can make do with an array of regular expressions.
  • 9. 4a. unjar desc 'Extract app and jruby-complete for later combining' task :stage => 'package/bigjar/contents' do Dir.chdir('package/bigjar/contents') do sh 'jar -xf ../../jar/appapp.jar' sh 'jar -xf ../../jar/lib/java/jruby-complete.jar' end end At this point, you’ve got your app.jar and a stock jruby-complete.jar. That fits the “C” grade on our success criteria, so we could stop here. But it’s not too big of an extra step to combine those into a single .jar. That should earn us at least a “B.” First, extract them into the same directory.
  • 10. 4b. manifest desc 'Point the big jar manifest at our app' task :manifest do manifest = IO.read 'package/bigjar/contents/META-INF/MANIFEST.MF' manifest.gsub! /^Main-Class: .+$/, 'Main-Class: org.rubyforge.rawr.Main' File.open('package/bigjar/manifest', 'w') do |f| f.write manifest end end Then, change the main class in the manifest from the JRuby interpreter to the rawr-generated bootstrapper.
  • 11. 4c. combine desc 'Combine staged app and jruby-complete files into one jar' task :package do Dir.chdir('package/bigjar') do sh 'jar -cfm appapp.jar manifest -C contents/ .' end end Finally, combine them all into one jar.
  • 12. 5-6-7-8 task :default => %w( gems:bundle gems:unjar rawr:jar app:stage app:manifest app:package) Just to run this idea into the ground, here are those four basic steps again, expressed as Rake tasks.
  • 13. } /undees/appapp An example of this technique is available on GitHub and Bitbucket. The demo app is a silly web front end around some iPhone app store data. To run it, you’ll need to download the app store CSV data provided by busted-loop.com and run a couple of Rake tasks to populate your database first. See the Rakefile for details.
  • 14. overall grade: B- A single .jar, with no embedded stylesheets or images, is nearly enough to earn a solid B according to our success criteria. All that’s left to do is fix one minor quirk (the app currently has to be run from a subfolder of the working directory).