1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers.soap.xfire.transport;
12
13 import org.mule.MuleException;
14 import org.mule.impl.message.ExceptionPayload;
15 import org.mule.providers.soap.xfire.XFireConnector;
16 import org.mule.umo.UMOEventContext;
17 import org.mule.umo.UMOException;
18 import org.mule.umo.UMOMessage;
19 import org.mule.umo.manager.UMOWorkManager;
20 import org.mule.util.StringUtils;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.io.PipedInputStream;
26 import java.io.PipedOutputStream;
27 import java.io.Reader;
28 import java.io.StringReader;
29 import java.io.UnsupportedEncodingException;
30
31 import javax.resource.spi.work.Work;
32 import javax.resource.spi.work.WorkException;
33 import javax.xml.stream.XMLStreamReader;
34 import javax.xml.stream.XMLStreamWriter;
35
36 import edu.emory.mathcs.backport.java.util.concurrent.Semaphore;
37 import org.apache.commons.io.output.ByteArrayOutputStream;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40 import org.codehaus.xfire.MessageContext;
41 import org.codehaus.xfire.XFire;
42 import org.codehaus.xfire.XFireException;
43 import org.codehaus.xfire.XFireRuntimeException;
44 import org.codehaus.xfire.exchange.AbstractMessage;
45 import org.codehaus.xfire.exchange.InMessage;
46 import org.codehaus.xfire.exchange.OutMessage;
47 import org.codehaus.xfire.service.Service;
48 import org.codehaus.xfire.soap.SoapConstants;
49 import org.codehaus.xfire.transport.AbstractChannel;
50 import org.codehaus.xfire.transport.Channel;
51 import org.codehaus.xfire.transport.Session;
52 import org.codehaus.xfire.transport.Transport;
53 import org.codehaus.xfire.util.STAXUtils;
54
55
56
57
58 public class MuleLocalChannel extends AbstractChannel
59 {
60 protected static final String SENDER_URI = "senderUri";
61 protected static final String OLD_CONTEXT = "urn:xfire:transport:local:oldContext";
62
63
64
65
66 protected transient Log logger = LogFactory.getLog(getClass());
67
68 private final Session session;
69 protected UMOWorkManager workManager;
70
71 public MuleLocalChannel(String uri, Transport transport, Session session)
72 {
73 this.session = session;
74 setUri(uri);
75 setTransport(transport);
76 }
77
78 public void open()
79 {
80
81 }
82
83 public void send(final MessageContext context, final OutMessage message) throws XFireException
84 {
85 if (message.getUri().equals(Channel.BACKCHANNEL_URI))
86 {
87 final OutputStream out = (OutputStream)context.getProperty(Channel.BACKCHANNEL_URI);
88 if (out != null)
89 {
90 final XMLStreamWriter writer = STAXUtils.createXMLStreamWriter(out, message.getEncoding(),
91 context);
92
93 message.getSerializer().writeMessage(message, writer, context);
94 }
95 else
96 {
97 MessageContext oldContext = (MessageContext)context.getProperty(OLD_CONTEXT);
98
99 sendViaNewChannel(context, oldContext, message, (String)context.getProperty(SENDER_URI));
100 }
101 }
102 else
103 {
104 MessageContext receivingContext = new MessageContext();
105 receivingContext.setXFire(context.getXFire());
106 receivingContext.setService(getService(context.getXFire(), message.getUri()));
107 receivingContext.setProperty(OLD_CONTEXT, context);
108 receivingContext.setProperty(SENDER_URI, getUri());
109 receivingContext.setSession(session);
110
111 sendViaNewChannel(context, receivingContext, message, message.getUri());
112 }
113 }
114
115 protected Service getService(XFire xfire, String uri) throws XFireException
116 {
117 if (null == xfire)
118 {
119 logger.warn("No XFire instance in context, unable to determine service");
120 return null;
121 }
122
123 int i = uri.indexOf("//");
124
125 if (i == -1)
126 {
127 throw new XFireException("Malformed service URI");
128 }
129
130 String name = uri.substring(i + 2);
131 Service service = xfire.getServiceRegistry().getService(name);
132
133 if (null == service)
134 {
135
136 logger.warn("Unable to locate '" + name + "' in ServiceRegistry");
137 }
138
139 return service;
140 }
141
142 private void sendViaNewChannel(final MessageContext context,
143 final MessageContext receivingContext,
144 final OutMessage message,
145 final String uri) throws XFireException
146 {
147 try
148 {
149 Channel channel;
150 PipedInputStream stream = new PipedInputStream();
151 PipedOutputStream outStream = new PipedOutputStream(stream);
152 try
153 {
154 channel = getTransport().createChannel(uri);
155 }
156 catch (Exception e)
157 {
158 throw new XFireException("Couldn't create channel.", e);
159 }
160
161 Semaphore s = new Semaphore(2);
162 try
163 {
164 getWorkManager().scheduleWork(new WriterWorker(outStream, message, context, s));
165 getWorkManager().scheduleWork(
166 new ReaderWorker(stream, message, channel, uri, receivingContext, s));
167 }
168 catch (WorkException e)
169 {
170 throw new XFireException("Couldn't schedule worker threads. " + e.getMessage(), e);
171 }
172
173 try
174 {
175 s.acquire();
176 }
177 catch (InterruptedException e)
178 {
179
180 }
181 }
182 catch (IOException e)
183 {
184 throw new XFireRuntimeException("Couldn't create stream.", e);
185 }
186 }
187
188 public void close()
189 {
190
191 }
192
193 public boolean isAsync()
194 {
195 return true;
196 }
197
198 public UMOWorkManager getWorkManager()
199 {
200 return workManager;
201 }
202
203 public void setWorkManager(UMOWorkManager workManager)
204 {
205 this.workManager = workManager;
206 }
207
208 private class ReaderWorker implements Work
209 {
210
211 private InputStream stream;
212 private OutMessage message;
213 private Channel channel;
214 private String uri;
215 private MessageContext context;
216 private Semaphore semaphore;
217
218 public ReaderWorker(InputStream stream,
219 OutMessage message,
220 Channel channel,
221 String uri,
222 MessageContext context,
223 Semaphore semaphore)
224 {
225 this.stream = stream;
226 this.message = message;
227 this.channel = channel;
228 this.uri = uri;
229 this.context = context;
230 this.semaphore = semaphore;
231 }
232
233 public void run()
234 {
235 try
236 {
237 final XMLStreamReader reader = STAXUtils.createXMLStreamReader(stream, message.getEncoding(),
238 context);
239 final InMessage inMessage = new InMessage(reader, uri);
240 inMessage.setEncoding(message.getEncoding());
241
242 channel.receive(context, inMessage);
243
244 reader.close();
245 stream.close();
246 }
247 catch (Exception e)
248 {
249 throw new XFireRuntimeException("Couldn't read stream.", e);
250 }
251 finally
252 {
253 semaphore.release();
254 }
255 }
256
257 public void release()
258 {
259
260 }
261 }
262
263 private class WriterWorker implements Work
264 {
265
266 private OutputStream stream;
267 private OutMessage message;
268 private MessageContext context;
269 private Semaphore semaphore;
270
271 public WriterWorker(OutputStream stream,
272 OutMessage message,
273 MessageContext context,
274 Semaphore semaphore)
275 {
276 this.stream = stream;
277 this.message = message;
278 this.context = context;
279 this.semaphore = semaphore;
280 }
281
282 public void run()
283 {
284 try
285 {
286 final XMLStreamWriter writer = STAXUtils.createXMLStreamWriter(stream, message.getEncoding(),
287 context);
288 message.getSerializer().writeMessage(message, writer, context);
289
290 writer.close();
291 stream.close();
292
293 }
294 catch (Exception e)
295 {
296 throw new XFireRuntimeException("Couldn't write stream.", e);
297 }
298 finally
299 {
300 semaphore.release();
301 }
302 }
303
304 public void release()
305 {
306
307 }
308 }
309
310
311
312
313 protected String getService(UMOEventContext context)
314 {
315 String pathInfo = context.getEndpointURI().getPath();
316
317 if (StringUtils.isEmpty(pathInfo))
318 {
319 return context.getEndpointURI().getHost();
320 }
321
322 String serviceName;
323
324 int i = pathInfo.lastIndexOf("/");
325
326 if (i > -1)
327 {
328 serviceName = pathInfo.substring(i + 1);
329 }
330 else
331 {
332 serviceName = pathInfo;
333 }
334
335 return serviceName;
336 }
337
338 public Object onCall(UMOEventContext ctx) throws UMOException
339 {
340
341 try
342 {
343 MessageContext context = new MessageContext();
344
345 XFire xfire = (XFire)ctx.getComponentDescriptor().getProperties().get(
346 XFireConnector.XFIRE_PROPERTY);
347
348 context.setService(xfire.getServiceRegistry().getService(getService(ctx)));
349 context.setXFire(xfire);
350
351
352 ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
353
354
355 context.setProperty(Channel.BACKCHANNEL_URI, resultStream);
356
357 XMLStreamReader reader;
358
359
360 Object payload = ctx.getMessage().getPayload();
361 if (payload instanceof InputStream)
362 {
363 reader = STAXUtils.createXMLStreamReader((InputStream)payload, ctx.getEncoding(), context);
364 }
365 else if (payload instanceof Reader)
366 {
367 reader = STAXUtils.createXMLStreamReader((Reader)payload, context);
368 }
369 else
370 {
371 String text = ctx.getTransformedMessageAsString(ctx.getEncoding());
372 reader = STAXUtils.createXMLStreamReader(new StringReader(text), context);
373 }
374
375 InMessage in = new InMessage(reader, getUri());
376
377 String soapAction = getSoapAction(ctx.getMessage());
378 in.setProperty(SoapConstants.SOAP_ACTION, soapAction);
379
380 receive(context, in);
381
382 Object result = null;
383
384 try
385 {
386
387
388
389
390
391 AbstractMessage fault = context.getExchange().getFaultMessage();
392 if (fault != null && fault.getBody() != null)
393 {
394 result = resultStream.toString(fault.getEncoding());
395 ExceptionPayload exceptionPayload = new ExceptionPayload(new Exception(result.toString()));
396 ctx.getMessage().setExceptionPayload(exceptionPayload);
397 }
398 else if (context.getExchange().hasOutMessage())
399 {
400 result = resultStream.toString(context.getExchange().getOutMessage().getEncoding());
401 }
402 }
403 catch (UnsupportedEncodingException e1)
404 {
405 throw new MuleException(e1);
406 }
407
408 return result;
409
410 }
411 catch (UMOException e)
412 {
413 logger.warn("Could not dispatch message to XFire!", e);
414 throw e;
415 }
416 }
417
418 private String getSoapAction(UMOMessage message) {
419 String action = (String) message.getProperty(SoapConstants.SOAP_ACTION);
420
421 if (action != null && action.startsWith("\"") && action.endsWith("\"") && action.length() >= 2)
422 {
423 action = action.substring(1, action.length() - 1);
424 }
425
426 return action;
427 }
428
429 }