Bech on Enterprise Java
Thursday, August 03, 2006
  The BEA 8.1 Servlet Container implementation is causing problems for Jakarta Struts applications using filters.
I just discovered some strange behavior in a struts based application that uses Hibernate, and a mechanism based on Thread local variables to hold Hibernate Sessions.

Servlet filters are a great tool to handle aspects of your web application like custom Authorization & Authentication logging, modification of requests etc. The servlet 2.3 specs say the following in Section 6.2.1

"When the container receives an incoming request, it takes the first filter instance in the list and calls its doFilter method, passing in the ServletRequest and ServletResponse, and a reference to the FilterChain object it will use. "

The BEA developers have obviously interpreted this to mean incoming request from clients, i.e. "regular" http requests, and requests coming in via the RequestDispatcher class. The Oracle OC4J does not execute the filter chain for incoming RequestDispatcher calls. This is where it gets interesting for Struts based applications.

There are two types of "forwards" in struts, those with redirect="true", and redirect="false". When the redirect attribute of the forward tag in struts-config.xml is set to "true", a response is sent to the client, forcing it to send a new request to the server.

The actual HTTP Response going to the web browser may look something like this ;

HTTP/1.x 302 Moved Temporarily
Date: Thu, 03 Aug 2006 08:37:07 GMT
Server: Oracle Application Server Containers for J2EE 10g (10.1.2.0.2)
Content-Length: 222
Connection: Keep-Alive
Keep-Alive: timeout=15, max=100
Content-Type: text/html
Location: http://localhost:9999/adminssytem/viewEmployees.do



In this case, the filter chain should- and is, executed twice per client transaction. The user does not notice both requests though. This practice is quite common when using the HTTP Post method, so that the user can "reload" the page in his browser without re-posting the form data.

The forwards with redirect="false", uses a RequestDispatcher to forward requests internally. This is sometimes also called "Server Side redirect", and is very useful since you can chain struts actions together in a "Chain of responsibility pattern". By creating small reusable actions, you can easily use them as building blocks in your application.

The fact that BEA chooses to execute the filter chain, between struts actions has a huge impact on code relying on this mechanism. Taking the example of Authorization, a costly verification of user credentials will be executed between each Struts action. With long action chains, this can be a huge performance penalty.

In this Example;

<action path="/deletePhoneNumber"

type="DeletePhoneNumberAction"

name="PhoneForm"

scope="request">

<forward name="success" path="/viewPhoneNumbers.do"/>

</action>


<action path="/viewPhoneNumbers"

type="ViewPhoneNumbersAction"

name="PhoneForm"

scope="request">

<forward name="success" path="/WEB-INF/jsp/displayNumbers.jsp"/>

</action>

A filter with a .do mapping, will be executed two times in the Weblogic server.

1) On the initial HTTP Request hits the deletePhoneNumberAction.
2) After the DeletePhoneNumberAction is finished, and before the viewPhoneNumbers Action is executed.

This can impact design, cause bugs, and slow down the system significantly. If anyone has a workaround, or know of an entry in the weblogic.xml that solves this, please feel free to comment. It would also be interesting to know the rationale behind the decision to implement the Servlet container with a very “creative” interpretation of the specification in this case.

 
Comments:
Workaround is to set servlet-reload-check-secs flag to -1 in weblogic.xml.

-ravi (ravi.mangalagiri@gmail.com)
 
This sound a bit shady. I havn't tried if it acutally works, but that flag is meant for something else.

The solution we went for is to add an attribute to the request in the filter, if it's not already there.

The filter checks this value, and executes filterchain.dofilter() immediately if it's present, thereby skipping all other execution logic in the filter.
 
Post a Comment



<< Home
I hereby promise to blog my thoguhts and views on Enterprise java, design patterns, frameworks and all other things that make life as a software developer interesting.

Name:
Location: Oslo, Oslo, Norway

www.glennbech.com

ARCHIVES
May 2005 / June 2005 / July 2005 / January 2006 / February 2006 / June 2006 / July 2006 / August 2006 / October 2006 / November 2006 / March 2007 /


Powered by Blogger