1
2
3
4
5
6
7
8
9
10
11 package org.mule.module.cxf.transport;
12
13 import org.mule.DefaultMuleEvent;
14 import org.mule.DefaultMuleMessage;
15 import org.mule.RequestContext;
16 import org.mule.api.MuleContext;
17 import org.mule.api.MuleEvent;
18 import org.mule.api.MuleException;
19 import org.mule.api.MuleMessage;
20 import org.mule.api.MuleSession;
21 import org.mule.api.endpoint.OutboundEndpoint;
22 import org.mule.api.transformer.TransformerException;
23 import org.mule.api.transport.OutputHandler;
24 import org.mule.module.cxf.CxfConfiguration;
25 import org.mule.module.cxf.CxfConstants;
26 import org.mule.module.cxf.CxfOutboundMessageProcessor;
27 import org.mule.module.cxf.support.DelegatingOutputStream;
28 import org.mule.module.cxf.support.MuleProtocolHeadersOutInterceptor;
29 import org.mule.session.DefaultMuleSession;
30 import org.mule.transformer.types.DataTypeFactory;
31 import org.mule.transport.NullPayload;
32 import org.mule.transport.http.HttpConnector;
33 import org.mule.transport.http.HttpConstants;
34
35 import java.io.ByteArrayOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.OutputStream;
39 import java.io.PushbackInputStream;
40 import java.net.HttpURLConnection;
41 import java.net.MalformedURLException;
42 import java.util.HashMap;
43 import java.util.Map;
44 import java.util.logging.Logger;
45
46 import javax.xml.ws.BindingProvider;
47 import javax.xml.ws.Holder;
48
49 import org.apache.cxf.common.logging.LogUtils;
50 import org.apache.cxf.endpoint.ClientImpl;
51 import org.apache.cxf.interceptor.Fault;
52 import org.apache.cxf.message.Exchange;
53 import org.apache.cxf.message.ExchangeImpl;
54 import org.apache.cxf.message.Message;
55 import org.apache.cxf.message.MessageImpl;
56 import org.apache.cxf.phase.AbstractPhaseInterceptor;
57 import org.apache.cxf.phase.Phase;
58 import org.apache.cxf.service.model.EndpointInfo;
59 import org.apache.cxf.transport.AbstractConduit;
60 import org.apache.cxf.transport.Destination;
61 import org.apache.cxf.transport.MessageObserver;
62 import org.apache.cxf.ws.addressing.AttributedURIType;
63 import org.apache.cxf.ws.addressing.EndpointReferenceType;
64 import org.apache.cxf.wsdl.EndpointReferenceUtils;
65
66 import static org.apache.cxf.message.Message.DECOUPLED_CHANNEL_MESSAGE;
67 import static org.mule.api.config.MuleProperties.MULE_EVENT_PROPERTY;
68
69
70
71
72
73
74 public class MuleUniversalConduit extends AbstractConduit
75 {
76
77 private static final Logger LOGGER = LogUtils.getL7dLogger(MuleUniversalConduit.class);
78
79 private EndpointInfo endpoint;
80
81 private CxfConfiguration configuration;
82
83 private Destination decoupledDestination;
84
85 private String decoupledEndpoint;
86
87 private MuleUniversalTransport transport;
88
89 private int decoupledDestinationRefCount;
90
91 private boolean closeInput = true;
92
93 private Map<String,OutboundEndpoint> endpoints = new HashMap<String, OutboundEndpoint>();
94
95
96
97
98
99 public MuleUniversalConduit(MuleUniversalTransport transport,
100 CxfConfiguration configuration,
101 EndpointInfo ei,
102 EndpointReferenceType t)
103 {
104 super(getTargetReference(ei, t));
105 this.transport = transport;
106 this.endpoint = ei;
107 this.configuration = configuration;
108 }
109
110 @Override
111 public void close(Message msg) throws IOException
112 {
113 OutputStream os = msg.getContent(OutputStream.class);
114 if (os != null)
115 {
116 os.close();
117 }
118
119 if (closeInput)
120 {
121 InputStream in = msg.getContent(InputStream.class);
122 if (in != null)
123 {
124 in.close();
125 }
126 }
127 }
128
129 @Override
130 protected Logger getLogger()
131 {
132 return LOGGER;
133 }
134
135 @Override
136 public synchronized Destination getBackChannel()
137 {
138 if (decoupledDestination == null && decoupledEndpoint != null)
139 {
140 setUpDecoupledDestination();
141 }
142 return decoupledDestination;
143 }
144
145 protected void setUpDecoupledDestination()
146 {
147 EndpointInfo ei = new EndpointInfo();
148 ei.setAddress(decoupledEndpoint);
149 try
150 {
151 decoupledDestination = transport.getDestination(ei);
152 decoupledDestination.setMessageObserver(new InterposedMessageObserver());
153 duplicateDecoupledDestination();
154 }
155 catch (IOException e)
156 {
157 throw new RuntimeException(e);
158 }
159 }
160
161
162
163
164 public void prepare(final Message message) throws IOException
165 {
166
167 final ByteArrayOutputStream cache = new ByteArrayOutputStream();
168 final DelegatingOutputStream delegating = new DelegatingOutputStream(cache);
169 message.setContent(OutputStream.class, delegating);
170 message.setContent(DelegatingOutputStream.class, delegating);
171
172 AbstractPhaseInterceptor<Message> i = new AbstractPhaseInterceptor<Message>(Phase.PRE_STREAM)
173 {
174 public void handleMessage(Message m) throws Fault
175 {
176 try
177 {
178 dispatchMuleMessage(m);
179 }
180 catch (IOException e)
181 {
182 throw new Fault(e);
183 }
184 }
185 };
186 i.getAfter().add(MuleProtocolHeadersOutInterceptor.class.getName());
187 message.getInterceptorChain().add(i);
188
189 OutputHandler handler = new OutputHandler()
190 {
191 public void write(MuleEvent event, OutputStream out) throws IOException
192 {
193 out.write(cache.toByteArray());
194
195 delegating.setOutputStream(out);
196
197
198 message.getInterceptorChain().doIntercept(message);
199 }
200 };
201
202 MuleEvent event = (MuleEvent) message.getExchange().get(MULE_EVENT_PROPERTY);
203 if (event == null)
204 {
205 MuleContext muleContext = configuration.getMuleContext();
206 MuleMessage muleMsg = new DefaultMuleMessage(handler, muleContext);
207 MuleSession session = new DefaultMuleSession(muleContext);
208
209 String url = setupURL(message);
210
211 try
212 {
213 OutboundEndpoint ep = getEndpoint(muleContext, url);
214 event = new DefaultMuleEvent(muleMsg, ep, session);
215 }
216 catch (Exception e)
217 {
218 throw new Fault(e);
219 }
220 event.setTimeout(MuleEvent.TIMEOUT_NOT_SET_VALUE);
221 RequestContext.setEvent(event);
222 }
223 else
224 {
225 event.getMessage().setPayload(handler);
226 }
227 message.getExchange().put(CxfConstants.MULE_EVENT, event);
228 }
229
230 protected synchronized OutboundEndpoint getEndpoint(MuleContext muleContext, String uri) throws MuleException
231 {
232 if (endpoints.get(uri) != null)
233 {
234 return endpoints.get(uri);
235 }
236
237 OutboundEndpoint ndpoint = muleContext.getRegistry().lookupEndpointFactory().getOutboundEndpoint(uri);
238 endpoints.put(uri, ndpoint);
239 return ndpoint;
240 }
241
242 protected String setupURL(Message message) throws MalformedURLException
243 {
244 String value = (String) message.get(Message.ENDPOINT_ADDRESS);
245 String pathInfo = (String) message.get(Message.PATH_INFO);
246 String queryString = (String) message.get(Message.QUERY_STRING);
247 String username = (String) message.get(BindingProvider.USERNAME_PROPERTY);
248 String password = (String) message.get(BindingProvider.PASSWORD_PROPERTY);
249
250 String result = value != null ? value : getTargetOrEndpoint();
251
252 if (username != null) {
253 int slashIdx = result.indexOf("//");
254 if (slashIdx != -1) {
255 result = result.substring(0, slashIdx + 2) + username + ":" + password + "@" + result.substring(slashIdx+2);
256 }
257 }
258
259
260 if (null != pathInfo && !result.endsWith(pathInfo))
261 {
262 result = result + pathInfo;
263 }
264 if (queryString != null)
265 {
266 result = result + "?" + queryString;
267 }
268 return result;
269 }
270
271 protected void dispatchMuleMessage(Message m) throws IOException {
272 try
273 {
274 MuleEvent reqEvent = (MuleEvent) m.getExchange().get(CxfConstants.MULE_EVENT);
275
276 MuleMessage req = reqEvent.getMessage();
277 req.setOutboundProperty(HttpConnector.HTTP_DISABLE_STATUS_CODE_EXCEPTION_CHECK, Boolean.TRUE.toString());
278
279 MuleEvent resEvent = processNext(reqEvent, m.getExchange());
280
281 if (resEvent == null || !reqEvent.getEndpoint().getExchangePattern().hasResponse())
282 {
283 m.getExchange().put(ClientImpl.FINISHED, Boolean.TRUE);
284 return;
285 }
286
287
288 MuleMessage result = resEvent.getMessage();
289 InputStream is = getResponseBody(m, result);
290 if (is != null)
291 {
292 Message inMessage = new MessageImpl();
293
294 String encoding = result.getEncoding();
295 inMessage.put(Message.ENCODING, encoding);
296 String contentType = result.getOutboundProperty(HttpConstants.HEADER_CONTENT_TYPE, "text/xml");
297 if (encoding != null && contentType.indexOf("charset") < 0)
298 {
299 contentType += "; charset=" + result.getEncoding();
300 }
301 inMessage.put(Message.CONTENT_TYPE, contentType);
302 inMessage.put(CxfConstants.MULE_EVENT, resEvent);
303 inMessage.setContent(InputStream.class, is);
304 inMessage.setExchange(m.getExchange());
305 getMessageObserver().onMessage(inMessage);
306 }
307 }
308 catch (Exception e)
309 {
310 if (e instanceof IOException)
311 {
312 throw (IOException) e;
313 }
314
315 IOException ex = new IOException("Could not send message to Mule.");
316 ex.initCause(e);
317 throw ex;
318 }
319 }
320
321 protected InputStream getResponseBody(Message m, MuleMessage result) throws TransformerException, IOException
322 {
323 boolean response = result != null
324 && !NullPayload.getInstance().equals(result.getPayload())
325 && !isOneway(m.getExchange());
326
327 if (response)
328 {
329
330
331 InputStream is = result.getPayload(DataTypeFactory.create(InputStream.class));
332 PushbackInputStream pb = new PushbackInputStream(is);
333 result.setPayload(pb);
334
335 int b = pb.read();
336 if (b != -1)
337 {
338 pb.unread(b);
339 return pb;
340 }
341 }
342
343 return null;
344 }
345
346 protected boolean isOneway(Exchange exchange)
347 {
348 return exchange != null && exchange.isOneWay();
349 }
350
351 protected String getTargetOrEndpoint()
352 {
353 if (target != null)
354 {
355 return target.getAddress().getValue();
356 }
357
358 return endpoint.getAddress().toString();
359 }
360
361 public void onClose(final Message m) throws IOException
362 {
363
364 }
365
366 protected MuleEvent processNext(MuleEvent event,
367 Exchange exchange) throws MuleException
368 {
369 CxfOutboundMessageProcessor processor = (CxfOutboundMessageProcessor) exchange.get(CxfConstants.CXF_OUTBOUND_MESSAGE_PROCESSOR);
370 MuleEvent response;
371 if (processor == null)
372 {
373
374 OutboundEndpoint ep = (OutboundEndpoint) event.getEndpoint();
375 response = ep.process(event);
376 }
377 else
378 {
379 response = processor.processNext(event);
380
381 Holder<MuleEvent> holder = (Holder<MuleEvent>) exchange.get("holder");
382 holder.value = response;
383 }
384
385 return response;
386 }
387
388 @Override
389 public void close()
390 {
391
392
393
394 if (decoupledDestination != null)
395 {
396 releaseDecoupledDestination();
397 }
398 }
399
400 protected synchronized void duplicateDecoupledDestination()
401 {
402 decoupledDestinationRefCount++;
403 }
404
405 protected synchronized void releaseDecoupledDestination()
406 {
407 if (--decoupledDestinationRefCount == 0)
408 {
409
410 decoupledDestination.shutdown();
411 }
412 }
413
414 public String getDecoupledEndpoint()
415 {
416 return decoupledEndpoint;
417 }
418
419 public void setDecoupledEndpoint(String decoupledEndpoint)
420 {
421 this.decoupledEndpoint = decoupledEndpoint;
422 }
423
424
425
426
427
428
429
430
431 protected static EndpointReferenceType getTargetReference(EndpointInfo ei, EndpointReferenceType t)
432 {
433 EndpointReferenceType ref = null;
434 if (null == t)
435 {
436 ref = new EndpointReferenceType();
437 AttributedURIType address = new AttributedURIType();
438 address.setValue(ei.getAddress());
439 ref.setAddress(address);
440 if (ei.getService() != null)
441 {
442 EndpointReferenceUtils.setServiceAndPortName(ref, ei.getService().getName(), ei.getName()
443 .getLocalPart());
444 }
445 }
446 else
447 {
448 ref = t;
449 }
450 return ref;
451 }
452
453
454
455
456
457
458 protected class InterposedMessageObserver implements MessageObserver
459 {
460
461
462
463
464
465 public void onMessage(Message inMessage)
466 {
467
468 inMessage.setExchange(new ExchangeImpl());
469 inMessage.put(DECOUPLED_CHANNEL_MESSAGE, Boolean.TRUE);
470 inMessage.put(Message.RESPONSE_CODE, HttpURLConnection.HTTP_OK);
471 inMessage.remove(Message.ASYNC_POST_RESPONSE_DISPATCH);
472
473 incomingObserver.onMessage(inMessage);
474 }
475 }
476
477 public void setCloseInput(boolean closeInput)
478 {
479 this.closeInput = closeInput;
480 }
481
482 protected CxfConfiguration getConnector()
483 {
484 return configuration;
485 }
486
487 protected EndpointInfo getEndpoint()
488 {
489 return endpoint;
490 }
491
492 protected MuleUniversalTransport getTransport()
493 {
494 return transport;
495 }
496 }