Coverage Report - org.mule.transport.cxf.transport.MuleUniversalConduit
 
Classes in this File Line Coverage Branch Coverage Complexity
MuleUniversalConduit
63%
62/98
42%
15/36
0
MuleUniversalConduit$1
67%
4/6
N/A
0
MuleUniversalConduit$2
100%
5/5
N/A
0
MuleUniversalConduit$InterposedMessageObserver
0%
0/7
N/A
0
 
 1  
 /*
 2  
  * $Id: MuleUniversalConduit.java 12283 2008-07-10 18:16:53Z dandiep $
 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.transport.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.DefaultMuleSession;
 18  
 import org.mule.RegistryContext;
 19  
 import org.mule.RequestContext;
 20  
 import org.mule.api.MuleEvent;
 21  
 import org.mule.api.MuleEventContext;
 22  
 import org.mule.api.MuleException;
 23  
 import org.mule.api.MuleMessage;
 24  
 import org.mule.api.MuleSession;
 25  
 import org.mule.api.endpoint.OutboundEndpoint;
 26  
 import org.mule.api.transport.MessageAdapter;
 27  
 import org.mule.api.transport.OutputHandler;
 28  
 import org.mule.transport.DefaultMessageAdapter;
 29  
 import org.mule.transport.cxf.CxfConnector;
 30  
 import org.mule.transport.cxf.CxfConstants;
 31  
 import org.mule.transport.cxf.support.DelegatingOutputStream;
 32  
 import org.mule.transport.cxf.support.MuleProtocolHeadersOutInterceptor;
 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.net.HttpURLConnection;
 40  
 import java.net.MalformedURLException;
 41  
 import java.util.logging.Logger;
 42  
 
 43  
 import org.apache.cxf.interceptor.Fault;
 44  
 import org.apache.cxf.message.Exchange;
 45  
 import org.apache.cxf.message.ExchangeImpl;
 46  
 import org.apache.cxf.message.Message;
 47  
 import org.apache.cxf.message.MessageImpl;
 48  
 import org.apache.cxf.phase.AbstractPhaseInterceptor;
 49  
 import org.apache.cxf.phase.Phase;
 50  
 import org.apache.cxf.service.model.EndpointInfo;
 51  
 import org.apache.cxf.transport.AbstractConduit;
 52  
 import org.apache.cxf.transport.Destination;
 53  
 import org.apache.cxf.transport.MessageObserver;
 54  
 import org.apache.cxf.ws.addressing.AttributedURIType;
 55  
 import org.apache.cxf.ws.addressing.EndpointReferenceType;
 56  
 import org.apache.cxf.wsdl.EndpointReferenceUtils;
 57  
 
 58  
 /**
 59  
  * A Conduit is primarily responsible for sending messages from CXF to somewhere
 60  
  * else. This conduit takes messages which are being written and sends them to the
 61  
  * Mule bus.
 62  
  */
 63  0
 public class MuleUniversalConduit extends AbstractConduit
 64  
 {
 65  
 
 66  2
     private static final Logger LOGGER = Logger.getLogger(MuleUniversalConduit.class.getName());
 67  
 
 68  
     private EndpointInfo endpoint;
 69  
 
 70  
     private CxfConnector connector;
 71  
 
 72  
     private Destination decoupledDestination;
 73  
 
 74  
     private String decoupledEndpoint;
 75  
 
 76  
     private MuleUniversalTransport transport;
 77  
 
 78  
     private int decoupledDestinationRefCount;
 79  
 
 80  
     /**
 81  
      * @param ei The Endpoint being invoked by this destination.
 82  
      * @param t The EPR associated with this Conduit - i.e. the reply destination.
 83  
      */
 84  
     public MuleUniversalConduit(MuleUniversalTransport transport,
 85  
                                 CxfConnector connector,
 86  
                                 EndpointInfo ei,
 87  
                                 EndpointReferenceType t)
 88  
     {
 89  72
         super(getTargetReference(ei, t));
 90  72
         this.transport = transport;
 91  72
         this.endpoint = ei;
 92  72
         this.connector = connector;
 93  72
     }
 94  
 
 95  
     @Override
 96  
     protected Logger getLogger()
 97  
     {
 98  72
         return LOGGER;
 99  
     }
 100  
 
 101  
     public synchronized Destination getBackChannel()
 102  
     {
 103  0
         if (decoupledDestination == null && decoupledEndpoint != null)
 104  
         {
 105  0
             setUpDecoupledDestination();
 106  
         }
 107  0
         return decoupledDestination;
 108  
     }
 109  
 
 110  
     private void setUpDecoupledDestination()
 111  
     {
 112  0
         EndpointInfo ei = new EndpointInfo();
 113  0
         ei.setAddress(decoupledEndpoint);
 114  
         try
 115  
         {
 116  0
             decoupledDestination = transport.getDestination(ei);
 117  0
             decoupledDestination.setMessageObserver(new InterposedMessageObserver());
 118  0
             duplicateDecoupledDestination();
 119  
         }
 120  0
         catch (IOException e)
 121  
         {
 122  0
             throw new RuntimeException(e);
 123  0
         }
 124  0
     }
 125  
 
 126  
     /**
 127  
      * Prepare the message for writing.
 128  
      */
 129  
     public void prepare(final Message message) throws IOException
 130  
     {
 131  
         // save in a separate place in case we need to resend the request
 132  76
         final ByteArrayOutputStream cache = new ByteArrayOutputStream();
 133  76
         final DelegatingOutputStream delegating = new DelegatingOutputStream(cache);
 134  76
         message.setContent(OutputStream.class, delegating);
 135  
         
 136  76
         AbstractPhaseInterceptor<Message> i = new AbstractPhaseInterceptor<Message>(Phase.PRE_STREAM)
 137  
         {
 138  76
             public void handleMessage(Message m) throws Fault
 139  
             {
 140  
                 try
 141  
                 {
 142  76
                     dispatchMuleMessage(m);
 143  
                 }
 144  0
                 catch (IOException e)
 145  
                 {
 146  0
                     throw new Fault(e);
 147  76
                 }
 148  76
             }
 149  
         };
 150  76
         i.getAfter().add(MuleProtocolHeadersOutInterceptor.class.getName());
 151  76
         message.getInterceptorChain().add(i);
 152  
         
 153  76
         OutputHandler handler = new OutputHandler()
 154  
         {
 155  76
             public void write(MuleEvent event, OutputStream out) throws IOException
 156  
             {
 157  76
                 out.write(cache.toByteArray());
 158  
                 
 159  76
                 delegating.setOutputStream(out);
 160  
                 
 161  
                 // resume writing!
 162  76
                 message.getInterceptorChain().doIntercept(message);
 163  76
             }
 164  
         };
 165  
 
 166  
         // We can create a generic StreamMessageAdapter here as the underlying
 167  
         // transport will create one specific to the transport
 168  76
         DefaultMessageAdapter req = new DefaultMessageAdapter(handler);
 169  76
         message.getExchange().put(CxfConstants.MULE_MESSAGE, req);
 170  76
     }
 171  
     
 172  
     protected void dispatchMuleMessage(Message m) throws IOException {
 173  76
         String uri = setupURL(m);
 174  
 
 175  76
         LOGGER.info("Sending message to " + uri);
 176  
         try
 177  
         {
 178  76
             OutboundEndpoint ep = RegistryContext.getRegistry().lookupEndpointFactory().getOutboundEndpoint(uri);
 179  
 
 180  76
             MessageAdapter req = (MessageAdapter) m.getExchange().get(CxfConstants.MULE_MESSAGE);
 181  
             
 182  76
             MuleMessage result = sendStream(req, ep);
 183  
 
 184  
             // If we have a result, send it back to CXF
 185  76
             if (result != null && !isOneway(m.getExchange()))
 186  
             {
 187  74
                 Message inMessage = new MessageImpl();
 188  74
                 String contentType = req.getStringProperty(HttpConstants.HEADER_CONTENT_TYPE, "text/xml");
 189  
 
 190  74
                 inMessage.put(Message.ENCODING, result.getEncoding());
 191  74
                 inMessage.put(Message.CONTENT_TYPE, contentType);
 192  74
                 inMessage.setContent(InputStream.class, result.getPayload(InputStream.class));
 193  
                 // inMessage.setContent(InputStream.class,
 194  
                 // result.getPayload(InputStream.class));
 195  74
                 inMessage.setExchange(m.getExchange());
 196  74
                 getMessageObserver().onMessage(inMessage);
 197  
             }
 198  
         }
 199  0
         catch (Exception e)
 200  
         {
 201  0
             if (e instanceof IOException)
 202  
             {
 203  0
                 throw (IOException) e;
 204  
             }
 205  
 
 206  0
             IOException ex = new IOException("Could not send message to Mule.");
 207  0
             ex.initCause(e);
 208  0
             throw ex;
 209  76
         }
 210  76
     }
 211  
 
 212  
     private boolean isOneway(Exchange exchange)
 213  
     {
 214  76
         return exchange != null && exchange.isOneWay();
 215  
     }
 216  
     
 217  
     private String setupURL(Message message) throws MalformedURLException
 218  
     {
 219  76
         String value = (String) message.get(Message.ENDPOINT_ADDRESS);
 220  76
         String pathInfo = (String) message.get(Message.PATH_INFO);
 221  76
         String queryString = (String) message.get(Message.QUERY_STRING);
 222  
 
 223  76
         String result = value != null ? value : getTargetOrEndpoint();
 224  
 
 225  
         // REVISIT: is this really correct?
 226  76
         if (null != pathInfo && !result.endsWith(pathInfo))
 227  
         {
 228  0
             result = result + pathInfo;
 229  
         }
 230  76
         if (queryString != null)
 231  
         {
 232  0
             result = result + "?" + queryString;
 233  
         }
 234  76
         return result;
 235  
     }
 236  
 
 237  
     private String getTargetOrEndpoint()
 238  
     {
 239  74
         if (target != null)
 240  
         {
 241  74
             return target.getAddress().getValue();
 242  
         }
 243  
 
 244  0
         return endpoint.getAddress().toString();
 245  
     }
 246  
 
 247  
     public void onClose(final Message m) throws IOException
 248  
     {
 249  0
     }
 250  
     
 251  
     protected MuleMessage sendStream(MessageAdapter sa, OutboundEndpoint ep) throws MuleException
 252  
     {
 253  76
         MuleEventContext eventContext = RequestContext.getEventContext();
 254  76
         MuleSession session = null;
 255  76
         if (eventContext != null)
 256  
         {
 257  76
             session = eventContext.getSession();
 258  
         }
 259  
 
 260  76
         MuleMessage message = new DefaultMuleMessage(sa);
 261  76
         if (session == null)
 262  
         {
 263  0
             session = new DefaultMuleSession(message, connector.getSessionHandler(), connector.getMuleContext());
 264  
         }
 265  
 
 266  76
         MuleEvent event = new DefaultMuleEvent(message, ep, session, true);
 267  76
         event.setTimeout(MuleEvent.TIMEOUT_NOT_SET_VALUE);
 268  76
         RequestContext.setEvent(event);
 269  
 
 270  76
         return ep.send(event);
 271  
     }
 272  
 
 273  
     public void close()
 274  
     {
 275  
         // in decoupled case, close response Destination if reference count
 276  
         // hits zero
 277  
         //
 278  0
         if (decoupledDestination != null)
 279  
         {
 280  0
             releaseDecoupledDestination();
 281  
         }
 282  0
     }
 283  
 
 284  
     private synchronized void duplicateDecoupledDestination()
 285  
     {
 286  0
         decoupledDestinationRefCount++;
 287  0
     }
 288  
 
 289  
     private synchronized void releaseDecoupledDestination()
 290  
     {
 291  0
         if (--decoupledDestinationRefCount == 0)
 292  
         {
 293  
             // LOG.log(Level.INFO, "shutting down decoupled destination");
 294  0
             decoupledDestination.shutdown();
 295  
         }
 296  0
     }
 297  
 
 298  
     public String getDecoupledEndpoint()
 299  
     {
 300  0
         return decoupledEndpoint;
 301  
     }
 302  
 
 303  
     public void setDecoupledEndpoint(String decoupledEndpoint)
 304  
     {
 305  0
         this.decoupledEndpoint = decoupledEndpoint;
 306  0
     }
 307  
 
 308  
     /**
 309  
      * Get the target endpoint reference.
 310  
      * 
 311  
      * @param ei the corresponding EndpointInfo
 312  
      * @param t the given target EPR if available
 313  
      * @param bus the Bus
 314  
      * @return the actual target
 315  
      */
 316  
     protected static EndpointReferenceType getTargetReference(EndpointInfo ei, EndpointReferenceType t)
 317  
     {
 318  72
         EndpointReferenceType ref = null;
 319  72
         if (null == t)
 320  
         {
 321  72
             ref = new EndpointReferenceType();
 322  72
             AttributedURIType address = new AttributedURIType();
 323  72
             address.setValue(ei.getAddress());
 324  72
             ref.setAddress(address);
 325  72
             if (ei.getService() != null)
 326  
             {
 327  72
                 EndpointReferenceUtils.setServiceAndPortName(ref, ei.getService().getName(), ei.getName()
 328  
                     .getLocalPart());
 329  
             }
 330  72
         }
 331  
         else
 332  
         {
 333  0
             ref = t;
 334  
         }
 335  72
         return ref;
 336  
     }
 337  
 
 338  
     /**
 339  
      * Used to set appropriate message properties, exchange etc. as required for an
 340  
      * incoming decoupled response (as opposed what's normally set by the Destination
 341  
      * for an incoming request).
 342  
      */
 343  0
     protected class InterposedMessageObserver implements MessageObserver
 344  
     {
 345  
         /**
 346  
          * Called for an incoming message.
 347  
          * 
 348  
          * @param inMessage
 349  
          */
 350  
         public void onMessage(Message inMessage)
 351  
         {
 352  
             // disposable exchange, swapped with real Exchange on correlation
 353  0
             inMessage.setExchange(new ExchangeImpl());
 354  0
             inMessage.put(DECOUPLED_CHANNEL_MESSAGE, Boolean.TRUE);
 355  0
             inMessage.put(Message.RESPONSE_CODE, HttpURLConnection.HTTP_OK);
 356  0
             inMessage.remove(Message.ASYNC_POST_RESPONSE_DISPATCH);
 357  
 
 358  0
             incomingObserver.onMessage(inMessage);
 359  0
         }
 360  
     }
 361  
 }