it.greenvulcano.gvesb.virtual.http.HTTPCallOperation.java Source code

Java tutorial

Introduction

Here is the source code for it.greenvulcano.gvesb.virtual.http.HTTPCallOperation.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2016 GreenVulcano ESB Open Source Project.
 * All rights reserved.
 *
 * This file is part of GreenVulcano ESB.
 *
 * GreenVulcano ESB 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 3 of the License, or
 * (at your option) any later version.
 *
 * GreenVulcano ESB 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.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with GreenVulcano ESB. If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/
package it.greenvulcano.gvesb.virtual.http;

import it.greenvulcano.configuration.XMLConfig;
import it.greenvulcano.gvesb.buffer.GVBuffer;
import it.greenvulcano.gvesb.gvdp.DataProviderManager;
import it.greenvulcano.gvesb.gvdp.IDataProvider;
import it.greenvulcano.gvesb.http.ProtocolFactory;
import it.greenvulcano.gvesb.http.auth.HttpAuth;
import it.greenvulcano.gvesb.http.auth.HttpAuthFactory;
import it.greenvulcano.gvesb.http.proxy.HttpProxy;
import it.greenvulcano.gvesb.internal.data.GVBufferPropertiesHelper;
import it.greenvulcano.gvesb.virtual.CallException;
import it.greenvulcano.gvesb.virtual.CallOperation;
import it.greenvulcano.gvesb.virtual.ConnectionException;
import it.greenvulcano.gvesb.virtual.InitializationException;
import it.greenvulcano.gvesb.virtual.InvalidDataException;
import it.greenvulcano.gvesb.virtual.OperationKey;
import it.greenvulcano.util.metadata.PropertiesHandler;
import it.greenvulcano.util.xml.XMLUtils;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.Map;

import javax.activation.DataHandler;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Part;
import javax.mail.internet.ContentType;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;

import org.apache.axiom.util.base64.Base64EncodingOutputStream;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.methods.OptionsMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.slf4j.Logger;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

/**
 * @version 3.0.0 Jul 26, 2010
 * @author GreenVulcano Developer Team
 * 
 * 
 */
public class HTTPCallOperation implements CallOperation {
    enum HttpMethodName {
        OPTIONS, GET, HEAD, POST, PUT, DELETE
    }

    private static final Logger logger = org.slf4j.LoggerFactory.getLogger(HTTPCallOperation.class);
    private static final String RESPONSE_PREFIX = "GVHTTP_RESPONSE_";
    private static final String RESPONSE_STATUS = RESPONSE_PREFIX + "STATUS";
    private static final String RESPONSE_MESSAGE = RESPONSE_PREFIX + "MESSAGE";
    private static final String RESPONSE_HEADER_PREFIX = RESPONSE_PREFIX + "HEADER_";
    public static final int DEFAULT_CONN_TIMEOUT = 10000;
    public static final int DEFAULT_SO_TIMEOUT = 30000;

    private String methodURI;
    private String contextPath;
    private boolean uriEscaped = true;
    private HttpClient httpClient;
    private String host;
    private String port;
    private Protocol protocol = null;
    private String refDP;
    private HttpMethodName methodName;
    private int connTimeout = DEFAULT_CONN_TIMEOUT;
    private int soTimeout = DEFAULT_SO_TIMEOUT;
    private HttpProxy proxy = null;
    private HttpAuth auth = null;

    private OperationKey key = null;

