Coverage Report - org.mule.module.cxf.transport.MuleUniversalConduit
 
Classes in this File Line Coverage Branch Coverage Complexity
MuleUniversalConduit
0%
0/133
0%
0/56
0
MuleUniversalConduit$1
0%
0/5
N/A
0
MuleUniversalConduit$2
0%
0/6
N/A
0
MuleUniversalConduit$InterposedMessageObserver
0%
0/7
N/A
0
 
 1  
 /*
 2  
  * $Id: MuleUniversalConduit.java 20385 2010-11-29 20:25:26Z dfeist $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.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.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  
  * A Conduit is primarily responsible for sending messages from CXF to somewhere
 70  
  * else. This conduit takes messages which are being written and sends them to the
 71  
  * Mule bus.
 72  
  */
 73  0
 public class MuleUniversalConduit extends AbstractConduit
 74  
 {
 75  
 
 76  0
     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  0
     private boolean closeInput = true;
 85  
 
 86  0
     private Map<String,OutboundEndpoint> endpoints = new HashMap<String, OutboundEndpoint>();
 87  
     
 88  
     /**
 89  
      * @param ei The Endpoint being invoked by this destination.
 90  
      * @param t The EPR associated with this Conduit - i.e. the reply destination.
 91  
      */
 92  
     public MuleUniversalConduit(MuleUniversalTransport transport,
 93  
                                 CxfConfiguration configuration,
 94  
                                 EndpointInfo ei,
 95  
                                 EndpointReferenceType t)
 96  
     {
 97  0
         super(getTargetReference(ei, t));
 98  0
         this.transport = transport;
 99  0
         this.endpoint = ei;
 100  0
         this.configuration = configuration;
 101  0
     }
 102  
     
 103  
     @Override
 104  
     public void close(Message msg) throws IOException
 105  
     {
 106  0
         OutputStream os = msg.getContent(OutputStream.class);
 107  0
         if (os != null)
 108  
         {
 109  0
             os.close();
 110  
         }
 111  
         
 112  0
         if (closeInput)
 113  
         {
 114  0
             InputStream in = msg.getContent(InputStream.class);
 115  0
             if (in != null)
 116  
             {
 117  0
                 in.close();
 118  
             }
 119  
         }
 120  0
     }
 121  
 
 122  
     @Override
 123  
     protected Logger getLogger()
 124  
     {
 125  0
         return LOGGER;
 126  
     }
 127  
 
 128  
     /**
 129  
      * Prepare the message for writing.
 130  
      */
 131  
     public void prepare(final Message message) throws IOException
 132  
     {
 133  
         // save in a separate place in case we need to resend the request
 134  0
         final ByteArrayOutputStream cache = new ByteArrayOutputStream();
 135  0
         final DelegatingOutputStream delegating = new DelegatingOutputStream(cache);
 136  0
         message.setContent(OutputStream.class, delegating);
 137  0
         message.setContent(DelegatingOutputStream.class, delegating);
 138  
         
 139  0
         OutputHandler handler = new OutputHandler()
 140  0
         {
 141  
             public void write(MuleEvent event, OutputStream out) throws IOException
 142  
             {
 143  0
                 out.write(cache.toByteArray());
 144  
                 
 145  0
                 delegating.setOutputStream(out);
 146  
                 
 147  
                 // resume writing!
 148  0
                 message.getInterceptorChain().doIntercept(message);
 149  0
             }
 150  
         };
 151  
 
 152  0
         MuleEvent event = (MuleEvent) message.getExchange().get(MULE_EVENT_PROPERTY);
 153  0
         if (event == null)
 154  
         {
 155  
             // we've got an out of band WS-RM message or a message from a standalone client
 156  0
             MuleContext muleContext = configuration.getMuleContext();
 157  0
             MuleMessage muleMsg = new DefaultMuleMessage(handler, muleContext);
 158  0
             MuleSession session = new DefaultMuleSession(muleContext);
 159  
             
 160  0
             String url = setupURL(message);
 161  
             
 162  
             try
 163  
             {
 164  0
                 OutboundEndpoint ep = getEndpoint(muleContext, url);
 165  0
                 event = new DefaultMuleEvent(muleMsg, ep, session);
 166  
             }
 167  0
             catch (Exception e)
 168  
             {
 169  0
                 throw new Fault(e);
 170  0
             }
 171  0
             event.setTimeout(MuleEvent.TIMEOUT_NOT_SET_VALUE);
 172  0
             RequestContext.setEvent(event);
 173  0
         }
 174  
         else 
 175  
         {
 176  0
             event.getMessage().setPayload(handler);
 177  0
             message.getExchange().put(CxfConstants.MULE_EVENT, event);
 178  
         }
 179  
         
 180  0
         final MuleEvent finalEvent = event;
 181  0
         AbstractPhaseInterceptor<Message> i = new AbstractPhaseInterceptor<Message>(Phase.PRE_STREAM)
 182  0
         {
 183  
             public void handleMessage(Message m) throws Fault
 184  
             {
 185  
                 try
 186  
                 {
 187  0
                     dispatchMuleMessage(m, finalEvent);
 188  
                 }
 189  0
                 catch (IOException e)
 190  
                 {
 191  0
                     throw new Fault(e);
 192  0
                 }
 193  0
             }
 194  
         };
 195  0
         i.getAfter().add(MuleProtocolHeadersOutInterceptor.class.getName());
 196  0
         message.getInterceptorChain().add(i);
 197  0
     }
 198  
 
 199  
     protected synchronized OutboundEndpoint getEndpoint(MuleContext muleContext, String uri) throws MuleException
 200  
     {
 201  0
         if (endpoints.get(uri) != null)
 202  
         {
 203  0
             return endpoints.get(uri);
 204  
         }
 205  
 
 206  0
         OutboundEndpoint ndpoint = muleContext.getEndpointFactory().getOutboundEndpoint(uri);
 207  0
         endpoints.put(uri, ndpoint);
 208  0
         return ndpoint;
 209  
     }
 210  
     
 211  
     public String setupURL(Message message) throws MalformedURLException
 212  
     {
 213  0
         String value = (String) message.get(Message.ENDPOINT_ADDRESS);
 214  0
         String pathInfo = (String) message.get(Message.PATH_INFO);
 215  0
         String queryString = (String) message.get(Message.QUERY_STRING);
 216  0
         String username = (String) message.get(BindingProvider.USERNAME_PROPERTY);
 217  0
         String password = (String) message.get(BindingProvider.PASSWORD_PROPERTY);
 218  
 
 219  0
         String result = value != null ? value : getTargetOrEndpoint();
 220  
 
 221  0
         if (username != null) {
 222  0
              int slashIdx = result.indexOf("//");
 223  0
              if (slashIdx != -1) {
 224  0
                  result = result.substring(0, slashIdx + 2) + username + ":" + password + "@" + result.substring(slashIdx+2);
 225  
              }
 226  
         }
 227  
 
 228  
         // REVISIT: is this really correct?
 229  0
         if (null != pathInfo && !result.endsWith(pathInfo))
 230  
         {
 231  0
             result = result + pathInfo;
 232  
         }
 233  0
         if (queryString != null)
 234  
         {
 235  0
             result = result + "?" + queryString;
 236  
         }
 237  0
         return result;
 238  
     }
 239  
     
 240  
     protected void dispatchMuleMessage(Message m, MuleEvent reqEvent) throws IOException {
 241  
         try
 242  
         {   
 243  0
             MuleMessage req = reqEvent.getMessage();
 244  0
             req.setOutboundProperty(HttpConnector.HTTP_DISABLE_STATUS_CODE_EXCEPTION_CHECK, Boolean.TRUE.toString());
 245  
 
 246  0
             MuleEvent resEvent = processNext(reqEvent, m.getExchange());
 247  
 
 248  0
             if (resEvent == null || !reqEvent.getEndpoint().getExchangePattern().hasResponse())
 249  
             {
 250  0
                 m.getExchange().put(ClientImpl.FINISHED, Boolean.TRUE);
 251  0
                 return;
 252  
             }
 253  
             
 254  
             // If we have a result, send it back to CXF
 255  0
             MuleMessage result = resEvent.getMessage();
 256  0
             InputStream is = getResponseBody(m, result);
 257  0
             if (is != null)
 258  
             {
 259  0
                 Message inMessage = new MessageImpl();
 260  
 
 261  0
                 String encoding = result.getEncoding();
 262  0
                 inMessage.put(Message.ENCODING, encoding);
 263  0
                 String contentType = result.getOutboundProperty(HttpConstants.HEADER_CONTENT_TYPE, "text/xml");
 264  0
                 if (encoding != null && contentType.indexOf("charset") < 0)
 265  
                 {
 266  0
                     contentType += "; charset=" + result.getEncoding();
 267  
                 }
 268  0
                 inMessage.put(Message.CONTENT_TYPE, contentType);
 269  0
                 inMessage.put(CxfConstants.MULE_EVENT, resEvent);
 270  0
                 inMessage.setContent(InputStream.class, is);
 271  0
                 inMessage.setExchange(m.getExchange());
 272  0
                 getMessageObserver().onMessage(inMessage);
 273  
             }
 274  
         }
 275  0
         catch (Exception e)
 276  
         {
 277  0
             if (e instanceof IOException)
 278  
             {
 279  0
                 throw (IOException) e;
 280  
             }
 281  
 
 282  0
             IOException ex = new IOException("Could not send message to Mule.");
 283  0
             ex.initCause(e);
 284  0
             throw ex;
 285  0
         }
 286  0
     }
 287  
 
 288  
     protected InputStream getResponseBody(Message m, MuleMessage result) throws TransformerException, IOException
 289  
     {
 290  0
         boolean response = result != null
 291  
             && !NullPayload.getInstance().equals(result.getPayload())
 292  
             && !isOneway(m.getExchange());
 293  
         
 294  0
         if (response)
 295  
         {
 296  
             // Sometimes there may not actually be a body, in which case
 297  
             // we want to act appropriately. E.g. one way invocations over a proxy
 298  0
             InputStream is = result.getPayload(DataTypeFactory.create(InputStream.class));
 299  0
             PushbackInputStream pb = new PushbackInputStream(is);
 300  0
             result.setPayload(pb);
 301  
             
 302  0
             int b = pb.read();
 303  0
             if (b != -1)
 304  
             {
 305  0
                 pb.unread(b);
 306  0
                 return pb;
 307  
             }
 308  
         }
 309  
         
 310  0
         return null;
 311  
     }
 312  
 
 313  
     protected boolean isOneway(Exchange exchange)
 314  
     {
 315  0
         return exchange != null && exchange.isOneWay();
 316  
     }
 317  
     
 318  
     protected String getTargetOrEndpoint()
 319  
     {
 320  0
         if (target != null)
 321  
         {
 322  0
             return target.getAddress().getValue();
 323  
         }
 324  
 
 325  0
         return endpoint.getAddress().toString();
 326  
     }
 327  
 
 328  
     public void onClose(final Message m) throws IOException
 329  
     {
 330  
         // template method
 331  0
     }
 332  
     
 333  
     protected MuleEvent processNext(MuleEvent event,
 334  
                                     Exchange exchange) throws MuleException
 335  
     {
 336  0
         CxfOutboundMessageProcessor processor = (CxfOutboundMessageProcessor) exchange.get(CxfConstants.CXF_OUTBOUND_MESSAGE_PROCESSOR);
 337  
         MuleEvent response;
 338  0
         if (processor == null)
 339  
         {
 340  
             // we're sending from a CXF client, not from mule
 341  0
             OutboundEndpoint ep = (OutboundEndpoint) event.getEndpoint();
 342  0
             response = ep.process(event);
 343  0
         }
 344  
         else
 345  
         {
 346  0
            response = processor.processNext(event);
 347  
            
 348  0
            Holder<MuleEvent> holder = (Holder<MuleEvent>) exchange.get("holder");
 349  0
            holder.value = response;
 350  
         }
 351  
         
 352  0
         return response;
 353  
     }
 354  
 
 355  
     @Override
 356  
     public void close()
 357  
     {
 358  0
     }
 359  
 
 360  
     /**
 361  
      * Get the target endpoint reference.
 362  
      * 
 363  
      * @param ei the corresponding EndpointInfo
 364  
      * @param t the given target EPR if available
 365  
      * @return the actual target
 366  
      */
 367  
     protected static EndpointReferenceType getTargetReference(EndpointInfo ei, EndpointReferenceType t)
 368  
     {
 369  0
         EndpointReferenceType ref = null;
 370  0
         if (null == t)
 371  
         {
 372  0
             ref = new EndpointReferenceType();
 373  0
             AttributedURIType address = new AttributedURIType();
 374  0
             address.setValue(ei.getAddress());
 375  0
             ref.setAddress(address);
 376  0
             if (ei.getService() != null)
 377  
             {
 378  0
                 EndpointReferenceUtils.setServiceAndPortName(ref, ei.getService().getName(), ei.getName()
 379  
                     .getLocalPart());
 380  
             }
 381  0
         }
 382  
         else
 383  
         {
 384  0
             ref = t;
 385  
         }
 386  0
         return ref;
 387  
     }
 388  
 
 389  
     /**
 390  
      * Used to set appropriate message properties, exchange etc. as required for an
 391  
      * incoming decoupled response (as opposed what's normally set by the Destination
 392  
      * for an incoming request).
 393  
      */
 394  0
     protected class InterposedMessageObserver implements MessageObserver
 395  
     {
 396  
         /**
 397  
          * Called for an incoming message.
 398  
          * 
 399  
          * @param inMessage
 400  
          */
 401  
         public void onMessage(Message inMessage)
 402  
         {
 403  
             // disposable exchange, swapped with real Exchange on correlation
 404  0
             inMessage.setExchange(new ExchangeImpl());
 405  0
             inMessage.put(DECOUPLED_CHANNEL_MESSAGE, Boolean.TRUE);
 406  0
             inMessage.put(Message.RESPONSE_CODE, HttpURLConnection.HTTP_OK);
 407  0
             inMessage.remove(Message.ASYNC_POST_RESPONSE_DISPATCH);
 408  
 
 409  0
             incomingObserver.onMessage(inMessage);
 410  0
         }
 411  
     }
 412  
     
 413  
     public void setCloseInput(boolean closeInput)
 414  
     {
 415  0
         this.closeInput = closeInput;
 416  0
     }
 417  
 
 418  
     protected CxfConfiguration getConnector()
 419  
     {
 420  0
         return configuration;
 421  
     }
 422  
 
 423  
     protected EndpointInfo getEndpoint()
 424  
     {
 425  0
         return endpoint;
 426  
     }
 427  
 
 428  
     protected MuleUniversalTransport getTransport()
 429  
     {
 430  0
         return transport;
 431  
     }
 432  
 }