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