Intentional Software - Democratizing Software Creation
Business users doing programming? Simonyi and Kolk presents how Intentional Software offers a radical new software approach that separates business knowledge from software engineering knowledge.
Tracking change and innovation in the enterprise software development community

Posted by Mirko Stocker on Mar 07, 2008 12:10 PM
There's one command you need to enter the united world of Ruby and Java: include Java .
Delivering a Breakthrough Java Computing Experience
Info 2.0: IBM's vision for the world of Web 2.0 and enterprise mashups (Webcast)
Create a photo album application with Project Zero and REST design principles
Evaluation Guide: Is Your SCM Tool Ready for Agile?
IBM Agile Development eKit: Free Articles, Expert Q&A, Educational Resources
This will allow you to instantiate Java classes, call their methods and even derive from them as if they were just ordinary Ruby objects. There are a few subtle differences, this article will show you how to manage them so you can quickly devise new applications and deploy them to your users at lightning-speed.
This article is based on a sample application that implements a simple ObjectSpace browser using JRuby and Swing. Ruby's ObjectSpace feature provides a way to access all objects of the system. For example, all living strings can be printed like this:
ObjectSpace.each_object(String) do |string|This yields about 28000 strings when run from within my irb session. Using Swing and JRuby, we can now display the different classes, their instances and the available methods in a nice graphical interface. You can even invoke parameterless methods by clicking on them in the rightmost panel:
puts string
end
ObjectSpace support in JRuby is disabled by default because of the performance penalty it imposes on the runtime, but more on that later.
I'd like to point out a few interesting details of the implementation and give some hints on how to get started on using the Java integration features of JRuby.
Once you've included Java into your script, you can start subclassing existing Java classes. This can be done by simply specifying the fully qualified name of the Java class. In the example application, the main window extends JFrame. It also includes the javax.swing and java.awt packages into the class' scope so you don't have to specify the full name for every usage:
class MainWindow < javax.swing.JFrame
include_package 'javax.swing'
include_package 'java.awt' ...
Alternatively, you can also include specific classes using the include_class function, which doesn't pollute the namespace with constants for classes you'll never use.
Calling super constructors works just as with plain Ruby code, which means that the frame title can be set by calling super("JRuby Object Browser") on the first line of the initialize-method.
With the whole javax.swing package included into the class, instantiating Java classes is straightforward:
list_panel = JPanel.new
list_panel.layout = GridLayout.new(0, 3)
If you take a closer look at the second line, one might think that we directly access the layout-field of the JPanel, but that's not case. JRuby adds some convenience methods to Java objects, so the above statement could also be written in the accustomed way:
list_panel.setLayout(GridLayout.new(0, 3))
Instead of using getters and setters, you can seemingly access fields directly. There is even more syntactic sugar JRuby adds to Java objects that makes the whole experience feel more Ruby-like: you can use the snake_case notation instead of the actually defined camel case names for any method calls. From this follows the third way to call the setLayout method:
list_panel.set_layout(GridLayout.new(0, 3))
Be cautious when calling setter-methods from within their own class, Ruby might think you want to create a local variable, so you have to call it explicitely with self as the receiver:
self.default_close_operation = WindowConstants::EXIT_ON_CLOSE
Another difference between Java and Ruby is the accessing of constants, like EXIT_ON_CLOSE in the previous snippet. Just remember to replace all . accesses with :: if you're translating some code from Java to Ruby.
Until now, most changes JRuby brings to Swing development don't seem to be very revolutionary, but we haven't covered one important aspect yet: listeners. In Java, hooking up a listener with an event often means implementing an interface in an anonymous class:
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
...
}
});
This really clutters your code if you need to attach a lot of listeners. With JRuby, this can be reduced to the following two lines of code (and you can even omit the event variable if you don't use it):
button.add_action_listener do |event|
...
end
These are the basics you need to know to start using Swing with JRuby. Even though JRuby makes GUI development with Swing more comfortable, you still have to write a lot of code manually, especially when you need to use complex layouts. If you want to make the creation of Swing-UIs even simpler, take a look at Three approaches to JRuby GUI APIs.
Ruby applications and libraries are usually distributed with the help of RubyGems, but in order to take advantage of it, you already need to have Ruby and RubyGems installed, which likely isn't the case for the average end-user. This problem has already been solved for traditional (MRI / C-Ruby) programs in the form of RubyScript2Exe[1], which bundles your scripts and a Ruby interpreter into a nice package that can be run on multiple platforms. Users of JRuby don't have to feel left out in the rain, quite the contrary, they have an even mightier tool at hand to quickly deploy applications: Java Web Start.
Java Web Start is included in the Java Runtime Environment and should therefore be present on most systems. Making an application ready for Web Start is rather easy, all that is needed is a Jar containing all the files and a JNLP (Java Network Launching Protocol) description file. We demonstrate the process of creating a web-startable Ruby application on the basis of the ObjectSpace browser application.
The prerequisite for Web Start is a Jar that contains the application, so we'll take a look at that first. JRuby provides two different libraries: the "minimal" jruby.jar and jruby-complete.jar, which bundles the whole Ruby standard library. If you don't use anything from the standard library, you can use the smaller jruby.jar and decrease the download by roughly one megabyte.
The simplest way to get your script running is to add the .rb files to jruby.jar. The following command adds our example, rob.rb, to the zip.
jar uf jruby.jar rob.rb
To check if it worked, you can start your application with java, requiring our Ruby script. The application needs the ObjectSpace, which we need to enable by passing the jruby.objectspace.enabled=true property to Java:
java -Djruby.objectspace.enabled=true -jar jruby.jar -r rob
The -r option automatically requires the specified file and thus runs our script.
One of the exciting new features of JRuby 1.1 is the ahead of time (AOT) compilation support. Currently, just in time compilation in JRuby is restricted to 2048 methods, ahead of time compiling can help to mitigate that restriction. jrubyc, the JRuby compiler, is still under development, so I'd advise to use the latest JRuby release available. Compiling a plain Ruby file to a classfile is as simple as invoking the compiler with the script(s) as arguments:
jrubyc rob.rb
This will create a ruby directory containing a rob.class file. Instead of including the ruby directory into the jruby.jar as we did above, we're going to create a separate Jar to hold the application. After all, modifying the existing Jar doesn't really seem to be such a neat solution. Jars can be made by the tool of the same name:
jar -cfe rob.jar ruby/rob.class rubyThis will create a small Jar called rob.jar with our class inside, adding the ruby/rob.class as the main-class to be specified in the Manifest. This allows us to simplify the invocation, as we can now simply point to the class and don't have to speficy the require on the command line anymore. To execute it, we have to make sure that
rob.jar is on the classpath:
java -Djruby.objectspace.enabled=true -cp rob.jar:jruby.jar ruby.rob
Before we can continue to writing the JNLP-File, we need to sign the Jars. That's a unfortunate necessity because JRuby uses reflection and thus needs to have extended permissions, see the JRuby Wiki for more details. The easiest way is to create yourself a test certificate using the keytool that comes with the JDK:
keytool -genkey -keystore myKeystore -alias myself
keytool -selfcert -alias myself -keystore myKeystore
From now on, every time you modify one of the Jars, you have to update the signature or you'll get a SecurityException when running it.
jarsigner -keystore myKeystore jruby.jar myself
jarsigner -keystore myKeystore rob.jar myself
Now that we have the Jars prepared, we can actually take a look at that JNLP file. The following presents a minimal configuration for the application. Some fields are required by the specification, like the title, vendor and j2se tags as well as the security section. The jar-tag denotes the final location of the Jars. It can also point to a local file, using a file://-URL, which can be convenient during development. The ObjectSpace property needs to be set here too, this can be done with the property-tag.
<?xml version="1.0" encoding="utf-8"?>
<jnlp>
<information>
<title>Ruby Object Browser</title>
<vendor>Mirko Stocker</vendor>
</information>
<resources>
<jar href="http://misto.ch/rob/rob.jar"/>
<jar href="http://misto.ch/rob/jruby.jar"/>
<j2se version="1.5+"/>
<property name="jruby.objectspace.enabled" value="true"/>
</resources>
<application-desc main-class="ruby.rob"/>
<security>
<all-permissions/>
</security>
</jnlp>
If you skipped the AOT section or just want to keep the one-jar way, then you'll have to modify the jnlp file to also include the -e arguments, so your application-desc will look like:
[...]
<application-desc>
<argument>-r</argument>
<argument>rob</argument>
</application-desc>
[...]
The final step is to upload the Jars and the JNLP file to the specified location. You should now be able to open the link in your browser or using the javaws tool directly from a shell.
In order for your browser to launch the application with Web Start, the JNLP file needs to be delivered with the application/x-java-jnlp-file MIME-Type. So if your browser just displays the content of the JNLP file and javaws isn't launched automatically, you need to adapt the webserver configuration. For example, Apache needs the following directive in mime.types:
application/x-java-jnlp-file jnlp
The JRuby wiki is a great source for general information about JRuby.
Download the code for Ruby Object Browser.
Guys, how the hell can you speak about a hello world webstart deployement without submiting a webstart demo? I means really, you've done the required work, now it's just about hosting it on any trash server so why don't you do it? I like webstart on the RIA potential of applets, but it's just that I really can't understand that way guys are trying to sell webstart or JavaFX.
1.) If you need to be convinced of the benefits of Webstart: http://java.sun.com/products/javawebstart/demos.html 2.) To play with this sample app, download the provided code (be sure to update the jar paths in the jnlp file to fit your system). This article is not trying to "sell" Web Start - it's showing how to use it with JRuby. Selling Web Start is Sun's business.
Business users doing programming? Simonyi and Kolk presents how Intentional Software offers a radical new software approach that separates business knowledge from software engineering knowledge.
Jason Rudolph discusses Java/Grails integration, Grails plugins, creating a Grails sample application, Grails app structure, data querying and persistence, validation, controllers and tag libraries.
The Scrum Product Owner role is powerful, valuable and challenging to implement. It brings healthier relationships between customers and developers, and competitive advantage - if you do it right.
Effective Java, Second Edition by Joshua Bloch is an updated version of the classic first edition, which won a 2001 Jolt Award. InfoQ asked Bloch questions about the areas that the new edition covers.
A new article by I. Drobiazko and R. Zubairov introduces v. 5 of the Apache Tapestry component-oriented web framework. The tutorial shows how to create a component and covers IoC in Tapestry and Ajax.
In this interview, Burton Group consultant Pete Lacey talks to Stefan Tilkov about his disillusionment with SOAP, his opinion on REST, and addresses some of the perceived shortcomings REST vs. WS-*.
Jay Fields presents his concept of Business Natural Languages - a type of Domain Specific Languages geared towards being readable by domain experts.
Adoption and interest for Distributed Version Control Systems is constantly rising. We will introduce the concept of DVCS and have a look at 3 actors in the area: git, Mercurial and Bazaar.
2 comments
Reply