More on the BEA 8.1 Servlet Filter & RequestDispatcher issue
After doing some more research, it seems that the BEA developers found the Servlet 2.3 specification to be "ambigous", and decided to create an implementation that executes filters on both incoming http requests from cleients, and on request dispatcher requests.
This issue is resolved in the Servlet 2.4 spec. and there is a "dispatcher" element in the "filter" tag in web.xml
The valid values are:
- REQUEST: (default) only when the request comes directly from the client
- FORWARD
- INCLUDE
Please notice that the default behaviour has changed. Upgrading to Weblogic 9.2 or or doing a manual check in the filter for repeated requests solves the problem.
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.doIn 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.