com.konakart.actions.gateways.WorldPayXMLRedirectResponseAction.java Source code

Java tutorial

Introduction

Here is the source code for com.konakart.actions.gateways.WorldPayXMLRedirectResponseAction.java

Source

//
// (c) 2006 DS Data Systems UK Ltd, All rights reserved.
//
// DS Data Systems and KonaKart and their respective logos, are 
// trademarks of DS Data Systems UK Ltd. All rights reserved.
//
// The information in this document is free software; you can redistribute 
// it and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//

package com.konakart.actions.gateways;

import java.security.MessageDigest;
import java.util.Enumeration;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;

import com.konakart.al.KKAppEng;
import com.konakart.app.IpnHistory;
import com.konakart.app.KKException;
import com.konakart.app.OrderUpdate;
import com.konakart.appif.IpnHistoryIf;
import com.konakart.appif.OrderIf;
import com.konakart.appif.OrderUpdateIf;
import com.konakart.bl.ConfigConstants;
import com.konakart.bl.modules.payment.worldpayxmlredirect.WorldPayXMLRedirect;

/**
 * This class is an Action class for receiving the result from WorldPay. The customer is redirected
 * back to this action class from WorldPay. The parameters are used to determine whether the
 * transaction was successful or not.
 */
public class WorldPayXMLRedirectResponseAction extends BaseGatewayAction {
    /**
     * The <code>Log</code> instance for this application.
     */
    protected Log log = LogFactory.getLog(WorldPayXMLRedirectResponseAction.class);

    // Return codes and descriptions
    private static final int RET0 = 0;

    private static final String RET0_DESC = "Transaction OK";

    private static final int RET4 = -4;

    private static final String RET4_DESC = "There was an unexpected exception. Exception message = ";

    // Order history comments. These comments are associated with the order.
    private static final String ORDER_HISTORY_COMMENT_OK = "WorldPay payment successful. WorldPay Order Key = ";

    // private static final String ORDER_HISTORY_COMMENT_PENDING =
    // "WorldPay payment is pending. WorldPay Order Key = ";

    private static final String ORDER_HISTORY_COMMENT_KO = "WorldPay payment not successful. WorldPay Reply = ";

    private static final String ORDER_HISTORY_COMMENT_KO_1 = " for Order Key  = ";

    private static final long serialVersionUID = 1L;

