Ruby for Java Programmers, Part V

27 02 2006

If you’ve been following the previous articles in this series (Part I, Part II, Part III and Part IV) but are not yet satisfied with the range of solutions I presented for calling Ruby code from Java, here’s another one for you.

This one involves running your Java code as a separate process and interacting with it using some form of Web service (XML-RPC, SOAP or a RESTful service). We’ll use XML-RPC for this sample, mainly because it’s very easy to set up and use. You’ll need Apache XML-RPC version 2 to make the code run. Here’s the java code:

public class RPCFetcher {
    public static void main(String args[]) throws Exception {
        WebServer server = new WebServer(8080);
        server.addHandler("$default", new RPCFetcher());
        server.start();
    }

    public Vector fetch(String url) throws Exception {
        URL feedUrl = new URL(url);
        FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance();
        FeedFetcher fetcher = new HttpURLFeedFetcher(feedInfoCache);
        SyndFeed feed = fetcher.retrieveFeed(feedUrl);
        Vector items = new Vector();
        for (Iterator it = feed.getEntries().iterator() ; it.hasNext() ; ) {
            SyndEntry entry = (SyndEntry) it.next();
            Hashtable map = new Hashtable();
            map.put("link", entry.getLink());
            map.put("title", entry.getTitle());
            map.put("publishedDate", entry.getPublishedDate());
            items.add(map);
        }
        return items;
    }
}

Compared to the previous samples, there’s not much else you need to do, besides creating an instance of WebServer to handle incoming HTTP requests and dispatch them to the appropriate method. However, you need to convert your Java types to something that XML-RPC is able to understand, i.e. strings, numbers, dates, Vectors, Hashtables and little else.

The Ruby client code is much simpler:

require 'xmlrpc/client'
server = XMLRPC::Client.new 'localhost', '/', 8080
entries = server.call('fetch', 'http://agylen.com/feed')
entries.each do | entry |
  p "#{entry['publishedDate'].to_time} #{entry['title']}"
end

Possible drawbacks of this technique are the necessity of having a separate process running and the overhead of HTTP communication and XML-RPC protocol encoding and decoding.

Thanks to Nick Stuart and Erik Hatcher for laying down the basics.





Ruby for Java Programmers, Part IV

8 02 2006

In the previous installments of this series, I did some experiments trying to make Java and Ruby coexist by using two bridges: rjb and YAJB. This time, I’m going to try to solve the same problem using JRuby.

JRuby is not simply a bridge, it is a “1.8.2 compatible Ruby interpreter written in 100% pure Java”. As it is written in Java and consequently runs on the JVM, it should provide a much better integration. At the very least, it allows you to use some typical Ruby idioms when traversing Java collection classes, or accessing bean properties by name:

require 'java'

include_class 'Fetcher'

feed = Fetcher.fetch(ARGV[0])

feed.entries.each do | entry |
  p "#{entry.publishedDate} #{entry.title}"
end

Compare that to the sample I posted here.

You should be aware of a couple of limitations, though:

  • JRuby is not a complete implementation of Ruby. Some things are missing that, for instance, won’t allow you to run Rails on JRuby just yet. However, the development team seems to be progressing nicely along this road and supporting Rails is one of their foremost objectives.
  • Ruby extensions written in C will not be loaded. This is probably never going to change. If you need a particular C extension, you should try to find an alternative in pure Ruby or Java.




Ruby for Java Programmers, Part III

26 01 2006

Just tried to perform the same test I did in Part II using YAJB instead of rjb. Unfortunately, I wasn’t able to obtain any result, since even a simple program like:

require 'yajb/jbridge'
include JavaBridge
jimport "java.io.*"

fails with a java.lang.OutOfMemoryError. This is on OS X 10.4, YMMV.





Ruby for Java Programmers, Part II

25 01 2006

Part I is here.

As promised, I will now try to invoke some more complex Java classes from Ruby code. Since I might need this for a real project and one of the things I find missing in Ruby is an RSS/Atom parser that offers the same features as Rome, I figured I might just try fetch and parse an RSS feed using Rome via Ruby.

Even something simple as fetching a single feed using Rome involves a handful of classes and methods. If all you need is getting at feed entries from your Ruby code, you’d be much better of if you encapsulate API calls in some higher-level class that is intended to be called from Ruby. This will avoid you the hassle of importing more than one class and calling overridden methods for which you’ll have to supply signatures and such trivia. This is just what I did in Fetcher.java:

