Coverage Report - org.mule.providers.soap.xfire.XFireMessageDispatcher
 
Classes in this File Line Coverage Branch Coverage Complexity
XFireMessageDispatcher
57%
94/166
44%
35/80
3.667
 
 1  
 /*
 2  
  * $Id: XFireMessageDispatcher.java 10164 2007-12-28 11:32:14Z marie.rizzo $
 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;
 12  
 
 13  
 import org.mule.config.MuleProperties;
 14  
 import org.mule.impl.MuleMessage;
 15  
 import org.mule.providers.AbstractMessageDispatcher;
 16  
 import org.mule.providers.FatalConnectException;
 17  
 import org.mule.providers.soap.SoapConstants;
 18  
 import org.mule.providers.soap.i18n.SoapMessages;
 19  
 import org.mule.providers.soap.xfire.i18n.XFireMessages;
 20  
 import org.mule.providers.soap.xfire.transport.MuleUniversalTransport;
 21  
 import org.mule.umo.UMOEvent;
 22  
 import org.mule.umo.UMOMessage;
 23  
 import org.mule.umo.endpoint.UMOEndpointURI;
 24  
 import org.mule.umo.endpoint.UMOImmutableEndpoint;
 25  
 import org.mule.umo.provider.DispatchException;
 26  
 import org.mule.umo.transformer.TransformerException;
 27  
 import org.mule.util.ClassUtils;
 28  
 import org.mule.util.StringUtils;
 29  
 import org.mule.util.TemplateParser;
 30  
 
 31  
 import java.util.ArrayList;
 32  
 import java.util.Arrays;
 33  
 import java.util.HashMap;
 34  
 import java.util.Iterator;
 35  
 import java.util.List;
 36  
 import java.util.Map;
 37  
 import java.util.Properties;
 38  
 import java.util.Set;
 39  
 
 40  
 import javax.activation.DataHandler;
 41  
 import javax.xml.namespace.QName;
 42  
 
 43  
 import org.codehaus.xfire.XFire;
 44  
 import org.codehaus.xfire.aegis.AegisBindingProvider;
 45  
 import org.codehaus.xfire.aegis.type.TypeMapping;
 46  
 import org.codehaus.xfire.aegis.type.basic.BeanType;
 47  
 import org.codehaus.xfire.client.Client;
 48  
 import org.codehaus.xfire.handler.Handler;
 49  
 import org.codehaus.xfire.service.OperationInfo;
 50  
 import org.codehaus.xfire.service.Service;
 51  
 import org.codehaus.xfire.transport.Transport;
 52  
 
 53  
 /**
 54  
  * The XFireMessageDispatcher is used for making Soap client requests to remote
 55  
  * services.
 56  
  */
 57  
 public class XFireMessageDispatcher extends AbstractMessageDispatcher
 58  
 {
 59  
     // Since the MessageDispatcher is guaranteed to serve a single thread,
 60  
     // the Dispatcher can own the xfire Client as an instance variable
 61  38
     protected Client client = null;
 62  
     protected final XFireConnector connector;
 63  38
     private final TemplateParser soapActionTemplateParser = TemplateParser.createAntStyleParser();
 64  
 
 65  
     public XFireMessageDispatcher(UMOImmutableEndpoint endpoint)
 66  
     {
 67  38
         super(endpoint);
 68  38
         this.connector = (XFireConnector) endpoint.getConnector();
 69  38
     }
 70  
 
 71  
     protected void doConnect() throws Exception
 72  
     {
 73  32
         if (client == null)
 74  
         {
 75  32
             final XFire xfire = connector.getXfire();
 76  32
             final String serviceName = getServiceName(endpoint);
 77  32
             final Service service = xfire.getServiceRegistry().getService(serviceName);
 78  
 
 79  32
             if (service == null)
 80  
             {
 81  0
                 throw new FatalConnectException(XFireMessages.serviceIsNull(serviceName), this);
 82  
             }
 83  
             
 84  32
             List inList = connector.getServerInHandlers();
 85  32
             if (inList != null)
 86  
             {
 87  0
                 for (int i = 0; i < inList.size(); i++)
 88  
                 {
 89  0
                     Handler handler = (Handler) ClassUtils.instanciateClass(
 90  
                                         inList.get(i).toString(), ClassUtils.NO_ARGS, this.getClass());
 91  0
                     service.addInHandler(handler);
 92  
                 }
 93  
             }
 94  
             
 95  32
             List outList = connector.getServerOutHandlers();
 96  32
             if (outList != null)
 97  
             {
 98  0
                 for (int i = 0; i < outList.size(); i++)
 99  
                 {
 100  0
                     Handler handler = (Handler) ClassUtils.instanciateClass(
 101  
                                         outList.get(i).toString(), ClassUtils.NO_ARGS, this.getClass());
 102  0
                     service.addOutHandler(handler);
 103  
                 }
 104  
             }
 105  
 
 106  
             try
 107  
             {
 108  32
                 this.client = createXFireClient(endpoint, service, xfire);
 109  
             }
 110  0
             catch (Exception ex)
 111  
             {
 112  0
                 disconnect();
 113  0
                 throw ex;
 114  32
             }
 115  
         }
 116  32
     }
 117  
 
 118  
     protected Client createXFireClient(UMOImmutableEndpoint endpoint, Service service, XFire xfire) throws Exception
 119  
     {
 120  32
         return createXFireClient(endpoint, service, xfire, null);
 121  
     }
 122  
 
 123  
     protected Client createXFireClient(UMOImmutableEndpoint endpoint, Service service, XFire xfire, String transportClass) throws Exception
 124  
     {
 125  
         Class transportClazz;
 126  
 
 127  32
         if (connector.getClientTransport() == null)
 128  
         {
 129  32
             if (!StringUtils.isBlank(transportClass))
 130  
             {
 131  0
                 transportClazz = ClassUtils.loadClass(transportClass, this.getClass());
 132  
             }
 133  
             else
 134  
             {
 135  34
                 transportClazz = MuleUniversalTransport.class;
 136  
             }
 137  
         }
 138  
         else
 139  
         {
 140  0
             transportClazz = ClassUtils.loadClass(connector.getClientTransport(), this.getClass());
 141  
         }
 142  
         
 143  32
         Transport transport = (Transport) transportClazz.getConstructor(null).newInstance(null);
 144  32
         Client client = new Client(transport, service, endpoint.getEndpointURI().toString());
 145  32
         client.setXFire(xfire);
 146  32
         client.setEndpointUri(endpoint.getEndpointURI().toString());
 147  32
         return configureXFireClient(client);
 148  
     }
 149  
 
 150  
     protected Client configureXFireClient(Client client) throws Exception
 151  
     {       
 152  38
         client.addInHandler(new MuleHeadersInHandler());
 153  38
         client.addOutHandler(new MuleHeadersOutHandler());
 154  
 
 155  38
         List inList = connector.getClientInHandlers();
 156  38
         if (inList != null)
 157  
         {
 158  0
             for (int i = 0; i < inList.size(); i++)
 159  
             {
 160  0
                 Handler handler = (Handler) ClassUtils.instanciateClass(
 161  
                                         inList.get(i).toString(), ClassUtils.NO_ARGS, this.getClass());
 162  0
                 client.addInHandler(handler);
 163  
             }
 164  
         }
 165  
         
 166  38
         List outList = connector.getClientOutHandlers();
 167  38
         if (outList != null)
 168  
         {
 169  0
             for (int i = 0; i < outList.size(); i++)
 170  
             {
 171  0
                 Handler handler = (Handler) ClassUtils.instanciateClass(
 172  
                                         outList.get(i).toString(), ClassUtils.NO_ARGS, this.getClass());
 173  0
                 client.addOutHandler(handler);
 174  
             }
 175  
         }
 176  
         
 177  38
         if (this.connector.getExtraProperties() != null)
 178  
         {
 179  0
             Properties props = new Properties();
 180  0
             props.putAll(this.connector.getExtraProperties());
 181  0
             Object[] keys = props.keySet().toArray();
 182  0
             for (int i = 0; i < props.size(); i++)
 183  
             {
 184  0
                 client.setProperty(keys[i].toString(), props.getProperty((String) keys[i]));
 185  
             }
 186  
         }
 187  
         
 188  38
         return client;
 189  
     }
 190  
 
 191  
     protected void doDisconnect() throws Exception
 192  
     {
 193  38
         client = null;
 194  38
     }
 195  
 
 196  
     protected void doDispose()
 197  
     {
 198  
         // nothing to do
 199  38
     }
 200  
 
 201  
     protected String getMethod(UMOEvent event) throws DispatchException
 202  
     {
 203  32
         String method = (String)event.getMessage().getProperty(MuleProperties.MULE_METHOD_PROPERTY);     
 204  
                 
 205  32
         if (method == null)
 206  
         {
 207  0
             UMOEndpointURI endpointUri = event.getEndpoint().getEndpointURI();
 208  0
             method = (String)endpointUri.getParams().get(MuleProperties.MULE_METHOD_PROPERTY);
 209  
         }
 210  
         
 211  32
         if (method == null)
 212  
         {
 213  0
             method = (String)event.getEndpoint().getProperties().get(MuleProperties.MULE_METHOD_PROPERTY);
 214  
         }   
 215  
         
 216  32
         if (method == null)
 217  
         {
 218  0
             throw new DispatchException(SoapMessages.cannotInvokeCallWithoutOperation(), 
 219  
                 event.getMessage(), event.getEndpoint());
 220  
         }
 221  
                 
 222  32
         return method;
 223  
     }
 224  
 
 225  
     protected Object[] getArgs(UMOEvent event) throws TransformerException
 226  
     {
 227  32
         Object payload = event.getTransformedMessage();
 228  
         Object[] args;
 229  
 
 230  32
         if (payload instanceof Object[])
 231  
         {
 232  2
             args = (Object[])payload;
 233  
         }
 234  
         else
 235  
         {
 236  30
             args = new Object[]{payload};
 237  
         }
 238  
 
 239  32
         UMOMessage message = event.getMessage();
 240  32
         Set attachmentNames = message.getAttachmentNames();
 241  32
         if (attachmentNames != null && !attachmentNames.isEmpty())
 242  
         {
 243  0
             List attachments = new ArrayList();
 244  0
             for (Iterator i = attachmentNames.iterator(); i.hasNext();)
 245  
             {
 246  0
                 attachments.add(message.getAttachment((String)i.next()));
 247  
             }
 248  0
             List temp = new ArrayList(Arrays.asList(args));
 249  0
             temp.add(attachments.toArray(new DataHandler[0]));
 250  0
             args = temp.toArray();
 251  
         }
 252  
 
 253  32
         return args;
 254  
     }
 255  
 
 256  
     protected UMOMessage doSend(UMOEvent event) throws Exception
 257  
     {
 258  30
         if (event.getEndpoint().getProperty("complexTypes") != null)
 259  
         {
 260  0
             configureClientForComplexTypes(this.client, event);
 261  
         }
 262  30
         this.client.setTimeout(event.getTimeout());
 263  30
         this.client.setProperty(MuleProperties.MULE_EVENT_PROPERTY, event);
 264  30
         String method = getMethod(event);
 265  
 
 266  
         // Set custom soap action if set on the event or endpoint
 267  30
         String soapAction = (String)event.getMessage().getProperty(SoapConstants.SOAP_ACTION_PROPERTY);
 268  30
         if (soapAction != null)
 269  
         {
 270  0
             soapAction = parseSoapAction(soapAction, new QName(method), event);
 271  0
             this.client.setProperty(org.codehaus.xfire.soap.SoapConstants.SOAP_ACTION, soapAction);
 272  
         }
 273  
 
 274  
         // Set Custom Headers on the client
 275  30
         Object[] arr = event.getMessage().getPropertyNames().toArray();
 276  
         String head;
 277  
 
 278  152
         for (int i = 0; i < arr.length; i++)
 279  
         {
 280  122
             head = (String) arr[i];
 281  122
             if ((head != null) && (!head.startsWith("MULE")))
 282  
             {
 283  40
                 this.client.setProperty((String) arr[i], event.getMessage().getProperty((String) arr[i]));
 284  
             }
 285  
         }
 286  
 
 287  30
         Object[] response = client.invoke(method, getArgs(event));
 288  
 
 289  22
         UMOMessage result = null;
 290  22
         if (response != null && response.length <= 1)
 291  
         {
 292  22
             if (response.length == 1)
 293  
             {
 294  20
                 result = new MuleMessage(response[0], event.getMessage());
 295  
             }
 296  
         }
 297  
         else
 298  
         {
 299  0
             result = new MuleMessage(response, event.getMessage());
 300  
         }
 301  
 
 302  22
         return result;
 303  
     }
 304  
 
 305  
     protected void doDispatch(UMOEvent event) throws Exception
 306  
     {
 307  2
         this.client.setTimeout(event.getTimeout());
 308  2
         this.client.setProperty(MuleProperties.MULE_EVENT_PROPERTY, event);
 309  2
         this.client.invoke(getMethod(event), getArgs(event));
 310  2
     }
 311  
 
 312  
     /**
 313  
      * Make a specific request to the underlying transport
 314  
      * 
 315  
      * @param timeout the maximum time the operation should block before returning.
 316  
      *            The call should return immediately if there is data available. If
 317  
      *            no data becomes available before the timeout elapses, null will be
 318  
      *            returned
 319  
      * @return the result of the request wrapped in a UMOMessage object. Null will be
 320  
      *         returned if no data was avaialable
 321  
      * @throws Exception if the call to the underlying protocal cuases an exception
 322  
      */
 323  
     protected UMOMessage doReceive(long timeout) throws Exception
 324  
     {
 325  12
         String serviceName = getServiceName(endpoint);
 326  
 
 327  12
         XFire xfire = connector.getXfire();
 328  12
         Service service = xfire.getServiceRegistry().getService(serviceName);
 329  
 
 330  12
         Client client = new Client(new MuleUniversalTransport(), service, endpoint.getEndpointURI()
 331  
             .toString());
 332  12
         client.setXFire(xfire);
 333  12
         client.setTimeout((int)timeout);
 334  12
         client.setEndpointUri(endpoint.getEndpointURI().toString());
 335  
 
 336  12
         String method = (String)endpoint.getProperty(MuleProperties.MULE_METHOD_PROPERTY);
 337  12
         OperationInfo op = service.getServiceInfo().getOperation(method);
 338  
 
 339  12
         Properties params = endpoint.getEndpointURI().getUserParams();
 340  12
         String args[] = new String[params.size()];
 341  12
         int i = 0;
 342  32
         for (Iterator iterator = params.values().iterator(); iterator.hasNext(); i++)
 343  
         {
 344  20
             args[i] = iterator.next().toString();
 345  
         }
 346  
 
 347  12
         Object[] response = client.invoke(op, args);
 348  
 
 349  12
         if (response != null && response.length == 1)
 350  
         {
 351  12
             return new MuleMessage(response[0]);
 352  
         }
 353  
         else
 354  
         {
 355  0
             return new MuleMessage(response);
 356  
         }
 357  
     }
 358  
 
 359  
     /**
 360  
      * Get the service that is mapped to the specified request.
 361  
      * @param endpoint endpoint containing a service path
 362  
      * @return service name
 363  
      */
 364  
     protected String getServiceName(UMOImmutableEndpoint endpoint)
 365  
     {
 366  44
         String pathInfo = endpoint.getEndpointURI().getPath();
 367  
 
 368  44
         if (StringUtils.isEmpty(pathInfo))
 369  
         {
 370  0
             return endpoint.getEndpointURI().getHost();
 371  
         }
 372  
 
 373  
         String serviceName;
 374  
 
 375  44
         int i = pathInfo.lastIndexOf('/');
 376  
 
 377  44
         if (i > -1)
 378  
         {
 379  44
             serviceName = pathInfo.substring(i + 1);
 380  
         }
 381  
         else
 382  
         {
 383  0
             serviceName = pathInfo;
 384  
         }
 385  
 
 386  44
         return serviceName;
 387  
     }
 388  
 
 389  
     public String parseSoapAction(String soapAction, QName method, UMOEvent event)
 390  
     {
 391  
 
 392  0
         UMOEndpointURI endpointURI = event.getEndpoint().getEndpointURI();
 393  0
         Map properties = new HashMap();
 394  0
         UMOMessage msg = event.getMessage();
 395  0
         for (Iterator iterator = msg.getPropertyNames().iterator(); iterator.hasNext();)
 396  
         {
 397  0
             String propertyKey = (String)iterator.next();
 398  0
             properties.put(propertyKey, msg.getProperty(propertyKey));
 399  0
         }
 400  0
         properties.put(MuleProperties.MULE_METHOD_PROPERTY, method.getLocalPart());
 401  0
         properties.put("methodNamespace", method.getNamespaceURI());
 402  0
         properties.put("address", endpointURI.getAddress());
 403  0
         properties.put("scheme", endpointURI.getScheme());
 404  0
         properties.put("host", endpointURI.getHost());
 405  0
         properties.put("port", String.valueOf(endpointURI.getPort()));
 406  0
         properties.put("path", endpointURI.getPath());
 407  0
         properties.put("hostInfo", endpointURI.getScheme()
 408  
                                    + "://"
 409  
                                    + endpointURI.getHost()
 410  
                                    + (endpointURI.getPort() > -1
 411  
                                                    ? ":" + String.valueOf(endpointURI.getPort()) : ""));
 412  0
         if (event.getComponent() != null)
 413  
         {
 414  0
             properties.put("serviceName", event.getComponent().getDescriptor().getName());
 415  
         }
 416  
 
 417  0
         soapAction = soapActionTemplateParser.parse(properties, soapAction);
 418  
 
 419  0
         if (logger.isDebugEnabled())
 420  
         {
 421  0
             logger.debug("SoapAction for this call is: " + soapAction);
 422  
         }
 423  
 
 424  0
         return soapAction;
 425  
     }
 426  
 
 427  
     protected void configureClientForComplexTypes(Client client, UMOEvent event) throws ClassNotFoundException
 428  
     {
 429  0
         Map complexTypes = (Map) event.getEndpoint().getProperty("complexTypes");
 430  0
         Object[] beans = complexTypes.keySet().toArray();
 431  
 
 432  0
         AegisBindingProvider bp = (AegisBindingProvider) client.getService().getBindingProvider();
 433  0
         TypeMapping typeMapping = bp.getTypeMapping(client.getService());
 434  
 
 435  
         // for each complex type
 436  0
         for (int i = 0; i < beans.length; i++)
 437  
         {
 438  0
             BeanType bt = new BeanType();
 439  0
             String[] queue = ((String) complexTypes.get(beans[i])).split(":", 2);
 440  0
             bt.setSchemaType(new QName(queue[1], queue[0]));
 441  0
             bt.setTypeClass(Class.forName(beans[i].toString()));
 442  0
             typeMapping.register(bt);
 443  
         }
 444  0
     }
 445  
 }