Struts action not rendering correct path after change in controller

2.5k Views Asked by At

I'm working on a very old J2EE/struts site and, because of PayPal's recent discontinuation of support for the SSL 3 protocol, am trying to implement a new hosted checkout process whereby a payment gateway accepts a POST with order details, handles credit card validation, and returns a response code (and a million other values) via another POST.

I'm trying to utilize the existing actions in struts, but am getting hung up because the path specified in struts-config.xml (/store/order/confirmation.do) is not being rendered; instead, after the POST request from the remote server is processed and the ActionMapping.findForward() is called, the application just renders the same path that was requested in the POST back from the remote server (/store/checkout/submitOrder.do).

If I try to add redirect="true" to the forward in struts-config.xml, I get redirected to the proper path, but with a pagecontext exception that I can't debug because it's not logged.

The way this used to work was that the submitOrder form was empty -- just a submit input. Then, the checkout detail from the session-based shopping cart and associated customerbillingforms would be handed off to a special verisign library to generate a response. I now want to use the form POST from the new provider, but am stuck on this redirection fiasco.

The line in struts-config.xml looks like this:

<action path="/store/checkout/submitOrder" type="com.company.action.CheckoutAction" parameter="submitOrder" scope="request">
  <set-property property="secure" value="true"/>
  <forward name="success" path="/store/order/confirmation.do"/>
</action>

And the action goes like this:

public ActionForward submitOrder(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception {
  String method = request.getMethod();
  if (method != null && method.equals("POST")) {
    ShoppingCart sc = (ShoppingCart) request.getSession(false).getAttribute("shoppingCart");
    if (sc == null) { throw new SessionExpiredException("Submit Order - Shopping Cart is not in session"); }
    ResourceBundle appConfig = ResourceBundle.getBundle("resources.application");

    PFProClient client = new PFProClient();

    /* THIS saveOrder() METHOD WAS RE-WRITTEN TO TAKE the httpservletrequest (form POST) instead of an instance of VerisignResponse, defined in another library. */

    client.saveOrder(sc, request);
    User user = (User)request.getSession(false).getAttribute(Globals.USER);
    if (user != null) { UserModel.saveUser(user, sc.getCustomer(), sc.getOrder()); }
    //Remove items from session
    request.getSession().setAttribute("customerBillingForm", null);
    request.getSession().setAttribute("customerShippingForm", null);
    request.getSession().setAttribute("customerCreditForm", null);
    request.getSession().setAttribute("cartForm", null);
    request.getSession().setAttribute("shoppingCart", null);
    //remove the shopping cart from the cookie & DB
    ShoppingCartUtils.deleteSavedCartFromCookie(response, request);
    //remove the CHECKING_OUT flag
    request.getSession().setAttribute(Globals.CHECKING_OUT, null);
    //remove the PAYING_WITH_PAYPAL flag
    request.getSession().setAttribute(Globals.PAYING_WITH_PAYPAL, null);
    // Set cart in request for order confirmation page
    request.setAttribute("shoppingCart", sc);
    return mapping.findForward("success");
  } else {
    // HTTP method was not POST
  }
  return mapping.findForward("success");
}

EDIT

I've verified that the submitOrder action is being processed as a POST request. I'm wondering if, since the previous POST was just an empty form, the extra POST parameters are fouling something up and preventing the proper routing.

In tiles-defs.xml, the resource for the confirmation.do view is:

<definition name="confirm.order" path="/templates/layouts/order-confirmation.jsp">
  ...
  <put name="content" value="/store/checkout/confirmOrder.jsp"/>
</definition>

The application is serving the confirmOrder.jsp view, but not routing to /store/order/confirmation.do, so any attempts to reload the page prompt the user to resubmit the form, which is obviously undesirable.

I also removed a reference to name="emptyForm" from the submitOrder action definition (since the form POST coming from the remote server won't have the emptyForm name attribute) in struts-config.xml, which is defined as:

<form-bean name="emptyForm" type="org.apache.struts.action.DynaActionForm"/>

I'm not sure what effect that would have either.

1

There are 1 best solutions below

3
On BEST ANSWER

With forwards, the client will always think it's still looking at the requested resource (submitOrder.do) because there's no way for it to know any better (i.e. a single request was made for a resource and a response came back). The response content should be coming from the forward resource (confirmation.do) though.

If the response content is not coming from confirmation.do, then we are looking at a different issue. In this case, most likely the PayPal callback is using a different request method than POST, which would bypass most of the submitOrder() code (// HTTP method was not POST). And the Struts Action behind confirmation.do, missing necessary session or request attributes, perhaps displays the submitOrder page.