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

Java tutorial

Introduction

Here is the source code for com.konakart.actions.gateways.BaseGatewayAction.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.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

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

import com.konakart.actions.BaseAction;
import com.konakart.al.KKAppEng;
import com.konakart.al.KKAppException;
import com.konakart.app.EmailOptions;
import com.konakart.app.IpnHistory;
import com.konakart.app.KKException;
import com.konakart.app.NameValue;
import com.konakart.appif.EmailOptionsIf;
import com.konakart.appif.IpnHistoryIf;
import com.konakart.appif.KKEngIf;
import com.konakart.appif.NameValueIf;
import com.konakart.appif.OrderIf;
import com.konakart.appif.PaymentDetailsIf;
import com.konakart.bl.ConfigConstants;
import com.konakart.util.RegExpUtils;
import com.konakart.util.Utils;

/**
 * Base Gateway Action for KonaKart application.
 */
public class BaseGatewayAction extends BaseAction {
    /**
     * The <code>Log</code> instance for this application.
     */
    private Log log = LogFactory.getLog(BaseGatewayAction.class);

    private static final long serialVersionUID = 1L;

    /**
     * Validate the order and ensure that we are using the correct payment gateway
     * 
     * @param order
     * @param code
     * @throws KKAppException
     */
    protected void validateOrder(OrderIf order, String code) throws KKAppException {
        if (order == null) {
            throw new KKAppException("There is no order.");
        }

        if (order.getPaymentDetails() == null) {
            throw new KKAppException("There is no PaymentDetails object attached to the order.");
        }

        if (order.getPaymentDetails().getCode() == null) {
            throw new KKAppException(
                    "The PaymentDetails object contains a null code so we cannot determine which payment gateway to use.");
        }

        if (!order.getPaymentDetails().getCode().equals(code)) {
            throw new KKAppException(
                    "The PaymentDetails object contains the gateway code: " + order.getPaymentDetails().getCode()
                            + " which does not equal the code of the gateway being used: " + code);
        }
    }

    /**
     * Sends data to the payment gateway via a POST. Parameters are received from the PaymentDetails
     * object and the credit card parameters that have just been input by the customer are sent in a
     * separate list; the ccParmList. Any miscellaneous parameters can also be added to the
     * ccParmList if required.
     * 
     * @param pd
     *            the PaymentDetails object
     * @param ccParmList
     * @return The response to the post
     * @throws IOException
     */
    public String postData(PaymentDetailsIf pd, List<NameValueIf> ccParmList) throws IOException {
        return postData(null, pd, ccParmList);
    }

    /**
     * Sends data to the payment gateway via a POST. Parameters are received from the PaymentDetails
     * object and the credit card parameters that have just been input by the customer are sent in a
     * separate list; the ccParmList. Any miscellaneous parameters can also be added to the
     * ccParmList if required. If postData is not null, then the data it contains is used instead of
     * the data from the PaymentDetails and ccParmList.
     * 
     * @param postData
     *            The data to be posted. Can be null.
     * @param pd
     *            the PaymentDetails object
     * @param ccParmList
     * @return The response to the post
     * @throws IOException
     */
    public String postData(StringBuffer postData, PaymentDetailsIf pd, List<NameValueIf> ccParmList)
            throws IOException {
        URL url = new URL(pd.getRequestUrl());
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setDoInput(true);

        if (pd.getReferrer() != null && pd.getReferrer().length() > 1) {
            connection.setRequestProperty("Referer", pd.getReferrer());
        }

        // This one is deprecated but we still need to call it
        customizeConnection(connection);

        // This is the one that should be used from v5.5.0.0
        customizeConnection(connection, pd, ccParmList);

        PrintWriter out = new PrintWriter(connection.getOutputStream());

        StringBuffer sb = (postData == null) ? getGatewayRequest(pd, ccParmList) : postData;

        if (log.isDebugEnabled()) {
            log.debug("Post URL = " + pd.getRequestUrl());
            log.debug("Post string =\n" + RegExpUtils.maskCreditCard(sb.toString()));
        }

        // Send the message
        out.print(sb.toString());
        out.close();

        // Get back the response
        StringBuffer respSb = new StringBuffer();
        BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
        String line = in.readLine();

        while (line != null) {
            respSb.append(line);
            line = in.readLine();
        }

        in.close();

        return respSb.toString();
    }

