JRuby -- Java/Ruby Synergy Keith Bennett keithrbennett --at-- gmail.com @keithrbennett
What is JRuby? An implementation of the Ruby language on the Java Virtual Machine: • Open Source • Main site at http://jruby.org/ • Source Code at https://github.com/jruby/jruby • Matz writes C so we don't have to; the JRuby team writes Java so we don't have to. • Both1.8 and 1.9 compatible.
Non-Java Languages on the JVM "The Java virtual machine knows nothing of the Java programming language, only of a particular binary format, the class file format." - from http://java.sun.com/developer/technicalArticles/DynTypeLang/ • JRuby • Scala • Clojure • Groovy • JavaScript
Technical Benefits of Running Ruby on the JVM • mature and stable platform • more portable – runs on older and obscure OS's that have JVM's • access to a huge number of libraries, e.g. XML, SOAP • excellent performance, garbage collection, and multithreading • performance tuning and profiling tools (e.g. jvisualvm) • excellent I18N (internationalization) support • highly scalable • can drive Java API's
Benefits of Ruby on the JVM for Enterprise Java Shops • all the technical benefits previously mentioned, plus: • can use Ruby DB tools such as Active Record (esp. useful for migrations), DBI, etc. • can introduce development staff to scripting languages in general, and Ruby in particular • can automate one-off tasks that were previously too cost prohibitive to automate • can grow Ruby expertise that can be applied to various kinds of tasks (e.g. testing, scripting, web development) • can introduce it in a way that will not be distributed with production code • can use it for saner and more rapid development of Swing or SWT client-side GUI apps (see JRuby as a Better Language for the JVM - http://krbtech.wordpress.com/2009/02/26/jruby-a- better-language-for-the-javavirtual-machine/
Benefits of Using JRuby for Ruby Developers • all the technical benefits previously mentioned, plus: • enables expanding customer base to include Java shops, many of which are very large and well funded. • enables creation of better solutions by increasing the set of parts that can be assembled into a solution -- sometimes Java is better (e.g. XML, SOAP support).
Calling Java from Ruby require 'java' java.lang.System.properties.sort.each do |k,v| printf("%-30s %sn", k, v) } end displays: awt.nativeDoubleBuffering true awt.toolkit apple.awt.CToolkit file.encoding UTF-8 file.encoding.pkg sun.io file.separator / gopherProxySet false java.awt.printerjob apple.awt.CPrinterJob java.class.path java.class.version 50.0 …
Adding Ruby methods to Java Classes require 'java' java_import java.lang.System class System def self.properties_pp s = '' properties.sort.each do |k,v| s << sprintf("%-34s %sn", k, v) end s end end puts System.properties_pp
JRuby Method Generation JRuby generates snake-cased named methods for Java camel-case named methods, and conventional reader and writer methods à la attr_accessor: # The java.util.Locale class contains only getDefault and setDefault. # JRuby adds the others: jruby-1.6.5 :003 > puts Locale.methods.sort.grep /[Dd]efault/ default default= getDefault get_default setDefault set_default Also, JRuby makes the Enumerable interface available to some kinds of Java objects, enabling the above, and the following: Locale.iSOCountries.each { |country_code| puts country_code } Locale.iSOLanguages.each { |language_code| puts language_code }
JRuby to Java Type Conversions jruby-1.6.5 :027 > 123.class => Fixnum jruby-1.6.5 :028 > 123.to_java.class => Java::JavaLang::Long
Calling JRuby from Java import org.jruby.embed.ScriptingContainer; public class ScriptingContainerExample { public static void main(String[] args) { ScriptingContainer container = new ScriptingContainer(); container.put("$greeting", "Hello from JRuby!"); // optional // container.setLoadPaths(aJavaListOfDirectories); // optional container.setCompatVersion(org.jruby.CompatVersion.RUBY1_9); // optional container.runScriptlet("puts $greeting"); } } // >javac -cp ".:$JRUBY_JAR" ScriptingContainerExample.java // >java -cp ".:$JRUBY_JAR" ScriptingContainerExample // Hello from JRuby!
Special Java Support Calls • java_import - Imports java classes • java_send - for specifying which function to call, by signature • java_alias - for creating an alias for a Java function with signature • java_method - for creating a callable reference to a Java function with signature • field_accessor - for accessing Java instance variables, even private ones • add_class_annotation - Adds a class annotation to a Ruby class • become_java! - "promotes" a Ruby class to be a Java class • include - can be used to signal that this class implements a Java interface
Compiling JRuby The JRuby distribution comes with jrubyc, a compiler that can produce either Java class files, or Java source (run jrubyc --help for details). rvm jruby echo "puts 'hello'" > hello.rb jrubyc hello.rb ls -l hello* javap -v hello | less Free code obfuscation: Since only the .class file is need to run your app, you can withhold the source code from your users and provide only the .class file. The .class file can be decompiled, but will be difficult to comprehend, since Java byte code is similar in concept to assembler code.
Omitting the ‘J’ in JRuby Normally, it is necessary to run JRuby commands (jruby, jirb) with their distinctive names beginning with j. rvm eliminates the need for this. rvm jruby which ruby # /Users/kbennett/.rvm/rubies/jruby-1.6.5/bin/ruby which jruby # /Users/kbennett/.rvm/rubies/jruby-1.6.5/bin/jruby ls -l /Users/kbennett/.rvm/rubies/jruby-1.6.5/bin # lrwxr-xr-x 1 kbennett staff 5 Jan 19 13:25 ruby -> jruby
Defaulting to 1.9 Most people will want JRuby to run in 1.9 mode. To automate this, ensure that the environment variable JRUBY_OPTS will contain --1.9. Most developers will accomplish this by inserting the following line in their shell startup script (e.g. .bashrc, .zshrc): export JRUBY_OPTS=--1.9 This can be overridden by eliminating or replacing that environment variable’s value: JRUBY_OPTS= ruby ... # or export JRUBY_OPTS=
Nailgun Nailgun is a tool packaged with JRuby that enables sharing a single JRuby virtual machine instance by JRuby scripts to eliminate the delay associated with JVM startup. # If $JRUBY_OPTS contains “--1.9” so that JRuby runs # in 1.9 mode by default, then this must be overridden # for the Nailgun server to start. # See but at http://jira.codehaus.org/browse/JRUBY-5611. # Start up the shared Nailgun server: JRUBY_OPTS= jruby –ng-server time ruby -e "puts 123" #123 #ruby -e "puts 123" 2.89s user 0.14s system 217% cpu 1.390 total time ruby --ng -e "puts 123" #123 #ruby --ng -e "puts 123" 0.00s user 0.00s system 0% cpu 0.488 total
Warbler “Warbler is a gem that makes a .war file out of a Rails, Merb, or Rack-based application. The intent is to provide a minimal, flexible, ruby-like way to bundle all your application files for deployment to a Java application server.” - http://kenai.com/projects/warbler/pages/Home Similarly, you can combine jruby.jar and your Ruby code into a single .jar file that can be executed simply and automatically by the operating system.
JVisualVM JVisualVM is a monitoring, profiling, and troubleshooting tool packaged with the JDK (Java Development Kit).
Sample Multithreaded Program num_threads = 5 threads = [] (0...num_threads).each do |n| threads << Thread.new do loop { puts "#{' ' * (5 * n)}#{n}n" } end end threads.each { |thread| thread.join }
Multithreading CPU Usage by Ruby Version rvm 1.8 ruby multithread.rb PID COMMAND %CPU TIME #TH #WQ #POR #MREG RPRVT RSHRD RSIZE 367 Terminal 105.8 01:20.36 5/1 1 123- 166+ 267M+ 43M 278M+ 1104 ruby 82.7 00:13.40 1/1 0 18 28 1248K 240K 2108K rvm 1.9 ruby multithread.rb PID COMMAND %CPU TIME #TH #WQ #POR #MREG RPRVT RSHRD RSIZE 1249 ruby 167.6 00:20.85 7/2 0 41 61 2972K+ 240K 4632K+ 367 Terminal 153.0 03:49.55 5/1 1 125 267 716M+ 43M 772M+ # What happened? I thought 1.9 used a GIL (Global Interpreter Lock)? rvm jruby ruby multithread.rb ID COMMAND %CPU TIME #TH #WQ #POR #MREG RPRVT RSHRD RSIZE 1364 java 137.1 00:25.84 23/2 1 201 236 80M 3144K 93M 367 Terminal 120.8 05:05.62 6/1 2 127- 291 813M+ 43M 901M+
References • JRuby Main Site: http://jruby.org • JRuby Book: http://pragprog.com/book/jruby/using-jruby • Charlie Nutter's JRuby Slide Show: http://www.slideshare.net/CharlesNutter/rubyconf-uruguay-2010-jruby • JRuby as a Better Language for the JVM - http://krbtech.wordpress.com/ 2009/02/26/jruby-a-better-language-for-the-javavirtual-machine/ • Multilanguage Swing Github Repo: https://github.com/keithrbennett/multilanguage-swing • This slideshow: http://www.slideshare.net/keithrbennett/jruby-synergyofrubyandjava

Jruby synergy-of-ruby-and-java

  • 1.
    JRuby -- Java/RubySynergy Keith Bennett keithrbennett --at-- gmail.com @keithrbennett
  • 2.
    What is JRuby? Animplementation of the Ruby language on the Java Virtual Machine: • Open Source • Main site at http://jruby.org/ • Source Code at https://github.com/jruby/jruby • Matz writes C so we don't have to; the JRuby team writes Java so we don't have to. • Both1.8 and 1.9 compatible.
  • 3.
    Non-Java Languages onthe JVM "The Java virtual machine knows nothing of the Java programming language, only of a particular binary format, the class file format." - from http://java.sun.com/developer/technicalArticles/DynTypeLang/ • JRuby • Scala • Clojure • Groovy • JavaScript
  • 4.
    Technical Benefits ofRunning Ruby on the JVM • mature and stable platform • more portable – runs on older and obscure OS's that have JVM's • access to a huge number of libraries, e.g. XML, SOAP • excellent performance, garbage collection, and multithreading • performance tuning and profiling tools (e.g. jvisualvm) • excellent I18N (internationalization) support • highly scalable • can drive Java API's
  • 5.
    Benefits of Rubyon the JVM for Enterprise Java Shops • all the technical benefits previously mentioned, plus: • can use Ruby DB tools such as Active Record (esp. useful for migrations), DBI, etc. • can introduce development staff to scripting languages in general, and Ruby in particular • can automate one-off tasks that were previously too cost prohibitive to automate • can grow Ruby expertise that can be applied to various kinds of tasks (e.g. testing, scripting, web development) • can introduce it in a way that will not be distributed with production code • can use it for saner and more rapid development of Swing or SWT client-side GUI apps (see JRuby as a Better Language for the JVM - http://krbtech.wordpress.com/2009/02/26/jruby-a- better-language-for-the-javavirtual-machine/
  • 6.
    Benefits of UsingJRuby for Ruby Developers • all the technical benefits previously mentioned, plus: • enables expanding customer base to include Java shops, many of which are very large and well funded. • enables creation of better solutions by increasing the set of parts that can be assembled into a solution -- sometimes Java is better (e.g. XML, SOAP support).
  • 7.
    Calling Java fromRuby require 'java' java.lang.System.properties.sort.each do |k,v| printf("%-30s %sn", k, v) } end displays: awt.nativeDoubleBuffering true awt.toolkit apple.awt.CToolkit file.encoding UTF-8 file.encoding.pkg sun.io file.separator / gopherProxySet false java.awt.printerjob apple.awt.CPrinterJob java.class.path java.class.version 50.0 …
  • 8.
    Adding Ruby methodsto Java Classes require 'java' java_import java.lang.System class System def self.properties_pp s = '' properties.sort.each do |k,v| s << sprintf("%-34s %sn", k, v) end s end end puts System.properties_pp
  • 9.
    JRuby Method Generation JRubygenerates snake-cased named methods for Java camel-case named methods, and conventional reader and writer methods à la attr_accessor: # The java.util.Locale class contains only getDefault and setDefault. # JRuby adds the others: jruby-1.6.5 :003 > puts Locale.methods.sort.grep /[Dd]efault/ default default= getDefault get_default setDefault set_default Also, JRuby makes the Enumerable interface available to some kinds of Java objects, enabling the above, and the following: Locale.iSOCountries.each { |country_code| puts country_code } Locale.iSOLanguages.each { |language_code| puts language_code }
  • 10.
    JRuby to JavaType Conversions jruby-1.6.5 :027 > 123.class => Fixnum jruby-1.6.5 :028 > 123.to_java.class => Java::JavaLang::Long
  • 11.
    Calling JRuby fromJava import org.jruby.embed.ScriptingContainer; public class ScriptingContainerExample { public static void main(String[] args) { ScriptingContainer container = new ScriptingContainer(); container.put("$greeting", "Hello from JRuby!"); // optional // container.setLoadPaths(aJavaListOfDirectories); // optional container.setCompatVersion(org.jruby.CompatVersion.RUBY1_9); // optional container.runScriptlet("puts $greeting"); } } // >javac -cp ".:$JRUBY_JAR" ScriptingContainerExample.java // >java -cp ".:$JRUBY_JAR" ScriptingContainerExample // Hello from JRuby!
  • 12.
    Special Java SupportCalls • java_import - Imports java classes • java_send - for specifying which function to call, by signature • java_alias - for creating an alias for a Java function with signature • java_method - for creating a callable reference to a Java function with signature • field_accessor - for accessing Java instance variables, even private ones • add_class_annotation - Adds a class annotation to a Ruby class • become_java! - "promotes" a Ruby class to be a Java class • include - can be used to signal that this class implements a Java interface
  • 13.
    Compiling JRuby The JRubydistribution comes with jrubyc, a compiler that can produce either Java class files, or Java source (run jrubyc --help for details). rvm jruby echo "puts 'hello'" > hello.rb jrubyc hello.rb ls -l hello* javap -v hello | less Free code obfuscation: Since only the .class file is need to run your app, you can withhold the source code from your users and provide only the .class file. The .class file can be decompiled, but will be difficult to comprehend, since Java byte code is similar in concept to assembler code.
  • 14.
    Omitting the ‘J’in JRuby Normally, it is necessary to run JRuby commands (jruby, jirb) with their distinctive names beginning with j. rvm eliminates the need for this. rvm jruby which ruby # /Users/kbennett/.rvm/rubies/jruby-1.6.5/bin/ruby which jruby # /Users/kbennett/.rvm/rubies/jruby-1.6.5/bin/jruby ls -l /Users/kbennett/.rvm/rubies/jruby-1.6.5/bin # lrwxr-xr-x 1 kbennett staff 5 Jan 19 13:25 ruby -> jruby
  • 15.
    Defaulting to 1.9 Mostpeople will want JRuby to run in 1.9 mode. To automate this, ensure that the environment variable JRUBY_OPTS will contain --1.9. Most developers will accomplish this by inserting the following line in their shell startup script (e.g. .bashrc, .zshrc): export JRUBY_OPTS=--1.9 This can be overridden by eliminating or replacing that environment variable’s value: JRUBY_OPTS= ruby ... # or export JRUBY_OPTS=
  • 16.
    Nailgun Nailgun is atool packaged with JRuby that enables sharing a single JRuby virtual machine instance by JRuby scripts to eliminate the delay associated with JVM startup. # If $JRUBY_OPTS contains “--1.9” so that JRuby runs # in 1.9 mode by default, then this must be overridden # for the Nailgun server to start. # See but at http://jira.codehaus.org/browse/JRUBY-5611. # Start up the shared Nailgun server: JRUBY_OPTS= jruby –ng-server time ruby -e "puts 123" #123 #ruby -e "puts 123" 2.89s user 0.14s system 217% cpu 1.390 total time ruby --ng -e "puts 123" #123 #ruby --ng -e "puts 123" 0.00s user 0.00s system 0% cpu 0.488 total
  • 17.
    Warbler “Warbler is agem that makes a .war file out of a Rails, Merb, or Rack-based application. The intent is to provide a minimal, flexible, ruby-like way to bundle all your application files for deployment to a Java application server.” - http://kenai.com/projects/warbler/pages/Home Similarly, you can combine jruby.jar and your Ruby code into a single .jar file that can be executed simply and automatically by the operating system.
  • 18.
    JVisualVM JVisualVM is amonitoring, profiling, and troubleshooting tool packaged with the JDK (Java Development Kit).
  • 19.
    Sample Multithreaded Program num_threads= 5 threads = [] (0...num_threads).each do |n| threads << Thread.new do loop { puts "#{' ' * (5 * n)}#{n}n" } end end threads.each { |thread| thread.join }
  • 20.
    Multithreading CPU Usageby Ruby Version rvm 1.8 ruby multithread.rb PID COMMAND %CPU TIME #TH #WQ #POR #MREG RPRVT RSHRD RSIZE 367 Terminal 105.8 01:20.36 5/1 1 123- 166+ 267M+ 43M 278M+ 1104 ruby 82.7 00:13.40 1/1 0 18 28 1248K 240K 2108K rvm 1.9 ruby multithread.rb PID COMMAND %CPU TIME #TH #WQ #POR #MREG RPRVT RSHRD RSIZE 1249 ruby 167.6 00:20.85 7/2 0 41 61 2972K+ 240K 4632K+ 367 Terminal 153.0 03:49.55 5/1 1 125 267 716M+ 43M 772M+ # What happened? I thought 1.9 used a GIL (Global Interpreter Lock)? rvm jruby ruby multithread.rb ID COMMAND %CPU TIME #TH #WQ #POR #MREG RPRVT RSHRD RSIZE 1364 java 137.1 00:25.84 23/2 1 201 236 80M 3144K 93M 367 Terminal 120.8 05:05.62 6/1 2 127- 291 813M+ 43M 901M+
  • 21.
    References • JRuby MainSite: http://jruby.org • JRuby Book: http://pragprog.com/book/jruby/using-jruby • Charlie Nutter's JRuby Slide Show: http://www.slideshare.net/CharlesNutter/rubyconf-uruguay-2010-jruby • JRuby as a Better Language for the JVM - http://krbtech.wordpress.com/ 2009/02/26/jruby-a-better-language-for-the-javavirtual-machine/ • Multilanguage Swing Github Repo: https://github.com/keithrbennett/multilanguage-swing • This slideshow: http://www.slideshare.net/keithrbennett/jruby-synergyofrubyandjava