it.greenvulcano.gvesb.virtual.gv_multipart.MultipartCallOperation.java Source code

Java tutorial

Introduction

Here is the source code for it.greenvulcano.gvesb.virtual.gv_multipart.MultipartCallOperation.java

Source

/*******************************************************************************
 * Copyright (c) 2009, 2017 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.gv_multipart;

import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.IntStream;

import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.FormBodyPart;
import org.apache.http.entity.mime.FormBodyPartBuilder;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import it.greenvulcano.configuration.XMLConfig;
import it.greenvulcano.configuration.XMLConfigException;
import it.greenvulcano.gvesb.buffer.GVBuffer;
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;

/**
 * 
 * @version 4.0 november/2017
 * @author GreenVulcano Developer Team
 */
public class MultipartCallOperation implements CallOperation {

    private static final Logger logger = LoggerFactory.getLogger(MultipartCallOperation.class);

    /**
     * The configured operation key
     */
    private OperationKey key = null;

    /**
     * The name of the multipat-call
     */
    private String name;

    /**
     * The URL called by the multipart call 
     */
    private String url = null;

    /**
     * The connection timeout
     */
    private int connectionTimeout;

    /**
     * the read timeout
     */
    private int readTimeout;

    /**
     * The body of the call
     */
    private String body;

    /**
     * The map of call the headers
     */
    private Map<String, String> headers = new LinkedHashMap<>();

    /**
     * The map of call the parameters
     */
    private Map<String, String> params = new LinkedHashMap<>();

    /**
     * The multipart entity builder
     */
    MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();

    /**
     * The http entity
     */
    HttpEntity httpEntity = null;

    private ContentType contentType;

    private static final String RESPONSE_STATUS = "GVHTTP_RESPONSE_STATUS";
    private static final String RESPONSE_MESSAGE = "GVHTTP_RESPONSE_MESSAGE";
    private static final String RESPONSE_HEADER_PREFIX = "GVHTTP_RESPONSE_HEADER_";

    private FormBodyPart formBodyPart;
    private FormBodyPartBuilder formBodyBuilder;
    private File file;
    private String fileName;
    private boolean isByteArray = false;
    private boolean isFileProperty = false;
    private String filePartName;

    /**
     * 
     * @param node
     *          The configuration node containing all informations. 
     * 
     * @see it.greenvulcano.gvesb.virtual.Operation#init(org.w3c.dom.Node)
     */
    @Override
    public void init(Node node) throws InitializationException {
        logger.debug("Init start");

        try {
            name = XMLConfig.get(node, "@name");
            String host = XMLConfig.get(node.getParentNode(), "@endpoint");
            String uri = XMLConfig.get(node, "@request-uri");
            url = host.concat(uri);
            connectionTimeout = XMLConfig.getInteger(node, "@conn-timeout", 3000);
            readTimeout = XMLConfig.getInteger(node, "@so-timeout", 6000);

            readMultipartCallConfiguration(node);
            readMultipartCallParts(node);

            logger.debug("Init stop");
        } catch (Exception exc) {
            throw new InitializationException("GV_INIT_SERVICE_ERROR",
                    new String[][] { { "message", exc.getMessage() } }, exc);
        }

    }

    /**
     * 
     * Reads the configuration of the Multipart node
     * 
     * @param node
     * @throws XMLConfigException
     */
    private void readMultipartCallConfiguration(Node node) throws XMLConfigException {

        if (XMLConfig.exists(node, "./headers")) {
            fillMap(XMLConfig.getNodeList(node, "./headers/header"), headers);
            if (headers.get("Content-Type") != null) {
                multipartEntityBuilder.setContentType(getContentType(headers.get("Content-Type")));
                headers.remove("Content-Type");
            }
            if (headers.get("charset") != null) {
                multipartEntityBuilder.setCharset(Charset.forName(headers.get("charset")));
                headers.remove("charset");
            }
        }

        if (XMLConfig.exists(node, "./parameters")) {
            fillMap(XMLConfig.getNodeList(node, "./parameters/param"), params);
        }

        Node bodyNode = XMLConfig.getNode(node, "./body");
        //TODO:da vedere se serve
        //           if (Objects.nonNull(bodyNode)) { 
        //              
        //              sendGVBufferObject = Boolean.valueOf(XMLConfig.get(bodyNode, "@gvbuffer-object", "false"));
        //              
        //              body = bodyNode.getTextContent();
        //           } else {
        //              body = null;
        //           }
    }

