Rjb

21
Ruby-Java Bridge Ruby-Java Bridge Leveraging existing Java Leveraging existing Java solutions in your solutions in your Ruby/Rails Ruby/Rails applications applications Wes Gamble Wes Gamble Bison Consulting Bison Consulting [email protected] [email protected]

description

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

Transcript of Rjb

Page 1: Rjb

Ruby-Java BridgeRuby-Java BridgeLeveraging existing JavaLeveraging existing Java

solutions in your Ruby/Railssolutions in your Ruby/Rails

applicationsapplications

Wes GambleWes Gamble

Bison ConsultingBison Consulting

[email protected]@att.net

Page 2: Rjb

Java in 4 (or 5) bulletsJava in 4 (or 5) bullets 1995 - ???, Object oriented, statically typed1995 - ???, Object oriented, statically typed Java runs on a virtual machine that interprets Java runs on a virtual machine that interprets

compiled Java bytecodes. Each hardware compiled Java bytecodes. Each hardware architecture has its own JVM runtime (JRE)architecture has its own JVM runtime (JRE)

Originally, the expected use of Java was in Originally, the expected use of Java was in “applets” that ran in Web browsers to allow “applets” that ran in Web browsers to allow complex client side Web app. processing, but complex client side Web app. processing, but over time, people began to use it for more over time, people began to use it for more server side concerns, leading to…server side concerns, leading to…

J2EE (many many standards, frameworks, J2EE (many many standards, frameworks, etc.)etc.)

J2ME, other stuffJ2ME, other stuff

Page 3: Rjb

So what – why do we care So what – why do we care about Java, anyway?about Java, anyway?

Web app. development in Java for close to 10 Web app. development in Java for close to 10 years – there are a lot of great libraries out years – there are a lot of great libraries out therethere

Sometimes Ruby falls short of our needs – Sometimes Ruby falls short of our needs – limited libraries available to solve problemslimited libraries available to solve problems

Some of us come from the Java world, and are Some of us come from the Java world, and are already familiar with how to solve certain already familiar with how to solve certain application problems with Java technologyapplication problems with Java technology

Some Ruby libraries are C-based which Some Ruby libraries are C-based which requires recompilation if you deploy on requires recompilation if you deploy on multiple platforms – Java libraries run multiple platforms – Java libraries run anywhereanywhere

Page 4: Rjb

Ruby/Java integration Ruby/Java integration solutionssolutions

Rjb: A simple API that allows Ruby code to use Java Rjb: A simple API that allows Ruby code to use Java objects objects http://rjb.rubyforge.org/http://rjb.rubyforge.org/Written by Akio Tajima, aka “arton”Written by Akio Tajima, aka “arton”

Yajb: older, doesn’t appear to be under active Yajb: older, doesn’t appear to be under active development development http://raa.ruby-lang.org/project/yajb/http://raa.ruby-lang.org/project/yajb/

Java implementation of Java implementation of Ruby interpreterRuby interpreter

Ambitious, making huge Ambitious, making huge stridesstrides

Hoping to rival native Ruby Hoping to rival native Ruby speedspeed

http://jruby.codehaus.org/http://jruby.codehaus.org/

Page 5: Rjb

Why Rjb instead of JRuby?Why Rjb instead of JRuby?

Simple and easy to useSimple and easy to use Not a complete replacement of the Not a complete replacement of the

entire Ruby interpreter like JRubyentire Ruby interpreter like JRuby Works with regular interpreter Works with regular interpreter

seamlessly (C-based extensions have seamlessly (C-based extensions have to be re-implemented in Java to run in to be re-implemented in Java to run in JRuby)JRuby)

JRuby is close to, but arguably not JRuby is close to, but arguably not quite ready for prime time yetquite ready for prime time yet

Page 6: Rjb

How does Rjb work?How does Rjb work?

Ruby

rjb

Proxy class

Proxy instance

JVM

Created using JNI

Java class

Java instance

caller

Importclass

klass.new

method()

Page 7: Rjb

Using Rjb – System Using Rjb – System RequirementsRequirements

Java runtime environment (JRE)Java runtime environment (JRE) JAVA_HOME environment variable setJAVA_HOME environment variable set Unix/Linux only: LD_LIBRARY_PATH needs to Unix/Linux only: LD_LIBRARY_PATH needs to

