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