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