Ruby-Java Bridge Leveraging existing Java solutions in your Ruby/Rails applications Wes Gamble Bison Consulting [email_address]
Java in 4 (or 5) bullets 1995 - ???, Object oriented, statically typed Java runs on a virtual machine that interprets compiled Java bytecodes.  Each hardware architecture has its own JVM runtime (JRE) Originally, the expected use of Java was in “applets” that ran in Web browsers to allow complex client side Web app. processing, but over time, people began to use it for more server side concerns, leading to… J2EE (many many standards, frameworks, etc.) J2ME, other stuff
So what – why do we care about Java, anyway? Web app. development in Java for close to 10 years – there are a lot of great libraries out there Sometimes Ruby falls short of our needs – limited libraries available to solve problems Some of us come from the Java world, and are already familiar with how to solve certain application problems with Java technology Some Ruby libraries are C-based which requires recompilation if you deploy on multiple platforms – Java libraries run anywhere
Ruby/Java integration solutions Rjb: A simple API that allows Ruby code to use Java objects  http://rjb.rubyforge.org/ Written by Akio Tajima, aka “arton” Yajb: older, doesn’t appear to be under active development  http://raa.ruby-lang.org/project/yajb/ Java implementation of Ruby interpreter Ambitious, making huge strides Hoping to rival native Ruby speed http://jruby.codehaus.org/
Why Rjb instead of JRuby? Simple and easy to use Not a complete replacement of the entire Ruby interpreter like JRuby Works with regular interpreter seamlessly (C-based extensions have to be re-implemented in Java to run in JRuby) JRuby is close to, but arguably not quite ready for prime time yet
How does Rjb work? Ruby rjb Proxy class Proxy instance JVM Created using JNI Java class Java instance caller Import class klass.new method()
Using Rjb – System Requirements Java runtime environment (JRE) JAVA_HOME environment variable set Unix/Linux only: LD_LIBRARY_PATH needs to point to Java shared object (.so) files  (e.g. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386: $JAVA_HOME/jre/lib/i386/client) OS X: rjb does not look up JAVA_HOME environment variable, but /System/Library/Frameworks/JavaVM.framework/Libraries/libjvm_compat.dylib directly. So you need to set appropriate Java version using /System/Library/Frameworks/JavaVM.framework/Libraries symbolic link.
Using Rjb – Load the JVM require  'rjb' gem  'rjb' ,  '>= 1.0.3‘ separator = Config::CONFIG[ 'target_os' ] =~  /win/ ? ';' : ':’ classpath = [ "#{RAILS_ROOT}/lib/jxl.jar" ,  "#{RAILS_ROOT}/lib/qbservices.jar" ,  "#{RAILS_ROOT}/lib/jtds-1.2.jar" ].join(separator) Rjb::load(classpath, [ '-Xmx512M' ])  #POOF – Java runtime! Do this once for the app. (environment.rb in a Rails app.)  Optional unless classpath, JVM options required.
Using Rjb – Example #1 #Returns a Java jxl.Workbook object which may then be used “natively”.  Don't forget that it's a Java object!  This is an example of a class method call – no object instantiation. def  ESimplyUtil.parse_excel(filename) file_class = Rjb::import( 'java.io.File' ) workbook_class = Rjb::import( 'jxl.Workbook' ) workbook = workbook_class.getWorkbook(file_class. new (filename)) end …… workbook = ESimplyUtil.parse_excel(“test.xls”) workbook.getSheet(2) Manipulating an Excel spreadsheet using JExcelAPI
Using Rjb – Example #2 #EstimateService is a Java class  #The EstimateService.estimate method returns an Estimate Java object #Estimate.getEstimateItems returns a Java collection def  generate_cost_estimate estimate_service = Rjb::import( 'EstimateService' ). new @estimate  = estimate_service.estimate( ‘564765’ ) @estimate_item  =  @estimate .getEstimateItems[ 0 ] end Using a custom Java library created by another developer
Using Rjb – Type Management All Java primitives are automatically coerced into appropriate Ruby objects Ruby strings are coerced into Java strings Java objects are wrapped in an anonymous Ruby class (BTW, these wrapped Java objects cannot be marshaled/unmarshaled because they have no class name) However, input parameters to Java methods must have their type specified if the methods are overridden.  Rjb doesn’t dynamically determine which one of the overridden methods to call.
Using Rjb – Type Management When type information is required, a string is passed that contains encoded type information (see J2SE Class#getName API docs. for more detail) Example: Calling the Java String constructor method that takes a byte array and a string (character set) as arguments – assume str_class is a ‘java.lang.String’ str_class.new_with_sig('[BLjava.lang.String;', [48, 49, 50], 'Windows-31j') [B means “byte array” (the [ means array and the B means byte) Ljava.lang.String; is the class name of the 2 nd  argument
Using Rjb – Constructors To instantiate a Java class using the default constructor, use  klass.new To instantiate a Java class that takes parameters, use klass#new_with_sig(sig, arg[, more args]) where sig is the encoded type signature string and args are the actual arguments
Using Rjb – Constructor Example Assume that str is a Java string class No argument constructor instance = str.new  #Ruby with rjb String instance = new String();  //equivalent Java Constructor with arguments instance = str.new_with_sig('Ljava.lang.String;', 'hiki is a wiki engine')  #Ruby with rjb String instance = new String(“hiki is a wiki engine”)  //equivalent Java
Using Rjb – Invoking methods on Java objects If the Java method is NOT overloaded, then simply use java_obj.meth(arg1, arg2…, argn) If the Java method is overloaded, then you must provide type information for each argument, so use obj#_invoke(name, sig, arg[, more args])  where name is method name, sig is encoded type signature, and args are arguments
Using Rjb – Method Call Example Assume that str_obj is an instance of java.lang.String Non-overridden method size_of_string = str_obj.length  #Ruby with rjb java_size_of_string = java_str_obj.length();  //equivalent Java Overridden method index_of_h = str_obj._invoke(‘indexOf’, ‘C’, ‘h’) #Ruby with rjb java_index_of_h = java_str_obj.indexOf(‘h’)  //equivalent Java
Quick Demo
The other direction – using Ruby objects in Java You can bind a Ruby object to a Java interface using Rjb::bind(obj, infc_name) as long as the Ruby object implements all of the methods in the Java interface You can throw Java exceptions from such Ruby objects if you want using Rjb::throw
Threading concerns Ruby threads are “green threads,” (all contained in one OS process) Java threads are native OS threads  Because of this, if you bound a Ruby object to a Java interface, and there was Java code that could access this Ruby object from a thread other than the main thread, you could crash the app. when the garbage collection started You’re safe doing the “call Ruby from Java thing” if you are sure that the Java caller will be single threaded
The future of Rjb? May depend some on JRuby Jrb plays nicely with native Ruby so that may matter Useful as a point solution for already existing apps. that cannot be ported to JRuby for some reason
Resources Rjb – main page:  http://rjb.rubyforge.org/ How to build Rjb:  http://arton.no-ip.info/collabo/backyard/?HowToBuildRjb How Rjb works:  http://arton.no-ip.info/collabo/backyard/? RjbMechanism Old Rjb main page:  http://arton.no-ip.info/collabo/backyard/? RubyJavaBridge Enterprise Integration with Ruby , Schmidt, 2006, pp. 230-235 Java type encoding scheme:  http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getName( )

Rjb

  • 1.
    Ruby-Java Bridge Leveragingexisting Java solutions in your Ruby/Rails applications Wes Gamble Bison Consulting [email_address]
  • 2.
    Java in 4(or 5) bullets 1995 - ???, Object oriented, statically typed Java runs on a virtual machine that interprets compiled Java bytecodes. Each hardware architecture has its own JVM runtime (JRE) Originally, the expected use of Java was in “applets” that ran in Web browsers to allow complex client side Web app. processing, but over time, people began to use it for more server side concerns, leading to… J2EE (many many standards, frameworks, etc.) J2ME, other stuff
  • 3.
    So what –why do we care about Java, anyway? Web app. development in Java for close to 10 years – there are a lot of great libraries out there Sometimes Ruby falls short of our needs – limited libraries available to solve problems Some of us come from the Java world, and are already familiar with how to solve certain application problems with Java technology Some Ruby libraries are C-based which requires recompilation if you deploy on multiple platforms – Java libraries run anywhere
  • 4.
    Ruby/Java integration solutionsRjb: A simple API that allows Ruby code to use Java objects http://rjb.rubyforge.org/ Written by Akio Tajima, aka “arton” Yajb: older, doesn’t appear to be under active development http://raa.ruby-lang.org/project/yajb/ Java implementation of Ruby interpreter Ambitious, making huge strides Hoping to rival native Ruby speed http://jruby.codehaus.org/
  • 5.
    Why Rjb insteadof JRuby? Simple and easy to use Not a complete replacement of the entire Ruby interpreter like JRuby Works with regular interpreter seamlessly (C-based extensions have to be re-implemented in Java to run in JRuby) JRuby is close to, but arguably not quite ready for prime time yet
  • 6.
    How does Rjbwork? Ruby rjb Proxy class Proxy instance JVM Created using JNI Java class Java instance caller Import class klass.new method()
  • 7.
    Using Rjb –System Requirements Java runtime environment (JRE) JAVA_HOME environment variable set Unix/Linux only: LD_LIBRARY_PATH needs to point to Java shared object (.so) files (e.g. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386: $JAVA_HOME/jre/lib/i386/client) OS X: rjb does not look up JAVA_HOME environment variable, but /System/Library/Frameworks/JavaVM.framework/Libraries/libjvm_compat.dylib directly. So you need to set appropriate Java version using /System/Library/Frameworks/JavaVM.framework/Libraries symbolic link.
  • 8.
    Using Rjb –Load the JVM require 'rjb' gem 'rjb' , '>= 1.0.3‘ separator = Config::CONFIG[ 'target_os' ] =~ /win/ ? ';' : ':’ classpath = [ "#{RAILS_ROOT}/lib/jxl.jar" , "#{RAILS_ROOT}/lib/qbservices.jar" , "#{RAILS_ROOT}/lib/jtds-1.2.jar" ].join(separator) Rjb::load(classpath, [ '-Xmx512M' ]) #POOF – Java runtime! Do this once for the app. (environment.rb in a Rails app.) Optional unless classpath, JVM options required.
  • 9.
    Using Rjb –Example #1 #Returns a Java jxl.Workbook object which may then be used “natively”. Don't forget that it's a Java object! This is an example of a class method call – no object instantiation. def ESimplyUtil.parse_excel(filename) file_class = Rjb::import( 'java.io.File' ) workbook_class = Rjb::import( 'jxl.Workbook' ) workbook = workbook_class.getWorkbook(file_class. new (filename)) end …… workbook = ESimplyUtil.parse_excel(“test.xls”) workbook.getSheet(2) Manipulating an Excel spreadsheet using JExcelAPI
  • 10.
    Using Rjb –Example #2 #EstimateService is a Java class #The EstimateService.estimate method returns an Estimate Java object #Estimate.getEstimateItems returns a Java collection def generate_cost_estimate estimate_service = Rjb::import( 'EstimateService' ). new @estimate = estimate_service.estimate( ‘564765’ ) @estimate_item = @estimate .getEstimateItems[ 0 ] end Using a custom Java library created by another developer
  • 11.
    Using Rjb –Type Management All Java primitives are automatically coerced into appropriate Ruby objects Ruby strings are coerced into Java strings Java objects are wrapped in an anonymous Ruby class (BTW, these wrapped Java objects cannot be marshaled/unmarshaled because they have no class name) However, input parameters to Java methods must have their type specified if the methods are overridden. Rjb doesn’t dynamically determine which one of the overridden methods to call.
  • 12.
    Using Rjb –Type Management When type information is required, a string is passed that contains encoded type information (see J2SE Class#getName API docs. for more detail) Example: Calling the Java String constructor method that takes a byte array and a string (character set) as arguments – assume str_class is a ‘java.lang.String’ str_class.new_with_sig('[BLjava.lang.String;', [48, 49, 50], 'Windows-31j') [B means “byte array” (the [ means array and the B means byte) Ljava.lang.String; is the class name of the 2 nd argument
  • 13.
    Using Rjb –Constructors To instantiate a Java class using the default constructor, use klass.new To instantiate a Java class that takes parameters, use klass#new_with_sig(sig, arg[, more args]) where sig is the encoded type signature string and args are the actual arguments
  • 14.
    Using Rjb –Constructor Example Assume that str is a Java string class No argument constructor instance = str.new #Ruby with rjb String instance = new String(); //equivalent Java Constructor with arguments instance = str.new_with_sig('Ljava.lang.String;', 'hiki is a wiki engine') #Ruby with rjb String instance = new String(“hiki is a wiki engine”) //equivalent Java
  • 15.
    Using Rjb –Invoking methods on Java objects If the Java method is NOT overloaded, then simply use java_obj.meth(arg1, arg2…, argn) If the Java method is overloaded, then you must provide type information for each argument, so use obj#_invoke(name, sig, arg[, more args]) where name is method name, sig is encoded type signature, and args are arguments
  • 16.
    Using Rjb –Method Call Example Assume that str_obj is an instance of java.lang.String Non-overridden method size_of_string = str_obj.length #Ruby with rjb java_size_of_string = java_str_obj.length(); //equivalent Java Overridden method index_of_h = str_obj._invoke(‘indexOf’, ‘C’, ‘h’) #Ruby with rjb java_index_of_h = java_str_obj.indexOf(‘h’) //equivalent Java
  • 17.
  • 18.
    The other direction– using Ruby objects in Java You can bind a Ruby object to a Java interface using Rjb::bind(obj, infc_name) as long as the Ruby object implements all of the methods in the Java interface You can throw Java exceptions from such Ruby objects if you want using Rjb::throw
  • 19.
    Threading concerns Rubythreads are “green threads,” (all contained in one OS process) Java threads are native OS threads Because of this, if you bound a Ruby object to a Java interface, and there was Java code that could access this Ruby object from a thread other than the main thread, you could crash the app. when the garbage collection started You’re safe doing the “call Ruby from Java thing” if you are sure that the Java caller will be single threaded
  • 20.
    The future ofRjb? May depend some on JRuby Jrb plays nicely with native Ruby so that may matter Useful as a point solution for already existing apps. that cannot be ported to JRuby for some reason
  • 21.
    Resources Rjb –main page: http://rjb.rubyforge.org/ How to build Rjb: http://arton.no-ip.info/collabo/backyard/?HowToBuildRjb How Rjb works: http://arton.no-ip.info/collabo/backyard/? RjbMechanism Old Rjb main page: http://arton.no-ip.info/collabo/backyard/? RubyJavaBridge Enterprise Integration with Ruby , Schmidt, 2006, pp. 230-235 Java type encoding scheme: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getName( )