Published on

Presentation to Houston Ruby/Rails group on rjb (04/07).

Published in: Technology
  • Be the first to comment

  • Be the first to like this

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide


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