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