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.transformer.TransformerException;
20 import org.mule.api.transport.DispatchException;
21 import org.mule.message.DefaultExceptionPayload;
22 import org.mule.module.cxf.i18n.CxfMessages;
23 import org.mule.module.cxf.security.WebServiceSecurityException;
24 import org.mule.processor.AbstractInterceptingMessageProcessor;
25 import org.mule.transport.http.HttpConnector;
26 import org.mule.transport.http.HttpConstants;
27 import org.mule.util.TemplateParser;
28
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.regex.Pattern;
38
39 import javax.activation.DataHandler;
40 import javax.xml.namespace.QName;
41 import javax.xml.ws.BindingProvider;
42 import javax.xml.ws.Holder;
43
44 import org.apache.commons.httpclient.HttpException;
45 import org.apache.cxf.endpoint.Client;
46 import org.apache.cxf.endpoint.Endpoint;
47 import org.apache.cxf.frontend.MethodDispatcher;
48 import org.apache.cxf.service.model.BindingOperationInfo;
49 import org.apache.cxf.ws.addressing.WSAContextUtils;
50
51
52
53
54
55 public class CxfOutboundMessageProcessor extends AbstractInterceptingMessageProcessor
56 {
57
58 private static final String URI_REGEX = "cxf:\\[(.+?)\\]:(.+?)/\\[(.+?)\\]:(.+?)";
59 Pattern URI_PATTERN = Pattern.compile(URI_REGEX);
60
61 private final TemplateParser soapActionTemplateParser = TemplateParser.createMuleStyleParser();
62 private CxfPayloadToArguments payloadToArguments = CxfPayloadToArguments.NULL_PAYLOAD_AS_PARAMETER;
63 private Client client;
64 private boolean proxy;
65 private String operation;
66 private BindingProvider clientProxy;
67 private String decoupledEndpoint;
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 super.processNext(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
162 String soapAction = event.getMessage().getOutboundProperty(SoapConstants.SOAP_ACTION_PROPERTY);
163 if (soapAction != null)
164 {
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 Map<String, Object> ctx = new HashMap<String, Object>();
206 ctx.put(Client.REQUEST_CONTEXT, props);
207 ctx.put(Client.RESPONSE_CONTEXT, props);
208
209
210 Object[] arr = event.getMessage().getPropertyNames().toArray();
211 String head;
212
213 for (int i = 0; i < arr.length; i++)
214 {
215 head = (String)arr[i];
216 if ((head != null) && (!head.startsWith("MULE")))
217 {
218 props.put((String)arr[i], event.getMessage().getProperty((String)arr[i]));
219 }
220 }
221
222 Object[] response = client.invoke(bop, getArgs(event), ctx);
223
224 return buildResponseMessage(event, responseHolder.value, response);
225 }
226
227 public Method getMethod(MuleEvent event) throws Exception
228 {
229 Method method = null;
230 if (method == null)
231 {
232 String opName = (String)event.getMessage().getProperty(CxfConstants.OPERATION);
233 if (opName != null)
234 {
235 method = getMethodFromOperation(opName);
236 }
237
238 if (method == null)
239 {
240 opName = operation;
241 if (opName != null)
242 {
243 method = getMethodFromOperation(opName);
244 }
245 }
246 }
247
248 if (method == null)
249 {
250 throw new MessagingException(CxfMessages.noOperationWasFoundOrSpecified(), event);
251 }
252 return method;
253 }
254
255 protected BindingOperationInfo getOperation(final String opName) throws Exception
256 {
257
258
259
260 Endpoint ep = client.getEndpoint();
261 BindingOperationInfo bop = getBindingOperationFromEndpoint(ep, opName);
262 if (bop == null)
263 {
264 bop = tryToGetTheOperationInDotNetNamingConvention(ep, opName);
265 if (bop == null)
266 {
267 throw new Exception("No such operation: " + opName);
268 }
269 }
270
271 if (bop.isUnwrappedCapable())
272 {
273 bop = bop.getUnwrappedOperation();
274 }
275 return bop;
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291 protected BindingOperationInfo tryToGetTheOperationInDotNetNamingConvention(Endpoint ep,
292 final String opName)
293 {
294 final String capitalizedOpName = opName.substring(0, 1).toUpperCase() + opName.substring(1);
295 return getBindingOperationFromEndpoint(ep, capitalizedOpName);
296 }
297
298 protected BindingOperationInfo getBindingOperationFromEndpoint(Endpoint ep, final String operationName)
299 {
300 QName q = new QName(ep.getService().getName().getNamespaceURI(), operationName);
301 BindingOperationInfo bop = ep.getBinding().getBindingInfo().getOperation(q);
302 return bop;
303 }
304
305 private Method getMethodFromOperation(String op) throws Exception
306 {
307 BindingOperationInfo bop = getOperation(op);
308 MethodDispatcher md = (MethodDispatcher)client.getEndpoint()
309 .getService()
310 .get(MethodDispatcher.class.getName());
311 return md.getMethod(bop);
312 }
313
314 protected String getMethodOrOperationName(MuleEvent event) throws DispatchException
315 {
316
317
318
319 String method = event.getMessage().getInvocationProperty(CxfConstants.OPERATION);
320
321 if (method == null)
322 {
323 method = event.getMessage().getInvocationProperty(MuleProperties.MULE_METHOD_PROPERTY);
324 }
325
326 if (method == null)
327 {
328 method = operation;
329 }
330
331 if (method == null && proxy)
332 {
333 return "invoke";
334 }
335
336 return method;
337 }
338
339 public BindingOperationInfo getOperation(MuleEvent event) throws Exception
340 {
341 String opName = getMethodOrOperationName(event);
342
343 if (opName == null)
344 {
345 opName = operation;
346 }
347
348 return getOperation(opName);
349 }
350
351 private Map<String, Object> getInovcationProperties(MuleEvent event)
352 {
353 Map<String, Object> props = new HashMap<String, Object>();
354 props.put(CxfConstants.MULE_EVENT, event);
355 props.put(CxfConstants.CXF_OUTBOUND_MESSAGE_PROCESSOR, this);
356
357
358 if (decoupledEndpoint != null)
359 {
360 props.put(WSAContextUtils.REPLYTO_PROPERTY, decoupledEndpoint);
361 }
362
363 return props;
364 }
365
366 protected MuleEvent buildResponseMessage(MuleEvent request, MuleEvent transportResponse, Object[] response)
367 {
368
369 if (transportResponse == null)
370 {
371 return null;
372 }
373
374
375 Object payload;
376 if (response == null || response.length == 0)
377 {
378 payload = null;
379 }
380 else if (response.length == 1)
381 {
382 payload = response[0];
383 }
384 else
385 {
386 payload = response;
387 }
388
389 MuleMessage message = transportResponse.getMessage();
390 String statusCode = message.getInboundProperty(HttpConnector.HTTP_STATUS_PROPERTY);
391 if (statusCode != null && Integer.parseInt(statusCode) != HttpConstants.SC_OK)
392 {
393 String exPayload;
394 try
395 {
396 exPayload = message.getPayloadAsString();
397 }
398 catch (Exception e)
399 {
400 exPayload = "Invalid status code: " + statusCode;
401 }
402 message.setExceptionPayload(new DefaultExceptionPayload(new HttpException(exPayload)));
403 }
404 else
405 {
406 message.setPayload(payload);
407 }
408
409 return transportResponse;
410 }
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453 public void setPayloadToArguments(CxfPayloadToArguments payloadToArguments)
454 {
455 this.payloadToArguments = payloadToArguments;
456 }
457
458 protected boolean isClientProxyAvailable()
459 {
460 return clientProxy != null;
461 }
462
463 public boolean isProxy()
464 {
465 return proxy;
466 }
467
468 public void setProxy(boolean proxy)
469 {
470 this.proxy = proxy;
471 }
472
473 public String getOperation()
474 {
475 return operation;
476 }
477
478 public void setOperation(String operation)
479 {
480 this.operation = operation;
481 }
482
483 public void setClientProxy(BindingProvider clientProxy)
484 {
485 this.clientProxy = clientProxy;
486 }
487
488 public CxfPayloadToArguments getPayloadToArguments()
489 {
490 return payloadToArguments;
491 }
492
493 public Client getClient()
494 {
495 return client;
496 }
497
498 public void setDecoupledEndpoint(String decoupledEndpoint)
499 {
500 this.decoupledEndpoint = decoupledEndpoint;
501 }
502
503 }