point to Java shared object (.so) files point to Java shared object (.so) files (e.g. export (e.g. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386:LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$JAVA_HOME/jre/lib/i386:

$JAVA_HOME/jre/lib/i386/client)$JAVA_HOME/jre/lib/i386/client)

OS X: rjb does not look up JAVA_HOME OS X: rjb does not look up JAVA_HOME environment variable, but environment variable, but /System/Library/Frameworks/JavaVM.framework//System/Library/Frameworks/JavaVM.framework/Libraries/libjvm_compat.dylib directly. So you Libraries/libjvm_compat.dylib directly. So you need to set appropriate Java version using need to set appropriate Java version using /System/Library/Frameworks/JavaVM.framework//System/Library/Frameworks/JavaVM.framework/Libraries symbolic link. Libraries symbolic link.

Page 8: Rjb

Using Rjb – Load the JVMUsing 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. Do this once for the app. (environment.rb in a Rails app.) (environment.rb in a Rails app.) Optional unless classpath, JVM options Optional unless classpath, JVM options required.required.

Page 9: Rjb

Using Rjb – Example #1Using 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 Manipulating an Excel spreadsheet using JExcelAPIusing JExcelAPI

Page 10: Rjb

Using Rjb – Example #2Using 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 Using a custom Java library created by another developeranother developer

Page 11: Rjb

Using Rjb – Type Using Rjb – Type ManagementManagement

All Java primitives are automatically coerced All Java primitives are automatically coerced into appropriate Ruby objectsinto appropriate Ruby objects

Ruby strings are coerced into Java stringsRuby strings are coerced into Java strings Java objects are wrapped in an anonymous Java objects are wrapped in an anonymous

Ruby class (BTW, these wrapped Java objects Ruby class (BTW, these wrapped Java objects cannot be marshaled/unmarshaled because cannot be marshaled/unmarshaled because they have no class name)they have no class name)

However, input parameters to Java methods However, input parameters to Java methods must have their type specified if the methods must have their type specified if the methods are overridden. Rjb doesn’t dynamically are overridden. Rjb doesn’t dynamically determine which one of the overridden determine which one of the overridden methods to call.methods to call.

Page 12: Rjb

Using Rjb – Type Using Rjb – Type ManagementManagement

