Package org.jboss.soa.esb.actions.routing.http

Source Code of org.jboss.soa.esb.actions.routing.http.HttpRouter

/*
* JBoss, Home of Professional Open Source
* Copyright 2006, JBoss Inc., and others contributors as indicated
* by the @authors tag. All rights reserved.
* See the copyright.txt in the distribution for a
* full listing of individual contributors.
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License, v. 2.1.
* This program is distributed in the hope that it will be useful, but WITHOUT A
* 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,
* v.2.1 along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*
* (C) 2005-2006, JBoss Inc.
*/
package org.jboss.soa.esb.actions.routing.http;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.log4j.Logger;
import org.jboss.internal.soa.esb.util.Encoding;
import org.jboss.internal.soa.esb.util.StreamUtils;
import org.jboss.soa.esb.ConfigurationException;
import org.jboss.soa.esb.actions.ActionLifecycleException;
import org.jboss.soa.esb.actions.ActionProcessingException;
import org.jboss.soa.esb.actions.routing.AbstractRouter;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.http.HttpClientFactory;
import org.jboss.soa.esb.http.HttpHeader;
import org.jboss.soa.esb.http.HttpRequest;
import org.jboss.soa.esb.http.HttpResponse;
import org.jboss.soa.esb.http.configurators.Connection;
import org.jboss.soa.esb.listeners.ListenerTagNames;
import org.jboss.soa.esb.listeners.message.MessageDeliverException;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.Properties;
import org.jboss.soa.esb.message.ResponseHeader;
import org.jboss.soa.esb.message.ResponseStatus;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.message.format.MessageType;
import org.jboss.soa.esb.util.FileUtil;
import org.jboss.soa.esb.util.Util;

/**
* Http router.
* <p/>
* Uses HttpClient via the <a href="http://wiki.jboss.org/wiki/Wiki.jsp?page=HttpClientFactory">HttpClientFactory</a>.
*
* @author <a href="mailto:tom.fennelly@jboss.com">tom.fennelly@jboss.com</a>
*/
public class HttpRouter extends AbstractRouter {

    private static Logger logger = Logger.getLogger(HttpRouter.class);

    private ConfigTree config;
    private java.util.Properties httpClientProps = new java.util.Properties();
    private HttpClient httpclient;
    private URL endpointUrl;
    private String method;
    private HttpMethodFactory methodFactory;
    private ResponseType responseType;
    private String contentType;
    private ConfigTree[] requestHeaders;
    private boolean httpResponseStatusEnabled;
   
    private final String[] mappedHeaderList ;

    private static Set<String> coreProperties;
    static {
        coreProperties = new HashSet<String>();
        coreProperties.add("endpointUrl");
        coreProperties.add("method");
        coreProperties.add("responseType");
        coreProperties.add("Content-Type");
    }
   
    public HttpRouter(ConfigTree config) throws ConfigurationException {
        super(config);
        this.config = config;
        try {
            endpointUrl = new URL(config.getRequiredAttribute("endpointUrl"));
        } catch (MalformedURLException e) {
            throw new ConfigurationException("Invalid endpoint URL '" + config.getRequiredAttribute("endpointUrl") + "'.", e);
        }

        //Overriding to set true by default
        unwrap = config.getAttribute("unwrap", "true").equals("true");

        // Extract the HttpClient creation properties from the ConfigTree.  These are passed
        // to the HttpClientFacatory...
        extractHttpClientProps(config);
        httpclient = HttpClientFactory.createHttpClient(httpClientProps);
       
        method = config.getRequiredAttribute("method");
       
        responseType = ResponseType.valueOf(config.getAttribute("responseType", ResponseType.STRING.toString()));
        methodFactory = HttpMethodFactory.Factory.getInstance(method.toUpperCase(), config, endpointUrl);
        contentType = config.getAttribute("Content-Type");

        mappedHeaderList = extractMappedHeaderListConfig();
       
        requestHeaders = config.getChildren("header");
       
        httpResponseStatusEnabled = ResponseStatus.isHttpEnabled(config);
    }

