I have a Struts 1 application that uses a little bit a Ajax to create and delete some objects in the application. For both the create and the delete operations, when the operation is posted by the browser it gets processed twice by the server.
This is not a case of the ajax being posted twice by the browser. I used a the Paros proxy tool to confirm that the ajax request is sent only once by the browser, but my action class still gets called twice.
Using Eclipse I set a debug breakpoint, and have noticed that the call stack is not the same for each time through my action class.
First pass I get
MyActionClass.getDisplayPage(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse) line: 65
MyActionClass(Action).execute(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse) line: 224
ExecuteAction.execute(ActionContext, Action, ActionConfig, ActionForm) line: 53
ExecuteAction(AbstractExecuteAction).execute(ActionContext) line: 64
ExecuteAction(ActionCommandBase).execute(Context) line: 48
ChainBase.execute(Context) line: 190
LookupCommand.execute(Context) line: 304
ChainBase.execute(Context) line: 190
ComposableRequestProcessor.process(HttpServletRequest, HttpServletResponse) line: 280
ActionServlet.process(HttpServletRequest, HttpServletResponse) line: 1858
ActionServlet.doPost(HttpServletRequest, HttpServletResponse) line: 459
Second pass I get (extra lines marked with ***
)
MyActionClass.getDisplayPage(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse) line: 65
***MyActionClass.unspecified(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse) line: 199
***MyActionClass(DispatchAction).dispatchMethod(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse, String) line: 242
***MyActionClass(DispatchAction).execute(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse) line: 167
***MyActionClass(Action).execute(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse) line: 217
ExecuteAction.execute(ActionContext, Action, ActionConfig, ActionForm) line: 53
ExecuteAction(AbstractExecuteAction).execute(ActionContext) line: 64
ExecuteAction(ActionCommandBase).execute(Context) line: 48
ChainBase.execute(Context) line: 190
LookupCommand.execute(Context) line: 304
ChainBase.execute(Context) line: 190
ComposableRequestProcessor.process(HttpServletRequest, HttpServletResponse) line: 280
ActionServlet.process(HttpServletRequest, HttpServletResponse) line: 1858
ActionServlet.doPost(HttpServletRequest, HttpServletResponse) line: 459
Other than the marked differences, the call stacks are identical.
Here is the struts config action pertaining to this post
<action path="/myAjaxRequest"
type="com..example.MyActionClass"
name="myActionForm"
parameter="save">
</action>
Does anybody have any ideas what the where the second pass through is coming from? I don't know where to begin to look.
Turns out this behaviour is caused by a "feature" of the application. Whoever designed the application overrode the DispatchAction.execute() method. The overriding execute() method, when receiving a null ActionForward from an action class, will attempt to call the action again using a different call path.
Since my action is servicing an ajax request, it was returning null on purpose after executing successfully. The result was that my action was being called again by the execute() method, and the request would be processed a second time.