Coverage Report - org.mule.transport.http.HttpClientMessageDispatcher
 
Classes in this File Line Coverage Branch Coverage Complexity
HttpClientMessageDispatcher
62%
74/120
42%
17/40
3.5
 
 1  
 /*
 2  
  * $Id: HttpClientMessageDispatcher.java 10963 2008-02-22 19:18:44Z dirk.olmes $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.transport.http;
 12  
 
 13  
 import org.mule.DefaultMuleMessage;
 14  
 import org.mule.api.MuleEvent;
 15  
 import org.mule.api.MuleMessage;
 16  
 import org.mule.api.endpoint.OutboundEndpoint;
 17  
 import org.mule.api.transformer.Transformer;
 18  
 import org.mule.api.transformer.TransformerException;
 19  
 import org.mule.api.transport.DispatchException;
 20  
 import org.mule.api.transport.OutputHandler;
 21  
 import org.mule.message.DefaultExceptionPayload;
 22  
 import org.mule.transport.AbstractMessageDispatcher;
 23  
 import org.mule.transport.http.transformers.ObjectToHttpClientMethodRequest;
 24  
 import org.mule.util.StringUtils;
 25  
 
 26  
 import java.io.IOException;
 27  
 import java.io.InputStream;
 28  
 import java.net.URI;
 29  
 import java.net.URISyntaxException;
 30  
 import java.util.Iterator;
 31  
 import java.util.Map;
 32  
 
 33  
 import org.apache.commons.httpclient.Cookie;
 34  
 import org.apache.commons.httpclient.Header;
 35  
 import org.apache.commons.httpclient.HostConfiguration;
 36  
 import org.apache.commons.httpclient.HttpClient;
 37  
 import org.apache.commons.httpclient.HttpMethod;
 38  
 import org.apache.commons.httpclient.cookie.CookiePolicy;
 39  
 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
 40  
 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
 41  
 import org.apache.commons.httpclient.params.HttpMethodParams;
 42  
 import org.apache.commons.httpclient.protocol.Protocol;
 43  
 
 44  
 /**
 45  
  * <code>HttpClientMessageDispatcher</code> dispatches Mule events over HTTP.
 46  
  */
 47  
 public class HttpClientMessageDispatcher extends AbstractMessageDispatcher
 48  
 {
 49  
     /**
 50  
      * Range start for http error status codes.
 51  
      */
 52  
     public static final int ERROR_STATUS_CODE_RANGE_START = 400;
 53  
     private final HttpConnector connector;
 54  64
     private volatile HttpClient client = null;
 55  
     private final Transformer sendTransformer;
 56  
 
 57  
     public HttpClientMessageDispatcher(OutboundEndpoint endpoint)
 58  
     {
 59  64
         super(endpoint);
 60  64
         this.connector = (HttpConnector) endpoint.getConnector();
 61  64
         this.sendTransformer = new ObjectToHttpClientMethodRequest();
 62  64
     }
 63  
     
 64  
     protected void doConnect() throws Exception
 65  
     {
 66  64
         if (client == null)
 67  
         {
 68  64
             client = connector.doClientConnect();
 69  
         }
 70  64
     }
 71  
 
 72  
     protected void doDisconnect() throws Exception
 73  
     {
 74  64
         client = null;
 75  64
     }
 76  
 
 77  
     protected void doDispatch(MuleEvent event) throws Exception
 78  
     {
 79  0
         HttpMethod httpMethod = getMethod(event);
 80  
         try
 81  
         {
 82  0
             execute(event, httpMethod);
 83  
             
 84  0
             if (httpMethod.getStatusCode() >= ERROR_STATUS_CODE_RANGE_START)
 85  
             {
 86  0
                 logger.error(httpMethod.getResponseBodyAsString());
 87  0
                 throw new DispatchException(event.getMessage(), event.getEndpoint(), new Exception(
 88  
                     "Http call returned a status of: " + httpMethod.getStatusCode() + " "
 89  
                                     + httpMethod.getStatusText()));
 90  
             }
 91  
         }
 92  
         finally
 93  
         {
 94  0
             httpMethod.releaseConnection();
 95  0
         }
 96  0
     }
 97  
 
 98  
     protected HttpMethod execute(MuleEvent event, HttpMethod httpMethod)
 99  
         throws Exception
 100  
     {
 101  
         // TODO set connection timeout buffer etc
 102  
         try
 103  
         {
 104  140
             URI uri = event.getEndpoint().getEndpointURI().getUri();
 105  
 
 106  140
             this.processCookies(event);
 107  
 
 108  
             // TODO can we use the return code for better reporting?
 109  140
             client.executeMethod(getHostConfig(uri), httpMethod);
 110  
 
 111  140
             return httpMethod;
 112  
         }
 113  0
         catch (IOException e)
 114  
         {
 115  
             // TODO employ dispatcher reconnection strategy at this point
 116  0
             throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
 117  
         }
 118  0
         catch (Exception e)
 119  
         {
 120  0
             throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
 121  
         }
 122  
         
 123  
     }
 124  
 
 125  
     protected void processCookies(MuleEvent event)
 126  
     {
 127  140
         MuleMessage msg = event.getMessage();
 128  140
         Object cookieObject = msg.removeProperty(HttpConnector.HTTP_COOKIES_PROPERTY);
 129  140
         if (cookieObject instanceof Cookie[])
 130  
         {
 131  
             // cookies came in via a regular HTTP request
 132  0
             Cookie[] cookies = (Cookie[]) cookieObject;
 133  0
             if (cookies != null && cookies.length > 0)
 134  
             {
 135  0
                 String policy = (String) msg.removeProperty(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY);
 136  0
                 client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy));
 137  0
                 client.getState().addCookies(cookies);
 138  
             }
 139  0
         }
 140  140
         else if (cookieObject instanceof Map)
 141  
         {
 142  
             // cookies were configured on the endpoint
 143  2
             client.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
 144  
 
 145  2
             String host = this.getEndpoint().getEndpointURI().getHost();
 146  2
             String path = this.getEndpoint().getEndpointURI().getPath();
 147  2
             Map cookieMap = (Map) cookieObject;
 148  2
             Iterator keyIter = cookieMap.keySet().iterator();
 149  4
             while (keyIter.hasNext())
 150  
             {
 151  2
                 String key = (String) keyIter.next();
 152  2
                 String value = (String) cookieMap.get(key);
 153  2
                 Cookie cookie = new Cookie(host, key, value, path, null, false);
 154  2
                 client.getState().addCookie(cookie);
 155  2
             }
 156  2
         }
 157  138
         else if (cookieObject != null)
 158  
         {
 159  0
             throw new IllegalArgumentException("Invalid cookies " + cookieObject);
 160  
         }
 161  140
     }
 162  
 
 163  
     protected HttpMethod getMethod(MuleEvent event) throws TransformerException
 164  
     {
 165  142
         MuleMessage msg = event.getMessage();
 166  142
         setPropertyFromEndpoint(event, msg, HttpConnector.HTTP_CUSTOM_HEADERS_MAP_PROPERTY);
 167  
         
 168  
         HttpMethod httpMethod;
 169  142
         Object body = event.transformMessage();
 170  
 
 171  140
         if (body instanceof HttpMethod)
 172  
         {
 173  126
             httpMethod = (HttpMethod)body;
 174  
         }
 175  
         else 
 176  
         {
 177  14
             httpMethod = (HttpMethod) sendTransformer.transform(msg);
 178  
         }
 179  
         
 180  
         
 181  140
         return httpMethod;
 182  
     }
 183  
 
 184  
     protected void setPropertyFromEndpoint(MuleEvent event, MuleMessage msg, String prop)
 185  
     {
 186  142
         Object o = msg.getProperty(prop, null);
 187  142
         if (o == null) {
 188  
             
 189  142
             o = event.getEndpoint().getProperty(prop);
 190  142
             if (o != null) {
 191  0
                 msg.setProperty(prop, o);
 192  
             }
 193  
         }
 194  142
     }
 195  
 
 196  
     protected HttpMethod createEntityMethod(MuleEvent event, Object body, EntityEnclosingMethod postMethod)
 197  
         throws TransformerException
 198  
     {
 199  
         HttpMethod httpMethod;
 200  0
         if (body instanceof String)
 201  
         {
 202  0
             ObjectToHttpClientMethodRequest trans = new ObjectToHttpClientMethodRequest();
 203  0
             httpMethod = (HttpMethod)trans.transform(body.toString());
 204  0
         }
 205  0
         else if (body instanceof byte[])
 206  
         {
 207  0
             byte[] buffer = event.transformMessageToBytes();
 208  0
             postMethod.setRequestEntity(new ByteArrayRequestEntity(buffer, event.getEncoding()));
 209  0
             httpMethod = postMethod;
 210  0
         }
 211  
         else 
 212  
         {
 213  0
             if (!(body instanceof OutputHandler)) 
 214  
             {
 215  0
                 body = event.transformMessage(OutputHandler.class);
 216  
             }
 217  
             
 218  0
             OutputHandler outputHandler = (OutputHandler)body;
 219  0
             postMethod.setRequestEntity(new StreamPayloadRequestEntity(outputHandler, event));
 220  0
             postMethod.setContentChunked(true);
 221  0
             httpMethod = postMethod;
 222  
         }
 223  
         
 224  0
         return httpMethod;
 225  
     }
 226  
 
 227  
     /*
 228  
      * (non-Javadoc)
 229  
      * 
 230  
      * @see org.mule.api.transport.Connector#send(org.mule.api.MuleEvent)
 231  
      */
 232  
     protected MuleMessage doSend(MuleEvent event) throws Exception
 233  
     {        
 234  142
         HttpMethod httpMethod = getMethod(event);
 235  140
         connector.setupClientAuthorization(event, httpMethod, client, endpoint);
 236  
         
 237  140
         httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new MuleHttpMethodRetryHandler());
 238  
 
 239  140
         Object body = null;
 240  140
         boolean releaseConn = false;
 241  
         try
 242  
         {
 243  140
             httpMethod = execute(event, httpMethod);
 244  
 
 245  140
             DefaultExceptionPayload ep = null;
 246  140
             if (httpMethod.getStatusCode() >= ERROR_STATUS_CODE_RANGE_START)
 247  
             {
 248  6
                 ep = new DefaultExceptionPayload(new DispatchException(event.getMessage(), event.getEndpoint(),
 249  
                     new Exception("Http call returned a status of: " + httpMethod.getStatusCode() + " "
 250  
                                   + httpMethod.getStatusText())));
 251  
             }
 252  
             
 253  
             
 254  140
             InputStream is = httpMethod.getResponseBodyAsStream();
 255  140
             if (is == null)
 256  
             {
 257  0
                 body = StringUtils.EMPTY;
 258  0
                 releaseConn = true;
 259  
             }            
 260  
             else
 261  
             {
 262  140
                 is = new ReleasingInputStream(is, httpMethod);
 263  140
                 body = is;
 264  
             }
 265  
             
 266  140
             Header[] headers = httpMethod.getResponseHeaders();
 267  140
             HttpMessageAdapter adapter = new HttpMessageAdapter(new Object[]{body, headers});
 268  
 
 269  140
             String status = String.valueOf(httpMethod.getStatusCode());
 270  
 
 271  140
             adapter.setProperty(HttpConnector.HTTP_STATUS_PROPERTY, status);
 272  140
             if (logger.isDebugEnabled())
 273  
             {
 274  0
                 logger.debug("Http response is: " + status);
 275  
             }
 276  
             
 277  140
             MuleMessage m = new DefaultMuleMessage(adapter);
 278  
           
 279  140
             m.setExceptionPayload(ep);
 280  140
             return m;
 281  
         }
 282  0
         catch (Exception e)
 283  
         {
 284  0
             releaseConn = true;
 285  0
             if (e instanceof DispatchException)
 286  
             {
 287  0
                 throw (DispatchException) e;
 288  
             }
 289  
             
 290  0
             throw new DispatchException(event.getMessage(), event.getEndpoint(), e);
 291  
         }
 292  
         finally
 293  
         {
 294  140
             if (releaseConn) 
 295  
             {
 296  0
                 httpMethod.releaseConnection();
 297  
             }
 298  
         }
 299  
     }
 300  
 
 301  
     protected HostConfiguration getHostConfig(URI uri) throws URISyntaxException
 302  
     {
 303  140
         Protocol protocol = Protocol.getProtocol(uri.getScheme().toLowerCase());
 304  
 
 305  140
         String host = uri.getHost();
 306  140
         int port = uri.getPort();
 307  140
         HostConfiguration config = new HostConfiguration();
 308  140
         config.setHost(host, port, protocol);
 309  140
         if (StringUtils.isNotBlank(connector.getProxyHostname()))
 310  
         {
 311  
             // add proxy support
 312  0
             config.setProxy(connector.getProxyHostname(), connector.getProxyPort());
 313  
         }
 314  140
         return config;
 315  
     }
 316  
 
 317  
     protected void doDispose()
 318  
     {
 319  
         // template method
 320  64
     }
 321  
 }