All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cybersource.ws.client.Connection Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2003-2014 CyberSource Corporation
 *
 * THE SOFTWARE AND THE DOCUMENTATION ARE PROVIDED ON AN "AS IS" AND "AS
 * AVAILABLE" BASIS WITH NO WARRANTY.  YOU AGREE THAT YOUR USE OF THE SOFTWARE AND THE
 * DOCUMENTATION IS AT YOUR SOLE RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR
 * COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE. TO THE FULLEST
 * EXTENT PERMISSIBLE UNDER APPLICABLE LAW, CYBERSOURCE AND ITS AFFILIATES EXPRESSLY DISCLAIM ALL
 * WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, WITH RESPECT TO THE SOFTWARE AND THE
 * DOCUMENTATION, INCLUDING ALL WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
 * SATISFACTORY QUALITY, ACCURACY, TITLE AND NON-INFRINGEMENT, AND ANY WARRANTIES THAT MAY ARISE
 * OUT OF COURSE OF PERFORMANCE, COURSE OF DEALING OR USAGE OF TRADE.  NEITHER CYBERSOURCE NOR
 * ITS AFFILIATES WARRANT THAT THE FUNCTIONS OR INFORMATION CONTAINED IN THE SOFTWARE OR THE
 * DOCUMENTATION WILL MEET ANY REQUIREMENTS OR NEEDS YOU MAY HAVE, OR THAT THE SOFTWARE OR
 * DOCUMENTATION WILL OPERATE ERROR FREE, OR THAT THE SOFTWARE OR DOCUMENTATION IS COMPATIBLE
 * WITH ANY PARTICULAR OPERATING SYSTEM.
 */

package com.cybersource.ws.client;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;


/**
 * It is a factory class for creating an instance for HttpClientConnection or
 * JDKHttpURLConnection or PoolingHttpClientConnection.
 */
abstract public class Connection {
    final MerchantConfig mc;
    private final DocumentBuilder builder;
    final LoggerWrapper logger;

    /**
     * It initializes three arguments MerchantConfig, DocumentBuilder and Logger
     * Any class extending this class must implement three argument constructor
     *
     * @param mc
     * @param builder
     * @param logger
     */
    protected Connection(MerchantConfig mc, DocumentBuilder builder,
                         LoggerWrapper logger) {
        this.mc = mc;
        this.builder = builder;
        this.logger = logger;
    }

    /**
     * Get connection instance based on properties
     *
     * @param mc
     * @param builder
     * @param logger
     * @return Connection
     * @throws ClientException
     */
    public static Connection getInstance(
            MerchantConfig mc, DocumentBuilder builder, LoggerWrapper logger) throws ClientException {
        if (mc.getUseHttpClientWithConnectionPool()) {
            return new PoolingHttpClientConnection(mc, builder, logger);
        } else if (mc.getUseHttpClient()) {
            return new HttpClientConnection(mc, builder, logger);
        } else {
            // HttpClient is not set in properties file then JDKHttpURLConnection class instance.
            return new JDKHttpURLConnection(mc, builder, logger);
        }
    }

    /**
     * To check is request sent or not
     *
     * @return boolean
     */
    abstract public boolean isRequestSent();

    /**
     * To release the connection related objects
     *
     * @throws ClientException
     */
    abstract public void release() throws ClientException;

    /**
     * method to post request
     *
     * @param request
     * @param startTime
     * @throws IOException
     * @throws TransformerConfigurationException
     * @throws TransformerException
     * @throws MalformedURLException
     * @throws ProtocolException
     */
    abstract void postDocument(Document request, long startTime)
            throws IOException, TransformerConfigurationException,
            TransformerException, MalformedURLException,
            ProtocolException;


    abstract int getHttpResponseCode()
            throws IOException;

    abstract InputStream getResponseStream()
            throws IOException;


    abstract InputStream getResponseErrorStream()
            throws IOException;