    /**
     * Invoked from <code>OperationFactory</code> when an <code>Operation</code>
     * needs initialization.<br>
     * 
     * @see it.greenvulcano.gvesb.virtual.Operation#init(org.w3c.dom.Node)
     */
    @Override
    public void init(Node config) throws InitializationException {
        httpClient = new HttpClient();

        try {
            Node endpointNode = XMLConfig.getNode(config, "endpoint");
            host = XMLConfig.get(endpointNode, "@host");
            port = XMLConfig.get(endpointNode, "@port", "80");
            contextPath = XMLConfig.get(endpointNode, "@context-path", "");
            boolean secure = XMLConfig.getBoolean(endpointNode, "@secure", false);
            connTimeout = XMLConfig.getInteger(endpointNode, "@conn-timeout", DEFAULT_CONN_TIMEOUT);
            soTimeout = XMLConfig.getInteger(endpointNode, "@so-timeout", DEFAULT_SO_TIMEOUT);

            HttpConnectionManagerParams params = httpClient.getHttpConnectionManager().getParams();
            params.setConnectionTimeout(connTimeout);
            params.setSoTimeout(soTimeout);

            Node protocolNode = XMLConfig.getNode(endpointNode, "CustomProtocol");
            if (protocolNode != null) {
                protocol = ProtocolFactory.create(protocolNode);
            } else {
                protocol = Protocol.getProtocol(secure ? "https" : "http");
            }

            proxy = new HttpProxy();
            proxy.init(XMLConfig.getNode(endpointNode, "Proxy"));

            auth = HttpAuthFactory.getInstance(XMLConfig.getNode(endpointNode, "*[@type='http-auth']"));

            Node methodNode = XMLConfig.getNode(config, "method");
            refDP = XMLConfig.get(methodNode, "@ref-dp", "");

            methodURI = XMLConfig.get(methodNode, "@request-uri", "/");
            methodName = HttpMethodName.valueOf(XMLConfig.get(methodNode, "@name"));
            uriEscaped = XMLConfig.getBoolean(methodNode, "@uri-escaped", true);
        } catch (Exception exc) {
            throw new InitializationException("GV_CONFIGURATION_ERROR",
                    new String[][] { { "message", exc.getMessage() } }, exc);
        }
    }

    /**
     * @see it.greenvulcano.gvesb.virtual.CallOperation#perform(it.greenvulcano.gvesb.buffer.GVBuffer)
     */
    @Override
    public GVBuffer perform(GVBuffer gvBuffer) throws ConnectionException, CallException, InvalidDataException {
        logger.debug("BEGIN perform(GVBuffer gvBuffer)");
        HttpMethod method = null;
        try {
            String currMethodURI = null;
            Map<String, Object> params = GVBufferPropertiesHelper.getPropertiesMapSO(gvBuffer, true);

            String currHost = PropertiesHandler.expand(host, params, gvBuffer);
            String currPort = PropertiesHandler.expand(port, params, gvBuffer);
            logger.debug("Server Host: " + currHost + " - Port: " + currPort);
            httpClient.getHostConfiguration().setHost(currHost, Integer.parseInt(currPort), protocol);

            auth.setAuthentication(httpClient, host, Integer.parseInt(currPort), gvBuffer, params);
            proxy.setProxy(httpClient, gvBuffer, params);

            currMethodURI = PropertiesHandler.expand(contextPath + methodURI, params, gvBuffer);
            logger.debug("MethodURI[escaped:" + uriEscaped + "]=[" + currMethodURI + "]");
            switch (methodName) {
            case OPTIONS:
                method = new OptionsMethod();
                break;
            case GET:
                method = new GetMethod();
                break;
            case HEAD:
                method = new HeadMethod();
                break;
            case POST:
                method = new PostMethod();
                break;
            case PUT:
                method = new PutMethod();
                break;
            case DELETE:
                method = new DeleteMethod();
                break;
            default:
                throw new CallException("GV_CALL_SERVICE_ERROR",
                        new String[][] { { "service", gvBuffer.getService() }, { "system", gvBuffer.getSystem() },
                                { "id", gvBuffer.getId().toString() },
                                { "message", "Unknown method = " + methodName } });
            }
            method.setURI(new URI(currMethodURI, uriEscaped));

            if ((refDP != null) && (refDP.length() > 0)) {
                logger.debug("Calling configured Data Provider: " + refDP);
                DataProviderManager dataProviderManager = DataProviderManager.instance();
                IDataProvider dataProvider = dataProviderManager.getDataProvider(refDP);
                try {
                    dataProvider.setContext(method);
                    dataProvider.setObject(gvBuffer);
                    method = (HttpMethod) dataProvider.getResult();
                } finally {
                    dataProviderManager.releaseDataProvider(refDP, dataProvider);
                }
            }

            int status = httpClient.executeMethod(method);
            gvBuffer.setProperty(RESPONSE_STATUS, String.valueOf(status));
            String statusTxt = method.getStatusText();
            gvBuffer.setProperty(RESPONSE_MESSAGE, (statusTxt != null ? statusTxt : "NULL"));
            Header[] responseHeaders = method.getResponseHeaders();
            for (Header header : responseHeaders) {
                String headerName = RESPONSE_HEADER_PREFIX + header.getName();
                String value = header.getValue();
                if (value == null) {
                    value = "";
                }
                gvBuffer.setProperty(headerName, value);
            }
            String cType = "text/html";
            Header cTypeHeader = method.getResponseHeader("Content-Type");
            if (cTypeHeader != null) {
                String cTypeValue = cTypeHeader.getValue();
                if (cTypeValue != null) {
                    cType = cTypeValue;
                }
            }
            logger.debug("Response content-type: " + cType);
            ContentType contentType = new ContentType(cType);
            byte[] responseBody = method.getResponseBody();
            Object object = responseBody;
            if (contentType.getPrimaryType().equals("multipart")) {
                object = handleMultipart(responseBody, cType);
            }
            gvBuffer.setObject(object);
        } catch (CallException exc) {
            throw exc;
        } catch (Exception exc) {
            logger.error("ERROR perform(GVBuffer gvBuffer)", exc);
            throw new CallException("GV_CALL_SERVICE_ERROR",
                    new String[][] { { "service", gvBuffer.getService() }, { "system", gvBuffer.getSystem() },
                            { "id", gvBuffer.getId().toString() }, { "message", exc.getMessage() } },
                    exc);
        } finally {
            try {
                if (method != null) {
                    method.releaseConnection();
                }
            } catch (Exception exc) {
                logger.warn("Error while releasing connection", exc);
            }
            logger.debug("END perform(GVBuffer gvBuffer)");
        }
        return gvBuffer;
    }