import java.net.URL;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.fetcher.FeedFetcher;
import com.sun.syndication.fetcher.impl.FeedFetcherCache;
import com.sun.syndication.fetcher.impl.HashMapFeedInfoCache;
import com.sun.syndication.fetcher.impl.HttpURLFeedFetcher;

public class Fetcher {
	public static SyndFeed fetch(String url) throws Exception {
		URL feedUrl = new URL(url);
		FeedFetcherCache feedInfoCache = HashMapFeedInfoCache.getInstance();
		FeedFetcher fetcher = new HttpURLFeedFetcher(feedInfoCache);
		SyndFeed feed = fetcher.retrieveFeed(feedUrl);
		return feed;
	}
}

Calling this class from Ruby is straightforward enough:

require 'rjb'

Rjb::load('.:rome-0.7.jar:rome-fetcher-0.7.jar:jdom.jar:jdom.jar', [])

fetcher = Rjb::import('Fetcher')
feed = fetcher.fetch(ARGV[0])
p feed.getTitle
entries = feed.getEntries.iterator
while entries.hasNext do
    entry = entries.next
    p "#{entry.getPublishedDate.toString} #{entry.getTitle}"
end

Two things to note here. First, it would be great if the Ruby-Java bridge would pick up JavaBeans conventions and allow you to simply write entry.title instead of entry.getTitle.

Second, I will probably need to convert Java dates to Ruby Time objects by formatting as a string and then parsing it back. It would also be useful if the Ruby-Java bridge could provide more automatic type conversions, where such convertions are possible, besides simple strings.





Ruby for Java programmers, Part I

23 01 2006

This is the first article in a series that I plan to write in order to describe my experiments with combining together Ruby and Java. The reason I’m doing this is that, as much as I find Ruby on Rails to be fun and agile and all-around great, still I haven’t grasped much of Ruby the language yet, so I sometimes find myself wanting to reuse some Java code (and there’s a helluva lot of it around, free for grabs) instead of thinking about a rewrite.

One of the things I’d really want to be able to do is call Java code from Ruby. There are some projects intended to provide a Ruby-to-Java bridge, even though none of them seems to be really mature. The ones I found mentioned more often seem to be RubyJavaBridge and YAJB.

Let’s start with the former. After downloading and unzipping the file, you should read the provided readme.txt file, as there don’t seem to be instructions on the website for actually performing the build. If you’re under OS X, make sure the JAVA_HOME environment variable is set (should be something like /Library/Java/Home, unless your setup is peculiar). Also, ignore everything about the LD_LIBRARY_PATH variable, again if you’re on OS X.

Then you can try configuring and compiling the sources with:

    ruby setup.rb config
    ruby setup.rb setup

On OS X, this will fail, as the off_t type is used but never declared. I assume it gets defined in one of the included C header files in Linux and Windows, but under OS X it’s to be found in <sys/types.h>, which is not included. You can fix it by adding the following statement:

#include <sys/types.h>

to file ext/rjb.h, around line 25 should be fine. After this, everything should compile and install fine just by following the instructions.

Next I did a series of tests with simple Java types to confirm that the JVM was loaded and that the basic functionality of the bridge was fine. In the coming days I plan to invoke some more complex library and report my findings in further installments of this series.





Amsterdam Java Meetup – 24 February

18 01 2006

Alef: “After the first successful Java Meetup in Amsterdam, held last November 11th, I’d like to promote all this to a quarterly event. That’s why you’ll have to block February 24th in your agenda coz’ from 6 o’clock on, there will be beers again in a place yet to be announced.”

As I am in Amsterdam now, and will probably be here most of the time between now and the end of February, it would be interesting to join. However, I’m wondering whether the official language of the meetup will be Dutch or English and, if the former is the case, whether my knowledge of Dutch can be brought up to the level required to follow a conversation about Java in slightly more than a month ;) .

Update: I just noticed that the 24 is a Friday. Too bad, as even if I’ll probably be in Amsterdam that week, I’ll be taking a plane back home by Friday afternoon.





On Rails

14 12 2005

On the trainNo, this post is not about Ruby on Rails (they just released version 1.0, by the way), but it’s half about rails, as in “railways”, and half about Ruby the language.

