1
2
3
4
5
6
7
8
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
45
46
47
48
49
50
51
52
53
54
55
56
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 this(name, muleContext, messageSource, outboundEndpoint, new DynamicWsdlProxyRequestProcessor(
69 outboundEndpoint));
70 }
71
72 public WSProxy(String name,
73 MuleContext muleContext,
74 MessageSource messageSource,
75 OutboundEndpoint outboundEndpoint,
76 String wsdlContents) throws MuleException
77 {
78 this(name, muleContext, messageSource, outboundEndpoint, new StaticWsdlProxyRequestProcessor(
79 wsdlContents));
80 }
81
82 public WSProxy(String name,
83 MuleContext muleContext,
84 MessageSource messageSource,
85 OutboundEndpoint outboundEndpoint,
86 URI wsdlUri) throws MuleException
87 {
88 this(name, muleContext, messageSource, outboundEndpoint,
89 new DynamicWsdlProxyRequestProcessor(wsdlUri));
90 }
91
92 private WSProxy(String name,
93 MuleContext muleContext,
94 MessageSource messageSource,
95 OutboundEndpoint outboundEndpoint,
96 AbstractProxyRequestProcessor proxyMessageProcessor) throws MuleException
97 {
98 super(name, muleContext);
99
100 if (messageSource == null)
101 {
102 throw new FlowConstructInvalidException(
103 MessageFactory.createStaticMessage("messageSource can't be null on: " + this.toString()),
104 this);
105 }
106
107 super.setMessageSource(messageSource);
108
109 if (outboundEndpoint == null)
110 {
111 throw new FlowConstructInvalidException(
112 MessageFactory.createStaticMessage("outboundEndpoint can't be null on: " + this.toString()),
113 this);
114 }
115
116 this.outboundEndpoint = outboundEndpoint;
117
118 this.proxyMessageProcessor = proxyMessageProcessor;
119 }
120
121 @Override
122 protected void configureMessageProcessors(MessageProcessorChainBuilder builder)
123 {
124 builder.chain(new ProcessingTimeInterceptor());
125 builder.chain(new LoggingInterceptor());
126 builder.chain(new FlowConstructStatisticsMessageProcessor());
127 builder.chain(proxyMessageProcessor);
128 builder.chain(new StopFurtherMessageProcessingMessageProcessor());
129 builder.chain(new TransformerTemplate(new CopyInboundToOutboundPropertiesTransformerCallback()));
130 builder.chain(outboundEndpoint);
131 }
132
133 @Override
134 protected void validateConstruct() throws FlowConstructInvalidException
135 {
136 super.validateConstruct();
137
138 if ((messageSource instanceof InboundEndpoint)
139 && (!((InboundEndpoint) messageSource).getExchangePattern().equals(
140 MessageExchangePattern.REQUEST_RESPONSE)))
141 {
142 throw new FlowConstructInvalidException(
143 MessageFactory.createStaticMessage("WSProxy only works with a request-response inbound endpoint."),
144 this);
145 }
146
147 if (!outboundEndpoint.getExchangePattern().equals(MessageExchangePattern.REQUEST_RESPONSE))
148 {
149 throw new FlowConstructInvalidException(
150 MessageFactory.createStaticMessage("WSProxy only works with a request-response outbound endpoint."),
151 this);
152 }
153 }
154
155 private static final class CopyInboundToOutboundPropertiesTransformerCallback
156 implements TransformerCallback
157 {
158 public Object doTransform(MuleMessage message) throws Exception
159 {
160 for (final String inboundPropertyName : message.getInboundPropertyNames())
161 {
162 message.setOutboundProperty(inboundPropertyName,
163 message.getInboundProperty(inboundPropertyName));
164 }
165
166 return message;
167 }
168 }
169
170 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 protected final Log logger = LogFactory.getLog(WSProxy.class);
177
178 public MuleEvent process(MuleEvent event) throws MuleException
179 {
180 if (isWsdlRequest(event))
181 {
182 return buildWsdlResult(event);
183 }
184
185 if (logger.isDebugEnabled())
186 {
187 logger.debug("Forwarding SOAP message");
188 }
189
190 return event;
191 }
192
193 private MuleEvent buildWsdlResult(MuleEvent event) throws MuleException
194 {
195 try
196 {
197 final String wsdlContents = getWsdlContents(event);
198 event.getMessage().setPayload(wsdlContents);
199
200
201
202 event.setStopFurtherProcessing(true);
203 return event;
204 }
205 catch (final Exception e)
206 {
207 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
216
217 final String httpRequest = event.getMessage().<String> getInboundProperty(HTTP_REQUEST);
218
219 if (httpRequest == null)
220 {
221 logger.warn("WS Proxy can't rewrite WSDL for non-HTTP " + event);
222 return false;
223 }
224
225 final String lowerHttpRequest = httpRequest.toLowerCase();
226
227
228 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
241
242
243
244
245
246 StaticWsdlProxyRequestProcessor(String wsdlContents) throws FlowConstructInvalidException
247 {
248 if (StringUtils.isBlank(wsdlContents))
249 {
250 throw new FlowConstructInvalidException(
251 MessageFactory.createStaticMessage("wsdlContents can't be empty"));
252 }
253
254 this.wsdlContents = wsdlContents;
255 }
256
257 @Override
258 protected String getWsdlContents(MuleEvent event) throws Exception
259 {
260 if (logger.isDebugEnabled())
261 {
262 logger.debug("Serving static WSDL");
263 }
264
265 return wsdlContents;
266 }
267 }
268
269 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
281
282
283
284
285
286 DynamicWsdlProxyRequestProcessor(final URI wsdlUri) throws FlowConstructInvalidException
287 {
288 if (wsdlUri == null)
289 {
290 throw new FlowConstructInvalidException(
291 MessageFactory.createStaticMessage("wsdlUri can't be null"));
292 }
293
294 final String wsdlAddress = wsdlUri.toString();
295
296 wsdlAddressProvider = new WsdlAddressProvider()
297 {
298 public String get(MuleEvent event)
299 {
300 return wsdlAddress;
301 }
302 };
303
304 logger.info("Using url " + wsdlAddress + " as WSDL");
305 }
306
307
308
309
310
311
312
313
314 DynamicWsdlProxyRequestProcessor(OutboundEndpoint outboundEndpoint)
315 throws FlowConstructInvalidException
316 {
317 if (outboundEndpoint == null)
318 {
319 throw new FlowConstructInvalidException(
320 MessageFactory.createStaticMessage("outboundEndpoint can't be null"));
321 }
322
323 final String wsAddress = outboundEndpoint.getAddress();
324
325 if (outboundEndpoint instanceof DynamicOutboundEndpoint)
326 {
327 wsdlAddressProvider = new WsdlAddressProvider()
328 {
329 public String get(MuleEvent event)
330 {
331 final String resolvedWsAddress = event.getMuleContext().getExpressionManager().parse(
332 wsAddress, event.getMessage(), true);
333
334 return makeWsdlAddress(resolvedWsAddress);
335 }
336 };
337
338 logger.info("Using dynamic WSDL with service address: " + wsAddress);
339 }
340 else
341 {
342 final String wsdlAddress = makeWsdlAddress(wsAddress);
343
344 wsdlAddressProvider = new WsdlAddressProvider()
345 {
346 public String get(MuleEvent event)
347 {
348 return wsdlAddress;
349 }
350 };
351
352 logger.info("Setting WSDL address to: " + wsdlAddress);
353 }
354 }
355
356 private static String makeWsdlAddress(String wsAddress)
357 {
358 return StringUtils.substringBefore(wsAddress, "?").concat("?wsdl");
359 }
360
361 @Override
362 protected String getWsdlContents(MuleEvent event) throws Exception
363 {
364 final String wsdlAddress = wsdlAddressProvider.get(event);
365 String wsdlString;
366
367 final MuleContext muleContext = event.getMuleContext();
368 final InboundEndpoint webServiceEndpoint = muleContext.getRegistry()
369 .lookupEndpointFactory()
370 .getInboundEndpoint(wsdlAddress);
371
372 if (logger.isDebugEnabled())
373 {
374 logger.debug("Retrieving WSDL from web service with: " + webServiceEndpoint);
375 }
376
377 final MuleMessage replyWSDL = webServiceEndpoint.request(event.getTimeout());
378 wsdlString = replyWSDL.getPayloadAsString();
379
380
381 final String realWsdlAddress = wsdlAddress.split("\\?")[0];
382 final String proxyWsdlAddress = event.getEndpoint().getEndpointURI().getUri().toString();
383 wsdlString = wsdlString.replaceAll(realWsdlAddress, proxyWsdlAddress);
384
385 if (wsdlString.indexOf(LOCALHOST) > -1)
386 {
387 wsdlString = wsdlString.replaceAll(LOCALHOST, InetAddress.getLocalHost().getHostName());
388 }
389
390 if (logger.isDebugEnabled())
391 {
392 logger.debug("WSDL retrieved successfully");
393 }
394
395 return wsdlString;
396 }
397 }
398
399 @Override
400 public String toString()
401 {
402 return ObjectUtils.toString(this);
403 }
404
405 @Override
406 public String getConstructType()
407 {
408 return "Web-Service-Proxy";
409 }
410 }