1
2
3
4
5
6
7 package org.mule.module.cxf;
8
9 import org.mule.api.DefaultMuleException;
10 import org.mule.api.MessagingException;
11 import org.mule.api.MuleEvent;
12 import org.mule.api.MuleException;
13 import org.mule.api.MuleMessage;
14 import org.mule.api.config.MuleProperties;
15 import org.mule.api.endpoint.EndpointURI;
16 import org.mule.api.transformer.TransformerException;
17 import org.mule.api.transport.DispatchException;
18 import org.mule.message.DefaultExceptionPayload;
19 import org.mule.module.cxf.i18n.CxfMessages;
20 import org.mule.module.cxf.security.WebServiceSecurityException;
21 import org.mule.processor.AbstractInterceptingMessageProcessor;
22 import org.mule.transport.http.HttpConnector;
23 import org.mule.transport.http.HttpConstants;
24 import org.mule.util.StringUtils;
25 import org.mule.util.TemplateParser;
26
27 import java.lang.reflect.InvocationTargetException;
28 import java.lang.reflect.Method;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.HashMap;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import java.util.regex.Pattern;
36
37 import javax.activation.DataHandler;
38 import javax.xml.namespace.QName;
39 import javax.xml.ws.BindingProvider;
40 import javax.xml.ws.Holder;
41
42 import org.apache.commons.httpclient.HttpException;
43 import org.apache.cxf.endpoint.Client;
44 import org.apache.cxf.endpoint.Endpoint;
45 import org.apache.cxf.frontend.MethodDispatcher;
46 import org.apache.cxf.interceptor.Fault;
47 import org.apache.cxf.service.model.BindingOperationInfo;
48 import org.apache.cxf.ws.addressing.WSAContextUtils;
49
50
51
52
53
54 public class CxfOutboundMessageProcessor extends AbstractInterceptingMessageProcessor
55 {
56
57 private static final String URI_REGEX = "cxf:\\[(.+?)\\]:(.+?)/\\[(.+?)\\]:(.+?)";
58 Pattern URI_PATTERN = Pattern.compile(URI_REGEX);
59
60 private final TemplateParser soapActionTemplateParser = TemplateParser.createMuleStyleParser();
61 private CxfPayloadToArguments payloadToArguments = CxfPayloadToArguments.NULL_PAYLOAD_AS_PARAMETER;
62 private Client client;
63 private boolean proxy;
64 private String operation;
65 private BindingProvider clientProxy;
66 private String decoupledEndpoint;
67
68 public CxfOutboundMessageProcessor(Client client)
69 {
70 this.client = client;
71 }
72
73 protected void cleanup()
74 {
75
76
77 Map<String, Object> requestContext = client.getRequestContext();
78 requestContext.clear();
79 Map<String, Object> responseContext = client.getResponseContext();
80 responseContext.clear();
81 }
82
83 protected Object[] getArgs(MuleEvent event) throws TransformerException
84 {
85 Object payload;
86
87 payload = event.getMessage().getPayload();
88
89 if (proxy)
90 {
91 return new Object[]{ event.getMessage() };
92 }
93
94 Object[] args = payloadToArguments.payloadToArrayOfArguments(payload);
95
96 MuleMessage message = event.getMessage();
97 Set<?> attachmentNames = message.getInboundAttachmentNames();
98 if (attachmentNames != null && !attachmentNames.isEmpty())
99 {
100 List<DataHandler> attachments = new ArrayList<DataHandler>();
101 for (Object attachmentName : attachmentNames)
102 {
103 attachments.add(message.getInboundAttachment((String)attachmentName));
104 }
105 List<Object> temp = new ArrayList<Object>(Arrays.asList(args));
106 temp.add(attachments.toArray(new DataHandler[attachments.size()]));
107 args = temp.toArray();
108 }
109
110 if (args.length == 0)
111 {
112 return null;
113 }
114 return args;
115 }
116
117 public MuleEvent process(MuleEvent event) throws MuleException
118 {
119 try
120 {
121 MuleEvent res;
122 if (!isClientProxyAvailable())
123 {
124 res = doSendWithClient(event);
125 }
126 else
127 {
128 res = doSendWithProxy(event);
129 }
130 return res;
131 }
132
133
134 catch(Fault f)
135 {
136 if(f.getCause() instanceof MuleException)
137 {
138 throw (MuleException) f.getCause();
139 }
140 throw f;
141 }
142 catch (MuleException e)
143 {
144 throw e;
145 }
146 catch (Exception e)
147 {
148 throw new DefaultMuleException(e);
149 }
150 finally
151 {
152 cleanup();
153 }
154 }
155
156
157
158
159 @Override
160 public MuleEvent processNext(MuleEvent event) throws MuleException
161 {
162 return super.processNext(event);
163 }
164
165 protected MuleEvent doSendWithProxy(MuleEvent event) throws Exception
166 {
167 Method method = getMethod(event);
168
169 Map<String, Object> props = getInovcationProperties(event);
170
171 Holder<MuleEvent> responseHolder = new Holder<MuleEvent>();
172 props.put("holder", responseHolder);
173
174
175 String soapAction = event.getMessage().getOutboundProperty(SoapConstants.SOAP_ACTION_PROPERTY);
176 if (soapAction != null)
177 {
178 soapAction = parseSoapAction(soapAction, new QName(method.getName()), event);
179 props.put(org.apache.cxf.binding.soap.SoapBindingConstants.SOAP_ACTION, soapAction);
180 }
181
182 clientProxy.getRequestContext().putAll(props);
183
184 Object response;
185 try
186 {
187 Object[] args = getArgs(event);
188 response = method.invoke(clientProxy, args);
189 }
190 catch (InvocationTargetException e)
191 {
192 Throwable ex = e.getTargetException();
193
194 if (ex != null && ex.getMessage().contains("Security"))
195 {
196 throw new WebServiceSecurityException(event, e);
197 }
198 else
199 {
200 throw e;
201 }
202 }
203
204
205 MuleEvent muleRes = responseHolder.value;
206 return buildResponseMessage(event, muleRes, new Object[]{ response });
207 }
208
209 protected MuleEvent doSendWithClient(MuleEvent event) throws Exception
210 {
211 BindingOperationInfo bop = getOperation(event);
212
213 Map<String, Object> props = getInovcationProperties(event);
214
215
216 Holder<MuleEvent> responseHolder = new Holder<MuleEvent>();
217 props.put("holder", responseHolder);
218
219
220 String soapAction = event.getMessage().getOutboundProperty(SoapConstants.SOAP_ACTION_PROPERTY);
221 if (soapAction != null)
222 {
223 soapAction = parseSoapAction(soapAction, bop.getName(), event);
224 props.put(org.apache.cxf.binding.soap.SoapBindingConstants.SOAP_ACTION, soapAction);
225 event.getMessage().setProperty(SoapConstants.SOAP_ACTION_PROPERTY, soapAction);
226 }
227
228 Map<String, Object> ctx = new HashMap<String, Object>();
229 ctx.put(Client.REQUEST_CONTEXT, props);
230 ctx.put(Client.RESPONSE_CONTEXT, props);
231
232
233 Object[] arr = event.getMessage().getPropertyNames().toArray();
234 String head;
235
236 for (int i = 0; i < arr.length; i++)
237 {
238 head = (String)arr[i];
239 if ((head != null) && (!head.startsWith("MULE")))
240 {
241 props.put((String)arr[i], event.getMessage().getProperty((String)arr[i]));
242 }
243 }
244
245 Object[] response = client.invoke(bop, getArgs(event), ctx);
246
247 return buildResponseMessage(event, responseHolder.value, response);
248 }
249
250 public Method getMethod(MuleEvent event) throws Exception
251 {
252 Method method = null;
253 if (method == null)
254 {
255 String opName = (String)event.getMessage().getProperty(CxfConstants.OPERATION);
256 if (opName != null)
257 {
258 method = getMethodFromOperation(opName);
259 }
260
261 if (method == null)
262 {
263 opName = operation;
264 if (opName != null)
265 {
266 method = getMethodFromOperation(opName);
267 }
268 }
269 }
270
271 if (method == null)
272 {
273 throw new MessagingException(CxfMessages.noOperationWasFoundOrSpecified(), event);
274 }
275 return method;
276 }
277
278 protected BindingOperationInfo getOperation(final String opName) throws Exception
279 {
280
281
282
283 Endpoint ep = client.getEndpoint();
284 BindingOperationInfo bop = getBindingOperationFromEndpoint(ep, opName);
285 if (bop == null)
286 {
287 bop = tryToGetTheOperationInDotNetNamingConvention(ep, opName);
288 if (bop == null)
289 {
290 throw new Exception("No such operation: " + opName);
291 }
292 }
293
294 if (bop.isUnwrappedCapable())
295 {
296 bop = bop.getUnwrappedOperation();
297 }
298 return bop;
299 }
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314 protected BindingOperationInfo tryToGetTheOperationInDotNetNamingConvention(Endpoint ep,
315 final String opName)
316 {
317 final String capitalizedOpName = opName.substring(0, 1).toUpperCase() + opName.substring(1);
318 return getBindingOperationFromEndpoint(ep, capitalizedOpName);
319 }
320
321 protected BindingOperationInfo getBindingOperationFromEndpoint(Endpoint ep, final String operationName)
322 {
323 QName q = new QName(ep.getService().getName().getNamespaceURI(), operationName);
324 BindingOperationInfo bop = ep.getBinding().getBindingInfo().getOperation(q);
325 return bop;
326 }
327
328 private Method getMethodFromOperation(String op) throws Exception
329 {
330 BindingOperationInfo bop = getOperation(op);
331 MethodDispatcher md = (MethodDispatcher)client.getEndpoint()
332 .getService()
333 .get(MethodDispatcher.class.getName());
334 return md.getMethod(bop);
335 }
336
337 protected String getMethodOrOperationName(MuleEvent event) throws DispatchException
338 {
339
340
341
342 String method = event.getMessage().getInvocationProperty(CxfConstants.OPERATION);
343
344 if (method == null)
345 {
346 method = event.getMessage().getInvocationProperty(MuleProperties.MULE_METHOD_PROPERTY);
347 }
348
349 if (method == null)
350 {
351 method = operation;
352 }
353
354 if (method == null && proxy)
355 {
356 return "invoke";
357 }
358
359 return method;
360 }
361
362 public BindingOperationInfo getOperation(MuleEvent event) throws Exception
363 {
364 String opName = getMethodOrOperationName(event);
365
366 if (opName == null)
367 {
368 opName = operation;
369 }
370
371 return getOperation(opName);
372 }
373
374 private Map<String, Object> getInovcationProperties(MuleEvent event)
375 {
376 Map<String, Object> props = new HashMap<String, Object>();
377 props.put(CxfConstants.MULE_EVENT, event);
378 props.put(CxfConstants.CXF_OUTBOUND_MESSAGE_PROCESSOR, this);
379 props.put(org.apache.cxf.message.Message.ENDPOINT_ADDRESS, event.getEndpoint().getEndpointURI().toString());
380
381 if (decoupledEndpoint != null)
382 {
383 props.put(WSAContextUtils.REPLYTO_PROPERTY, decoupledEndpoint);
384 }
385
386 return props;
387 }
388
389 protected MuleEvent buildResponseMessage(MuleEvent request, MuleEvent transportResponse, Object[] response)
390 {
391
392 if (transportResponse == null)
393 {
394 return null;
395 }
396
397
398 Object payload;
399 if (response == null || response.length == 0)
400 {
401 payload = null;
402 }
403 else if (response.length == 1)
404 {
405 payload = response[0];
406 }
407 else
408 {
409 payload = response;
410 }
411
412 MuleMessage message = transportResponse.getMessage();
413
414 String httpStatusCode = message.getInboundProperty(HttpConnector.HTTP_STATUS_PROPERTY);
415 if(isProxy() && httpStatusCode != null)
416 {
417 message.setOutboundProperty(HttpConnector.HTTP_STATUS_PROPERTY, httpStatusCode);
418 }
419
420 message.setPayload(payload);
421
422 return transportResponse;
423 }
424
425 public String parseSoapAction(String soapAction, QName method, MuleEvent event)
426 {
427 EndpointURI endpointURI = event.getEndpoint().getEndpointURI();
428 Map<String, String> properties = new HashMap<String, String>();
429 MuleMessage msg = event.getMessage();
430
431 for (String name : msg.getInvocationPropertyNames())
432 {
433 final String value = msg.getInvocationProperty(name, StringUtils.EMPTY);
434 properties.put(name, value);
435 }
436 for (String name : msg.getOutboundPropertyNames())
437 {
438 final String value = msg.getOutboundProperty(name, StringUtils.EMPTY);
439 properties.put(name, value);
440 }
441 properties.put(MuleProperties.MULE_METHOD_PROPERTY, method.getLocalPart());
442 properties.put("methodNamespace", method.getNamespaceURI());
443 properties.put("address", endpointURI.getAddress());
444 properties.put("scheme", endpointURI.getScheme());
445 properties.put("host", endpointURI.getHost());
446 properties.put("port", String.valueOf(endpointURI.getPort()));
447 properties.put("path", endpointURI.getPath());
448 properties.put("hostInfo",
449 endpointURI.getScheme() + "://" + endpointURI.getHost()
450 + (endpointURI.getPort() > -1 ? ":" + String.valueOf(endpointURI.getPort()) : ""));
451 if (event.getFlowConstruct() != null)
452 {
453 properties.put("serviceName", event.getFlowConstruct().getName());
454 }
455
456 soapAction = soapActionTemplateParser.parse(properties, soapAction);
457
458 if (logger.isDebugEnabled())
459 {
460 logger.debug("SoapAction for this call is: " + soapAction);
461 }
462
463 return soapAction;
464 }
465
466 public void setPayloadToArguments(CxfPayloadToArguments payloadToArguments)
467 {
468 this.payloadToArguments = payloadToArguments;
469 }
470
471 protected boolean isClientProxyAvailable()
472 {
473 return clientProxy != null;
474 }
475
476 public boolean isProxy()
477 {
478 return proxy;
479 }
480
481 public void setProxy(boolean proxy)
482 {
483 this.proxy = proxy;
484 }
485
486 public String getOperation()
487 {
488 return operation;
489 }
490
491 public void setOperation(String operation)
492 {
493 this.operation = operation;
494 }
495
496 public void setClientProxy(BindingProvider clientProxy)
497 {
498 this.clientProxy = clientProxy;
499 }
500
501 public CxfPayloadToArguments getPayloadToArguments()
502 {
503 return payloadToArguments;
504 }
505
506 public Client getClient()
507 {
508 return client;
509 }
510
511 public void setDecoupledEndpoint(String decoupledEndpoint)
512 {
513 this.decoupledEndpoint = decoupledEndpoint;
514 }
515
516 }