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