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