    public Message process(Message message) throws ActionProcessingException {
        HttpMethodBase method = null;
        try {
            if (unwrap) {
                    method = methodFactory.getInstance(message);
            } else {
                try {
                    Serializable payload = Util.serialize(message);
                    if (message.getType().equals(MessageType.JAVA_SERIALIZED)) {
                        String payloadStr = Encoding.encodeObject(payload);
                        method = methodFactory.getMethod(payloadStr, "application/x-java-serialized-object", Charset.defaultCharset().toString());
                    } else {
                        method = methodFactory.getMethod(payload.toString(), "text/xml", "UTF-8");
                    }
                } catch (ParserConfigurationException e) {
                    throw new ActionProcessingException(e);
                }
            }

            try {
                setRequestHeaders(method, message);
               
                int responseCode = httpclient.executeMethod(method);
                if(responseCode != HttpStatus.SC_OK) {
                    logger.warn("Received status code '" + responseCode + "' on HTTP " + method + " request to '" + endpointUrl + "'.");
                }
                attachResponseDetails(message, method, responseCode);

                InputStream resultStream = method.getResponseBodyAsStream();
                try {
                    byte[] bytes = readStream(resultStream);

                    if(responseType == ResponseType.STRING) {
                        getPayloadProxy().setPayload(message, new String(bytes, method.getResponseCharSet()));
                    } else {
                        getPayloadProxy().setPayload(message, bytes);
                    }
                } catch (MessageDeliverException e) {
                    throw new ActionProcessingException("problem setting message payload: " + e.getMessage(), e);
                } finally {
                    closeStream(resultStream);
                }
            } finally {
                method.releaseConnection();
            }
        } catch (IOException e) {
            throw new ActionProcessingException("problem processing HTTP I/O: " + e.getMessage(), e);
        }

        return message;
    }

    static byte[] readStream(final InputStream stream) throws IOException {
        if (stream != null) {
            return StreamUtils.readStream(stream);
        }
        else
           return new byte[0];
    }

    static void closeStream(final Closeable c) throws IOException {
        if (c != null) {
            c.close();
        }
    }
   
    private String[] extractMappedHeaderListConfig() throws ConfigurationException {
        final String mappedHeaders = config.getAttribute("MappedHeaderList");
        if (mappedHeaders != null) {
            final String[] headerList = mappedHeaders.split(",");
            final int numHeaders = headerList.length ;
            final ArrayList<String> headers = new ArrayList<String>(numHeaders) ;
           
            for(int count = 0 ; count < numHeaders ; count++) {
                final String header = headerList[count].trim() ;
                if (header.length() > 0) {
                    headers.add(header) ;
                }
            }
            return (String[])headers.toArray(new String[headers.size()]) ;
        } else {
            return new String[0] ;
        }
    }

    private void attachResponseDetails(Message message, HttpMethodBase method, int responseCode) {
        HttpResponse response = new HttpResponse(responseCode);
        Properties properties = message.getProperties();

        response.setEncoding(method.getResponseCharSet());
        response.setLength(method.getResponseContentLength());

        Header[] responseHeaders = method.getResponseHeaders();
        for(Header responseHeader : responseHeaders) {
          String name = responseHeader.getName();
          String value = responseHeader.getValue();
            response.addHeader(new org.jboss.soa.esb.http.HttpHeader(name, value));
            // JBESB-2511
            new ResponseHeader(name, value).setPropertyNameThis(properties);
        }
        // JBESB-2761
        if (httpResponseStatusEnabled) {
          ResponseStatus.setHttpProperties(properties, responseCode, method.getStatusLine().getReasonPhrase());
        }
       
        response.setResponse(message);
    }

    private void setRequestHeaders(HttpMethodBase method, Message message) {
        //Try best to keep all the well-known HTTP headers that were sent from the client.
        setMappedHttpHeaders(method, message);
       
        //The setting of HTTP headers from config still takes precedence. So do not set
        //a HTTP header in config if you want to keep the value sent from the client.
        for (int i = 0; i < requestHeaders.length; i++) {
            ConfigTree header = requestHeaders[i];
            String name = header.getAttribute("name");
            String value = header.getAttribute("value");

            if(name != null && value != null) {
                method.setRequestHeader(name, value);
            } else {
                logger.error("null Http request header name/value: '" + name + "':'" + value + "'.");
            }
        }
        if (contentType != null) {
            method.setRequestHeader("Content-Type", contentType);
        } else if (method.getRequestHeader("Content-Type") == null) {
            method.setRequestHeader("Content-Type", "text/xml;charset=UTF-8") ;
        }
    }
   
  private void setMappedHttpHeaders(HttpMethodBase method, Message message) {
      HttpRequest request = HttpRequest.getRequest(message);
      Properties properties = message.getProperties();
      for (String headerName : mappedHeaderList) {
        String headerValue = null;
        if (request != null) {
          headerValue = getHttpHeaderValue(request, headerName);
        }
        if (headerValue == null) {
          headerValue = getHttpHeaderValue(properties, headerName);
        }
        if (headerValue != null) {
          method.setRequestHeader(headerName, headerValue);
        }
      }
  }
 
