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