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