    /**
     * 
     * Reads the parts of the Multipart node
     * 
     * @param node
     * @throws XMLConfigException
     */
    private void readMultipartCallParts(Node node) throws XMLConfigException {
        if (XMLConfig.exists(node, "./parts")) {
            if (XMLConfig.exists(node, "./parts/byteArrayPart")) {
                createByteArrayPart(XMLConfig.getNodeList(node, "./parts/byteArrayPart/part"),
                        XMLConfig.get(node, "./parts/byteArrayPart/@name"),
                        XMLConfig.get(node, "./parts/byteArrayPart/@contenttype"),
                        XMLConfig.get(node, "./parts/byteArrayPart/@filename"));
            }
            if (XMLConfig.exists(node, "./parts/filePart")) {
                createFilePart(XMLConfig.get(node, "./parts/filePart/@name"),
                        XMLConfig.get(node, "./parts/filePart/@filepath"),
                        XMLConfig.get(node, "./parts/filePart/@filename"),
                        XMLConfig.get(node, "./parts/filePart/@contenttype"));
            }
            if (XMLConfig.exists(node, "./parts/stringPart")) {
                createStringPart(XMLConfig.getNodeList(node, "./parts/stringPart"),
                        XMLConfig.get(node, "./parts/stringPart/@name"),
                        XMLConfig.get(node, "./parts/stringPart/@contenttype"));
            }
            if (XMLConfig.exists(node, "./parts/formPart")) {
                createFormPart(XMLConfig.getNodeList(node, "./parts/formPart/param"),
                        XMLConfig.get(node, "./parts/formPart/@name"),
                        XMLConfig.get(node, "./parts/formPart/@contenttype"));
            }
        }
    }

    /**
     * Get the text from a CDATA
     * 
     * @param e
     * @return
     */
    public static String getCharacterDataFromElement(Element element) {
        NodeList list = element.getChildNodes();
        String data;

        for (int index = 0; index < list.getLength(); index++) {
            if (list.item(index) instanceof CharacterData) {
                CharacterData child = (CharacterData) list.item(index);
                data = child.getData();
                if (data != null && data.trim().length() > 0)
                    return child.getData();
            }
        }
        return "";
    }

    /**
     * Adds a Byte Array Part on the Multipart call
     * 
     * @param nodeList
     * @param name
     */
    private void createByteArrayPart(NodeList nodeList, String name, String contentType, String fileName) {

        this.contentType = getContentType(contentType);
        this.fileName = fileName;
        isByteArray = true;
    }

    /**
     * Adds a File Part on the Multipart call
     * 
     * @param nodeList
     * @param name
     */
    private void createFilePart(String partName, String filePath, String fileName, String contentType) {
        this.contentType = getContentType(contentType);
        if (filePath.startsWith("@{{")) {
            isFileProperty = true;
            filePartName = partName;

        } else {
            file = new File(filePath);
            FileBody filePart = new FileBody(file, this.contentType, fileName);
            multipartEntityBuilder.addPart(partName, filePart);
        }
    }

    /**
     * Adds a String Part on the Multipart call
     * 
     * @param nodeList
     * @param name
     */
    private void createStringPart(NodeList nodeList, String name, String contentType) {
        this.contentType = getContentType(contentType);
        Element element = (Element) nodeList.item(0);

        multipartEntityBuilder.addTextBody(name, getCharacterDataFromElement(element), this.contentType);
    }

    /**
     * Adds a Form Part on the Multipart call
     * 
     * @param nodeList
     * @param name
     */
    private void createFormPart(NodeList nodeList, String name, String contentType) {

        this.contentType = getContentType(contentType);
        StringBody stringBody = new StringBody(name, this.contentType);
        formBodyBuilder = FormBodyPartBuilder.create(name, stringBody);

        IntStream.range(0, nodeList.getLength()).mapToObj(nodeList::item).forEach(node -> {
            try {
                if (!("Content-Type".equals(XMLConfig.get(node, "@name")))) {
                    formBodyBuilder.addField(XMLConfig.get(node, "@name"), XMLConfig.get(node, "@value"));
                }
            } catch (XMLConfigException e) {
                e.printStackTrace();
            }
        });
        formBodyPart = formBodyBuilder.setName(name).build();
        multipartEntityBuilder.addPart(formBodyPart);
    }

