Coverage Report - org.mule.module.cxf.transport.MuleUniversalConduit
 
Classes in this File Line Coverage Branch Coverage Complexity
MuleUniversalConduit
0%
0/155
0%
0/64
0
MuleUniversalConduit$1
0%
0/6
N/A
0
MuleUniversalConduit$2
0%
0/5
N/A
0
MuleUniversalConduit$InterposedMessageObserver
0%
0/7
N/A
0
 
 1  
 /*
 2  
  * $Id: MuleUniversalConduit.java 20109 2010-11-07 05:20:30Z mike.schilling $
 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 org.mule.DefaultMuleEvent;
 14  
 import org.mule.DefaultMuleMessage;
 15  
 import org.mule.RequestContext;
 16  
 import org.mule.api.MuleContext;
 17  
 import org.mule.api.MuleEvent;
 18  
 import org.mule.api.MuleException;
 19  
 import org.mule.api.MuleMessage;
 20  
 import org.mule.api.MuleSession;
 21  
 import org.mule.api.endpoint.OutboundEndpoint;
 22  
 import org.mule.api.transformer.TransformerException;
 23  
 import org.mule.api.transport.OutputHandler;
 24  
 import org.mule.module.cxf.CxfConfiguration;
 25  
 import org.mule.module.cxf.CxfConstants;
 26  
 import org.mule.module.cxf.CxfOutboundMessageProcessor;
 27  
 import org.mule.module.cxf.support.DelegatingOutputStream;
 28  
 import org.mule.module.cxf.support.MuleProtocolHeadersOutInterceptor;
 29  
 import org.mule.session.DefaultMuleSession;
 30  
 import org.mule.transformer.types.DataTypeFactory;
 31  
 import org.mule.transport.NullPayload;
 32  
 import org.mule.transport.http.HttpConnector;
 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.io.PushbackInputStream;
 40  
 import java.net.HttpURLConnection;
 41  
 import java.net.MalformedURLException;
 42  
 import java.util.HashMap;
 43  
 import java.util.Map;
 44  
 import java.util.logging.Logger;
 45  
 
 46  
 import javax.xml.ws.BindingProvider;
 47  
 import javax.xml.ws.Holder;
 48  
 
 49  
 import org.apache.cxf.common.logging.LogUtils;
 50  
 import org.apache.cxf.endpoint.ClientImpl;
 51  
 import org.apache.cxf.interceptor.Fault;
 52  
 import org.apache.cxf.message.Exchange;
 53  
 import org.apache.cxf.message.ExchangeImpl;
 54  
 import org.apache.cxf.message.Message;
 55  
 import org.apache.cxf.message.MessageImpl;
 56  
 import org.apache.cxf.phase.AbstractPhaseInterceptor;
 57  
 import org.apache.cxf.phase.Phase;
 58  
 import org.apache.cxf.service.model.EndpointInfo;
 59  
 import org.apache.cxf.transport.AbstractConduit;
 60  
 import org.apache.cxf.transport.Destination;
 61  
 import org.apache.cxf.transport.MessageObserver;
 62  
 import org.apache.cxf.ws.addressing.AttributedURIType;
 63  
 import org.apache.cxf.ws.addressing.EndpointReferenceType;
 64  
 import org.apache.cxf.wsdl.EndpointReferenceUtils;
 65  
 
 66  
 import static org.apache.cxf.message.Message.DECOUPLED_CHANNEL_MESSAGE;
 67  
 import static org.mule.api.config.MuleProperties.MULE_EVENT_PROPERTY;
 68  
 
 69  
 /**
 70  
  * A Conduit is primarily responsible for sending messages from CXF to somewhere
 71  
  * else. This conduit takes messages which are being written and sends them to the
 72  
  * Mule bus.
 73  
  */
 74  0
 public class MuleUniversalConduit extends AbstractConduit
 75  
 {
 76  
 
 77  0
     private static final Logger LOGGER = LogUtils.getL7dLogger(MuleUniversalConduit.class);
 78  
 
 79  
     private EndpointInfo endpoint;
 80  
 
 81  
     private CxfConfiguration configuration;
 82  
 
 83  
     private Destination decoupledDestination;
 84  
 
 85  
     private String decoupledEndpoint;
 86  
 
 87  
     private MuleUniversalTransport transport;
 88  
 
 89  
     private int decoupledDestinationRefCount;
 90  
 
 91  0
     private boolean closeInput = true;
 92  
 
 93  0
     private Map<String,OutboundEndpoint> endpoints = new HashMap<String, OutboundEndpoint>();
 94  
     
 95  
     /**
 96  
      * @param ei The Endpoint being invoked by this destination.
 97  
      * @param t The EPR associated with this Conduit - i.e. the reply destination.
 98  
      */
 99  
     public MuleUniversalConduit(MuleUniversalTransport transport,
 100  
                                 CxfConfiguration configuration,
 101  
                                 EndpointInfo ei,
 102  
                                 EndpointReferenceType t)
 103  
     {
 104  0
         super(getTargetReference(ei, t));
 105  0
         this.transport = transport;
 106  0
         this.endpoint = ei;
 107  0
         this.configuration = configuration;
 108  0
     }
 109  
     
 110  
     @Override
 111  
     public void close(Message msg) throws IOException
 112  
     {
 113  0
         OutputStream os = msg.getContent(OutputStream.class);
 114  0
         if (os != null)
 115  
         {
 116  0
             os.close();
 117  
         }
 118  
         
 119  0
         if (closeInput)
 120  
         {
 121  0
             InputStream in = msg.getContent(InputStream.class);
 122  0
             if (in != null)
 123  
             {
 124  0
                 in.close();
 125  
             }
 126  
         }
 127  0
     }
 128  
 
 129  
     @Override
 130  
     protected Logger getLogger()
 131  
     {
 132  0
         return LOGGER;
 133  
     }
 134  
 
 135  
     @Override
 136  
     public synchronized Destination getBackChannel()
 137  
     {
 138  0
         if (decoupledDestination == null && decoupledEndpoint != null)
 139  
         {
 140  0
             setUpDecoupledDestination();
 141  
         }
 142  0
         return decoupledDestination;
 143  
     }
 144  
 
 145  
     protected void setUpDecoupledDestination()
 146  
     {
 147  0
         EndpointInfo ei = new EndpointInfo();
 148  0
         ei.setAddress(decoupledEndpoint);
 149  
         try
 150  
         {
 151  0
             decoupledDestination = transport.getDestination(ei);
 152  0
             decoupledDestination.setMessageObserver(new InterposedMessageObserver());
 153  0
             duplicateDecoupledDestination();
 154  
         }
 155  0
         catch (IOException e)
 156  
         {
 157  0
             throw new RuntimeException(e);
 158  0
         }
 159  0
     }
 160  
 
 161  
     /**
 162  
      * Prepare the message for writing.
 163  
      */
 164  
     public void prepare(final Message message) throws IOException
 165  
     {
 166  
         // save in a separate place in case we need to resend the request
 167  0
         final ByteArrayOutputStream cache = new ByteArrayOutputStream();
 168  0
         final DelegatingOutputStream delegating = new DelegatingOutputStream(cache);
 169  0
         message.setContent(OutputStream.class, delegating);
 170  0
         message.setContent(DelegatingOutputStream.class, delegating);
 171  
         
 172  0
         AbstractPhaseInterceptor<Message> i = new AbstractPhaseInterceptor<Message>(Phase.PRE_STREAM)
 173  0
         {
 174  
             public void handleMessage(Message m) throws Fault
 175  
             {
 176  
                 try
 177  
                 {
 178  0
                     dispatchMuleMessage(m);
 179  
                 }
 180  0
                 catch (IOException e)
 181  
                 {
 182  0
                     throw new Fault(e);
 183  0
                 }
 184  0
             }
 185  
         };
 186  0
         i.getAfter().add(MuleProtocolHeadersOutInterceptor.class.getName());
 187  0
         message.getInterceptorChain().add(i);
 188  
         
 189  0
         OutputHandler handler = new OutputHandler()
 190  0
         {
 191  
             public void write(MuleEvent event, OutputStream out) throws IOException
 192  
             {
 193  0
                 out.write(cache.toByteArray());
 194  
                 
 195  0
                 delegating.setOutputStream(out);
 196  
                 
 197  
                 // resume writing!
 198  0
                 message.getInterceptorChain().doIntercept(message);
 199  0
             }
 200  
         };
 201  
 
 202  0
         MuleEvent event = (MuleEvent) message.getExchange().get(MULE_EVENT_PROPERTY);
 203  0
         if (event == null)
 204  
         {
 205  0
             MuleContext muleContext = configuration.getMuleContext();
 206  0
             MuleMessage muleMsg = new DefaultMuleMessage(handler, muleContext);
 207  0
             MuleSession session = new DefaultMuleSession(muleContext);
 208  
             
 209  0
             String url = setupURL(message);
 210  
             
 211  
             try
 212  
             {
 213  0
                 OutboundEndpoint ep = getEndpoint(muleContext, url);
 214  0
                 event = new DefaultMuleEvent(muleMsg, ep, session);
 215  
             }
 216  0
             catch (Exception e)
 217  
             {
 218  0
                 throw new Fault(e);
 219  0
             }
 220  0
             event.setTimeout(MuleEvent.TIMEOUT_NOT_SET_VALUE);
 221  0
             RequestContext.setEvent(event);
 222  0
         }
 223  
         else
 224  
         {
 225  0
             event.getMessage().setPayload(handler);
 226  
         }
 227  0
         message.getExchange().put(CxfConstants.MULE_EVENT, event);
 228  0
     }
 229  
     
 230  
     protected synchronized OutboundEndpoint getEndpoint(MuleContext muleContext, String uri) throws MuleException
 231  
     {
 232  0
         if (endpoints.get(uri) != null)
 233  
         {
 234  0
             return endpoints.get(uri);
 235  
         }
 236  
 
 237  0
         OutboundEndpoint ndpoint = muleContext.getRegistry().lookupEndpointFactory().getOutboundEndpoint(uri);
 238  0
         endpoints.put(uri, ndpoint);
 239  0
         return ndpoint;
 240  
     }
 241  
     
 242  
     protected String setupURL(Message message) throws MalformedURLException
 243  
     {
 244  0
         String value = (String) message.get(Message.ENDPOINT_ADDRESS);
 245  0
         String pathInfo = (String) message.get(Message.PATH_INFO);
 246  0
         String queryString = (String) message.get(Message.QUERY_STRING);
 247  0
         String username = (String) message.get(BindingProvider.USERNAME_PROPERTY);
 248  0
         String password = (String) message.get(BindingProvider.PASSWORD_PROPERTY);
 249  
 
 250  0
         String result = value != null ? value : getTargetOrEndpoint();
 251  
 
 252  0
         if (username != null) {
 253  0
              int slashIdx = result.indexOf("//");
 254  0
              if (slashIdx != -1) {
 255  0
                  result = result.substring(0, slashIdx + 2) + username + ":" + password + "@" + result.substring(slashIdx+2);
 256  
              }
 257  
         }
 258  
 
 259  
         // REVISIT: is this really correct?
 260  0
         if (null != pathInfo && !result.endsWith(pathInfo))
 261  
         {
 262  0
             result = result + pathInfo;
 263  
         }
 264  0
         if (queryString != null)
 265  
         {
 266  0
             result = result + "?" + queryString;
 267  
         }
 268  0
         return result;
 269  
     }
 270  
     
 271  
     protected void dispatchMuleMessage(Message m) throws IOException {
 272  
         try
 273  
         {
 274  0
             MuleEvent reqEvent = (MuleEvent) m.getExchange().get(CxfConstants.MULE_EVENT);
 275  
             
 276  0
             MuleMessage req = reqEvent.getMessage();
 277  0
             req.setOutboundProperty(HttpConnector.HTTP_DISABLE_STATUS_CODE_EXCEPTION_CHECK, Boolean.TRUE.toString());
 278  
 
 279  0
             MuleEvent resEvent = processNext(reqEvent, m.getExchange());
 280  
 
 281  0
             if (resEvent == null || !reqEvent.getEndpoint().getExchangePattern().hasResponse())
 282  
             {
 283  0
                 m.getExchange().put(ClientImpl.FINISHED, Boolean.TRUE);
 284  0
                 return;
 285  
             }
 286  
             
 287  
             // If we have a result, send it back to CXF
 288  0
             MuleMessage result = resEvent.getMessage();
 289  0
             InputStream is = getResponseBody(m, result);
 290  0
             if (is != null)
 291  
             {
 292  0
                 Message inMessage = new MessageImpl();
 293  
 
 294  0
                 String encoding = result.getEncoding();
 295  0
                 inMessage.put(Message.ENCODING, encoding);
 296  0
                 String contentType = result.getOutboundProperty(HttpConstants.HEADER_CONTENT_TYPE, "text/xml");
 297  0
                 if (encoding != null && contentType.indexOf("charset") < 0)
 298  
                 {
 299  0
                     contentType += "; charset=" + result.getEncoding();
 300  
                 }
 301  0
                 inMessage.put(Message.CONTENT_TYPE, contentType);
 302  0
                 inMessage.put(CxfConstants.MULE_EVENT, resEvent);
 303  0
                 inMessage.setContent(InputStream.class, is);
 304  0
                 inMessage.setExchange(m.getExchange());
 305  0
                 getMessageObserver().onMessage(inMessage);
 306  
             }
 307  
         }
 308  0
         catch (Exception e)
 309  
         {
 310  0
             if (e instanceof IOException)
 311  
             {
 312  0
                 throw (IOException) e;
 313  
             }
 314  
 
 315  0
             IOException ex = new IOException("Could not send message to Mule.");
 316  0
             ex.initCause(e);
 317  0
             throw ex;
 318  0
         }
 319  0
     }
 320  
 
 321  
     protected InputStream getResponseBody(Message m, MuleMessage result) throws TransformerException, IOException
 322  
     {
 323  0
         boolean response = result != null
 324  
             && !NullPayload.getInstance().equals(result.getPayload())
 325  
             && !isOneway(m.getExchange());
 326  
         
 327  0
         if (response)
 328  
         {
 329  
             // Sometimes there may not actually be a body, in which case
 330  
             // we want to act appropriately. E.g. one way invocations over a proxy
 331  0
             InputStream is = result.getPayload(DataTypeFactory.create(InputStream.class));
 332  0
             PushbackInputStream pb = new PushbackInputStream(is);
 333  0
             result.setPayload(pb);
 334  
             
 335  0
             int b = pb.read();
 336  0
             if (b != -1)
 337  
             {
 338  0
                 pb.unread(b);
 339  0
                 return pb;
 340  
             }
 341  
         }
 342  
         
 343  0
         return null;
 344  
     }
 345  
 
 346  
     protected boolean isOneway(Exchange exchange)
 347  
     {
 348  0
         return exchange != null && exchange.isOneWay();
 349  
     }
 350  
     
 351  
     protected String getTargetOrEndpoint()
 352  
     {
 353  0
         if (target != null)
 354  
         {
 355  0
             return target.getAddress().getValue();
 356  
         }
 357  
 
 358  0
         return endpoint.getAddress().toString();
 359  
     }
 360  
 
 361  
     public void onClose(final Message m) throws IOException
 362  
     {
 363  
         // template method
 364  0
     }
 365  
     
 366  
     protected MuleEvent processNext(MuleEvent event,
 367  
                                     Exchange exchange) throws MuleException
 368  
     {
 369  0
         CxfOutboundMessageProcessor processor = (CxfOutboundMessageProcessor) exchange.get(CxfConstants.CXF_OUTBOUND_MESSAGE_PROCESSOR);
 370  
         MuleEvent response;
 371  0
         if (processor == null)
 372  
         {
 373  
             // we're sending from a CXF client, not from mule
 374  0
             OutboundEndpoint ep = (OutboundEndpoint) event.getEndpoint();
 375  0
             response = ep.process(event);
 376  0
         }
 377  
         else
 378  
         {
 379  0
            response = processor.processNext(event);
 380  
            
 381  0
            Holder<MuleEvent> holder = (Holder<MuleEvent>) exchange.get("holder");
 382  0
            holder.value = response;
 383  
         }
 384  
         
 385  0
         return response;
 386  
     }
 387  
 
 388  
     @Override
 389  
     public void close()
 390  
     {
 391  
         // in decoupled case, close response Destination if reference count
 392  
         // hits zero
 393  
         //
 394  0
         if (decoupledDestination != null)
 395  
         {
 396  0
             releaseDecoupledDestination();
 397  
         }
 398  0
     }
 399  
 
 400  
     protected synchronized void duplicateDecoupledDestination()
 401  
     {
 402  0
         decoupledDestinationRefCount++;
 403  0
     }
 404  
 
 405  
     protected synchronized void releaseDecoupledDestination()
 406  
     {
 407  0
         if (--decoupledDestinationRefCount == 0)
 408  
         {
 409  
             // LOG.log(Level.INFO, "shutting down decoupled destination");
 410  0
             decoupledDestination.shutdown();
 411  
         }
 412  0
     }
 413  
 
 414  
     public String getDecoupledEndpoint()
 415  
     {
 416  0
         return decoupledEndpoint;
 417  
     }
 418  
 
 419  
     public void setDecoupledEndpoint(String decoupledEndpoint)
 420  
     {
 421  0
         this.decoupledEndpoint = decoupledEndpoint;
 422  0
     }
 423  
 
 424  
     /**
 425  
      * Get the target endpoint reference.
 426  
      * 
 427  
      * @param ei the corresponding EndpointInfo
 428  
      * @param t the given target EPR if available
 429  
      * @return the actual target
 430  
      */
 431  
     protected static EndpointReferenceType getTargetReference(EndpointInfo ei, EndpointReferenceType t)
 432  
     {
 433  0
         EndpointReferenceType ref = null;
 434  0
         if (null == t)
 435  
         {
 436  0
             ref = new EndpointReferenceType();
 437  0
             AttributedURIType address = new AttributedURIType();
 438  0
             address.setValue(ei.getAddress());
 439  0
             ref.setAddress(address);
 440  0
             if (ei.getService() != null)
 441  
             {
 442  0
                 EndpointReferenceUtils.setServiceAndPortName(ref, ei.getService().getName(), ei.getName()
 443  
                     .getLocalPart());
 444  
             }
 445  0
         }
 446  
         else
 447  
         {
 448  0
             ref = t;
 449  
         }
 450  0
         return ref;
 451  
     }
 452  
 
 453  
     /**
 454  
      * Used to set appropriate message properties, exchange etc. as required for an
 455  
      * incoming decoupled response (as opposed what's normally set by the Destination
 456  
      * for an incoming request).
 457  
      */
 458  0
     protected class InterposedMessageObserver implements MessageObserver
 459  
     {
 460  
         /**
 461  
          * Called for an incoming message.
 462  
          * 
 463  
          * @param inMessage
 464  
          */
 465  
         public void onMessage(Message inMessage)
 466  
         {
 467  
             // disposable exchange, swapped with real Exchange on correlation
 468  0
             inMessage.setExchange(new ExchangeImpl());
 469  0
             inMessage.put(DECOUPLED_CHANNEL_MESSAGE, Boolean.TRUE);
 470  0
             inMessage.put(Message.RESPONSE_CODE, HttpURLConnection.HTTP_OK);
 471  0
             inMessage.remove(Message.ASYNC_POST_RESPONSE_DISPATCH);
 472  
 
 473  0
             incomingObserver.onMessage(inMessage);
 474  0
         }
 475  
     }
 476  
     
 477  
     public void setCloseInput(boolean closeInput)
 478  
     {
 479  0
         this.closeInput = closeInput;
 480  0
     }
 481  
 
 482  
     protected CxfConfiguration getConnector()
 483  
     {
 484  0
         return configuration;
 485  
     }
 486  
 
 487  
     protected EndpointInfo getEndpoint()
 488  
     {
 489  0
         return endpoint;
 490  
     }
 491  
 
 492  
     protected MuleUniversalTransport getTransport()
 493  
     {
 494  0
         return transport;
 495  
     }
 496  
 }