org.apache.servicemix.http.processors.ProviderProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.servicemix.http.processors.ProviderProcessor.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.servicemix.http.processors;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.httpclient.protocol.Protocol;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.servicemix.common.JbiConstants;
import org.apache.servicemix.common.security.KeystoreManager;
import org.apache.servicemix.http.HttpComponent;
import org.apache.servicemix.http.HttpEndpoint;
import org.apache.servicemix.http.monitoring.HttpConnectionListener;
import org.apache.servicemix.soap.Context;
import org.apache.servicemix.soap.SoapExchangeProcessor;
import org.apache.servicemix.soap.SoapHelper;
import org.apache.servicemix.soap.marshalers.SoapMessage;
import org.apache.servicemix.soap.marshalers.SoapReader;
import org.apache.servicemix.soap.marshalers.SoapWriter;

import javax.jbi.messaging.*;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 
 * @author Guillaume Nodet
 * @version $Revision: 370186 $
 * @since 3.0
 */
public class ProviderProcessor extends AbstractProcessor implements SoapExchangeProcessor {

    private static Log log = LogFactory.getLog(ProviderProcessor.class);

    protected SoapHelper soapHelper;
    protected DeliveryChannel channel;
    private Map<String, PostMethod> methods;
    private Protocol protocol;
    private HttpConnectionListener listener;

    public ProviderProcessor(HttpEndpoint endpoint) {
        super(endpoint);
        this.soapHelper = new SoapHelper(endpoint);
        this.methods = new ConcurrentHashMap<String, PostMethod>();
    }

    private String getRelUri(String locationUri) {
        java.net.URI uri = java.net.URI.create(locationUri);
        String relUri = uri.getPath();
        if (!relUri.startsWith("/")) {
            relUri = "/" + relUri;
        }
        if (uri.getQuery() != null) {
            relUri += "?" + uri.getQuery();
        }
        if (uri.getFragment() != null) {
            relUri += "#" + uri.getFragment();
        }
        return relUri;
    }