    /**
      * Adds on a Map the key and the value the given NodeList
      * 
      * @param sourceNodeList
      * @param destinationMap
      */
    private void fillMap(NodeList sourceNodeList, Map<String, String> destinationMap) {

        if (sourceNodeList.getLength() == 0) {
            destinationMap.clear();
        } else {
            IntStream.range(0, sourceNodeList.getLength()).mapToObj(sourceNodeList::item).forEach(node -> {
                try {
                    destinationMap.put(XMLConfig.get(node, "@name"), XMLConfig.get(node, "@value"));
                } catch (Exception e) {
                    logger.error("Fail to read configuration", e);
                }
            });
        }
    }

    /**
     * creates a Content-Type element
     * 
     * @param contentType
     * @return created contentType
     */
    private ContentType getContentType(String contentType) {

        return ContentType.create(contentType);
    }

    /**
     * 
     * @param gvBuffer 
     *          for transport data in GreenVulcano
     * @return the GVBuffer
     * 
     * @see it.greenvulcano.gvesb.virtual.CallOperation#perform(it.greenvulcano.gvesb.buffer.GVBuffer)
     */
    @Override
    public GVBuffer perform(GVBuffer gvBuffer) throws ConnectionException, CallException, InvalidDataException {

        StringBuffer callDump = new StringBuffer();
        callDump.append("Performing RestCallOperation " + name).append("\n        ").append("URL: ").append(url);

        if (isByteArray == true && gvBuffer.getObject() != null) {
            byte[] requestData;
            if (gvBuffer.getObject() instanceof byte[]) {
                requestData = (byte[]) gvBuffer.getObject();
            } else {
                requestData = gvBuffer.getObject().toString().getBytes();
            }
            callDump.append("\n        ").append("Content-Length: " + requestData.length);
            ByteArrayBody byteArrayPart = new ByteArrayBody(requestData, contentType, fileName);
            multipartEntityBuilder.addPart(name, byteArrayPart);
        }

        else if (isFileProperty == true) {
            file = new File(gvBuffer.getProperty("DIR"));
            FileBody filePart = new FileBody(file, this.contentType, fileName);
            multipartEntityBuilder.addPart(filePartName, filePart);
        }

        try {
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost httpPost = new HttpPost(url);
            httpEntity = multipartEntityBuilder.build();
            String responseString = EntityUtils.toString(httpEntity);
            httpPost.setEntity(multipartEntityBuilder.build());
            for (Map.Entry<String, String> header : headers.entrySet()) {
                String key = header.getKey();
                String value = header.getValue();
                httpPost.setHeader(key, value);
            }
            CloseableHttpResponse response = httpClient.execute(httpPost);
            HttpEntity responseEntity = response.getEntity();
            Header[] responseHeaders = response.getAllHeaders();

            Header contentType = responseEntity.getContentType();

            InputStream responseStream = null;

            response.getStatusLine();
            responseStream = responseEntity.getContent();

            for (Header header : response.getAllHeaders()) {
                if (Objects.nonNull(header)) {
                    gvBuffer.setProperty(header.getName(), header.getValue());
                }
            }

            if (responseStream != null) {

                byte[] responseData = IOUtils.toByteArray(responseStream);
                String responseContentType = Optional
                        .ofNullable(gvBuffer.getProperty(RESPONSE_HEADER_PREFIX.concat("CONTENT-TYPE"))).orElse("");

                if (responseContentType.startsWith("application/json")
                        || responseContentType.startsWith("application/javascript")) {
                    gvBuffer.setObject(new String(responseData, "UTF-8"));
                } else {
                    gvBuffer.setObject(responseData);
                }

            } else {
                gvBuffer.setObject(null);
            }

            gvBuffer.setProperty(RESPONSE_STATUS, String.valueOf(response.getStatusLine()));
            gvBuffer.setProperty(RESPONSE_MESSAGE, String.valueOf(response));

            callDump.append("\n " + gvBuffer);

            response.close();

            logger.debug(callDump.toString());
        } catch (Exception exc) {
            throw new CallException("GV_CALL_SERVICE_ERROR",
                    new String[][] { { "service", gvBuffer.getService() }, { "system", gvBuffer.getSystem() },
                            { "tid", gvBuffer.getId().toString() }, { "message", exc.getMessage() } },
                    exc);
        }
        return gvBuffer;
    }

    @Override
    public void cleanUp() {
        // do nothing
    }

    @Override
    public void destroy() {
        // do nothing
    }

    @Override
    public String getServiceAlias(GVBuffer gvBuffer) {
        return gvBuffer.getService();
    }

    @Override
    public void setKey(OperationKey key) {
        this.key = key;
    }

    @Override
    public OperationKey getKey() {
        return key;
    }
}