Local Dispatch for Servlets
by Patrick Calahan (http://www.sutrotech.com)
Licensed under the Apache License, Version 2.0

download | javadocs

Overview

Provides a means for making URL-based, intra-VM servlet requests which bypass the servlet containers normal socket and security layers. Instead, the requests are sent directly to the servlets via the servlet RequestDispatcher machinery.

This is advantageous because it is faster and more efficient. Moreover, because the request is handled within the caller's thread, Exceptions thrown by the servlet can be propagated directly back to the caller.

Finally, this mechanism allows for a clean mechanism by which internal clients can bypass the servlet container's security layer. This is particularly useful if you are using servlets as a way to produce content that is consumed by callers within the VM, but you want that content to be made available only to internal clients. There is no standard and robust way to configure a web application for this sort of thing.

Note that lodi uses only standard servlet APIs.

lodi works by binding a particular URL scheme to a particular web application. A special URLStreamHandler is used to route the requests back to a particular servlet.

Packaging

lodi is packaged in two jars: lodi-system.jar and a lodi-webappjar. The system jar is where the URLStreamHandler lives and so must be in your bootstrap classpath. The webapp jar interfaces with your webapp and so must be in your webapp's classpath.

Note to Tomcat users: adding something in your bootstrap classpath is a lot harder than it sounds. They go out of their way to ignore your environment variables and so forth. You basically have two options: hack the startup scripts or merge the lodi-system.jar classes into Tomcat's boostrap.jar. I found the latter to be cleaner but YMMV.

Setup - Deploying the URLStreamHandler

To deploy the URLStreamHandler, all you have to do is write an empty class which extends net.pcal.lodi.system.HandlerBase and deploy it as a URLStreamHandler. This involves putting it in the right package and settings a system property - refer to the docs on java.net.URLStreamHandler for details.

Note that your extending class must also be in the bootstrap classpath as described above.

Setup - Registering your Webapp

The last setup step is to register your application back with the URLStreamHandler. To do this, all you need to do is call net.pcal.lodi.DirectDispatch.bind() with the ServletContext for your app and the HandlerBase extension class described in the previous step. This will take care of connecting your Handler to the Web Application so that requests can be routed.

It's recommended that you call bind in the init() method of one of your servlets.

Done! Using the Direct Dispatch mechanism

To issue a direct dispatch, all you do is create a regular URL connection using whatever scheme you registered your handler for. For example,

  String s = "myapp://home/index.jsp?someparam=somevalue";
  URL u = new URL(s);
  InputStream in = u.openStream();

will open a direct connection to your webapp to get index.jsp. This will be exactly as if you had invoked

  myapp://home/index.jsp?someparam=somevalue

From a browser, except for the advantages listed earlier: the dispatch is more efficient, occurs in the same thread, and cleanly bypasses the servlet container's security. (If index.jsp were a secured resource, you would not have to do any authentication in your calling code).

Exception Propagation

Exceptions generated while processing a servlet request can be propagated back to the caller. For this to happen, though, the servlet has to make one method call when the exception occurs (the Exception instance has to be smuggled past the servlet container). For example,

  try {
    // processing servlet request....
  } catch(SomeException e) {
    net.pcal.lodi.webapp.DirectDispatch.reportErrorCause(request, response, e);
    throw new ServletException(e);
  }

If this is done, then any caller opening a myapp: URL as shown previous would receive a SomeException when they call openStream.

This can make debugging and error reporting tremendously more useful and simple. No longer do you have to check HTTP return codes and/or parse the error page returned by the servlet container in order to figure out what went wrong.