    /**
     * @param responseBody
     * @throws MessagingException
     */
    private Document handleMultipart(byte[] responseBody, String contentType) throws Exception {
        ByteArrayDataSource bads = new ByteArrayDataSource(responseBody, contentType);
        MimeMultipart multipart = new MimeMultipart(bads);
        XMLUtils xml = XMLUtils.getParserInstance();
        Document doc = null;
        try {
            doc = xml.newDocument("MultipartHttpResponse");
        } finally {
            XMLUtils.releaseParserInstance(xml);
        }
        for (int i = 0; i < multipart.getCount(); i++) {
            dumpPart(multipart.getBodyPart(i), doc.getDocumentElement(), doc);
        }
        return doc;
    }

    private void dumpPart(Part p, Element msg, Document doc) throws Exception {
        Element content = null;
        if (p.isMimeType("text/plain")) {
            content = doc.createElement("PlainMessage");
            Text body = doc.createTextNode((String) p.getContent());
            content.appendChild(body);
        } else if (p.isMimeType("text/html")) {
            content = doc.createElement("HTMLMessage");
            CDATASection body = doc.createCDATASection((String) p.getContent());
            content.appendChild(body);
        } else if (p.isMimeType("multipart/*")) {
            Multipart mp = (Multipart) p.getContent();
            int count = mp.getCount();
            content = doc.createElement("Multipart");
            for (int i = 0; i < count; i++) {
                dumpPart(mp.getBodyPart(i), content, doc);
            }
        } else if (p.isMimeType("message/rfc822")) {
            content = doc.createElement("NestedMessage");
            dumpPart((Part) p.getContent(), content, doc);
        } else {
            content = doc.createElement("EncodedContent");
            DataHandler dh = p.getDataHandler();
            OutputStream os = new ByteArrayOutputStream();
            Base64EncodingOutputStream b64os = new Base64EncodingOutputStream(os);
            dh.writeTo(b64os);
            b64os.flush();
            b64os.close();
            content.appendChild(doc.createTextNode(os.toString()));
        }
        msg.appendChild(content);
        String filename = p.getFileName();
        if (filename != null) {
            content.setAttribute("file-name", filename);
        }
        String ct = p.getContentType();
        if (ct != null) {
            content.setAttribute("content-type", ct);
        }
        String desc = p.getDescription();
        if (desc != null) {
            content.setAttribute("description", desc);
        }
    }

    /**
     * @see it.greenvulcano.gvesb.virtual.Operation#cleanUp()
     */
    @Override
    public void cleanUp() {
        // do nothing
    }

    /**
     * @see it.greenvulcano.gvesb.virtual.Operation#destroy()
     */
    @Override
    public void destroy() {
        // do nothing
    }

    /**
     * @see it.greenvulcano.gvesb.virtual.Operation#getServiceAlias(it.greenvulcano.gvesb.buffer.GVBuffer)
     */
    @Override
    public String getServiceAlias(GVBuffer gvBuffer) {
        return gvBuffer.getService();
    }

    /**
     * @see it.greenvulcano.gvesb.virtual.Operation#setKey(it.greenvulcano.gvesb.virtual.OperationKey)
     */
    @Override
    public void setKey(OperationKey key) {
        this.key = key;
    }

    /**
     * @see it.greenvulcano.gvesb.virtual.Operation#getKey()
     */
    @Override
    public OperationKey getKey() {
        return key;
    }
}