    /**
     * Sends data to the payment gateway via a GET. Parameters are received from the PaymentDetails
     * object and the credit card parameters that have just been input by the customer are send in a
     * separate list; the ccParmList
     * 
     * @param pd
     * @param ccParmList
     * @return The response to the post
     * @throws IOException
     */
    public String getData(PaymentDetailsIf pd, List<NameValueIf> ccParmList) throws IOException {
        // Construct data for GET
        String urlStr = pd.getRequestUrl();
        StringBuffer sbRequest = getGatewayRequest(pd, ccParmList);

        if (log.isDebugEnabled()) {
            log.debug("GET URL = " + urlStr + RegExpUtils.maskCreditCard(sbRequest.toString()));
        }
        URL url = new URL(urlStr + sbRequest.toString());

        // Send data
        URLConnection conn = url.openConnection();

        // Get the response
        BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        StringBuffer sbReply = new StringBuffer();
        String line;
        while ((line = rd.readLine()) != null) {
            sbReply.append(line);
        }
        rd.close();
        String result = sbReply.toString();

        return result;
    }

    /**
     * This method can be specialized in the super class to customize the format of the request
     * 
     * @param pd
     *            the PaymentDetails
     * @param ccParmList
     *            the credit card parameters
     * @return a StringBuffer containing the gateway request
     */
    protected StringBuffer getGatewayRequest(PaymentDetailsIf pd, List<NameValueIf> ccParmList) {
        // Create the message from the parameters in the PaymentDetails object
        StringBuffer sb = new StringBuffer();

        if (pd.getParameters() != null) {
            for (int i = 0; i < pd.getParameters().length; i++) {
                NameValueIf nv = pd.getParameters()[i];
                if (i > 0) {
                    sb.append("&");
                }
                sb.append(nv.getName());
                sb.append("=");
                sb.append(nv.getValue());
            }
        }

        // Add the credit card parameters
        if (ccParmList != null) {
            for (Iterator<NameValueIf> iter = ccParmList.iterator(); iter.hasNext();) {
                NameValueIf nv = iter.next();
                sb.append("&");
                sb.append(nv.getName());
                sb.append("=");
                sb.append(nv.getValue());
            }
        }

        if (log.isDebugEnabled()) {
            int padding = 25;

            String logStr = "";
            if (pd.getParameters() != null) {
                for (int i = 0; i < pd.getParameters().length; i++) {
                    NameValueIf nv = pd.getParameters()[i];
                    logStr += "\n    " + Utils.padRight(nv.getName(), padding) + " = " + nv.getValue();
                }
            }

            if (ccParmList != null) {
                for (Iterator<NameValueIf> iter = ccParmList.iterator(); iter.hasNext();) {
                    NameValueIf nv = iter.next();
                    logStr += "\n    " + Utils.padRight(nv.getName(), padding) + " = "
                            + RegExpUtils.maskCreditCard(nv.getValue());
                }
            }

            log.debug("Post source data:" + logStr);
        }

        return sb;
    }

    /**
     * @param kkAppEng
     * @return Returns the logFileDirectory. We look it up every time.
     */
    public String getLogFileDirectory(KKAppEng kkAppEng) {
        try {
            String conf = kkAppEng.getConfig(ConfigConstants.KONAKART_LOG_FILE_DIRECTORY);
            if (conf != null) {
                return conf + System.getProperty("file.separator");
            }
        } catch (Exception e) {
            if (e.getMessage().contains("return by API")) {
                if (log.isWarnEnabled()) {
                    log.warn(e.getMessage());
                }
            } else {
                // unexpected
                e.printStackTrace();
            }
        }

        return "";
    }

