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