HttpRestRouter.java

    /*
     * 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 cl.mas.siniestros.esb.action.ejemplo;
    
    import java.io.Closeable;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.UnsupportedEncodingException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLDecoder;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Set;
    import org.apache.commons.httpclient.Header;
    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.publish.Publish;
    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.annotation.Process;
    import org.jboss.soa.esb.actions.routing.AbstractRouter;
    import org.jboss.soa.esb.actions.routing.http.HttpMethodFactory;
    import org.jboss.soa.esb.actions.routing.http.ResponseType;
    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.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.util.FileUtil;
    
    public class HttpRestRouter extends AbstractRouter {
    
        private static Logger logger = Logger.getLogger(HttpRestRouter.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 String rsPath = "";
        private String rsUrl;
    
        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");
            coreProperties.add("method");
        }
    
    
    
        public HttpRestRouter(ConfigTree config) throws ConfigurationException {
            super(config);
            this.config = config;
    
               rsUrl = config.getRequiredAttribute("endpointUrl");
            this.method = config.getRequiredAttribute("method");
            this.rsPath = config.getRequiredAttribute("path");
            String substring = this.rsPath.substring(0, 1);
            if("/".equals(substring))
                this.rsPath = this.rsPath.replaceFirst("/", "");   
            extractHttpClientProps(config);
            mappedHeaderList = extractMappedHeaderListConfig();
        }
    
        public void init(String url, String contentType)throws ConfigurationException {
    
            this.httpclient = HttpClientFactory.createHttpClient(httpClientProps);
    
            try {
                this.endpointUrl = new URL(url);
            } catch (MalformedURLException e) {
                throw new ConfigurationException("Invalid endpoint URL '" + config.getRequiredAttribute("endpointUrl") + "'.", e);
            }
            this.responseType = ResponseType.valueOf(config.getAttribute("responseType", ResponseType.STRING.toString()));
            this.methodFactory = HttpMethodFactory.Factory.getInstance(method.toUpperCase(), config, endpointUrl);
            this.contentType = config.getAttribute("Content-Type");
    
            this.requestHeaders = config.getChildren("header");
    
            this.httpResponseStatusEnabled = ResponseStatus.isHttpEnabled(config);
        }
    
        private String formURL(HttpRequest request) throws ActionProcessingException{
            String auxPath = "";
            String requestURI = request.getRequestURI();
            String esbUrl = request.getContextPath()+ request.getRequestPath();        
            String restURI = requestURI.replace(esbUrl, "");
            String subString = "";
            if(restURI != null && restURI.length() > 0)
                subString = restURI.substring(0, 1);
            if("/".equals(subString))
                restURI = restURI.replaceFirst("/", "");
            String[] listRsPath = this.rsPath.split("/");
            String[] listRsURI = restURI.split("/");
    
            if(listRsPath == null)
                throw new ActionProcessingException("listRSPath can not be null");
    
            if(listRsURI == null)
                throw new ActionProcessingException("listRsURI can not be null");
    
            if(listRsURI.length != listRsPath.length)
                throw new ActionProcessingException("listRSPath not equal listRsURI");
    
    
            if(listRsPath.length != 0){
                String[] token = new String[listRsPath.length];
                for (int i = 0; i < listRsPath.length; i++) {
                    if(listRsPath[i].startsWith("{")){
                        token[i] = listRsURI[i];
                    }else{
                        if(!listRsPath[i].equals(listRsURI[i]))
                            throw new ActionProcessingException("listRSPath not equal listRsURI");
                        token[i] = listRsPath[i];
                    }
                }
                auxPath = this.implode(token, "/");
            }
            auxPath = this.rsUrl  +"/"+ auxPath;
    
            return auxPath;
        }
    
         public static String implode(String[] ary, String delim) {
              String out = "";
               for(int i=0; i<ary.length; i++) {
                   if(i!=0) { out += delim; }
                   out += ary[i];
              }
         }
    
        @Process
        public Message process(Message message) throws ActionProcessingException {
            HttpMethodBase httpMethod = null;
            HttpRequest request = HttpRequest.getRequest(message);
    
    
            String path = this.formURL(request);      
            try {
                this.init(path, request.getContentType());
            } catch (ConfigurationException e1) {
                e1.printStackTrace();
                throw new ActionProcessingException(e1);
            }
            try {
                httpMethod = methodFactory.getInstance(message);
                httpMethod.setQueryString(request.getQueryString());           
    
                try {
                    setRequestHeaders(httpMethod, message);
    
                    int responseCode = httpclient.executeMethod(httpMethod);
                    if(responseCode != HttpStatus.SC_OK) {
                        logger.warn("Received status code '" + responseCode + "' on HTTP " + httpMethod + " request to '" + endpointUrl + "'.");
                    }
                    attachResponseDetails(message, httpMethod, responseCode);
    
                    InputStream resultStream = httpMethod.getResponseBodyAsStream();
                    try {
                        byte[] bytes = readStream(resultStream);
    
                        if(responseType == ResponseType.STRING) {
                            getPayloadProxy().setPayload(message, new String(bytes, httpMethod.getResponseCharSet()));
                        } else {
                            getPayloadProxy().setPayload(message, bytes);
                        }
                    } catch (MessageDeliverException e) {
                        throw new ActionProcessingException("problem setting message payload: " + e.getMessage(), e);
                    } finally {
                        closeStream(resultStream);
                    }
                } finally {
                    httpMethod.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) {
            setMappedHttpHeaders(method, message);        
            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();
                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()) {
                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 destroy() throws ActionLifecycleException {
            if (httpclient != null) {
                HttpClientFactory.shutdown(httpclient);
            }
            super.destroy();
        }
    
        private void extractHttpClientProps(ConfigTree config) {
            ConfigTree[] httpClientConfigTrees = config.getChildren("http-client-property");
    
            httpClientProps.setProperty(HttpClientFactory.TARGET_HOST_URL, this.rsUrl);
            final ConfigTree parent = config.getParent() ;
            if (parent != null) {
                final String maxThreads = config.getParent().getAttribute(ListenerTagNames.MAX_THREADS_TAG) ;
                if (maxThreads != null) {
                    httpClientProps.setProperty("3", maxThreads) ;
                }
            }
    
            for(ConfigTree httpClientProp : httpClientConfigTrees) {
                String propName = httpClientProp.getAttribute("name");
                String propValue = httpClientProp.getAttribute("value");
    
                if(propName != null && propValue != null) {
                    httpClientProps.setProperty(propName, propValue);
                }
            }
        }
    
        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("http-client-property", configTree);
                    httpClientProperty.setAttribute("name", name);
                    httpClientProperty.setAttribute("value", value);
                } else {
                    configTree.setAttribute(name, value);
                }
            }
    
            HttpRestRouter router = new HttpRestRouter(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) {
                    e.printStackTrace();
                }
                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");
        }
    
        @Override
        public void route(Object arg0) throws ActionProcessingException {
            // TODO Auto-generated method stub
    
        }
    }