Let’s Play: JRuby
One of the cool things to arise out of the last decade or so of programming language development is reimplementations. Plenty of people have said to themselves “why can’t I run $myFavouriteLanguage on the JVM?”. So they go and make it happen!
Anchor has historically been a strong Python house, but we’re pragmatic about getting things done. Nagios checks? We’ll write Perl and Ruby if it gets the job done. Automation tasks? Plenty of shell and Perl there.
Recently we’ve picked up JRuby. Put simply, JRuby ports the Ruby interpreter to the JVM – you still write pretty much the same Ruby code, but it runs on the JVM and the backtraces are four times longer. Why would you do this? It turns out there’s some really good reasons.
Here’s a big one: performance. It’s fair to say that Ruby owes much of its popularity to Rails, and people deploying Rails apps are always looking for ways to make it faster and more scalable. One of the early goals for JRuby was to run Rails apps, and they’ve succeeded, while also being much faster than the reference implementation.
Performance is never a bad thing, but we think there’s something much more interesting: direct access to native Java classes. This is amazingly powerful. Java ships with a large set of standard packages, and there plenty more out there for pretty much any conceivable need. JRuby gives you access to all of them.
Let me spin this to you as a scenario: You need to access a third-party accounting API, let’s pretend that the third party is some company like Netsuite. But, the only interfaces they provide are for Java and .NET, neither of which you’re prepared to deal with. So you switch to JRuby, pull in Netsuite’s library, then get some real work done instead of wrangling Java objects.
Accessing Netsuite’s API is now a matter of throwing some Ruby code together. We’ve been writing APIs using Grape, a Rack-compatible framework, so we get rapid development of the API itself, and hassle-free access to Netsuite!
It’s even remarkably clean for something that crosses language boundaries. This is a basic example for the Netsuite scenario, about as simple as it gets for something that’s actually useful:
#!/usr/bin/env jruby require 'java' require 'NetSuiteAPI.jar' # Instantiate our service object service = com::netsuite::webservices::platform_2012_2::NetSuiteService.new() # Hook up the service endpoint port = service.getNetSuitePort() # Enable session management on the binding provider so we retain our session # between SOAP calls rc = port.getRequestContext() rc.put(javax::xml::ws::BindingProvider::SESSION_MAINTAIN_PROPERTY, true) # Setup our login "Passport" passport = com::netsuite::webservices::platform::core_2012_2::Passport.new() passport.setEmail("[email protected]") passport.setPassword("feisty$cheese9meal") passport.setAccount("314159") # And attempt to login puts "Logging in.." result = port.login(passport) if !result.getStatus().isIsSuccess() then puts "Login failed, bailing out" exit end # Now we get to work, fetching the customer record for customer ID 200. recordRef = com::netsuite::webservices::platform::core_2012_2::RecordRef.new() recordRef.setType(com::netsuite::webservices::platform::core_2012_2::types::RecordType::CUSTOMER) recordRef.setInternalId("200") puts "Fetching customer record for customer ID 200.." result = port.get(recordRef) if !result.getStatus().isIsSuccess() then puts "Failed to get customer record, bailing out" port.logout() exit end puts "Success! Now frobbing your data" final_result = munge(result) pp final_result # We're done now, logout and close up puts "Logging out.." port.logout()
We reckon you should check out JRuby. We know you have a working ruby environment that you don’t want to mess up, so we recommend using rbenv to maintain your sanity. If you find some really novel uses for JRuby to bridge the two languages, we’d be interested to hear them.