Coverage Report - org.mule.module.client.remoting.RemoteDispatcherComponent
 
Classes in this File Line Coverage Branch Coverage Complexity
RemoteDispatcherComponent
0%
0/116
0%
0/34
3.286
 
 1  
 /*
 2  
  * $Id: RemoteDispatcherComponent.java 19191 2010-08-25 21:05:23Z tcarlson $
 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.client.remoting;
 12  
 
 13  
 import org.mule.DefaultMuleEvent;
 14  
 import org.mule.DefaultMuleMessage;
 15  
 import org.mule.MessageExchangePattern;
 16  
 import org.mule.RequestContext;
 17  
 import org.mule.api.DefaultMuleException;
 18  
 import org.mule.api.MuleContext;
 19  
 import org.mule.api.MuleEvent;
 20  
 import org.mule.api.MuleEventContext;
 21  
 import org.mule.api.MuleException;
 22  
 import org.mule.api.MuleMessage;
 23  
 import org.mule.api.MuleSession;
 24  
 import org.mule.api.config.MuleProperties;
 25  
 import org.mule.api.endpoint.EndpointBuilder;
 26  
 import org.mule.api.endpoint.EndpointFactory;
 27  
 import org.mule.api.endpoint.ImmutableEndpoint;
 28  
 import org.mule.api.endpoint.InboundEndpoint;
 29  
 import org.mule.api.endpoint.OutboundEndpoint;
 30  
 import org.mule.api.lifecycle.Callable;
 31  
 import org.mule.api.lifecycle.Initialisable;
 32  
 import org.mule.api.lifecycle.InitialisationException;
 33  
 import org.mule.api.service.Service;
 34  
 import org.mule.api.source.CompositeMessageSource;
 35  
 import org.mule.api.transformer.DataType;
 36  
 import org.mule.api.transformer.TransformerException;
 37  
 import org.mule.api.transformer.wire.WireFormat;
 38  
 import org.mule.component.SimpleCallableJavaComponent;
 39  
 import org.mule.config.i18n.CoreMessages;
 40  
 import org.mule.endpoint.EndpointURIEndpointBuilder;
 41  
 import org.mule.message.DefaultExceptionPayload;
 42  
 import org.mule.model.seda.SedaService;
 43  
 import org.mule.module.client.remoting.notification.RemoteDispatcherNotification;
 44  
 import org.mule.object.PrototypeObjectFactory;
 45  
 import org.mule.session.DefaultMuleSession;
 46  
 import org.mule.transport.AbstractConnector;
 47  
 import org.mule.transport.NullPayload;
 48  
 import org.mule.util.MapUtils;
 49  
 
 50  
 import java.io.ByteArrayInputStream;
 51  
 import java.lang.reflect.Method;
 52  
 import java.util.HashMap;
 53  
 import java.util.LinkedList;
 54  
 import java.util.List;
 55  
 import java.util.Map;
 56  
 
 57  
 import org.apache.commons.io.output.ByteArrayOutputStream;
 58  
 import org.apache.commons.logging.Log;
 59  
 import org.apache.commons.logging.LogFactory;
 60  
 
 61  
 /**
 62  
  * <code>RemoteDispatcherComponent</code> is a MuleManager interal server component
 63  
  * responsible for receiving remote requests and dispatching them locally. This
 64  
  * allows developer to tunnel requests through http ssl to a Mule instance behind a
 65  
  * firewall
 66  
  */
 67  
 
 68  0
 public class RemoteDispatcherComponent implements Callable, Initialisable
 69  
 {
 70  
     /**
 71  
      * logger used by this class
 72  
      */
 73  0
     protected static final Log logger = LogFactory.getLog(RemoteDispatcherComponent.class);
 74  
 
 75  
     public static final String MANAGER_COMPONENT_NAME = "_muleManagerComponent";
 76  
 
 77  
     /**
 78  
      * Use Serialization by default
 79  
      */
 80  
     protected WireFormat wireFormat;
 81  
 
 82  
     protected String encoding;
 83  
 
 84  0
     protected int synchronousEventTimeout = 5000;
 85  
 
 86  
     protected MuleContext muleContext;
 87  
 
 88  
     public void initialise() throws InitialisationException
 89  
     {
 90  0
         if (wireFormat == null)
 91  
         {
 92  0
             throw new InitialisationException(CoreMessages.objectIsNull("wireFormat"), this);
 93  
         }
 94  0
     }
 95  
 
 96  
     public Object onCall(MuleEventContext context) throws Exception
 97  
     {
 98  0
         muleContext = context.getMuleContext();
 99  0
         if(context.transformMessageToString().equals(ServerHandshake.SERVER_HANDSHAKE_PROPERTY))
 100  
         {
 101  0
             return doHandshake(context);
 102  
         }
 103  
 
 104  
         Object result;
 105  0
         logger.debug("Message received by RemoteDispatcherComponent");
 106  0
         ByteArrayInputStream in = new ByteArrayInputStream((byte[]) context.transformMessage(DataType.BYTE_ARRAY_DATA_TYPE));
 107  0
         RemoteDispatcherNotification action = (RemoteDispatcherNotification) ((MuleMessage)wireFormat.read(in)).getPayload();
 108  
 
 109  
         // because we serialized a message inside a message, we need to inject the the muleContext ourselves
 110  
         //TODO review the serialization format for RemoteDispatching
 111  0
         if(action.getMessage()!=null)
 112  
         {
 113  0
             Method m = action.getMessage().getClass().getDeclaredMethod("initAfterDeserialisation", MuleContext.class);
 114  0
             m.setAccessible(true);
 115  0
             m.invoke(action.getMessage(), muleContext);
 116  
         }
 117  
         
 118  0
         if (RemoteDispatcherNotification.ACTION_INVOKE == action.getAction())
 119  
         {
 120  0
             result = invokeAction(action, context);
 121  
         }
 122  0
         else if (RemoteDispatcherNotification.ACTION_SEND == action.getAction() ||
 123  
                  RemoteDispatcherNotification.ACTION_DISPATCH == action.getAction())
 124  
         {
 125  0
             result = sendAction(action, context);
 126  
         }
 127  0
         else if (RemoteDispatcherNotification.ACTION_RECEIVE == action.getAction())
 128  
         {
 129  0
             result = receiveAction(action, context);
 130  
         }
 131  
         else
 132  
         {
 133  0
             result = handleException(null, new DefaultMuleException(
 134  
                 CoreMessages.eventTypeNotRecognised("RemoteDispatcherNotification:" + action.getAction())));
 135  
         }
 136  0
         return result;
 137  
     }
 138  
 
 139  
     protected ServerHandshake doHandshake(MuleEventContext context) throws TransformerException
 140  
     {
 141  0
         ServerHandshake handshake  = new ServerHandshake();
 142  0
         handshake.setWireFormatClass(wireFormat.getClass().getName());
 143  0
         return handshake;
 144  
     }
 145  
 
 146  
     protected Object invokeAction(RemoteDispatcherNotification action, MuleEventContext context) throws MuleException
 147  
     {
 148  
         String destComponent;
 149  0
         MuleMessage result = null;
 150  0
         String endpoint = action.getResourceIdentifier();
 151  0
         if (action.getResourceIdentifier().startsWith("mule:"))
 152  
         {
 153  0
             destComponent = endpoint.substring(endpoint.lastIndexOf("/") + 1);
 154  
         }
 155  
         else
 156  
         {
 157  0
             destComponent = endpoint;
 158  
         }
 159  
 
 160  0
         if (destComponent != null)
 161  
         {
 162  0
             Service service = muleContext.getRegistry().lookupService(destComponent);
 163  0
             MuleSession session = new DefaultMuleSession(service, muleContext);
 164  
             // Need to do this otherise when the event is invoked the
 165  
             // transformer associated with the Mule Admin queue will be invoked, but
 166  
             // the message will not be of expected type
 167  
 
 168  0
             EndpointBuilder builder = new EndpointURIEndpointBuilder(RequestContext.getEvent().getEndpoint());
 169  
             // TODO - is this correct? it stops any other transformer from being set
 170  0
             builder.setTransformers(new LinkedList());
 171  0
             ImmutableEndpoint ep = muleContext.getRegistry().lookupEndpointFactory().getInboundEndpoint(builder);
 172  0
             MuleEvent event = new DefaultMuleEvent(action.getMessage(), ep, context.getSession());
 173  0
             event = RequestContext.setEvent(event);
 174  
 
 175  0
             if (context.getExchangePattern().hasResponse())
 176  
             {
 177  0
                 MuleEvent resultEvent = service.sendEvent(event);
 178  0
                 result = resultEvent == null ? null : resultEvent.getMessage();
 179  0
                 ByteArrayOutputStream out = new ByteArrayOutputStream();
 180  0
                 wireFormat.write(out, result, getEncoding());
 181  0
                 return out.toByteArray();
 182  
             }
 183  
             else
 184  
             {
 185  0
                 service.dispatchEvent(event);
 186  0
                 return null;
 187  
             }
 188  
         }
 189  
         else
 190  
         {
 191  0
             return handleException(result, new DefaultMuleException(
 192  
                 CoreMessages.couldNotDetermineDestinationComponentFromEndpoint(endpoint)));
 193  
         }
 194  
     }
 195  
 
 196  
     protected Object sendAction(RemoteDispatcherNotification action, MuleEventContext context) throws MuleException
 197  
     {
 198  0
         MuleMessage result = null;
 199  0
         OutboundEndpoint endpoint = null;
 200  0
         MuleContext managementContext = context.getMuleContext();
 201  
         try
 202  
         {
 203  0
             if (RemoteDispatcherNotification.ACTION_DISPATCH == action.getAction())
 204  
             {
 205  0
                 endpoint = managementContext.getRegistry().lookupEndpointFactory().getOutboundEndpoint(
 206  
                     action.getResourceIdentifier());
 207  0
                 context.dispatchEvent(action.getMessage(), endpoint);
 208  0
                 return null;
 209  
             }
 210  
             else
 211  
             {
 212  0
                 EndpointFactory endpointFactory = managementContext.getRegistry().lookupEndpointFactory();
 213  0
                 EndpointBuilder endpointBuilder = endpointFactory.getEndpointBuilder(action.getResourceIdentifier());
 214  0
                 endpointBuilder.setExchangePattern(MessageExchangePattern.REQUEST_RESPONSE);
 215  0
                 endpoint = managementContext.getRegistry().lookupEndpointFactory().getOutboundEndpoint(endpointBuilder);
 216  0
                 result = context.sendEvent(action.getMessage(), endpoint);
 217  0
                 if (result == null)
 218  
                 {
 219  0
                     return null;
 220  
                 }
 221  
                 else
 222  
                 {
 223  0
                     ByteArrayOutputStream out = new ByteArrayOutputStream();
 224  0
                     wireFormat.write(out, result, getEncoding());
 225  0
                     return out.toByteArray();
 226  
                 }
 227  
             }
 228  
         }
 229  0
         catch (Exception e)
 230  
         {
 231  0
             return handleException(result, e);
 232  
         }
 233  
     }
 234  
 
 235  
     protected Object receiveAction(RemoteDispatcherNotification action, MuleEventContext context) throws MuleException
 236  
     {
 237  0
         MuleMessage result = null;
 238  
         try
 239  
         {
 240  0
             ImmutableEndpoint endpoint = context.getMuleContext()
 241  
                 .getRegistry()
 242  
                 .lookupEndpointFactory()
 243  
                 .getOutboundEndpoint(action.getResourceIdentifier());
 244  
 
 245  0
             long timeout = MapUtils.getLongValue(action.getProperties(),
 246  
                 MuleProperties.MULE_EVENT_TIMEOUT_PROPERTY, getSynchronousEventTimeout());
 247  
 
 248  0
             result = endpoint.getConnector().request(action.getResourceIdentifier(), timeout);
 249  0
             if (result != null)
 250  
             {
 251  
                 // See if there is a default transformer on the connector
 252  0
                 List transformers = ((AbstractConnector) endpoint.getConnector()).getDefaultInboundTransformers(endpoint);
 253  0
                 if (transformers != null)
 254  
                 {
 255  0
                     result.applyTransformers(null, transformers);
 256  
                 }
 257  0
                 ByteArrayOutputStream out = new ByteArrayOutputStream();
 258  0
                 wireFormat.write(out, result, getEncoding());
 259  0
                 return out.toByteArray();
 260  
             }
 261  
             else
 262  
             {
 263  0
                 return null;
 264  
             }
 265  
         }
 266  0
         catch (Exception e)
 267  
         {
 268  0
             return handleException(result, e);
 269  
         }
 270  
 
 271  
     }
 272  
 
 273  
 
 274  
     public static Service getSerivce(InboundEndpoint endpoint,
 275  
                                                     WireFormat wireFormat,
 276  
                                                     String encoding,
 277  
                                                     int eventTimeout,
 278  
                                                     MuleContext muleContext) throws MuleException
 279  
     {
 280  
         try
 281  
         {
 282  0
             Service service = new SedaService(muleContext);
 283  0
             service.setName(MANAGER_COMPONENT_NAME);
 284  0
             service.setModel(muleContext.getRegistry().lookupSystemModel());
 285  
 
 286  0
             Map props = new HashMap();
 287  0
             props.put("wireFormat", wireFormat);
 288  0
             props.put("encoding", encoding);
 289  0
             props.put("synchronousEventTimeout", new Integer(eventTimeout));
 290  0
             service.setComponent(new SimpleCallableJavaComponent(new PrototypeObjectFactory(RemoteDispatcherComponent.class, props)));
 291  
 
 292  
 
 293  0
             if (!(service.getMessageSource() instanceof CompositeMessageSource))
 294  
             {
 295  0
                 throw new IllegalStateException("Only 'CompositeMessageSource' is supported with RemoteDispatcherService");
 296  
             }
 297  
 
 298  0
             ((CompositeMessageSource) service.getMessageSource()).addSource(endpoint);
 299  
 
 300  0
             return service;
 301  
         }
 302  0
         catch (Exception e)
 303  
         {
 304  0
             throw new InitialisationException(e, null);
 305  
         }
 306  
     }
 307  
 
 308  
     /**
 309  
      * Wraps an exception into a MuleMessage with an Exception payload and returns
 310  
      * the Xml representation of it
 311  
      * 
 312  
      * @param result the result of the invocation or null if the exception occurred
 313  
      *            before or during the invocation
 314  
      * @param e the Exception thrown
 315  
      * @return an Xml String message result
 316  
      */
 317  
     protected Object handleException(MuleMessage result, Throwable e)
 318  
     {
 319  0
         logger.error("Failed to process admin request: " + e.getMessage(), e);
 320  0
         if (result == null)
 321  
         {
 322  0
             result = new DefaultMuleMessage(NullPayload.getInstance(), (Map) null, muleContext);
 323  
         }
 324  0
         result.setExceptionPayload(new DefaultExceptionPayload(e));
 325  
         try
 326  
         {
 327  0
             ByteArrayOutputStream out = new ByteArrayOutputStream();
 328  0
             wireFormat.write(out, result, getEncoding());
 329  0
             return out.toByteArray();
 330  
         }
 331  0
         catch (Exception e1)
 332  
         {
 333  
             // TODO MULE-863: Is this sufficient?
 334  
             // log the inner exception here since the earlier exception was logged earlier
 335  0
             logger.error("Failed to format message, using direct string (details at debug level): " + e1.getMessage());
 336  0
             logger.debug(e1.toString(), e1);
 337  0
             return e.getMessage();
 338  
         }
 339  
     }
 340  
 
 341  
     public WireFormat getWireFormat()
 342  
     {
 343  0
         return wireFormat;
 344  
     }
 345  
 
 346  
     public void setWireFormat(WireFormat wireFormat)
 347  
     {
 348  0
         this.wireFormat = wireFormat;
 349  0
     }
 350  
 
 351  
     public String getEncoding()
 352  
     {
 353  0
         return encoding;
 354  
     }
 355  
 
 356  
     public void setEncoding(String encoding)
 357  
     {
 358  0
         this.encoding = encoding;
 359  0
     }
 360  
 
 361  
     public int getSynchronousEventTimeout()
 362  
     {
 363  0
         return synchronousEventTimeout;
 364  
     }
 365  
 
 366  
     public void setSynchronousEventTimeout(int synchronousEventTimeout)
 367  
     {
 368  0
         this.synchronousEventTimeout = synchronousEventTimeout;
 369  0
     }
 370  
 }