    /**
     * This method is optionally called from the sub class to load up the parameters into a
     * HashTable for efficient subsequent processing
     * 
     * @param pd
     *            PaymentDetails object
     * @param ccParmList
     *            name value pair list of CC parameters
     * @return a hash map containing the parameters for rapid lookup
     */
    protected HashMap<String, String> hashParameters(PaymentDetailsIf pd, List<NameValueIf> ccParmList) {
        HashMap<String, String> paramHash = new HashMap<String, String>();

        if (pd != null) {
            for (int c = 0; c < pd.getParameters().length; c++) {
                paramHash.put(pd.getParameters()[c].getName(), pd.getParameters()[c].getValue());
            }
        }

        if (ccParmList != null) {
            for (int c = 0; c < ccParmList.size(); c++) {
                paramHash.put(ccParmList.get(c).getName(), ccParmList.get(c).getValue());
            }
        }

        return paramHash;
    }

    /**
     * Get the value of the parameter with the specified name from the PaymentDetails object
     * 
     * @param paramName
     *            parameter name to look up
     * @param pd
     *            PaymentDetails object
     * @return value of the parameter or null if the parameter is not found
     */
    protected String getParameterFromPaymentDetails(String paramName, PaymentDetailsIf pd) {
        String value = null;

        if (pd != null && pd.getParameters() != null) {
            for (int c = 0; c < pd.getParameters().length; c++) {
                if (paramName.equals(pd.getParameters()[c].getName())) {
                    return pd.getParameters()[c].getValue();
                }
            }
        }

        return value;
    }

    /**
     * This method is normally specialized in the sub class to customize the connection
     * 
     * @param connection
     *            the HTTP connection object
     * @param pd
     *            the Payment Details
     * @param paramList
     *            Additional parameters (typically credit card details but can also be any
     *            miscellaneous extra parameters that may be required)
     */
    protected void customizeConnection(HttpURLConnection connection, PaymentDetailsIf pd,
            List<NameValueIf> paramList) {
    }

    /**
     * This method is normally specialized in the sub class to customize the connection
     * 
     * @param connection
     */
    @Deprecated
    protected void customizeConnection(HttpURLConnection connection) {
    }

    /**
     * Send an order confirmation eMail. The template used is different if the order is successful
     * or not.
     * 
     * @param kkAppEng
     * @param orderId
     * @param success
     * @throws KKException
     */
    protected void sendOrderConfirmationMail(KKAppEng kkAppEng, int orderId, boolean success) throws KKException {
        String countryCode = kkAppEng.getLocale().substring(0, 2);

        sendOrderConfirmationMail(kkAppEng.getEng(), kkAppEng.getSessionId(), countryCode, orderId, success);
    }

    /**
     * Send an order confirmation eMail. The template used is different if the order is successful
     * or not.
     * 
     * @param eng
     * @param sessionId
     * @param countryCode
     * @param orderId
     * @param success
     * @throws KKException
     */
    protected void sendOrderConfirmationMail(KKEngIf eng, String sessionId, String countryCode, int orderId,
            boolean success) throws KKException {
        EmailOptionsIf options = new EmailOptions();

        // Default behaviour is not to create or attach the PDF invoice
        options.setCreateInvoice(false);
        options.setAttachInvoice(false);

        options.setCountryCode(countryCode);

        if (success) {
            options.setTemplateName("OrderConfPaymentSuccess");

            // Attach the invoice to the confirmation email (Enterprise Only). Defaults to false.
            // options.setAttachInvoice(true);

            // Create the invoice (if not already present) for attaching to the confirmation email
            // (Enterprise Only). Defaults to false.
            // options.setCreateInvoice(true);

        } else {
            options.setTemplateName("OrderConfPaymentFailure");
        }

        eng.sendOrderConfirmationEmail1(sessionId, orderId, /* langIdForOrder */
                -1, options);
    }