With respect to the former, I was finally able to book my railway trip to Rome, despite my previously reported problems. I enjoyed traveling by train much more than traveling by plane. It’s true that it takes more time, but when you compare having to wait in line at the check-in counter, at the security control, at the gate, at the plane door, then traveling for one hour in a crammed space and finally having to wait for your luggage, to sitting quite comfortably for four hours, at half the price, the choice is clear.

Ruby die-hards might comment that the experience of traveling by plane is akin to programming in Java, which brings us to the second half of this post. While traveling, I did a bit of Ruby programming, just for fun. One thing that struck me negatively about Ruby is learning that Ruby strings are made up of 8-bit bytes. Uh-oh, I smell trouble ahead. Indeed, I hit trouble as soon as I tried to parse (using Lucas Carlson‘s SimpleRSS library) some RSS feeds that used different encodings (UTF-8 vs. ISO-8859-1, for example). If I were using Java and a Java XML parser, I’m pretty sure that the strings containing the text values extracted from the feed would have all been Unicode string and I would have had no problems mixing them or storing them in a UTF-8 encoded database.

I’m pretty sure this problem is mostly due to my ignorance of Ruby, but still I wonder whether using 8-bit characters in the era of globalization was a wise decision. I’d rather have Java’s 16-bit characters, if possible.

Update: Got it to work by determining the original encoding using open-uri‘s charset method and iconv to convert between it and UTF-8. Suboptimal, but it works.





Say "Hello!" to the TSS crowd

13 12 2005

Spring FrameworkMy recent post on Spring 2.0 was featured on the front page of TheServerSide. This brought some nice traffic, but most people left immediately and nobody bothered to leave even a short comment. Probably those who felt like commenting did so on TheServerSide’s own forum.

Reading those comments, I’m amazed at the amount of ignorance that is on display there. Comparing Spring to Struts and turning the former down because it’s not “standard” doesn’t reflect to well on the poster’s knowledge or intelligence.

Anyway, what I want to tell the TSS crowd is that you should take my extreme assertion (“I seriously wonder why anyone would want to develop anything substantial in Java nowadays without using Spring.”) with a grain of salt. Can you say “hyperbole”?

What prompted me to write that sentence was not much my fondness of Spring’s features and architectural beauty, which is certainly there. I just wanted to express my admiration for Spring’s core team dedication to its users and to the quality of its product. Doing a major release that is 100% backward-compatible, to the point of being able to simply drop the new library in place of the old one and have everything still work perfectly, is not something that happens frequently, particularly in the Open Source world.

So, if you want to find a way to architect your J2EE applications in a simple, lightweight, flexible and testable way, have a look at Spring. You won’t probably use everything of it, but that’s just fine. And you’ll certainly find that the parts you end up using will make your life easier.





Hani bileblogs Basecamp

12 12 2005

I’m surprised to see that David Heinemeier Hansson took offense at
the latest BileBlog:

This is awesome. In the sense of awesome meaning funny in a sad, tragic way where you feel sorry for the person.

It’s surprising that David fell for Hani’s prank, just like an ordinary Andy C. Oliver. Know what, David? Hani’s biles are the self-inflicted punishment that we Java-types deserve for our sins, like XML configuration files, EJB and all the JCP madness. We enjoy them just like Xians enjoy being punished for their sins. It’s all guilt.

Note for the humor-impaired: the above was largely ironic. However, there’s also some serious debate material in this thread, buried under all the mudslinging. We can start from the following Hani quote:

There’s no doubt that ajax, tagging, semantic fappery and all that other gibberish have some potential. Ultimately though, there is no revolution, nor even an evolution. It’s simply the ability to toss in a few more tools in the toolbox. Specialised tools, that can be effective when used against the right obstacle.”





Spring 2.0: What breaks?

12 12 2005

Matt Raible: “Spring 2.0: What breaks?

Nothing.

Of course, some things might break – but Rod can’t think of anything significant will. It should be a drop-in replacement for 1.x JARs. This really goes to show the value of a non-invasive POJO programming model. There will be some changes in best practices, but you are not forced to change anything.

This should be the norm, but hasn’t been so in enterprise Java.

Alef just did a demo of migrating JPetstore from 1.2.6 to 2.0. He copied the 2.0 JAR over the old one and redeployed to Geronimo 1.0 M5. After proving everything worked (in a browser), he changed some of the XML syntax and redeployed. Again, everything worked as expected. “

When I read things like this, I seriously wonder why anyone would want to develop anything substantial in Java nowadays without using Spring.