Coverage Report - org.mule.routing.outbound.AbstractOutboundRouter
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractOutboundRouter
0%
0/180
0%
0/100
0
AbstractOutboundRouter$1
0%
0/2
N/A
0
 
 1  
 /*
 2  
  * $Id: AbstractOutboundRouter.java 20555 2010-12-09 17:54:31Z aperepel $
 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.routing.outbound;
 12  
 
 13  
 import org.mule.DefaultMuleEvent;
 14  
 import org.mule.DefaultMuleMessage;
 15  
 import org.mule.api.MessagingException;
 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.config.MuleProperties;
 21  
 import org.mule.api.construct.FlowConstruct;
 22  
 import org.mule.api.construct.FlowConstructAware;
 23  
 import org.mule.api.context.MuleContextAware;
 24  
 import org.mule.api.endpoint.ImmutableEndpoint;
 25  
 import org.mule.api.endpoint.OutboundEndpoint;
 26  
 import org.mule.api.lifecycle.Disposable;
 27  
 import org.mule.api.lifecycle.Initialisable;
 28  
 import org.mule.api.lifecycle.InitialisationException;
 29  
 import org.mule.api.lifecycle.Startable;
 30  
 import org.mule.api.lifecycle.Stoppable;
 31  
 import org.mule.api.processor.MessageProcessor;
 32  
 import org.mule.api.routing.OutboundRouter;
 33  
 import org.mule.api.routing.RouterResultsHandler;
 34  
 import org.mule.api.routing.RoutingException;
 35  
 import org.mule.api.transaction.TransactionCallback;
 36  
 import org.mule.api.transaction.TransactionConfig;
 37  
 import org.mule.api.transport.DispatchException;
 38  
 import org.mule.config.i18n.CoreMessages;
 39  
 import org.mule.management.stats.RouterStatistics;
 40  
 import org.mule.processor.AbstractMessageProcessorOwner;
 41  
 import org.mule.routing.CorrelationMode;
 42  
 import org.mule.routing.DefaultRouterResultsHandler;
 43  
 import org.mule.transaction.TransactionTemplate;
 44  
 import org.mule.util.StringMessageUtils;
 45  
 import org.mule.util.SystemUtils;
 46  
 
 47  
 import java.util.Arrays;
 48  
 import java.util.Collections;
 49  
 import java.util.List;
 50  
 
 51  
 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
 52  
 import edu.emory.mathcs.backport.java.util.concurrent.atomic.AtomicBoolean;
 53  
 
 54  
 import org.apache.commons.logging.Log;
 55  
 import org.apache.commons.logging.LogFactory;
 56  
 
 57  
 /**
 58  
  * <code>AbstractOutboundRouter</code> is a base router class that tracks statistics about message processing
 59  
  * through the router.
 60  
  */
 61  0
 public abstract class AbstractOutboundRouter extends AbstractMessageProcessorOwner implements OutboundRouter
 62  
 {
 63  
     /**
 64  
      * These properties are automatically propagated by Mule from inbound to outbound
 65  
      */
 66  0
     protected static List<String> magicProperties = Arrays.asList(
 67  
         MuleProperties.MULE_CORRELATION_ID_PROPERTY, MuleProperties.MULE_CORRELATION_ID_PROPERTY,
 68  
         MuleProperties.MULE_CORRELATION_GROUP_SIZE_PROPERTY,
 69  
         MuleProperties.MULE_CORRELATION_SEQUENCE_PROPERTY, MuleProperties.MULE_SESSION_PROPERTY);
 70  
 
 71  
     /**
 72  
      * logger used by this class
 73  
      */
 74  0
     protected transient Log logger = LogFactory.getLog(getClass());
 75  
 
 76  0
     @SuppressWarnings("unchecked")
 77  
     protected List<MessageProcessor> routes = new CopyOnWriteArrayList();
 78  
 
 79  0
     protected String replyTo = null;
 80  
 
 81  
     /**
 82  
      * Determines if Mule stamps outgoing message with a correlation ID or not.
 83  
      */
 84  0
     protected CorrelationMode enableCorrelation = CorrelationMode.IF_NOT_SET;
 85  
 
 86  
     protected TransactionConfig transactionConfig;
 87  
 
 88  0
     protected RouterResultsHandler resultsHandler = new DefaultRouterResultsHandler();
 89  
 
 90  
     private RouterStatistics routerStatistics;
 91  
 
 92  0
     protected AtomicBoolean initialised = new AtomicBoolean(false);
 93  0
     protected AtomicBoolean started = new AtomicBoolean(false);
 94  
 
 95  
     public MuleEvent process(final MuleEvent event) throws MuleException
 96  
     {
 97  0
         TransactionTemplate<MuleEvent> tt = new TransactionTemplate<MuleEvent>(getTransactionConfig(),
 98  
             muleContext);
 99  
 
 100  0
         TransactionCallback<MuleEvent> cb = new TransactionCallback<MuleEvent>()
 101  0
         {
 102  
             public MuleEvent doInTransaction() throws Exception
 103  
             {
 104  0
                 return route(event);
 105  
             }
 106  
         };
 107  
         try
 108  
         {
 109  0
             return tt.execute(cb);
 110  
         }
 111  0
         catch (RoutingException e)
 112  
         {
 113  0
             throw e;
 114  
         }
 115  0
         catch (Exception e)
 116  
         {
 117  0
             throw new RoutingException(event, this, e);
 118  
         }
 119  
     }
 120  
 
 121  
     protected abstract MuleEvent route(MuleEvent event) throws MessagingException;
 122  
 
 123  
     protected final MuleEvent sendRequest(final MuleEvent routedEvent,
 124  
                                           final MuleMessage message,
 125  
                                           final MessageProcessor route,
 126  
                                           boolean awaitResponse) throws MuleException
 127  
     {
 128  0
         if (awaitResponse && replyTo != null)
 129  
         {
 130  0
             logger.debug("event was dispatched synchronously, but there is a ReplyTo route set, so using asynchronous dispatch");
 131  0
             awaitResponse = false;
 132  
         }
 133  
 
 134  0
         setMessageProperties(routedEvent.getSession().getFlowConstruct(), message, route);
 135  
 
 136  0
         if (logger.isDebugEnabled())
 137  
         {
 138  0
             if (route instanceof OutboundEndpoint)
 139  
             {
 140  0
                 logger.debug("Message being sent to: " + ((OutboundEndpoint) route).getEndpointURI());
 141  
             }
 142  0
             logger.debug(message);
 143  
         }
 144  
 
 145  0
         if (logger.isTraceEnabled())
 146  
         {
 147  
             try
 148  
             {
 149  0
                 logger.trace("Request payload: \n"
 150  
                              + StringMessageUtils.truncate(message.getPayloadForLogging(), 100, false));
 151  0
                 if (route instanceof OutboundEndpoint)
 152  
                 {
 153  0
                     logger.trace("outbound transformer is: " + ((OutboundEndpoint) route).getTransformers());
 154  
                 }
 155  
             }
 156  0
             catch (Exception e)
 157  
             {
 158  0
                 logger.trace("Request payload: \n(unable to retrieve payload: " + e.getMessage());
 159  0
                 if (route instanceof OutboundEndpoint)
 160  
                 {
 161  0
                     logger.trace("outbound transformer is: " + ((OutboundEndpoint) route).getTransformers());
 162  
                 }
 163  0
             }
 164  
         }
 165  
 
 166  
         MuleEvent result;
 167  
         try
 168  
         {
 169  0
             result = sendRequestEvent(routedEvent, message, route, awaitResponse);
 170  
         }
 171  0
         catch (MessagingException me)
 172  
         {
 173  0
             throw me;
 174  
         }
 175  0
         catch (Exception e)
 176  
         {
 177  0
             throw new RoutingException(routedEvent, null, e);
 178  0
         }
 179  
 
 180  0
         if (getRouterStatistics() != null)
 181  
         {
 182  0
             if (getRouterStatistics().isEnabled())
 183  
             {
 184  0
                 getRouterStatistics().incrementRoutedMessage(route);
 185  
             }
 186  
         }
 187  
 
 188  0
         if (result != null)
 189  
         {
 190  0
             MuleMessage resultMessage = result.getMessage();
 191  0
             if (logger.isTraceEnabled())
 192  
             {
 193  0
                 if (resultMessage != null)
 194  
                 {
 195  
                     try
 196  
                     {
 197  0
                         logger.trace("Response payload: \n"
 198  
                                      + StringMessageUtils.truncate(resultMessage.getPayloadForLogging(), 100,
 199  
                                          false));
 200  
                     }
 201  0
                     catch (Exception e)
 202  
                     {
 203  0
                         logger.trace("Response payload: \n(unable to retrieve payload: " + e.getMessage());
 204  0
                     }
 205  
                 }
 206  
             }
 207  
         }
 208  
 
 209  0
         return result;
 210  
     }
 211  
 
 212  
     protected void setMessageProperties(FlowConstruct service, MuleMessage message, MessageProcessor route)
 213  
     {
 214  0
         if (replyTo != null)
 215  
         {
 216  
             // if replyTo is set we'll probably want the correlationId set as
 217  
             // well
 218  0
             message.setReplyTo(replyTo);
 219  0
             message.setOutboundProperty(MuleProperties.MULE_REPLY_TO_REQUESTOR_PROPERTY, service.getName());
 220  0
             if (logger.isDebugEnabled() && route instanceof OutboundEndpoint)
 221  
             {
 222  0
                 logger.debug("Setting replyTo=" + replyTo + " for outbound route: "
 223  
                              + ((OutboundEndpoint) route).getEndpointURI());
 224  
             }
 225  
         }
 226  0
         if (enableCorrelation != CorrelationMode.NEVER)
 227  
         {
 228  0
             boolean correlationSet = message.getCorrelationId() != null;
 229  0
             if (correlationSet && (enableCorrelation == CorrelationMode.IF_NOT_SET))
 230  
             {
 231  0
                 if (logger.isDebugEnabled())
 232  
                 {
 233  0
                     logger.debug("CorrelationId is already set to '" + message.getCorrelationId()
 234  
                                  + "' , not setting it again");
 235  
                 }
 236  0
                 return;
 237  
             }
 238  0
             else if (correlationSet)
 239  
             {
 240  0
                 if (logger.isDebugEnabled())
 241  
                 {
 242  0
                     logger.debug("CorrelationId is already set to '" + message.getCorrelationId()
 243  
                                  + "', but router is configured to overwrite it");
 244  
                 }
 245  
             }
 246  
             else
 247  
             {
 248  0
                 if (logger.isDebugEnabled())
 249  
                 {
 250  0
                     logger.debug("No CorrelationId is set on the message, will set a new Id");
 251  
                 }
 252  
             }
 253  
 
 254  
             String correlation;
 255  0
             correlation = service.getMessageInfoMapping().getCorrelationId(message);
 256  0
             if (logger.isDebugEnabled())
 257  
             {
 258  0
                 logger.debug("Extracted correlation Id as: " + correlation);
 259  
             }
 260  
 
 261  0
             if (logger.isDebugEnabled())
 262  
             {
 263  0
                 StringBuffer buf = new StringBuffer();
 264  0
                 buf.append("Setting Correlation info on Outbound router");
 265  0
                 if (route instanceof OutboundEndpoint)
 266  
                 {
 267  0
                     buf.append(" for endpoint: ").append(((OutboundEndpoint) route).getEndpointURI());
 268  
                 }
 269  0
                 buf.append(SystemUtils.LINE_SEPARATOR).append("Id=").append(correlation);
 270  
                 // buf.append(", ").append("Seq=").append(seq);
 271  
                 // buf.append(", ").append("Group Size=").append(group);
 272  0
                 logger.debug(buf.toString());
 273  
             }
 274  0
             message.setCorrelationId(correlation);
 275  
             // message.setCorrelationGroupSize(group);
 276  
             // message.setCorrelationSequence(seq);
 277  
         }
 278  0
     }
 279  
 
 280  
     public List<MessageProcessor> getRoutes()
 281  
     {
 282  0
         return routes;
 283  
     }
 284  
 
 285  
     /*
 286  
      * For spring access
 287  
      */
 288  
     // TODO Use spring factory bean
 289  
     @Deprecated
 290  
     public void setMessageProcessors(List<MessageProcessor> routes) throws MuleException
 291  
     {
 292  0
         setRoutes(routes);
 293  0
     }
 294  
 
 295  
     public void setRoutes(List<MessageProcessor> routes) throws MuleException
 296  
     {
 297  0
         this.routes.clear();
 298  0
         for (MessageProcessor route : routes)
 299  
         {
 300  0
             addRoute(route);
 301  
         }
 302  0
     }
 303  
 
 304  
     public synchronized void addRoute(MessageProcessor route) throws MuleException
 305  
     {
 306  0
         if (initialised.get())
 307  
         {
 308  0
             if (route instanceof MuleContextAware)
 309  
             {
 310  0
                 ((MuleContextAware) route).setMuleContext(muleContext);
 311  
             }
 312  0
             if (route instanceof FlowConstructAware)
 313  
             {
 314  0
                 ((FlowConstructAware) route).setFlowConstruct(flowConstruct);
 315  
             }
 316  0
             if (route instanceof Initialisable)
 317  
             {
 318  0
                 ((Initialisable) route).initialise();
 319  
             }
 320  
         }
 321  0
         if (started.get())
 322  
         {
 323  0
             if (route instanceof Startable)
 324  
             {
 325  0
                 ((Startable) route).start();
 326  
             }
 327  
         }
 328  0
         routes.add(route);
 329  0
     }
 330  
 
 331  
     public synchronized void removeRoute(MessageProcessor route) throws MuleException
 332  
     {
 333  0
         if (started.get())
 334  
         {
 335  0
             if (route instanceof Stoppable)
 336  
             {
 337  0
                 ((Stoppable) route).stop();
 338  
             }
 339  
         }
 340  0
         if (initialised.get())
 341  
         {
 342  0
             if (route instanceof Disposable)
 343  
             {
 344  0
                 ((Disposable) route).dispose();
 345  
             }
 346  
         }
 347  0
         routes.remove(route);
 348  0
     }
 349  
 
 350  
     public String getReplyTo()
 351  
     {
 352  0
         return replyTo;
 353  
     }
 354  
 
 355  
     public void setReplyTo(String replyTo)
 356  
     {
 357  0
         this.replyTo = replyTo;
 358  0
     }
 359  
 
 360  
     public CorrelationMode getEnableCorrelation()
 361  
     {
 362  0
         return enableCorrelation;
 363  
     }
 364  
 
 365  
     public void setEnableCorrelation(CorrelationMode enableCorrelation)
 366  
     {
 367  0
         this.enableCorrelation = enableCorrelation;
 368  0
     }
 369  
 
 370  
     public void setEnableCorrelationAsString(String enableCorrelation)
 371  
     {
 372  0
         if (enableCorrelation != null)
 373  
         {
 374  0
             if (enableCorrelation.equals("ALWAYS"))
 375  
             {
 376  0
                 this.enableCorrelation = CorrelationMode.ALWAYS;
 377  
             }
 378  0
             else if (enableCorrelation.equals("NEVER"))
 379  
             {
 380  0
                 this.enableCorrelation = CorrelationMode.NEVER;
 381  
             }
 382  0
             else if (enableCorrelation.equals("IF_NOT_SET"))
 383  
             {
 384  0
                 this.enableCorrelation = CorrelationMode.IF_NOT_SET;
 385  
             }
 386  
             else
 387  
             {
 388  0
                 throw new IllegalArgumentException("Value for enableCorrelation not recognised: "
 389  
                                                    + enableCorrelation);
 390  
             }
 391  
         }
 392  0
     }
 393  
 
 394  
     public TransactionConfig getTransactionConfig()
 395  
     {
 396  0
         return transactionConfig;
 397  
     }
 398  
 
 399  
     public void setTransactionConfig(TransactionConfig transactionConfig)
 400  
     {
 401  0
         this.transactionConfig = transactionConfig;
 402  0
     }
 403  
 
 404  
     public boolean isDynamicRoutes()
 405  
     {
 406  0
         return false;
 407  
     }
 408  
 
 409  
     /**
 410  
      * @param name the route identifier
 411  
      * @return the route or null if the endpoint's Uri is not registered
 412  
      */
 413  
     public MessageProcessor getRoute(String name)
 414  
     {
 415  0
         for (MessageProcessor route : routes)
 416  
         {
 417  0
             if (route instanceof OutboundEndpoint)
 418  
             {
 419  0
                 OutboundEndpoint endpoint = (OutboundEndpoint) route;
 420  0
                 if (endpoint.getName().equals(name))
 421  
                 {
 422  0
                     return endpoint;
 423  
                 }
 424  0
             }
 425  
         }
 426  0
         return null;
 427  
     }
 428  
 
 429  
     public RouterResultsHandler getResultsHandler()
 430  
     {
 431  0
         return resultsHandler;
 432  
     }
 433  
 
 434  
     public void setResultsHandler(RouterResultsHandler resultsHandler)
 435  
     {
 436  0
         this.resultsHandler = resultsHandler;
 437  0
     }
 438  
 
 439  
     /**
 440  
      * Send message event to destination.
 441  
      */
 442  
     protected MuleEvent sendRequestEvent(MuleEvent routedEvent,
 443  
                                          MuleMessage message,
 444  
                                          MessageProcessor route,
 445  
                                          boolean awaitResponse) throws MuleException
 446  
     {
 447  0
         if (route == null)
 448  
         {
 449  0
             throw new DispatchException(CoreMessages.objectIsNull("Outbound Endpoint"), routedEvent, null);
 450  
         }
 451  
 
 452  0
         MuleEvent event = createEventToRoute(routedEvent, message, route);
 453  
 
 454  0
         if (awaitResponse)
 455  
         {
 456  0
             int timeout = message.getOutboundProperty(MuleProperties.MULE_EVENT_TIMEOUT_PROPERTY, -1);
 457  0
             if (timeout >= 0)
 458  
             {
 459  0
                 event.setTimeout(timeout);
 460  
             }
 461  
         }
 462  
 
 463  0
         return route.process(event);
 464  
     }
 465  
 
 466  
     /**
 467  
      * Create a new event to be routed to the target MP
 468  
      */
 469  
     protected MuleEvent createEventToRoute(MuleEvent routedEvent, MuleMessage message, MessageProcessor route)
 470  
     {
 471  0
         ImmutableEndpoint endpoint = (route instanceof ImmutableEndpoint) ? (ImmutableEndpoint) route : routedEvent.getEndpoint();
 472  0
         MuleEvent event = new DefaultMuleEvent(message, endpoint, routedEvent.getSession(), routedEvent.getProcessingTime());
 473  0
         return event;
 474  
     }
 475  
 
 476  
     /**
 477  
      * Create a fresh copy of a message.
 478  
      */
 479  
     protected MuleMessage cloneMessage(MuleMessage message)
 480  
     {
 481  0
         MuleMessage clonedMessage = new DefaultMuleMessage(message.getPayload(), message, muleContext);
 482  0
         return clonedMessage;
 483  
     }
 484  
 
 485  
     /**
 486  
      * Propagates a number of internal system properties to handle correlation, session, etc. Note that in and
 487  
      * out params can be the same message object when not dealing with replies.
 488  
      * 
 489  
      * @see #magicProperties
 490  
      */
 491  
     protected void propagateMagicProperties(MuleMessage in, MuleMessage out)
 492  
     {
 493  0
         for (String name : magicProperties)
 494  
         {
 495  0
             Object value = in.getInboundProperty(name);
 496  0
             if (value != null)
 497  
             {
 498  0
                 out.setOutboundProperty(name, value);
 499  
             }
 500  0
         }
 501  0
     }
 502  
 
 503  
     public void initialise() throws InitialisationException
 504  
     {
 505  0
         synchronized (routes)
 506  
         {
 507  0
             super.initialise();
 508  0
             initialised.set(true);
 509  0
         }
 510  0
     }
 511  
 
 512  
     public void dispose()
 513  
     {
 514  0
         synchronized (routes)
 515  
         {
 516  0
             super.dispose();
 517  0
             routes = Collections.<MessageProcessor> emptyList();
 518  0
             initialised.set(false);
 519  0
         }
 520  0
     }
 521  
 
 522  
     public void start() throws MuleException
 523  
     {
 524  0
         synchronized (routes)
 525  
         {
 526  0
             super.start();
 527  0
             started.set(true);
 528  0
         }
 529  0
     }
 530  
 
 531  
     public void stop() throws MuleException
 532  
     {
 533  0
         synchronized (routes)
 534  
         {
 535  0
             super.stop();
 536  0
             started.set(false);
 537  0
         }
 538  0
     }
 539  
 
 540  
     public MuleContext getMuleContext()
 541  
     {
 542  0
         return muleContext;
 543  
     }
 544  
 
 545  
     public void setRouterStatistics(RouterStatistics stats)
 546  
     {
 547  0
         this.routerStatistics = stats;
 548  0
     }
 549  
 
 550  
     public RouterStatistics getRouterStatistics()
 551  
     {
 552  0
         return routerStatistics;
 553  
     }
 554  
 
 555  
     @Override
 556  
     protected List<MessageProcessor> getOwnedMessageProcessors()
 557  
     {
 558  0
         return routes;
 559  
     }
 560  
 }