    /**
     * Saves an IPN History record. The KKAppEng should have a logged-in user with a valid
     * sessionId.
     * 
     * @param kkAppEng
     *            the KKAppEng application engine which should contain a valid sessionId
     * @param orderId
     *            the orderId involved in the transaction
     * @param moduleCode
     *            the code of the module
     * @param gatewayFullResponse
     *            full response from the gateway
     * @param gatewayResult
     *            summary gateway response
     * @param gatewayTransactionId
     *            an Id from the gateway that identifies the transaction
     * @param konakartResultDescription
     *            KonaKart result description
     * @param konakartResultId
     *            KonaKart result code
     * @throws KKException
     */
    protected void saveIPNrecord(KKAppEng kkAppEng, int orderId, String moduleCode, String gatewayFullResponse,
            String gatewayResult, String gatewayTransactionId, String konakartResultDescription,
            int konakartResultId) throws KKException {
        String txType = null;
        BigDecimal txAmount = null;

        saveIPNrecord(kkAppEng, orderId, moduleCode, gatewayFullResponse, gatewayResult, gatewayTransactionId,
                konakartResultDescription, konakartResultId, txType, txAmount);
    }

    /**
     * Saves an IPN History record. The KKAppEng should have a logged-in user with a valid
     * sessionId.
     * 
     * @param kkAppEng
     *            the KKAppEng application engine which should contain a valid sessionId
     * @param orderId
     *            the orderId involved in the transaction
     * @param moduleCode
     *            the code of the module
     * @param gatewayFullResponse
     *            full response from the gateway
     * @param gatewayResult
     *            summary gateway response
     * @param gatewayTransactionId
     *            an Id from the gateway that identifies the transaction
     * @param konakartResultDescription
     *            KonaKart result description
     * @param konakartResultId
     *            KonaKart result code
     * @param txType
     *            Transaction Type
     * @param txAmount
     *            Transaction Amount
     * @throws KKException
     */
    protected void saveIPNrecord(KKAppEng kkAppEng, int orderId, String moduleCode, String gatewayFullResponse,
            String gatewayResult, String gatewayTransactionId, String konakartResultDescription,
            int konakartResultId, String txType, BigDecimal txAmount) throws KKException {
        try {
            IpnHistoryIf ipnHistory = new IpnHistory();
            ipnHistory.setOrderId(orderId);
            ipnHistory.setModuleCode(moduleCode);
            ipnHistory.setDateAdded(new GregorianCalendar());
            ipnHistory.setGatewayFullResponse(gatewayFullResponse);
            ipnHistory.setGatewayResult(Utils.trim(gatewayResult, 128));
            ipnHistory.setGatewayTransactionId(gatewayTransactionId);
            ipnHistory.setKonakartResultDescription(Utils.trim(konakartResultDescription, 255));
            ipnHistory.setKonakartResultId(konakartResultId);
            ipnHistory.setCustomerId(kkAppEng.getCustomerMgr().getCurrentCustomer().getId());
            ipnHistory.setTxType(txType);
            ipnHistory.setTxAmount(txAmount);
            kkAppEng.getEng().saveIpnHistory(kkAppEng.getSessionId(), ipnHistory);
        } catch (KKException e) {
            log.warn("Exception occured trying to save IPN History record: " + e.getMessage());
            throw e;
        }
    }

    /**
     * Add more parameters to the PaymentDetails object. Normally this method would be on the
     * PaymentDetails class but it's placed here instead because of the automatic code generation
     * that occurs on the PaymentDetails class for web services, JSON and RMI etc.
     * 
     * @param pd
     *            the PaymentDetails object
     * @param newParameters
     *            The parameters to set.
     */
    protected void addParameters(PaymentDetailsIf pd, List<NameValueIf> newParameters) {
        List<NameValueIf> parmList = new ArrayList<NameValueIf>();

        // Add the new parameters to our temporary list
        if (newParameters != null) {
            for (int p = 0; p < newParameters.size(); p++) {
                parmList.add(newParameters.get(p));
            }
        }

        // Add the existing parameters to our temporary list
        if (pd.getParameters() != null) {
            for (int p = 0; p < pd.getParameters().length; p++) {
                parmList.add(pd.getParameters()[p]);
            }
        }

        // Now replace the parameters with a new set
        NameValue[] nvArray = new NameValue[parmList.size()];
        parmList.toArray(nvArray);
        pd.setParameters(nvArray);
    }

    /**
     * 
     * @param request
     * @return Returns the IP address
     */
    protected String getCustomerIPAddress(HttpServletRequest request) {
        return request.getRemoteAddr();
    }
}