View Javadoc

1   /*
2    * $Id: WSProxyService.java 8626 2007-09-26 17:01:19Z acooke $
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.providers.soap;
12  
13  import org.mule.config.i18n.CoreMessages;
14  import org.mule.impl.MuleMessage;
15  import org.mule.impl.UMODescriptorAware;
16  import org.mule.impl.endpoint.MuleEndpoint;
17  import org.mule.providers.NullPayload;
18  import org.mule.umo.UMODescriptor;
19  import org.mule.umo.UMOEventContext;
20  import org.mule.umo.UMOMessage;
21  import org.mule.umo.endpoint.UMOEndpoint;
22  import org.mule.umo.lifecycle.Callable;
23  import org.mule.umo.lifecycle.Initialisable;
24  import org.mule.umo.lifecycle.InitialisationException;
25  import org.mule.umo.routing.UMOOutboundRouter;
26  import org.mule.util.StringUtils;
27  import org.mule.util.IOUtils;
28  
29  import java.io.IOException;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /**
35   * This class is implemented to act as a Proxy for a Web Service. It listens for
36   * requests on the inbound endpoint and if it encounters the "WSDL" property in the
37   * address, it will fetch the WSDL from the original web service and return it back.
38   * In case the wsdlFile property is set, when the WSProxyService encounters a request
39   * for the wsdl, instead of fetching the WSDL from the original web service, it will
40   * return back the file expressed in the property. When a normal SOAP request is
41   * encountered, it will forward the call to the web service with no modifications to
42   * the SOAP message. The outbound router of this class must include the address of
43   * the webservice to be proxied. No need to include the method name as a parameter in
44   * the address, since it will be in the SOAP message as well. Furthermore a property
45   * named uriWsdl can optionally be set which as the name suggests, indicate the URL
46   * of the WSDL for the service. If this property is not set, the address of the WSDL
47   * will be assumed to be the value of uriWebservice followed by "?WSDL". It is
48   * important to note that both urls' of the webservice to be proxied and the WSDL
49   * address must contain no xfire or axis endpoints, just plain http endpoints. Even
50   * the inbound endpoint of the WSProxyService must be residing on an http protocol
51   * (with no xfire or axis).
52   * 
53   */
54  public class WSProxyService implements Callable, UMODescriptorAware, Initialisable
55  {
56  
57      private String urlWebservice;
58      private String wsdlEndpoint;
59      private String wsdlFile;
60      private String wsdlFileContents;
61      private boolean useFile = false;
62  
63      private static final String HTTP_REQUEST = "http.request";
64      private static final String WSDL_PARAM_1 = "?wsdl";
65      private static final String WSDL_PARAM_2 = "&wsdl";
66  
67      protected static transient Log logger = LogFactory.getLog(WSProxyService.class);
68  
69      /**
70       * @return returns the url of the WSDL
71       */
72      public String getWsdlEndpoint()
73      {
74          return wsdlEndpoint;
75      }
76  
77      /**
78       * @param urlWsdl Sets the property urlWsdl (the url of the WSDL of the web
79       *            service)
80       */
81      public void setWsdlEndpoint(String urlWsdl)
82      {
83          this.wsdlEndpoint = urlWsdl;
84      }
85  
86      /**
87       * @return returns the location of the local wsdl
88       */
89      public String getWsdlFile()
90      {
91          return wsdlFile;
92      }
93  
94      /**
95       * @param wsdlFile sets the location of the local wsdl file
96       */
97      public void setWsdlFile(String wsdlFile)
98      {
99          this.wsdlFile = wsdlFile;
100     }
101 
102     public Object onCall(UMOEventContext eventContext) throws Exception
103     {
104         // retrieve the message
105         UMOMessage message = eventContext.getMessage();
106 
107         // retrieve the original http request. This will be used to check if the user
108         // asked for the WSDL or just for the service
109         String httpRequest = ((String)message.getProperty(HTTP_REQUEST)).toLowerCase();
110 
111         // check if the inbound endpoint contains the WSDL parameter
112         if ((httpRequest.indexOf(WSDL_PARAM_1) != -1) || (httpRequest.indexOf(WSDL_PARAM_2) != -1))
113         {
114             logger.debug("Retrieving WSDL from web service");
115 
116             String wsdlString;
117 
118             if (this.useFile)
119             {
120                 // the processing is stopped so that the result is not passed through the
121                 // outbound router but will be passed back as a result
122                 eventContext.setStopFurtherProcessing(true);
123                 return wsdlFileContents;
124             }
125 
126             UMOEndpoint webServiceEndpoint = new MuleEndpoint(this.wsdlEndpoint, false);
127             UMOMessage replyWSDL = eventContext.sendEvent(new MuleMessage(NullPayload.getInstance()), webServiceEndpoint);
128 
129             wsdlString = replyWSDL.getPayloadAsString();
130 
131             // find all dependencies and change them
132             wsdlString = wsdlString.replaceAll(this.urlWebservice, eventContext.getEndpointURI().getAddress());
133 
134             // create a new mule message with the new WSDL
135             MuleMessage modifiedWsdl = new MuleMessage(wsdlString, message);
136 
137             logger.debug("WSDL retrieved successfully");
138 
139             // the processing is stopped so that the result is not passed through the
140             // outbound router but will be passed back as a result
141             eventContext.setStopFurtherProcessing(true);
142 
143             return modifiedWsdl;
144         }
145         else
146         // forward the normal call on the outbound router without any modification
147         {
148             logger.debug("Forwarding SOAP message");
149             return eventContext.getMessage();
150         }
151     }
152 
153     // called once upon initialisation
154     public void setDescriptor(UMODescriptor descriptor)
155     {
156         UMOOutboundRouter router = (UMOOutboundRouter)descriptor.getOutboundRouter().getRouters().get(0);
157         UMOEndpoint endpoint = (UMOEndpoint)router.getEndpoints().get(0);
158         this.urlWebservice = endpoint.getEndpointURI().getAddress();
159 
160         // remove any params from the url
161         int paramIndex;
162         if ((paramIndex = this.urlWebservice.indexOf("?")) != -1)
163         {
164             this.urlWebservice = this.urlWebservice.substring(0, paramIndex);
165         }
166     }
167 
168     public void initialise() throws InitialisationException
169     {
170         // if the wsdlFile property is not empty, the onCall() will use this file for WSDL requests
171         if (StringUtils.isNotBlank(this.wsdlFile))
172         {
173             try
174             {
175                 this.wsdlFileContents = IOUtils.getResourceAsString(this.wsdlFile, getClass());
176 
177                 if (StringUtils.isNotBlank(this.wsdlFileContents))
178                 {
179                     this.useFile = true;
180                     logger.info("Using file " + this.wsdlFile + " as WSDL file");
181                 }
182             }
183             catch (IOException fileError)
184             {
185                 throw new InitialisationException(CoreMessages.failedToLoad(this.wsdlFile), this);
186             }
187         }
188 
189         if (!this.useFile)
190         {
191             // if no wsdl property is set, create one which will include the original
192             // url of the webservice followed by ?WSDL
193             if (StringUtils.isBlank(this.wsdlEndpoint))
194             {
195                 this.wsdlEndpoint = this.urlWebservice.concat("?WSDL");
196                 logger.info("Defaulting to: " + this.wsdlEndpoint);
197             }
198             else
199             {
200                 logger.info("Using url " + this.wsdlEndpoint + " as WSDL");
201             }
202         }
203 
204     }
205 }