in Internet Services, Tools

connecting Tomcat and Apache

Please bear with me while I engage in the following diatribe about: “Why Is It So Darn Difficult to Connect Apache and Tomcat?” Anyone who has worked with mod_jk/mod_jk2 and its ilk know that connecting Apache and Tomcat over AJP (Apache JServ Protocol) is probably one of the more difficult server configuration tasks out there.

A little history: When Tomcat was still Apache/JServ (way back in the day), there was a mod_jserv that managed the AJP pipe between the front-end HTTP server (i.e. Apache HTTPD 1.x) and the back-end application server (JServ). Eventually, this evolved into mod_jk for the first series of Tomcat application servers.

All well and good, and the configuration is fairly straightforward, up to the point of actually talking to your web application: the dreaded JkMount syntax. The example directive looks like this:


JkMount /examples/* worker1

There are a number of problems with this syntax. First, it unnecessarily ties the paths that you use to access the web application from the backend with those that you use on the front-end. So for instance, I have no way to specify that I actually want to map “/julians_examples” on the front-end to “/examples” on the backend. Want to do that? Sorry — time to institute some kind of mod_rewrite hackery. Secondly, the “*” doesn’t mean what you think it means! It’s not a wildcard, so you can’t selectively map stuff; for instance, I can’t say JkMount /examples/foo* to map all resources starting with foo to the application server. This will tell AJP to look for a resource matching, literally, “/examples/foo*” and of course will fail as there’s no resource with that asterisk in there.

Ok, so along comes mod_jk2, which is supposed to be a refactoring of mod_jk. It has certain improvements, such as the ability to talk over a shared UNIX socket (instead of using a network-based AJP protocol), the configuration is simplified again, etc. But again, the web application mapping problem is prevalent! The syntax to map the front-end to the back-end is like this:


<Location "/foo">
JkUriSet worker ajp13:backend-server:8009
</Location>

ARGH! Still no way to specify that the front-end /foo should be mapped to some other back-end path!

Why is this so difficult? And why do we have so many connector projects (like mod_webapp) that have died? A few years ago, I looked into mod_webapp‘s WARP protocol and it seemed to be a breath of fresh air over this antique AJP13 protocol. What happened to it?

I should mention as a postscript that maybe, maybe, in HTTPd 2.1, the new mod_proxy_ajp will solve my problems. Its syntax looks like this:


<Location /examples/>
ProxyPass ajp://backend-server:8009/examples/
</Location>

Wow! Finally a way to say that I should map something on the front-end to a path that could possibly be different on the back-end.

I don’t understand why it’s taken us ten years (and counting) to get to this state. Is it just me that thinks this is totally bonkers?

As a footnote to this, I get the sense from the documentation that AJP13 is a very poorly documented protocol, and is still around simply due to momentum. Read these statements from the documentation, for example:

"This describes the Apache JServ Protocol version 1.3 (hereafter ajp13 ). There is, apparently, no current documentation of how the protocol works. "
"In general, the C code which Shachor wrote is very clean and comprehensible (if almost totally undocumented)."
"I also don’t know why certain design decisions were made. Where I was able, I’ve offered some possible justifications for certain choices, but those are only my guesses."

Undocumented code? Unjustifiable design decisions? Little current documentation about how the protocol works?

It’s things like this that are killing us in the Open Source community. I find it pretty difficult to pitch Tomcat as a worthy alternative to IBM WebSphere or BEA WebLogic when we have this kind of cruft sitting around, pretending to be an "enterprise-worthy" solution.