com.mirth.connect.connectors.http.HttpMessageDispatcher.java Source code

Java tutorial

Introduction

Here is the source code for com.mirth.connect.connectors.http.HttpMessageDispatcher.java

Source

/*
 * Copyright (c) Mirth Corporation. All rights reserved.
 * http://www.mirthcorp.com
 *
 * The software in this package is published under the terms of the MPL
 * license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 */

package com.mirth.connect.connectors.http;

import java.io.File;
import java.net.ConnectException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthPolicy;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.log4j.Logger;
import org.mule.providers.AbstractMessageDispatcher;
import org.mule.providers.QueueEnabledMessageDispatcher;
import org.mule.providers.TemplateValueReplacer;
import org.mule.umo.UMOEvent;
import org.mule.umo.UMOException;
import org.mule.umo.UMOMessage;
import org.mule.umo.endpoint.UMOEndpointURI;

import com.mirth.connect.model.MessageObject;
import com.mirth.connect.model.QueuedMessage;
import com.mirth.connect.server.Constants;
import com.mirth.connect.server.controllers.AlertController;
import com.mirth.connect.server.controllers.ChannelController;
import com.mirth.connect.server.controllers.ControllerFactory;
import com.mirth.connect.server.controllers.MessageObjectController;
import com.mirth.connect.server.controllers.MonitoringController;
import com.mirth.connect.server.controllers.MonitoringController.ConnectorType;
import com.mirth.connect.server.controllers.MonitoringController.Event;
import com.mirth.connect.server.util.VMRouter;

public class HttpMessageDispatcher extends AbstractMessageDispatcher implements QueueEnabledMessageDispatcher {
    private Logger logger = Logger.getLogger(this.getClass());
    private HttpConnector connector;

    private ChannelController channelController = ControllerFactory.getFactory().createChannelController();
    private MessageObjectController messageObjectController = ControllerFactory.getFactory()
            .createMessageObjectController();
    private MonitoringController monitoringController = ControllerFactory.getFactory().createMonitoringController();
    private AlertController alertController = ControllerFactory.getFactory().createAlertController();
    private TemplateValueReplacer replacer = new TemplateValueReplacer();
    private ConnectorType connectorType = ConnectorType.WRITER;

    private HttpClient client = new HttpClient();

    public HttpMessageDispatcher(HttpConnector connector) {
        super(connector);
        this.connector = connector;
    }

    @Override
    public void doDispatch(UMOEvent event) throws Exception {
        monitoringController.updateStatus(connector, connectorType, Event.BUSY);
        MessageObject mo = messageObjectController.getMessageObjectFromEvent(event);

        if (mo == null) {
            return;
        }

        try {
            if (connector.isUsePersistentQueues()) {
                /*
                 * Note that the endpoint URI is not URL decoded before it is
                 * put into the queue, so it will need to be decoded it is taken
                 * off the queue in sendPayload
                 */
                connector.putMessageInQueue(event.getEndpoint().getEndpointURI(), mo);
                return;
            } else {
                /*
                 * We need to URL decode the endpoint since a MuleEndpointURI
                 * escapes special characters by default. This will allow map
                 * replacements.
                 * 
                 * See: MIRTH-1645
                 */
                submitHttpRequest(URLDecoder.decode(event.getEndpoint().getEndpointURI().toString(), "utf-8"), mo);
            }
        } catch (Exception e) {
            alertController.sendAlerts(connector.getChannelId(), Constants.ERROR_404,
                    "Error connecting to HTTP server.", e);
            messageObjectController.setError(mo, Constants.ERROR_404, "Error connecting to HTTP server.", e, null);
            connector.handleException(e);
        } finally {
            monitoringController.updateStatus(connector, connectorType, Event.DONE);
        }
    }

    private void submitHttpRequest(String address, MessageObject mo) throws Exception {
        HttpMethod httpMethod = null;

        try {
            httpMethod = buildHttpRequest(replacer.replaceValues(address, mo), mo);

            // authentication

            if (connector.isDispatcherUseAuthentication()) {
                List<String> authenticationPreferences = new ArrayList<String>();

                if ("Digest".equalsIgnoreCase(connector.getDispatcherAuthenticationType())) {
                    authenticationPreferences.add(AuthPolicy.DIGEST);
                    logger.debug("using Digest authentication");
                } else {
                    authenticationPreferences.add(AuthPolicy.BASIC);
                    logger.debug("using Basic authentication");
                }

                client.getParams().setAuthenticationPreemptive(true);
                client.getParams().setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, authenticationPreferences);
                Credentials credentials = new UsernamePasswordCredentials(
                        replacer.replaceValues(connector.getDispatcherUsername(), mo),
                        replacer.replaceValues(connector.getDispatcherPassword(), mo));
                client.getState().setCredentials(
                        new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM), credentials);
                logger.debug("using authentication with credentials: " + credentials);
            }

            client.getParams().setSoTimeout(
                    NumberUtils.toInt(replacer.replaceValues(connector.getDispatcherSocketTimeout()), 30000));

            // execute the method
            logger.debug(
                    "executing method: type=" + httpMethod.getName() + ", uri=" + httpMethod.getURI().toString());
            int statusCode = client.executeMethod(httpMethod);
            logger.debug("received status code: " + statusCode);

            String response = null;

            if (connector.isDispatcherIncludeHeadersInResponse()) {
                HttpMessageConverter converter = new HttpMessageConverter();
                response = converter.httpResponseToXml(httpMethod.getStatusLine().toString(),
                        httpMethod.getResponseHeaders(), httpMethod.getResponseBodyAsString());
            } else {
                response = httpMethod.getResponseBodyAsString();
            }