    public String execute() {
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpServletResponse response = ServletActionContext.getResponse();

        // Create these outside of try / catch since they are needed in the case of a general
        // exception
        IpnHistoryIf ipnHistory = new IpnHistory();
        ipnHistory.setModuleCode(WorldPayXMLRedirect.WP_XML_REDIRECT_GATEWAY_CODE);
        KKAppEng kkAppEng = null;

        try {
            int custId;

            kkAppEng = this.getKKAppEng(request, response);

            custId = this.loggedIn(request, response, kkAppEng, "Checkout");

            // Check to see whether the user is logged in
            if (custId < 0) {
                return KKLOGIN;
            }

            // Set the customer id for the IPN history object
            ipnHistory.setCustomerId(custId);

            // Ensure we are using the correct protocol. Redirect if not.
            String redirForward = checkSSL(kkAppEng, request, custId, /* forceSSL */false);
            if (redirForward != null) {
                setupResponseForSSLRedirect(response, redirForward);
                return null;
            }

            // Get the order
            OrderIf order = kkAppEng.getOrderMgr().getCheckoutOrder();
            validateOrder(order, WorldPayXMLRedirect.WP_XML_REDIRECT_GATEWAY_CODE);

            // Set the order id for the ipnHistory object
            ipnHistory.setOrderId(order.getId());

            String orderKey = null;
            String paymentAmount = null;
            String paymentCurrency = null;
            String paymentStatus = null;
            String mac = null;
            String retCode = null;

            StringBuffer fullResponse = new StringBuffer();
            Enumeration<String> en = request.getParameterNames();
            while (en.hasMoreElements()) {
                String paramName = en.nextElement();
                String paramValue = request.getParameter(paramName);
                fullResponse.append(pad(paramName, 20) + " = ").append(paramValue).append("\n");
                if (paramName.equals("paymentStatus")) {
                    paymentStatus = paramValue;
                } else if (paramName.equals("paymentAmount")) {
                    paymentAmount = paramValue;
                } else if (paramName.equals("paymentCurrency")) {
                    paymentCurrency = paramValue;
                } else if (paramName.equals("orderKey")) {
                    orderKey = paramValue;
                } else if (paramName.equals("mac")) {
                    mac = paramValue;
                } else if (paramName.equals("retCode")) {
                    retCode = paramValue;
                }
            }

            // Set IPN History data
            ipnHistory.setGatewayFullResponse(fullResponse.toString());
            ipnHistory.setGatewayResult(paymentStatus);
            ipnHistory.setGatewayTransactionId(orderKey);

            if (log.isDebugEnabled()) {
                log.debug("WorldPay response =\n" + fullResponse.toString());
            }

            // If mac isn't null then we check it
            if (mac != null) {
                String sharedSecret = "";
                if (order.getPaymentDetails() != null) {
                    sharedSecret = order.getPaymentDetails().getCustom1();
                }

                StringBuffer sb = new StringBuffer();
                sb.append(orderKey);
                sb.append(paymentAmount);
                sb.append(paymentCurrency);
                sb.append(paymentStatus);
                sb.append(sharedSecret);

                String hashedValue = md5(sb.toString());

                if (!hashedValue.equals(mac)) {
                    if (log.isDebugEnabled()) {
                        log.debug("String before hashing = " + sb.toString());
                        log.debug("String after hashing  = " + hashedValue);
                    }

                    if (log.isWarnEnabled()) {
                        log.warn("WorldPay Response does not pass security test: ");
                        log.warn("mac from WorldPay : " + mac);
                        log.warn("Hashed String     : " + hashedValue);
                    }

                    // Save the ipnHistory
                    ipnHistory.setKonakartResultDescription(
                            getResultDescription("WorldPay Response does not pass security test:"
                                    + "\nmac from WorldPay : " + mac + "\nHashed String : " + hashedValue));
                    ipnHistory.setKonakartResultId(RET4);
                    kkAppEng.getEng().saveIpnHistory(kkAppEng.getSessionId(), ipnHistory);

                    // Redirect the user to an error screen
                    return "CheckoutError";
                }
            }

            // See if we need to send an email, by looking at the configuration
            String sendEmailsConfig = kkAppEng.getConfig(ConfigConstants.SEND_EMAILS);
            boolean sendEmail = false;
            if (sendEmailsConfig != null && sendEmailsConfig.equalsIgnoreCase("true")) {
                sendEmail = true;
            }

            OrderUpdateIf updateOrder = new OrderUpdate();
            updateOrder.setUpdatedById(kkAppEng.getActiveCustId());

            if (paymentStatus != null && paymentStatus.equals("AUTHORISED")) {
                String comment = ORDER_HISTORY_COMMENT_OK + orderKey;
                kkAppEng.getEng().updateOrder(kkAppEng.getSessionId(), order.getId(),
                        com.konakart.bl.OrderMgr.PAYMENT_RECEIVED_STATUS, /* customerNotified */
                        sendEmail, comment, updateOrder);

                // Update the inventory
                kkAppEng.getOrderMgr().updateInventory(order.getId());

                // Save the ipnHistory
                ipnHistory.setKonakartResultDescription(RET0_DESC);
                ipnHistory.setKonakartResultId(RET0);
                kkAppEng.getEng().saveIpnHistory(kkAppEng.getSessionId(), ipnHistory);

                // If we received no exceptions, delete the basket
                kkAppEng.getBasketMgr().emptyBasket();

                if (sendEmail) {
                    sendOrderConfirmationMail(kkAppEng, order.getId(), /* success */true);
                }

                return "Approved";

            } else if (retCode != null && retCode.equals("pending")) {

                /*
                 * Reach here if paying by bank transfer so we leave the order in a waiting for
                 * payment state although we could create a new "pending" state that differentiates
                 * between orders that haven't been paid for and orders that have been paid but just
                 * waiting for outcome.
                 */
                // String comment = ORDER_HISTORY_COMMENT_PENDING + orderKey;
                // kkAppEng.getEng().updateOrder(kkAppEng.getSessionId(), order.getId(),
                // com.konakart.bl.OrderMgr.PAYMENT_RECEIVED_STATUS, /* customerNotified */
                // sendEmail, comment, updateOrder);

                // Update the inventory
                // kkAppEng.getOrderMgr().updateInventory(order.getId());

                // Save the ipnHistory
                ipnHistory.setKonakartResultDescription(RET0_DESC);
                ipnHistory.setKonakartResultId(RET0);
                kkAppEng.getEng().saveIpnHistory(kkAppEng.getSessionId(), ipnHistory);

                // If we received no exceptions, delete the basket
                kkAppEng.getBasketMgr().emptyBasket();

                if (sendEmail) {
                    sendOrderConfirmationMail(kkAppEng, order.getId(), /* success */true);
                }

                return "Approved";

            } else {
                String comment = ORDER_HISTORY_COMMENT_KO + paymentStatus + ORDER_HISTORY_COMMENT_KO_1 + orderKey;
                kkAppEng.getEng().updateOrder(kkAppEng.getSessionId(), order.getId(),
                        com.konakart.bl.OrderMgr.PAYMENT_DECLINED_STATUS, /* customerNotified */
                        sendEmail, comment, updateOrder);

                // Save the ipnHistory
                ipnHistory.setKonakartResultDescription(RET0_DESC);
                ipnHistory.setKonakartResultId(RET0);
                ipnHistory.setCustomerId(kkAppEng.getCustomerMgr().getCurrentCustomer().getId());
                kkAppEng.getEng().saveIpnHistory(kkAppEng.getSessionId(), ipnHistory);

                if (sendEmail) {
                    sendOrderConfirmationMail(kkAppEng, order.getId(), /* success */false);
                }
                return "CheckoutError";
            }

        } catch (Exception e) {
            try {
                ipnHistory.setKonakartResultDescription(RET4_DESC + e.getMessage());
                ipnHistory.setKonakartResultId(RET4);
                if (kkAppEng != null) {
                    kkAppEng.getEng().saveIpnHistory(kkAppEng.getSessionId(), ipnHistory);
                }
            } catch (KKException e1) {
                return super.handleException(request, e1);
            }
            return super.handleException(request, e);
        }
    }