    public void process(MessageExchange exchange) throws Exception {
        if (exchange.getStatus() == ExchangeStatus.DONE || exchange.getStatus() == ExchangeStatus.ERROR) {
            PostMethod method = methods.remove(exchange.getExchangeId());
            if (method != null) {
                method.releaseConnection();
            }
            return;
        }
        boolean txSync = exchange.isTransacted()
                && Boolean.TRUE.equals(exchange.getProperty(JbiConstants.SEND_SYNC));
        txSync |= endpoint.isSynchronous();
        NormalizedMessage nm = exchange.getMessage("in");
        if (nm == null) {
            throw new IllegalStateException("Exchange has no input message");
        }

        String locationURI = endpoint.getLocationURI();

        // Incorporated because of JIRA SM-695
        Object newDestinationURI = nm.getProperty(JbiConstants.HTTP_DESTINATION_URI);
        if (newDestinationURI != null) {
            locationURI = (String) newDestinationURI;
            log.debug("Location URI overridden: " + locationURI);
        }

        PostMethod method = new PostMethod(getRelUri(locationURI));
        SoapMessage soapMessage = new SoapMessage();
        soapHelper.getJBIMarshaler().fromNMS(soapMessage, nm);
        Context context = soapHelper.createContext(soapMessage);
        soapHelper.onSend(context);
        SoapWriter writer = soapHelper.getSoapMarshaler().createWriter(soapMessage);
        copyHeaderInformation(nm, method);
        RequestEntity entity = writeMessage(writer);
        // remove content-type header that may have been part of the in message
        if (!endpoint.isWantContentTypeHeaderFromExchangeIntoHttpRequest()) {
            method.removeRequestHeader(HEADER_CONTENT_TYPE);
            method.addRequestHeader(HEADER_CONTENT_TYPE, entity.getContentType());
        }
        if (entity.getContentLength() < 0) {
            method.removeRequestHeader(HEADER_CONTENT_LENGTH);
        } else {
            method.setRequestHeader(HEADER_CONTENT_LENGTH, Long.toString(entity.getContentLength()));
        }
        if (endpoint.isSoap() && method.getRequestHeader(HEADER_SOAP_ACTION) == null) {
            if (endpoint.getSoapAction() != null) {
                method.setRequestHeader(HEADER_SOAP_ACTION, endpoint.getSoapAction());
            } else {
                //                method.setRequestHeader(HEADER_SOAP_ACTION, "\"\"");
            }
        }
        method.setRequestHeader(HEADER_X_CORRELATION_ID,
                (String) exchange.getProperty(JbiConstants.CORRELATION_ID));
        String smxInstanceName = System.getProperty(SMX_INSTANCE_NAME_PROPERTY);
        if (smxInstanceName != null) {
            method.setRequestHeader(HEADER_X_POWERED_BY, smxInstanceName);
        } else {
            log.warn(SMX_INSTANCE_NAME_PROPERTY + " property was not set in servicemix.xml file");
        }

        method.setRequestEntity(entity);
        boolean close = true;
        try {
            // Set the retry handler
            int retries = getConfiguration().isStreamingEnabled() ? 0 : getConfiguration().getRetryCount();
            method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                    new DefaultHttpMethodRetryHandler(retries, true));
            // Set authentication
            if (endpoint.getBasicAuthentication() != null) {
                endpoint.getBasicAuthentication().applyCredentials(getClient(), exchange, nm);
            }
            // Execute the HTTP method
            //method.getParams().setLongParameter(HttpConnectionParams.CONNECTION_TIMEOUT, getClient().getParams().getSoTimeout());

            int response = -1;
            try {
                response = getClient().executeMethod(getHostConfiguration(locationURI, exchange, nm), method);
            } catch (Exception ex) {
                try {
                    if (listener != null) {
                        if (ex instanceof SocketException) {
                            log.error("Connection to address: " + locationURI + " was refused");
                            listener.onConnectionRefused(locationURI);
                        } else if (ex instanceof SocketTimeoutException) {
                            log.error("Connection to address: " + locationURI + " timed out");
                            listener.onTimeout(locationURI);
                        }
                    }
                } catch (Exception ex2) {
                    log.warn("Error in HttpConnectionListener: " + ex2.getMessage());
                } finally {
                    throw ex;
                }
            }
            try {
                if (listener != null) {
                    listener.onPostExecuted(locationURI, response);
                }
            } catch (Exception ex) {
                log.warn("Error in HttpConnectionListener: " + ex.getMessage());
            }
            if (response != HttpStatus.SC_OK && response != HttpStatus.SC_ACCEPTED) {
                if (!(exchange instanceof InOnly)) {
                    SoapReader reader = soapHelper.getSoapMarshaler().createReader();
                    Header contentType = method.getResponseHeader(HEADER_CONTENT_TYPE);
                    String content = convertResponseBodyToString(method);
                    logInOut(locationURI, response, method, soapMessage, content);
                    soapMessage = reader.read(new ByteArrayInputStream(content.getBytes()),
                            contentType != null ? contentType.getValue() : null);
                    context.setFaultMessage(soapMessage);
                    soapHelper.onAnswer(context);
                    Fault fault = exchange.createFault();
                    fault.setProperty(JbiConstants.PROTOCOL_HEADERS, getHeaders(method));
                    soapHelper.getJBIMarshaler().toNMS(fault, soapMessage);
                    exchange.setFault(fault);
                    if (txSync) {
                        channel.sendSync(exchange);
                    } else {
                        methods.put(exchange.getExchangeId(), method);
                        channel.send(exchange);
                        close = false;
                    }
                    return;
                } else {
                    String content = convertResponseBodyToString(method);
                    // even if it is InOnly, some out could come to us
                    logInOut(locationURI, response, method, soapMessage, content);
                    throw new Exception("Invalid status response: " + response);
                }
            }
            if (exchange instanceof InOut) {
                close = processInOut(exchange, method, context, txSync, close);
            } else if (exchange instanceof InOptionalOut) {
                close = processInOptionalOut(method, exchange, context, txSync, close);
            } else {
                exchange.setStatus(ExchangeStatus.DONE);
                channel.send(exchange);
            }
        } finally {
            if (close) {
                method.releaseConnection();
            }
        }
    }

    // this method is created because getResponseBodyAsString log waringings
    private String convertResponseBodyToString(PostMethod method) throws IOException {
        InputStream responseBodyStream = method.getResponseBodyAsStream();
        return streamToString(responseBodyStream);
    }

    private void logInOut(String locationURI, int responseCode, PostMethod method, SoapMessage requestSoapMessage,
            String responseContent) {
        if (log.isWarnEnabled()) {
            log.warn("Connections to address: " + locationURI + " ended with status: " + responseCode);
            log.warn("Request headers:");
            for (int i = 0; i < method.getRequestHeaders().length; i++) {
                Header header = method.getRequestHeaders()[i];
                log.warn(header.getName() + ": " + header.getValue());
            }
            log.warn("Request content:");
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            try {
                soapHelper.getSoapMarshaler().createWriter(requestSoapMessage).write(bos);
                log.warn(bos.toString());
            } catch (Exception e) {
                log.warn("Cannot marshall request body");
            }
            log.warn("Response headers:");
            for (int i = 0; i < method.getResponseHeaders().length; i++) {
                Header header = method.getResponseHeaders()[i];
                log.warn(header.getName() + ": " + header.getValue());
            }
            log.warn("Response content:");
            log.warn(responseContent);
        }
    }

    @SuppressWarnings("unchecked")
    private void copyHeaderInformation(NormalizedMessage nm, PostMethod method) {
        Map<String, String> headers = (Map<String, String>) nm.getProperty(JbiConstants.PROTOCOL_HEADERS);
        if (headers != null) {
            for (String name : headers.keySet()) {
                String value = headers.get(name);
                method.addRequestHeader(name, value);
            }
        }
    }

    private boolean processInOptionalOut(PostMethod method, MessageExchange exchange, Context context,
            boolean txSync, boolean close) throws Exception {
        if (method.getResponseContentLength() == 0) {
            exchange.setStatus(ExchangeStatus.DONE);
            channel.send(exchange);
        } else {
            NormalizedMessage msg = exchange.createMessage();
            SoapReader reader = soapHelper.getSoapMarshaler().createReader();
            SoapMessage soapMessage = reader.read(method.getResponseBodyAsStream(),
                    method.getResponseHeader(HEADER_CONTENT_TYPE).getValue());
            context.setOutMessage(soapMessage);
            soapHelper.onAnswer(context);
            if (getConfiguration().isWantHeadersFromHttpIntoExchange()) {
                msg.setProperty(JbiConstants.PROTOCOL_HEADERS, getHeaders(method));
            }
            soapHelper.getJBIMarshaler().toNMS(msg, soapMessage);
            ((InOptionalOut) exchange).setOutMessage(msg);
            if (txSync) {
                channel.sendSync(exchange);
            } else {
                methods.put(exchange.getExchangeId(), method);
                channel.send(exchange);
                close = false;
            }
        }
        return close;
    }

    private boolean processInOut(MessageExchange exchange, PostMethod method, Context context, boolean txSync,
            boolean close) throws Exception {
        NormalizedMessage msg = exchange.createMessage();
        SoapReader reader = soapHelper.getSoapMarshaler().createReader();
        Header contentType = method.getResponseHeader(HEADER_CONTENT_TYPE);
        SoapMessage soapMessage = reader.read(method.getResponseBodyAsStream(),
                contentType != null ? contentType.getValue() : null);
        context.setOutMessage(soapMessage);
        soapHelper.onAnswer(context);
        if (getConfiguration().isWantHeadersFromHttpIntoExchange()) {
            msg.setProperty(JbiConstants.PROTOCOL_HEADERS, getHeaders(method));
        }
        soapHelper.getJBIMarshaler().toNMS(msg, soapMessage);
        ((InOut) exchange).setOutMessage(msg);
        if (txSync) {
            channel.sendSync(exchange);
        } else {
            methods.put(exchange.getExchangeId(), method);
            channel.send(exchange);
            close = false;
        }
        return close;
    }

    private HostConfiguration getHostConfiguration(String locationURI, MessageExchange exchange,
            NormalizedMessage message) throws Exception {
        HostConfiguration host;
        URI uri = new URI(locationURI, false);
        if (uri.getScheme().equals("https")) {
            synchronized (this) {
                if (protocol == null) {
                    ProtocolSocketFactory sf = new CommonsHttpSSLSocketFactory(endpoint.getSsl(),
                            KeystoreManager.Proxy.create(endpoint.getKeystoreManager()));
                    protocol = new Protocol("https", sf, 443);
                }
            }
            HttpHost httphost = new HttpHost(uri.getHost(), uri.getPort(), protocol);
            host = new HostConfiguration();
            host.setHost(httphost);
        } else {
            host = new HostConfiguration();
            host.setHost(uri.getHost(), uri.getPort());
        }
        if (endpoint.getProxy() != null) {
            if ((endpoint.getProxy().getProxyHost() != null) && (endpoint.getProxy().getProxyPort() != 0)) {
                host.setProxy(endpoint.getProxy().getProxyHost(), endpoint.getProxy().getProxyPort());
            }
            if (endpoint.getProxy().getProxyCredentials() != null) {
                endpoint.getProxy().getProxyCredentials().applyProxyCredentials(getClient(), exchange, message);
            }
        } else if ((getConfiguration().getProxyHost() != null) && (getConfiguration().getProxyPort() != 0)) {
            host.setProxy(getConfiguration().getProxyHost(), getConfiguration().getProxyPort());
        }
        //host.getParams().setLongParameter(HttpConnectionParams.CONNECTION_TIMEOUT, getClient().getParams().getSoTimeout());
        return host;
    }

    public void init() throws Exception {
        channel = endpoint.getServiceUnit().getComponent().getComponentContext().getDeliveryChannel();
        if (listener != null) {
            listener.onProviderInit(endpoint.getLocationURI());
        }
    }

    public void start() throws Exception {
    }

    public void stop() throws Exception {
    }

    public void shutdown() throws Exception {
    }

    protected Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> headers = new HashMap<String, String>();
        Enumeration<?> enumeration = request.getHeaderNames();
        while (enumeration.hasMoreElements()) {
            String name = (String) enumeration.nextElement();
            String value = request.getHeader(name);
            headers.put(name, value);
        }
        return headers;
    }

    protected Map<String, String> getHeaders(HttpMethod method) {
        Map<String, String> headers = new HashMap<String, String>();
        Header[] h = method.getResponseHeaders();
        for (int i = 0; i < h.length; i++) {
            headers.put(h[i].getName(), h[i].getValue());
        }
        return headers;
    }

    protected RequestEntity writeMessage(SoapWriter writer) throws Exception {
        if (getConfiguration().isStreamingEnabled()) {
            return new StreamingRequestEntity(writer);
        } else {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            writer.write(baos);
            return new ByteArrayRequestEntity(baos.toByteArray(), writer.getContentType());
        }
    }

    protected HttpClient getClient() {
        HttpComponent comp = (HttpComponent) endpoint.getServiceUnit().getComponent();
        HttpClient client = comp.getClient();
        client.getParams().setSoTimeout(endpoint.getTimeout());
        client.getParams().getDefaults().setIntParameter(HttpConnectionParams.CONNECTION_TIMEOUT,
                endpoint.getTimeout());
        return client;
    }

    public void setListener(HttpConnectionListener listener) {
        this.listener = listener;
    }

    public static class StreamingRequestEntity implements RequestEntity {

        private SoapWriter writer;

        public StreamingRequestEntity(SoapWriter writer) {
            this.writer = writer;
        }

        public boolean isRepeatable() {
            return false;
        }

        public void writeRequest(OutputStream out) throws IOException {
            try {
                writer.write(out);
                out.flush();
            } catch (Exception e) {
                throw (IOException) new IOException("Could not write request").initCause(e);
            }
        }

        public long getContentLength() {
            // not known so we send negative value
            return -1;
        }

        public String getContentType() {
            return writer.getContentType();
        }

    }
}