    /**
     * Post the request document and validate the response for any faults from the Server.
     *
     * @param request - Request document
     * @return - Response XML as Document object.
     * @throws ClientException
     * @throws FaultException
     */
    public Document post(Document request, long startTime)
            throws ClientException, FaultException {
        try {
            postDocument(request, startTime);
            checkForFault();
            return (parseReceivedDocument());
        } catch (IOException e) {
            throw new ClientException(e, isRequestSent(), logger);
        } catch (TransformerConfigurationException e) {
            throw new ClientException(e, isRequestSent(), logger);
        } catch (TransformerException e) {
            throw new ClientException(e, isRequestSent(), logger);
        } catch (SAXException e) {
            throw new ClientException(e, isRequestSent(), logger);
        } catch (RuntimeException e) {
            throw new ClientException(e, isRequestSent(), logger);
        }
    }


    /**
     * Validate the Http response for any faults returned from the server.
     *
     * @throws FaultException
     * @throws ClientException
     */
    private void checkForFault()
            throws FaultException, ClientException {
        try {
            logger.log(Logger.LT_INFO, "waiting for response...");
            int responseCode = getHttpResponseCode();
            logResponseHeaders();
            // if successful, there's nothing left to do here.
            // we'll process the response in a later method.
            if (responseCode == HttpURLConnection.HTTP_OK) return;

            InputStream errorStream = getResponseErrorStream();

            // if there is no error stream, then it is not a fault
            if (errorStream == null) {
                throw new ClientException(responseCode, logger);
            }

            // read error stream into a byte array
            byte[] errorBytes;
            try {
                errorBytes = Utility.read(errorStream);
                errorStream.close();
            } catch (IOException ioe) {
                throw new ClientException(
                        responseCode, "Failed to read additional HTTP error",
                        true, logger);
            }

            // server will return HTTP 500 on a fault
            if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
                try {
                    ByteArrayInputStream bais
                            = new ByteArrayInputStream(errorBytes);

                    Document faultDoc = builder.parse(bais);
                    bais.close();

                    throw new FaultException(
                            faultDoc, mc.getEffectiveNamespaceURI(), logger);

                } catch (IOException ioe) {
                    // If an IO exception occurs, we're not sure whether
                    // or not it was a fault.  So we mark it as critical.
                    String text = new String(errorBytes);
                    throw new ClientException(
                            responseCode, text, true, logger);
                } catch (SAXException ioe) {
                    // If parsing fails, it means it's not a fault after all.
                    String text = new String(errorBytes);
                    throw new ClientException(responseCode, text, logger);
                }
            } else {
                // non-500 return codes are definitely not faults
                String text = new String(errorBytes);
                throw new ClientException(responseCode, text, logger);
            }
        }
        // catch other IOException's that we have not already handled.
        catch (IOException e) {
            throw new ClientException(e, true, logger);
        }
    }

    /**
     * Helps to parse/read the response xml into Document object.
     *
     * @return - returns a Document object
     * @throws IOException
     * @throws SAXException
     */
    private Document parseReceivedDocument()
            throws IOException, SAXException {
        logger.log(Logger.LT_INFO, "Parsing response...");
        //long startTime = System.nanoTime();
        Document document = builder.parse(getResponseStream());
        //System.out.println("Connection.parseReceivedDocument time taken to parse the response is " + TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
        return document;
    }

    /**
     * Converts the Document object into ByteArrayStream.
     *
     * @param doc - Document object
     * @return ByteArrayStream
     * @throws TransformerConfigurationException
     * @throws TransformerException
     */
    static ByteArrayOutputStream makeStream(Document doc)
            throws TransformerConfigurationException, TransformerException {
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        transformer.transform(
                new DOMSource(doc), new StreamResult(baos));

        return baos;
    }

    abstract public void logRequestHeaders();

    abstract public void logResponseHeaders();
}


/* Copyright 2006 CyberSource Corporation */





© 2015 - 2025 Weber Informatics LLC | Privacy Policy