lodi

Local Dispatch for Servlets

by Patrick Calahan (http://www.pcal.net)

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.