When type information is required, a string is When type information is required, a string is passed that contains encoded type information passed that contains encoded type information (see J2SE Class#getName API docs. for more (see J2SE Class#getName API docs. for more detail)detail)

Example:Example:– Calling the Java String constructor method that takes a Calling the Java String constructor method that takes a

byte array and a string (character set) as arguments – byte array and a string (character set) as arguments – assume str_class is a ‘java.lang.String’assume str_class is a ‘java.lang.String’

– str_class.new_with_sig('[BLjava.lang.String;', [48, 49, str_class.new_with_sig('[BLjava.lang.String;', [48, 49, 50], 'Windows-31j')50], 'Windows-31j')

– [B means “byte array” (the [ means array and the B [B means “byte array” (the [ means array and the B means byte)means byte)

– Ljava.lang.String; is the class name of the 2Ljava.lang.String; is the class name of the 2ndnd argument argument

Page 13: Rjb

Using Rjb – ConstructorsUsing Rjb – Constructors To instantiate a Java class using the To instantiate a Java class using the

default constructor, use default constructor, use

klass.newklass.new To instantiate a Java class that takes To instantiate a Java class that takes

parameters, useparameters, use

klass#new_with_sig(sig, arg[, more klass#new_with_sig(sig, arg[, more args]) where sig is the encoded type args]) where sig is the encoded type signature stringsignature string

and args are the actual argumentsand args are the actual arguments

Page 14: Rjb

Using Rjb – Constructor Using Rjb – Constructor ExampleExample

Assume that str is a Java string classAssume that str is a Java string class No argument constructorNo argument constructor

instance = str.new #Ruby with rjbinstance = str.new #Ruby with rjbString instance = new String(); //equivalent String instance = new String(); //equivalent

JavaJava Constructor with argumentsConstructor with arguments

instance = instance = str.new_with_sig('Ljava.lang.String;', 'hiki is str.new_with_sig('Ljava.lang.String;', 'hiki is a wiki engine') #Ruby with rjba wiki engine') #Ruby with rjb

String instance = new String(“hiki is a wiki String instance = new String(“hiki is a wiki engine”) //equivalent Javaengine”) //equivalent Java

Page 15: Rjb

Using Rjb – Invoking Using Rjb – Invoking methods on Java objectsmethods on Java objects If the Java method is NOT overloaded, then If the Java method is NOT overloaded, then simply usesimply use

java_obj.meth(arg1, arg2…, argn)java_obj.meth(arg1, arg2…, argn) If the Java method is overloaded, then you If the Java method is overloaded, then you

must provide type information for each must provide type information for each argument, so useargument, so use

obj#_invoke(name, sig, arg[, more obj#_invoke(name, sig, arg[, more args]) args]) where name is method name, sig is where name is method name, sig is encoded type signature, and args are encoded type signature, and args are argumentsarguments

Page 16: Rjb

Using Rjb – Method Call Using Rjb – Method Call ExampleExample

Assume that str_obj is an instance of Assume that str_obj is an instance of java.lang.Stringjava.lang.String

Non-overridden methodNon-overridden methodsize_of_string = str_obj.length #Ruby with rjbsize_of_string = str_obj.length #Ruby with rjb

java_size_of_string = java_str_obj.length(); java_size_of_string = java_str_obj.length(); //equivalent Java//equivalent Java

Overridden methodOverridden methodindex_of_h = str_obj._invoke(‘indexOf’, ‘C’, ‘h’) index_of_h = str_obj._invoke(‘indexOf’, ‘C’, ‘h’)

#Ruby with rjb#Ruby with rjbjava_index_of_h = java_str_obj.indexOf(‘h’) java_index_of_h = java_str_obj.indexOf(‘h’)

//equivalent Java//equivalent Java

Page 17: Rjb

Quick DemoQuick Demo

Page 18: Rjb

The other direction – The other direction – using Ruby objects in using Ruby objects in

JavaJava You can bind a Ruby object to a Java You can bind a Ruby object to a Java

interface using Rjb::bind(obj, interface using Rjb::bind(obj, infc_name) as long as the Ruby infc_name) as long as the Ruby object implements all of the methods object implements all of the methods in the Java interfacein the Java interface

You can throw Java exceptions from You can throw Java exceptions from such Ruby objects if you want using such Ruby objects if you want using Rjb::throwRjb::throw

Page 19: Rjb

Threading concernsThreading concerns Ruby threads are “green threads,” (all Ruby threads are “green threads,” (all

contained in one OS process)contained in one OS process) Java threads are native OS threads Java threads are native OS threads Because of this, if you bound a Ruby object to Because of this, if you bound a Ruby object to

a Java interface, and there was Java code that a Java interface, and there was Java code that could access this Ruby object from a thread could access this Ruby object from a thread other than the main thread, you could crash other than the main thread, you could crash the app. when the garbage collection startedthe app. when the garbage collection started

You’re safe doing the “call Ruby from Java You’re safe doing the “call Ruby from Java thing” if you are sure that the Java caller will thing” if you are sure that the Java caller will be single threadedbe single threaded

Page 20: Rjb

The future of Rjb?The future of Rjb? May depend some on JRubyMay depend some on JRuby Jrb plays nicely with native Ruby so Jrb plays nicely with native Ruby so

that may matterthat may matter Useful as a point solution for already Useful as a point solution for already

existing apps. that cannot be ported existing apps. that cannot be ported to JRuby for some reasonto JRuby for some reason

Page 21: Rjb

ResourcesResources Rjb – main page: http://rjb.rubyforge.org/Rjb – main page: http://rjb.rubyforge.org/

How to build Rjb: How to build Rjb: http://arton.no-ip.info/collabo/backyard/?HowToBuildRjbhttp://arton.no-ip.info/collabo/backyard/?HowToBuildRjb

How Rjb works: How Rjb works: http://arton.no-ip.info/collabo/backyard/?RjbMechanismhttp://arton.no-ip.info/collabo/backyard/?RjbMechanism

Old Rjb main page: Old Rjb main page: http://arton.no-ip.info/collabo/backyard/?http://arton.no-ip.info/collabo/backyard/?RubyJavaBridgeRubyJavaBridge

Enterprise Integration with RubyEnterprise Integration with Ruby, Schmidt, 2006, pp. , Schmidt, 2006, pp. 230-235230-235

Java type encoding scheme: Java type encoding scheme: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.hhttp://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getName()tml#getName()