I’m wiring the Ape up so I can run it with JRuby in a servlet in a real Java App Server, and while Marcin Mielżyński’s first-cut RubyServlet works fine, I suspect it’s not the only approach to dispatching. So I’m doing some research and thinking, and I’ve collected it here for anyone who cares.

The Problem · Using your app-server config files, you tell it to dispatch requests to RubyServlet, so in your web.xml you’d have something like this:

    <servlet-mapping>
        <servlet-name>RubyServlet</servlet-name>
        <url-pattern>/ape/*</url-pattern>
    </servlet-mapping>

So you have to design your URI space with some sort of a hook so you can route the right requests into Rubyland. Then RubyServlet has to figure out which Ruby class and method to call.

What Rails Did · Rails figures out what class and method to call based on parts of the URI path. Until recently there was also an egregious semicolon hack, but but as PragDave explains, they’re cleaning that up.

Marcin’s Solution · This isn’t actually, you know, documented anywhere, but Marcin’s Java code is easy enough to read. It’s about like Rails, using the last two parts of the URI to pick class and method, defaulting to a method-name of index. It also has code CamelCasing to capitalize class-names and also (not sure why this is done in Rails either) turn ape_drool to ApeDrool. So:

so ape calls Ape#index, ape/foo calls Ape#foo, ape_drool calls ApeDrool#index, and smelly/ape/dung calls Ape#dung (but looks for the code in smelly/Ape.rb). In all cases, the Ruby code gets the Request and Response objects, so it can find out anything it needs to about what’s going on.

Mongrel · Mongrel’s job is easier; because in that case your Ruby code controls its server, so you can pro-actively register your URIs; docs here. For example:

 h = Mongrel::HttpServer.new("0.0.0.0", "3000")
 h.register("/test", SimpleHandler.new)
 h.register("/files", Mongrel::DirHandler.new("."))
 h.run.join

What Servlet Actually Does · Per the Servlet Javadocs, and in particular the abstract javax.servlet.http.HttpServlet which is what you end up using, the idea is that you fill in methods for doGet, doPost and so on, and they get called with the request and response objects. Requests actually come in through a service method, which they expect you to not override, and it does the dispatching.

How Jython Works · Jython is clever, and took me a couple of minutes to figure out. First, it overrides the service method so that it can dig the path out of the request and do tricks similar to Rails or RubyServlet to figure out which Jython class to call; that class has to extend HttpServlet. Then, it compiles that Jython into bytecode, and then it calls the generated code’s service method, which presumbly ends up routing to the provided doGet and so on.

That compiling-to-bytecode trick sure is handy. JRuby guys?

The RESTless Ape · I’m perfectly OK with Marcin’s current technique; the Ape only ever calls one method, and cooking it into the URI causes me no pain. I guess I should ensure that it’s a POST not a GET because while the Ape tries to clean up after itself, it can change the state of the system.

But I kind of think the Ape is in a minority. Applications, in particular thoughtfully-designed RESTful applications, do care what the HTTP method is, and probably would like a bit more flexibility in routing requests to code than you get by mapping the last two steps in the URI path to class and method.

In fact, I suspect that the basic Java HttpServlet interface is more or less what a RESTful app designer would want, with dispatching to GET/POST/PUT/DELETE handlers. In particular, if I were building an APP server implementation, that’d be about right.

So I’ll sketch out some thoughts on what a RESTfulRubyServlet API might look like. Now, I don’t need it. In fact, maybe this is a YAGNI. But if dozens of people pipe up saying “I need that” then maybe I’ll build it; with Marcin’s code in front of me it would be no strain at all.

RESTfulRubyServlet · The initial problem remains; how do you figure out which class’ doGet and so on to call? I’d like to borrow Rails culture: not repeat myself and rely on Convention over Configuration to make it real easy to explain what to do to get things working.

I note that the typical structure of a Ruby project is a root directory with src and test subdirectories. So, why not use that? If you have a webapp named “foo” and foo/WEB-INF/web.xml says to use RESTfulRubyServlet, then you look for foo/src/servlet.rb and call Servlet#doGet, Servlet#doPost, and so on.

It’d be easy to build. Does the world need RESTfulRubyServlet and if so, is there a better design?



Contributions

Comment feed for ongoing:Comments feed

From: Dave Pawson (Apr 01 2007, at 01:32)

Tim, have a look at what Restlets have done re dispatching

http://www.restlet.org/documentation/1.0/api/org/restlet/Router.html

and

http://www.restlet.org/documentation/1.0/examples/self#part06

Seems to work nicely.

HTH

Dave P

[link]

From: Stefan Tilkov (Apr 02 2007, at 06:58)

Rails's routing DSL seems very well though-out, and could probably (with some refactoring) be used outside of Rails as well.

Here's a link for the basics:

http://manuals.rubyonrails.com/read/chapter/65

And here's how the REST support works (or used to work, with the neglectible semicolon change):

http://ryandaigle.com/articles/2006/8/1/whats-new-in-edge-rails-simply-restful-support-and-how-to-use-it

[link]

From: Colin Prince (Apr 02 2007, at 08:42)

Hi Tim, just a comment on the layout of your comments! Many times your commenters like to include useful URLs but these really stick out the sides of your layout. Perhaps for visual purposes they can be broken arbitrarily? The links themselves obviously should, still work.

Cheers and keep up the good work,

Colin.

[link]

From: James Manger (Apr 03 2007, at 05:24)

foo/WEB-INF/src/servlet.rb would be a better location, otherwise the source code is likely to be exposed directly by typing http://.

../foo/src/servlet.rb into the browser.

[link]

author · Dad
colophon · rights
picture of the day
March 30, 2007
· Technology (90 fragments)
· · Java (123 more)
· · Ruby (93 more)
· · Web (396 more)

By .

The opinions expressed here
are my own, and no other party
necessarily agrees with them.

A full disclosure of my
professional interests is
on the author page.

I’m on Mastodon!