            if (statusCode < HttpStatus.SC_BAD_REQUEST) {
                messageObjectController.setSuccess(mo, response, null);

                // send to reply channel
                if ((connector.getDispatcherReplyChannelId() != null)
                        && !connector.getDispatcherReplyChannelId().equals("sink")) {
                    new VMRouter().routeMessageByChannelId(connector.getDispatcherReplyChannelId(), response, true);
                }
            } else {
                alertController.sendAlerts(connector.getChannelId(), Constants.ERROR_404,
                        "Received error response from HTTP server.", null);
                messageObjectController.setError(mo, Constants.ERROR_404, response, null, null);
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (httpMethod != null) {
                httpMethod.releaseConnection();
            }
        }
    }

    @Override
    public void doDispose() {

    }

    @Override
    public UMOMessage doSend(UMOEvent event) throws Exception {
        doDispatch(event);
        return event.getMessage();
    }

    @Override
    public Object getDelegateSession() throws UMOException {
        return null;
    }

    @Override
    public UMOMessage receive(UMOEndpointURI endpointUri, long timeout) throws Exception {
        return null;
    }

    @Override
    public boolean sendPayload(QueuedMessage message) throws Exception {
        monitoringController.updateStatus(connector, connectorType, Event.BUSY);

        try {
            /*
             * We need to URL decode the endpoint since a MuleEndpointURI
             * escapes special characters by default. This will allow map
             * replacements.
             * 
             * See: MIRTH-1645 & MIRTH-1917
             */
            submitHttpRequest(URLDecoder.decode(message.getEndpointUri().toString(), "utf-8"),
                    message.getMessageObject());
        } catch (Exception e) {
            if (e.getClass() == ConnectException.class) {
                logger.warn("Can't connect to the queued endpoint: "
                        + channelController.getDeployedChannelById(connector.getChannelId()).getName() + " - "
                        + channelController.getDeployedDestinationName(connector.getName()) + " \r\n'"
                        + e.getMessage());
                messageObjectController.setError(message.getMessageObject(), Constants.ERROR_404,
                        "Connection refused", e, null);
                throw e;
            }

            messageObjectController.setError(message.getMessageObject(), Constants.ERROR_404,
                    "Error connecting to web service.", e, null);
            alertController.sendAlerts(connector.getChannelId(), Constants.ERROR_404,
                    "Error connecting to web service.", e);
            connector.handleException(new Exception(e));
        } finally {
            monitoringController.updateStatus(connector, connectorType, Event.DONE);
        }

        return true;
    }

    private HttpMethod buildHttpRequest(String address, MessageObject mo) throws Exception {
        String method = connector.getDispatcherMethod();
        String content = replacer.replaceValues(connector.getDispatcherContent(), mo);
        String contentType = connector.getDispatcherContentType();
        String charset = connector.getDispatcherCharset();
        boolean isMultipart = connector.isDispatcherMultipart();
        Map<String, String> headers = replacer.replaceValuesInMap(connector.getDispatcherHeaders(), mo);
        Map<String, String> parameters = replacer.replaceValuesInMap(connector.getDispatcherParameters(), mo);

        HttpMethod httpMethod = null;

        // populate the query parameters
        NameValuePair[] queryParameters = new NameValuePair[parameters.size()];
        int index = 0;

        for (Entry<String, String> parameterEntry : parameters.entrySet()) {
            queryParameters[index] = new NameValuePair(parameterEntry.getKey(), parameterEntry.getValue());
            index++;
            logger.debug("setting query parameter: [" + parameterEntry.getKey() + ", " + parameterEntry.getValue()
                    + "]");
        }

        // create the method
        if ("GET".equalsIgnoreCase(method)) {
            httpMethod = new GetMethod(address);
            httpMethod.setQueryString(queryParameters);
        } else if ("POST".equalsIgnoreCase(method)) {
            PostMethod postMethod = new PostMethod(address);

            if (isMultipart) {
                logger.debug("setting multipart file content");
                File tempFile = File.createTempFile(UUID.randomUUID().toString(), ".tmp");
                FileUtils.writeStringToFile(tempFile, content, charset);
                Part[] parts = new Part[] { new FilePart(tempFile.getName(), tempFile, contentType, charset) };
                postMethod.setQueryString(queryParameters);
                postMethod.setRequestEntity(new MultipartRequestEntity(parts, postMethod.getParams()));
            } else if (StringUtils.equals(contentType, "application/x-www-form-urlencoded")) {
                postMethod.setRequestBody(queryParameters);
            } else {
                postMethod.setQueryString(queryParameters);
                postMethod.setRequestEntity(new StringRequestEntity(content, contentType, charset));
            }

            httpMethod = postMethod;
        } else if ("PUT".equalsIgnoreCase(method)) {
            PutMethod putMethod = new PutMethod(address);
            putMethod.setRequestEntity(new StringRequestEntity(content, contentType, charset));
            putMethod.setQueryString(queryParameters);
            httpMethod = putMethod;
        } else if ("DELETE".equalsIgnoreCase(method)) {
            httpMethod = new DeleteMethod(address);
            httpMethod.setQueryString(queryParameters);
        }

        // set the headers
        for (Entry<String, String> headerEntry : headers.entrySet()) {
            httpMethod.setRequestHeader(new Header(headerEntry.getKey(), headerEntry.getValue()));
            logger.debug("setting method header: [" + headerEntry.getKey() + ", " + headerEntry.getValue() + "]");
        }

        return httpMethod;
    }
}