Coverage Report - org.mule.module.ws.construct.WSProxy
 
Classes in this File Line Coverage Branch Coverage Complexity
WSProxy
0%
0/29
0%
0/10
0
WSProxy$1
N/A
N/A
0
WSProxy$AbstractProxyRequestProcessor
0%
0/19
0%
0/10
0
WSProxy$CopyInboundToOutboundPropertiesTransformerCallback
0%
0/4
0%
0/2
0
WSProxy$DynamicWsdlProxyRequestProcessor
0%
0/35
0%
0/12
0
WSProxy$DynamicWsdlProxyRequestProcessor$1
0%
0/2
N/A
0
WSProxy$DynamicWsdlProxyRequestProcessor$2
0%
0/3
N/A
0
WSProxy$DynamicWsdlProxyRequestProcessor$3
0%
0/2
N/A
0
WSProxy$DynamicWsdlProxyRequestProcessor$WsdlAddressProvider
N/A
N/A
0
WSProxy$StaticWsdlProxyRequestProcessor
0%
0/8
0%
0/4
0
 
 1  
 /*
 2  
  * $Id: WSProxy.java 19884 2010-10-12 19:23:36Z ddossot $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.module.ws.construct;
 12  
 
 13  
 import java.net.InetAddress;
 14  
 import java.net.URI;
 15  
 
 16  
 import org.apache.commons.logging.Log;
 17  
 import org.apache.commons.logging.LogFactory;
 18  
 import org.mule.MessageExchangePattern;
 19  
 import org.mule.api.MessagingException;
 20  
 import org.mule.api.MuleContext;
 21  
 import org.mule.api.MuleEvent;
 22  
 import org.mule.api.MuleException;
 23  
 import org.mule.api.MuleMessage;
 24  
 import org.mule.api.construct.FlowConstructInvalidException;
 25  
 import org.mule.api.endpoint.InboundEndpoint;
 26  
 import org.mule.api.endpoint.OutboundEndpoint;
 27  
 import org.mule.api.processor.MessageProcessor;
 28  
 import org.mule.api.source.MessageSource;
 29  
 import org.mule.config.i18n.MessageFactory;
 30  
 import org.mule.construct.AbstractFlowConstruct;
 31  
 import org.mule.construct.processor.FlowConstructStatisticsMessageObserver;
 32  
 import org.mule.endpoint.DynamicOutboundEndpoint;
 33  
 import org.mule.interceptor.LoggingInterceptor;
 34  
 import org.mule.processor.StopFurtherMessageProcessingMessageProcessor;
 35  
 import org.mule.processor.builder.InterceptingChainMessageProcessorBuilder;
 36  
 import org.mule.transformer.TransformerTemplate;
 37  
 import org.mule.transformer.TransformerTemplate.TransformerCallback;
 38  
 import org.mule.util.ObjectUtils;
 39  
 import org.mule.util.StringUtils;
 40  
 
 41  
 /**
 42  
  * This class is implemented to act as a Proxy for a Web Service. It listens for
 43  
  * requests on the inbound endpoint and if it encounters the "WSDL" property in the
 44  
  * address, it will fetch the WSDL from the original web service and return it back.
 45  
  * In case the wsdlFile property is set, when the WSProxyService encounters a request
 46  
  * for the wsdl, instead of fetching the WSDL from the original web service, it will
 47  
  * return back the file expressed in the property. When a normal SOAP request is
 48  
  * encountered, it will forward the call to the web service with no modifications to
 49  
  * the SOAP message. The outbound router of this class must include the address of
 50  
  * the webservice to be proxied. No need to include the method name as a parameter in
 51  
  * the address, since it will be in the SOAP message as well. Furthermore a property
 52  
  * named uriWsdl can optionally be set which as the name suggests, indicate the URL
 53  
  * of the WSDL for the service. If this property is not set, the address of the WSDL
 54  
  * will be assumed to be the value of uriWebservice followed by "?WSDL".
 55  
  */
 56  
 public class WSProxy extends AbstractFlowConstruct
 57  
 {
 58  
     private final AbstractProxyRequestProcessor proxyMessageProcessor;
 59  
     private final OutboundEndpoint outboundEndpoint;
 60  
 
 61  
     public WSProxy(String name,
 62  
                    MuleContext muleContext,
 63  
                    MessageSource messageSource,
 64  
                    OutboundEndpoint outboundEndpoint) throws MuleException
 65  
     {
 66  0
         this(name, muleContext, messageSource, outboundEndpoint, new DynamicWsdlProxyRequestProcessor(
 67  
             outboundEndpoint));
 68  0
     }
 69  
 
 70  
     public WSProxy(String name,
 71  
                    MuleContext muleContext,
 72  
                    MessageSource messageSource,
 73  
                    OutboundEndpoint outboundEndpoint,
 74  
                    String wsdlContents) throws MuleException
 75  
     {
 76  0
         this(name, muleContext, messageSource, outboundEndpoint, new StaticWsdlProxyRequestProcessor(
 77  
             wsdlContents));
 78  0
     }
 79  
 
 80  
     public WSProxy(String name,
 81  
                    MuleContext muleContext,
 82  
                    MessageSource messageSource,
 83  
                    OutboundEndpoint outboundEndpoint,
 84  
                    URI wsdlUri) throws MuleException
 85  
     {
 86  0
         this(name, muleContext, messageSource, outboundEndpoint,
 87  
             new DynamicWsdlProxyRequestProcessor(wsdlUri));
 88  0
     }
 89  
 
 90  
     private WSProxy(String name,
 91  
                     MuleContext muleContext,
 92  
                     MessageSource messageSource,
 93  
                     OutboundEndpoint outboundEndpoint,
 94  
                     AbstractProxyRequestProcessor proxyMessageProcessor) throws MuleException
 95  
     {
 96  0
         super(name, muleContext);
 97  
 
 98  0
         if (messageSource == null)
 99  
         {
 100  0
             throw new FlowConstructInvalidException(
 101  
                 MessageFactory.createStaticMessage("messageSource can't be null on: " + this.toString()),
 102  
                 this);
 103  
         }
 104  
 
 105  0
         super.setMessageSource(messageSource);
 106  
 
 107  0
         if (outboundEndpoint == null)
 108  
         {
 109  0
             throw new FlowConstructInvalidException(
 110  
                 MessageFactory.createStaticMessage("outboundEndpoint can't be null on: " + this.toString()),
 111  
                 this);
 112  
         }
 113  
 
 114  0
         this.outboundEndpoint = outboundEndpoint;
 115  
 
 116  0
         this.proxyMessageProcessor = proxyMessageProcessor;
 117  0
     }
 118  
 
 119  
     @Override
 120  
     protected void configureMessageProcessors(InterceptingChainMessageProcessorBuilder builder)
 121  
     {
 122  0
         builder.chain(new LoggingInterceptor());
 123  0
         builder.chain(new FlowConstructStatisticsMessageObserver());
 124  0
         builder.chain(proxyMessageProcessor);
 125  0
         builder.chain(new StopFurtherMessageProcessingMessageProcessor());
 126  0
         builder.chain(new TransformerTemplate(new CopyInboundToOutboundPropertiesTransformerCallback()));
 127  0
         builder.chain(outboundEndpoint);
 128  0
     }
 129  
 
 130  
     @Override
 131  
     protected void validateConstruct() throws FlowConstructInvalidException
 132  
     {
 133  0
         super.validateConstruct();
 134  
 
 135  0
         if ((messageSource instanceof InboundEndpoint)
 136  
             && (!((InboundEndpoint) messageSource).getExchangePattern().equals(
 137  
                 MessageExchangePattern.REQUEST_RESPONSE)))
 138  
         {
 139  0
             throw new FlowConstructInvalidException(
 140  
                 MessageFactory.createStaticMessage("WSProxy only works with a request-response inbound endpoint."),
 141  
                 this);
 142  
         }
 143  
 
 144  0
         if (!outboundEndpoint.getExchangePattern().equals(MessageExchangePattern.REQUEST_RESPONSE))
 145  
         {
 146  0
             throw new FlowConstructInvalidException(
 147  
                 MessageFactory.createStaticMessage("WSProxy only works with a request-response outbound endpoint."),
 148  
                 this);
 149  
         }
 150  0
     }
 151  
 
 152  0
     private static final class CopyInboundToOutboundPropertiesTransformerCallback
 153  
         implements TransformerCallback
 154  
     {
 155  
         public Object doTransform(MuleMessage message) throws Exception
 156  
         {
 157  0
             for (final String inboundPropertyName : message.getInboundPropertyNames())
 158  
             {
 159  0
                 message.setOutboundProperty(inboundPropertyName,
 160  
                     message.getInboundProperty(inboundPropertyName));
 161  
             }
 162  
 
 163  0
             return message;
 164  
         }
 165  
     }
 166  
 
 167  0
     private static abstract class AbstractProxyRequestProcessor implements MessageProcessor
 168  
     {
 169  
         private static final String HTTP_REQUEST = "http.request";
 170  
         private static final String WSDL_PARAM_1 = "?wsdl";
 171  
         private static final String WSDL_PARAM_2 = "&wsdl";
 172  
 
 173  0
         protected final Log logger = LogFactory.getLog(WSProxy.class);
 174  
 
 175  
         public MuleEvent process(MuleEvent event) throws MuleException
 176  
         {
 177  0
             if (isWsdlRequest(event))
 178  
             {
 179  0
                 return buildWsdlResult(event);
 180  
             }
 181  
 
 182  0
             if (logger.isDebugEnabled())
 183  
             {
 184  0
                 logger.debug("Forwarding SOAP message");
 185  
             }
 186  
 
 187  0
             return event;
 188  
         }
 189  
 
 190  
         private MuleEvent buildWsdlResult(MuleEvent event) throws MuleException
 191  
         {
 192  
             try
 193  
             {
 194  0
                 final String wsdlContents = getWsdlContents(event);
 195  0
                 event.getMessage().setPayload(wsdlContents);
 196  
 
 197  
                 // the processing is stopped so that the result is not passed through
 198  
                 // the outbound router but will be passed back as a result
 199  0
                 event.setStopFurtherProcessing(true);
 200  0
                 return event;
 201  
             }
 202  0
             catch (final Exception e)
 203  
             {
 204  0
                 throw new MessagingException(
 205  
                     MessageFactory.createStaticMessage("Impossible to retrieve WSDL for proxied service"),
 206  
                     event, e);
 207  
             }
 208  
         }
 209  
 
 210  
         private boolean isWsdlRequest(MuleEvent event) throws MuleException
 211  
         {
 212  
             // retrieve the original HTTP request. This will be used to check if the
 213  
             // user asked for the WSDL or a service method.
 214  0
             final String httpRequest = event.getMessage().<String> getInboundProperty(HTTP_REQUEST);
 215  
 
 216  0
             if (httpRequest == null)
 217  
             {
 218  0
                 logger.warn("WS Proxy can't rewrite WSDL for non-HTTP " + event);
 219  0
                 return false;
 220  
             }
 221  
 
 222  0
             final String lowerHttpRequest = httpRequest.toLowerCase();
 223  
 
 224  
             // check if the inbound request contains the WSDL parameter
 225  0
             return (lowerHttpRequest.indexOf(WSDL_PARAM_1) != -1)
 226  
                    || (lowerHttpRequest.indexOf(WSDL_PARAM_2) != -1);
 227  
         }
 228  
 
 229  
         protected abstract String getWsdlContents(MuleEvent event) throws Exception;
 230  
     }
 231  
 
 232  
     private static class StaticWsdlProxyRequestProcessor extends AbstractProxyRequestProcessor
 233  
     {
 234  
         private final String wsdlContents;
 235  
 
 236  
         /**
 237  
          * Instantiates a request processor that returns a static WSDL contents when
 238  
          * the proxy receives a WSDL request.
 239  
          * 
 240  
          * @param wsdlContents the WSDL contents to use.
 241  
          * @throws FlowConstructInvalidException
 242  
          */
 243  
         StaticWsdlProxyRequestProcessor(String wsdlContents) throws FlowConstructInvalidException
 244  0
         {
 245  0
             if (StringUtils.isBlank(wsdlContents))
 246  
             {
 247  0
                 throw new FlowConstructInvalidException(
 248  
                     MessageFactory.createStaticMessage("wsdlContents can't be empty"));
 249  
             }
 250  
 
 251  0
             this.wsdlContents = wsdlContents;
 252  0
         }
 253  
 
 254  
         @Override
 255  
         protected String getWsdlContents(MuleEvent event) throws Exception
 256  
         {
 257  0
             if (logger.isDebugEnabled())
 258  
             {
 259  0
                 logger.debug("Serving static WSDL");
 260  
             }
 261  
 
 262  0
             return wsdlContents;
 263  
         }
 264  
     }
 265  
 
 266  0
     private static class DynamicWsdlProxyRequestProcessor extends AbstractProxyRequestProcessor
 267  
     {
 268  
         private interface WsdlAddressProvider
 269  
         {
 270  
             String get(MuleEvent event);
 271  
         }
 272  
 
 273  
         private static final String LOCALHOST = "localhost";
 274  
         private final WsdlAddressProvider wsdlAddressProvider;
 275  
 
 276  
         /**
 277  
          * Instantiates a request processor that fetches and rewrites addresses of a
 278  
          * remote WSDL when the proxy receives a WSDL request.
 279  
          * 
 280  
          * @param wsdlUri the URI to fetch the WSDL from.
 281  
          * @throws FlowConstructInvalidException
 282  
          */
 283  
         DynamicWsdlProxyRequestProcessor(final URI wsdlUri) throws FlowConstructInvalidException
 284  0
         {
 285  0
             if (wsdlUri == null)
 286  
             {
 287  0
                 throw new FlowConstructInvalidException(
 288  
                     MessageFactory.createStaticMessage("wsdlUri can't be null"));
 289  
             }
 290  
 
 291  0
             final String wsdlAddress = wsdlUri.toString();
 292  
 
 293  0
             wsdlAddressProvider = new WsdlAddressProvider()
 294  0
             {
 295  
                 public String get(MuleEvent event)
 296  
                 {
 297  0
                     return wsdlAddress;
 298  
                 }
 299  
             };
 300  
 
 301  0
             logger.info("Using url " + wsdlAddress + " as WSDL");
 302  0
         }
 303  
 
 304  
         /**
 305  
          * Instantiates a request processor that fetches and rewrites addresses of a
 306  
          * remote WSDL when the proxy receives a WSDL request.
 307  
          * 
 308  
          * @param outboundEndpoint the endpoint to fetch the WSDL from.
 309  
          * @throws FlowConstructInvalidException
 310  
          */
 311  
         DynamicWsdlProxyRequestProcessor(OutboundEndpoint outboundEndpoint)
 312  
             throws FlowConstructInvalidException
 313  0
         {
 314  0
             if (outboundEndpoint == null)
 315  
             {
 316  0
                 throw new FlowConstructInvalidException(
 317  
                     MessageFactory.createStaticMessage("outboundEndpoint can't be null"));
 318  
             }
 319  
 
 320  0
             final String wsAddress = outboundEndpoint.getAddress();
 321  
 
 322  0
             if (outboundEndpoint instanceof DynamicOutboundEndpoint)
 323  
             {
 324  0
                 wsdlAddressProvider = new WsdlAddressProvider()
 325  0
                 {
 326  
                     public String get(MuleEvent event)
 327  
                     {
 328  0
                         final String resolvedWsAddress = event.getMuleContext().getExpressionManager().parse(
 329  
                             wsAddress, event.getMessage(), true);
 330  
 
 331  0
                         return makeWsdlAddress(resolvedWsAddress);
 332  
                     }
 333  
                 };
 334  
 
 335  0
                 logger.info("Using dynamic WSDL with service address: " + wsAddress);
 336  
             }
 337  
             else
 338  
             {
 339  0
                 final String wsdlAddress = makeWsdlAddress(wsAddress);
 340  
 
 341  0
                 wsdlAddressProvider = new WsdlAddressProvider()
 342  0
                 {
 343  
                     public String get(MuleEvent event)
 344  
                     {
 345  0
                         return wsdlAddress;
 346  
                     }
 347  
                 };
 348  
 
 349  0
                 logger.info("Setting WSDL address to: " + wsdlAddress);
 350  
             }
 351  0
         }
 352  
 
 353  
         private static String makeWsdlAddress(String wsAddress)
 354  
         {
 355  0
             return StringUtils.substringBefore(wsAddress, "?").concat("?wsdl");
 356  
         }
 357  
 
 358  
         @Override
 359  
         protected String getWsdlContents(MuleEvent event) throws Exception
 360  
         {
 361  0
             final String wsdlAddress = wsdlAddressProvider.get(event);
 362  
             String wsdlString;
 363  
 
 364  0
             final MuleContext muleContext = event.getMuleContext();
 365  0
             final InboundEndpoint webServiceEndpoint = muleContext.getRegistry()
 366  
                 .lookupEndpointFactory()
 367  
                 .getInboundEndpoint(wsdlAddress);
 368  
 
 369  0
             if (logger.isDebugEnabled())
 370  
             {
 371  0
                 logger.debug("Retrieving WSDL from web service with: " + webServiceEndpoint);
 372  
             }
 373  
 
 374  0
             final MuleMessage replyWSDL = webServiceEndpoint.request(event.getTimeout());
 375  0
             wsdlString = replyWSDL.getPayloadAsString();
 376  
 
 377  
             // create a new mule message with the new WSDL
 378  0
             final String realWsdlAddress = wsdlAddress.split("\\?")[0];
 379  0
             final String proxyWsdlAddress = event.getEndpoint().getEndpointURI().getUri().toString();
 380  0
             wsdlString = wsdlString.replaceAll(realWsdlAddress, proxyWsdlAddress);
 381  
 
 382  0
             if (wsdlString.indexOf(LOCALHOST) > -1)
 383  
             {
 384  0
                 wsdlString = wsdlString.replaceAll(LOCALHOST, InetAddress.getLocalHost().getHostName());
 385  
             }
 386  
 
 387  0
             if (logger.isDebugEnabled())
 388  
             {
 389  0
                 logger.debug("WSDL retrieved successfully");
 390  
             }
 391  
 
 392  0
             return wsdlString;
 393  
         }
 394  
     }
 395  
 
 396  
     @Override
 397  
     public String toString()
 398  
     {
 399  0
         return ObjectUtils.toString(this);
 400  
     }
 401  
 }