RSS feed
<< April 30, 2004 | Home | May 2, 2004 >>

Filters vs Aspects

Web Application Filters were added to the 2.3 Servlet specification and have been enhanced in the just finalised 2.4 spec. Filters allow cross cutting concerns to be applied to a web application, which is exactly the gig of Aspect Oriented Programming (AOP).

Being born and breed with OOP, I have always viewed AOP in the cool but useless category. Thus I've never given myself the opportunity to use them for real. On the other hand, I view webapp Filters as useful but ugly. It would be great if AOP could replace/enhance Filters so we could get into the cool and useful territory.

So I downloaded AspectJ with the intent of seeing how AOP cross cutting concerns could help. The example I considered was the CompressionFilter, which can be applied to a web applications to gzip the content generated on the fly. A compression filter can be declared in web.xml with :

  <filter>
    <filter-name>Compression</filter-name>
    <filter-class>com.acme.CompressionFilter
    </filter-class>
  </filter>
  <filter-mapping>
    <filter-name>Compression</filter-name>
    <url-pattern>*.html</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>ERROR</dispatcher>
  </filter-mapping>
This CompressionFilter will apply to any request to a URL ending with html that is not an include request. The filter wraps the HttpServletResponse object with a facade, that in turn wraps any OutputStream or Writer provided by the response with a version capable of compression the output. The wrappers also allow HTTP headers to be intercepted and adjusted. The multiple wrappers involved have always stuck me as a bit over complex, error prone and in need of a better way. But it does allow the compression concern to be applied to a web application without considering how the html content is generated.

So how would aspectJ help applying such a cross cutting concern to a webapplication? Reading the tutorial I determined that the basic approach needed was to define a CompressionAspect that contains:

  • PointCut definitions that identified the getOutputStream and getWriter calls of the response object.
  • Advice to wrap the response stream/writer in a compressing stream/writer
  • PointCut definitions that identified the header setting methods of the response object.
  • Advice to intercept and adjust the HTTP headers and other meta data.
AspectJ certainly provides the Join Points and Advice types required to create this aspect, but unfortunately I was unable to define PointCut that capture the equivalent semantics of the CompressionFilter declaration above. I believe that the Point Cut semantics required are something along the lines of:
    calls to getOutputStream, getWriter & setContentLength methods on objects that implement the HttpServletResponse interface when RequestDispatcher.include is not on the calling stack and the associated request.getRequestURI() ending with '*.html' and the request is being handled by my webapplication/classloader
It was looking oh-so-good up to those last two clauses! The ending with '*.html' could be done with an if() point cut, except that there is no way to navigate from a response object to the associated request. I couldn't find any point cuts that would assist me with restricting the aspect to a particular web application or classloader.

My next thought was to get around this problem by creating a no-op Filter and hanging the PointCut off calls that go via it. I think this approach would have allowed me to specified the required PointCuts, but then I realized another problem. In order for these point cuts to work, I would need to use the AspectJ compiler to modify the response classes used by the web container and passed into the web application. This breaking of web application encapsulation was not something that I am prepared to do. It would modify my infrustructure and aspects from one webapplication to be passed if not executred to other webapplications.

AOP or at least AspectJ, does not appear to be a good replacement for Filters, as:

  • PointCuts are defined in the implementation domain (java calls and classes), while Filters are defined closer to the application domain (URLs, requests, responses). Using the implementation domain events to trigger application level concerns may be impossible or at the very least devoid of the application abstractions we so carefully build in OOP.
  • The technology of AspectJ does not appear appropriate for Container/Infrastructure based deployment. It is not appropriate for the container/infrastructure classes to be modified in order to support the application concerns of a particular application.
  • The declarative nature of aspects means that PointCuts needs to do a lot of work to reduce a global scope to a particular instance. It would be great if procedural semantics were available so you could say in code: "wrap that object with this aspect" or "apply this advice to that Point Cut". Such programatic code would also assist with the tracebility concerns of AOP.

So my first attempt at AOP has not been successful and I'm still left with the "cool but useless" feeling. The OOP design of Filters does allow cross cutting concerns to be implemented in a modular fashion, so useful if not cool applies. Maybe I'm still missing something or am trying the wrong problem. I hope that an AOP guru reading this will be able to correct the error of my ways?