    /**
     * Use this to truncate the result description so that it fits in the database column OK
     * 
     * @param desc
     *            the result description (which may be too long)
     * @return a truncated result description
     */
    private String getResultDescription(String desc) {
        if (desc == null) {
            return null;
        } else if (desc.length() <= 255) {
            return desc;
        }

        return desc.substring(0, 255);
    }

    /**
     * Calculates a hex MD5 based on input.
     * 
     * @param message
     *            String to calculate MD5 of.
     * 
     */
    private String md5(String message) throws java.security.NoSuchAlgorithmException {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (java.security.NoSuchAlgorithmException ex) {
            ex.printStackTrace();
            if (log.isDebugEnabled()) {
                log.debug(ex);
            }
            throw ex;
        }
        byte[] dig = md5.digest(message.getBytes());
        StringBuffer code = new StringBuffer();
        for (int i = 0; i < dig.length; ++i) {
            code.append(Integer.toHexString(0x0100 + (dig[i] & 0x00FF)).substring(1));
        }
        return code.toString();
    }

    /**
     * Used for reporting purposes
     * 
     * @param str
     * @param chars
     * @return
     */
    private String pad(String str, int chars) {
        if (str == null) {
            return str;
        }
        int charsToAdd = chars - str.length();
        String tempStr = str;
        for (int i = 0; i < charsToAdd; i++) {
            tempStr += " ";
        }
        return tempStr;
    }
}