    private String getHttpHeaderValue(HttpRequest request, String headerName) {
      String headerValue = null;
        for (HttpHeader header : request.getHeaders()) {
          String name = header.getName();
          // HTTP header field names are case-insensitive
            if (name.equalsIgnoreCase(headerName)) {
              headerValue = header.getValue();
              break;
            }
        }
        return headerValue;
    }
   
    private String getHttpHeaderValue(Properties properties, String headerName) {
      String headerValue = null;
        for (String name : properties.getNames()) {
          // HTTP header field names are case-insensitive
            if (name.equalsIgnoreCase(headerName)) {
              Object property = properties.getProperty(name);
              if (property != null) {
                headerValue = property.toString();
                if (headerValue.length() == 0) {
                  headerValue = null;
                }
              }
              break;
            }
        }
        return headerValue;
    }

    public String[] getMappedHeaderList() {
        return mappedHeaderList;
    }
   
    public void route(Object object) throws ActionProcessingException {
        // Not used!
    }

    public void destroy() throws ActionLifecycleException {
        if (httpclient != null) {
            HttpClientFactory.shutdown(httpclient);
        }
        super.destroy();
    }

  private void extractHttpClientProps(ConfigTree config) {
        ConfigTree[] httpClientConfigTrees = config.getChildren(HttpClientFactory.HTTP_CLIENT_PROPERTY);

        httpClientProps.setProperty(HttpClientFactory.TARGET_HOST_URL, endpointUrl.toString());
        final ConfigTree parent = config.getParent();
        if (parent != null) {
            final String maxThreads = parent.getAttribute(ListenerTagNames.MAX_THREADS_TAG);
            if (maxThreads != null) {
                httpClientProps.setProperty(Connection.MAX_TOTAL_CONNECTIONS, maxThreads);
                httpClientProps.setProperty(Connection.MAX_CONNECTIONS_PER_HOST, maxThreads);
            }
        }

        // The HttpClient properties are attached under the factory class/impl property as <http-client-property name="x" value="y" /> nodes
        for(ConfigTree httpClientProp : httpClientConfigTrees) {
            String propName = httpClientProp.getAttribute("name");
            String propValue = httpClientProp.getAttribute("value");

            if(propName != null && propValue != null) {
                httpClientProps.setProperty(propName, propValue);
            }
        }
    }
   
    // public for testing purposes, see SOAPProxyUnitTest.test_maxThreads*()
    public java.util.Properties getHttpClientProps() {
      return httpClientProps;
    }

    public static void main(String[] args) throws ConfigurationException, ActionProcessingException {
        ConfigTree configTree = new ConfigTree("config");

        for(String arg : args) {
            int equalsIdx = arg.indexOf('=');

            if(equalsIdx == -1) {
                throw new IllegalArgumentException("Arguments must be in 'name=value' format.");
            }

            String name = arg.substring(0, equalsIdx);
            String value = arg.substring(equalsIdx + 1);
            if(!coreProperties.contains(name) && !name.equals("payload")) {
                ConfigTree httpClientProperty = new ConfigTree(HttpClientFactory.HTTP_CLIENT_PROPERTY, configTree);
                httpClientProperty.setAttribute("name", name);
                httpClientProperty.setAttribute("value", value);
            } else {
                configTree.setAttribute(name, value);
            }
        }

        HttpRouter router = new HttpRouter(configTree);
        Message message = MessageFactory.getInstance().getMessage();

        String payload = configTree.getAttribute("payload");
        if(payload != null) {
            try {
                File file = new File(payload);
                if(file.exists()) {
                    payload = FileUtil.readTextFile(file);
                }
            } catch (Exception e) {
                // Ignore...
            }
            System.out.println("Request payload:\n" + payload);
            System.out.println("--------------------------\n");
            message.getBody().add(payload);
        }

        message = router.process(message);

        HttpResponse responseInfo = HttpResponse.getResponse(message);
        System.out.println();
        System.out.println("Response Status Code: " + responseInfo.getResponseCode());
        System.out.println("Response payload:\n" + message.getBody().get());
        System.out.println("--------------------------\n");
    }
}
TOP

Related Classes of org.jboss.soa.esb.actions.routing.http.HttpRouter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.