Coverage Report - org.mule.providers.soap.xfire.transport.MuleLocalChannel
 
Classes in this File Line Coverage Branch Coverage Complexity
MuleLocalChannel
51%
53/104
50%
16/32
2.722
MuleLocalChannel$ReaderWorker
0%
0/20
N/A
2.722
MuleLocalChannel$WriterWorker
0%
0/16
N/A
2.722
 
 1  
 /*
 2  
  * $Id: MuleLocalChannel.java 7963 2007-08-21 08:53:15Z dirk.olmes $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 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  
  * TODO document
 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  
      * logger used by this class
 65  
      */
 66  32
     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  32
     {
 73  32
         this.session = session;
 74  32
         setUri(uri);
 75  32
         setTransport(transport);
 76  32
     }
 77  
 
 78  
     public void open()
 79  
     {
 80  
         // template method
 81  32
     }
 82  
 
 83  
     public void send(final MessageContext context, final OutMessage message) throws XFireException
 84  
     {
 85  50
         if (message.getUri().equals(Channel.BACKCHANNEL_URI))
 86  
         {
 87  50
             final OutputStream out = (OutputStream)context.getProperty(Channel.BACKCHANNEL_URI);
 88  50
             if (out != null)
 89  
             {
 90  50
                 final XMLStreamWriter writer = STAXUtils.createXMLStreamWriter(out, message.getEncoding(),
 91  
                     context);
 92  
 
 93  50
                 message.getSerializer().writeMessage(message, writer, context);
 94  50
             }
 95  
             else
 96  
             {
 97  0
                 MessageContext oldContext = (MessageContext)context.getProperty(OLD_CONTEXT);
 98  
 
 99  0
                 sendViaNewChannel(context, oldContext, message, (String)context.getProperty(SENDER_URI));
 100  
             }
 101  50
         }
 102  
         else
 103  
         {
 104  0
             MessageContext receivingContext = new MessageContext();
 105  0
             receivingContext.setXFire(context.getXFire());
 106  0
             receivingContext.setService(getService(context.getXFire(), message.getUri()));
 107  0
             receivingContext.setProperty(OLD_CONTEXT, context);
 108  0
             receivingContext.setProperty(SENDER_URI, getUri());
 109  0
             receivingContext.setSession(session);
 110  
 
 111  0
             sendViaNewChannel(context, receivingContext, message, message.getUri());
 112  
         }
 113  50
     }
 114  
 
 115  
     protected Service getService(XFire xfire, String uri) throws XFireException
 116  
     {
 117  0
         if (null == xfire)
 118  
         {
 119  0
             logger.warn("No XFire instance in context, unable to determine service");
 120  0
             return null;
 121  
         }
 122  
 
 123  0
         int i = uri.indexOf("//");
 124  
 
 125  0
         if (i == -1)
 126  
         {
 127  0
             throw new XFireException("Malformed service URI");
 128  
         }
 129  
 
 130  0
         String name = uri.substring(i + 2);
 131  0
         Service service = xfire.getServiceRegistry().getService(name);
 132  
 
 133  0
         if (null == service)
 134  
         {
 135  
             // TODO this should be an exception...
 136  0
             logger.warn("Unable to locate '" + name + "' in ServiceRegistry");
 137  
         }
 138  
 
 139  0
         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  0
             PipedInputStream stream = new PipedInputStream();
 151  0
             PipedOutputStream outStream = new PipedOutputStream(stream);
 152  
             try
 153  
             {
 154  0
                 channel = getTransport().createChannel(uri);
 155  
             }
 156  0
             catch (Exception e)
 157  
             {
 158  0
                 throw new XFireException("Couldn't create channel.", e);
 159  0
             }
 160  
 
 161  0
             Semaphore s = new Semaphore(2);
 162  
             try
 163  
             {
 164  0
                 getWorkManager().scheduleWork(new WriterWorker(outStream, message, context, s));
 165  0
                 getWorkManager().scheduleWork(
 166  
                     new ReaderWorker(stream, message, channel, uri, receivingContext, s));
 167  
             }
 168  0
             catch (WorkException e)
 169  
             {
 170  0
                 throw new XFireException("Couldn't schedule worker threads. " + e.getMessage(), e);
 171  0
             }
 172  
 
 173  
             try
 174  
             {
 175  0
                 s.acquire();
 176  
             }
 177  0
             catch (InterruptedException e)
 178  
             {
 179  
                 // ignore is ok
 180  0
             }
 181  
         }
 182  0
         catch (IOException e)
 183  
         {
 184  0
             throw new XFireRuntimeException("Couldn't create stream.", e);
 185  0
         }
 186  0
     }
 187  
 
 188  
     public void close()
 189  
     {
 190  
         // template method
 191  0
     }
 192  
 
 193  
     public boolean isAsync()
 194  
     {
 195  0
         return true;
 196  
     }
 197  
 
 198  
     public UMOWorkManager getWorkManager()
 199  
     {
 200  0
         return workManager;
 201  
     }
 202  
 
 203  
     public void setWorkManager(UMOWorkManager workManager)
 204  
     {
 205  32
         this.workManager = workManager;
 206  32
     }
 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  0
         {
 225  0
             this.stream = stream;
 226  0
             this.message = message;
 227  0
             this.channel = channel;
 228  0
             this.uri = uri;
 229  0
             this.context = context;
 230  0
             this.semaphore = semaphore;
 231  0
         }
 232  
 
 233  
         public void run()
 234  
         {
 235  
             try
 236  
             {
 237  0
                 final XMLStreamReader reader = STAXUtils.createXMLStreamReader(stream, message.getEncoding(),
 238  
                     context);
 239  0
                 final InMessage inMessage = new InMessage(reader, uri);
 240  0
                 inMessage.setEncoding(message.getEncoding());
 241  
 
 242  0
                 channel.receive(context, inMessage);
 243  
 
 244  0
                 reader.close();
 245  0
                 stream.close();
 246  
             }
 247  0
             catch (Exception e)
 248  
             {
 249  0
                 throw new XFireRuntimeException("Couldn't read stream.", e);
 250  
             }
 251  
             finally
 252  
             {
 253  0
                 semaphore.release();
 254  0
             }
 255  0
         }
 256  
 
 257  
         public void release()
 258  
         {
 259  
             // template method
 260  0
         }
 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  0
         {
 276  0
             this.stream = stream;
 277  0
             this.message = message;
 278  0
             this.context = context;
 279  0
             this.semaphore = semaphore;
 280  0
         }
 281  
 
 282  
         public void run()
 283  
         {
 284  
             try
 285  
             {
 286  0
                 final XMLStreamWriter writer = STAXUtils.createXMLStreamWriter(stream, message.getEncoding(),
 287  
                     context);
 288  0
                 message.getSerializer().writeMessage(message, writer, context);
 289  
 
 290  0
                 writer.close();
 291  0
                 stream.close();
 292  
 
 293  
             }
 294  0
             catch (Exception e)
 295  
             {
 296  0
                 throw new XFireRuntimeException("Couldn't write stream.", e);
 297  
             }
 298  
             finally
 299  
             {
 300  0
                 semaphore.release();
 301  0
             }
 302  0
         }
 303  
 
 304  
         public void release()
 305  
         {
 306  
             // template method
 307  0
         }
 308  
     }
 309  
 
 310  
     /**
 311  
      * Get the service that is mapped to the specified request.
 312  
      */
 313  
     protected String getService(UMOEventContext context)
 314  
     {
 315  50
         String pathInfo = context.getEndpointURI().getPath();
 316  
 
 317  50
         if (StringUtils.isEmpty(pathInfo))
 318  
         {
 319  0
             return context.getEndpointURI().getHost();
 320  
         }
 321  
 
 322  
         String serviceName;
 323  
 
 324  50
         int i = pathInfo.lastIndexOf("/");
 325  
 
 326  50
         if (i > -1)
 327  
         {
 328  50
             serviceName = pathInfo.substring(i + 1);
 329  
         }
 330  
         else
 331  
         {
 332  0
             serviceName = pathInfo;
 333  
         }
 334  
 
 335  50
         return serviceName;
 336  
     }
 337  
 
 338  
     public Object onCall(UMOEventContext ctx) throws UMOException
 339  
     {
 340  
 
 341  
         try
 342  
         {
 343  50
             MessageContext context = new MessageContext();
 344  
   
 345  50
             XFire xfire = (XFire)ctx.getComponentDescriptor().getProperties().get(
 346  
                 XFireConnector.XFIRE_PROPERTY);
 347  
 
 348  50
             context.setService(xfire.getServiceRegistry().getService(getService(ctx)));
 349  50
             context.setXFire(xfire);
 350  
 
 351  
             // Channel.BACKCHANNEL_URI
 352  50
             ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
 353  
 
 354  
             // Return the result to us, not to the sender.
 355  50
             context.setProperty(Channel.BACKCHANNEL_URI, resultStream);
 356  
 
 357  
             XMLStreamReader reader;
 358  
 
 359  
             // TODO isStreaming()?
 360  50
             Object payload = ctx.getMessage().getPayload();
 361  50
             if (payload instanceof InputStream)
 362  
             {
 363  0
                 reader = STAXUtils.createXMLStreamReader((InputStream)payload, ctx.getEncoding(), context);
 364  
             }
 365  50
             else if (payload instanceof Reader)
 366  
             {
 367  0
                 reader = STAXUtils.createXMLStreamReader((Reader)payload, context);
 368  
             }
 369  
             else
 370  
             {
 371  50
                 String text = ctx.getTransformedMessageAsString(ctx.getEncoding());
 372  50
                 reader = STAXUtils.createXMLStreamReader(new StringReader(text), context);
 373  
             }
 374  
 
 375  50
             InMessage in = new InMessage(reader, getUri());
 376  
 
 377  50
             String soapAction = getSoapAction(ctx.getMessage());
 378  50
             in.setProperty(SoapConstants.SOAP_ACTION, soapAction);
 379  
 
 380  50
             receive(context, in);
 381  
 
 382  50
             Object result = null;
 383  
 
 384  
             try
 385  
             {
 386  
                 // We need to check if there is a fault message. If that's the case,
 387  
                 // we need to send back the fault to the client.
 388  
                 // TODO: see MULE-1113 for background about this workaround; I'm not
 389  
                 // even sure the fault reading is done correctly? (XFire API is a bit
 390  
                 // confusing)
 391  50
                 AbstractMessage fault = context.getExchange().getFaultMessage();
 392  50
                 if (fault != null && fault.getBody() != null)
 393  
                 {
 394  10
                     result = resultStream.toString(fault.getEncoding());
 395  10
                     ExceptionPayload exceptionPayload = new ExceptionPayload(new Exception(result.toString()));
 396  10
                     ctx.getMessage().setExceptionPayload(exceptionPayload);
 397  10
                 }
 398  40
                 else if (context.getExchange().hasOutMessage())
 399  
                 {
 400  40
                     result = resultStream.toString(context.getExchange().getOutMessage().getEncoding());
 401  
                 }
 402  
             }
 403  0
             catch (UnsupportedEncodingException e1)
 404  
             {
 405  0
                 throw new MuleException(e1);
 406  50
             }
 407  
 
 408  50
             return result;
 409  
 
 410  
         }
 411  0
         catch (UMOException e)
 412  
         {
 413  0
             logger.warn("Could not dispatch message to XFire!", e);
 414  0
             throw e;
 415  
         }
 416  
     }
 417  
 
 418  
     private String getSoapAction(UMOMessage message) {
 419  50
         String action = (String) message.getProperty(SoapConstants.SOAP_ACTION);
 420  
         
 421  50
         if (action != null && action.startsWith("\"") && action.endsWith("\"") && action.length() >= 2)
 422  
         {
 423  8
             action = action.substring(1, action.length() - 1);
 424  
         }
 425  
         
 426  50
         return action;
 427  
     }
 428  
 
 429  
 }