Coverage Report - org.mule.construct.AbstractFlowConstruct
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractFlowConstruct
0%
0/88
0%
0/20
0
AbstractFlowConstruct$1
0%
0/13
0%
0/2
0
AbstractFlowConstruct$1$1
0%
0/2
N/A
0
AbstractFlowConstruct$2
0%
0/7
N/A
0
AbstractFlowConstruct$3
0%
0/8
N/A
0
AbstractFlowConstruct$4
0%
0/6
N/A
0
AbstractFlowConstruct$ProcessIfPipelineStartedMessageProcessor
0%
0/3
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.construct;
 8  
 
 9  
 import org.mule.api.MuleContext;
 10  
 import org.mule.api.MuleEvent;
 11  
 import org.mule.api.MuleException;
 12  
 import org.mule.api.config.ThreadingProfile;
 13  
 import org.mule.api.construct.FlowConstruct;
 14  
 import org.mule.api.construct.FlowConstructAware;
 15  
 import org.mule.api.construct.FlowConstructInvalidException;
 16  
 import org.mule.api.context.MuleContextAware;
 17  
 import org.mule.api.exception.MessagingExceptionHandler;
 18  
 import org.mule.api.lifecycle.Disposable;
 19  
 import org.mule.api.lifecycle.Initialisable;
 20  
 import org.mule.api.lifecycle.InitialisationException;
 21  
 import org.mule.api.lifecycle.Lifecycle;
 22  
 import org.mule.api.lifecycle.LifecycleCallback;
 23  
 import org.mule.api.lifecycle.LifecycleException;
 24  
 import org.mule.api.lifecycle.LifecycleState;
 25  
 import org.mule.api.lifecycle.Startable;
 26  
 import org.mule.api.lifecycle.Stoppable;
 27  
 import org.mule.api.processor.MessageProcessor;
 28  
 import org.mule.api.processor.MessageProcessorBuilder;
 29  
 import org.mule.api.processor.MessageProcessorChain;
 30  
 import org.mule.api.processor.MessageProcessorChainBuilder;
 31  
 import org.mule.api.routing.MessageInfoMapping;
 32  
 import org.mule.api.source.MessageSource;
 33  
 import org.mule.config.i18n.CoreMessages;
 34  
 import org.mule.exception.DefaultServiceExceptionStrategy;
 35  
 import org.mule.lifecycle.EmptyLifecycleCallback;
 36  
 import org.mule.management.stats.FlowConstructStatistics;
 37  
 import org.mule.processor.AbstractFilteringMessageProcessor;
 38  
 import org.mule.processor.AbstractInterceptingMessageProcessor;
 39  
 import org.mule.processor.chain.DefaultMessageProcessorChainBuilder;
 40  
 import org.mule.routing.MuleMessageInfoMapping;
 41  
 import org.mule.util.ClassUtils;
 42  
 
 43  
 import java.beans.ExceptionListener;
 44  
 
 45  
 import org.apache.commons.logging.Log;
 46  
 import org.apache.commons.logging.LogFactory;
 47  
 
 48  
 /**
 49  
  * Abstract implementation of {@link FlowConstruct} that:
 50  
  * <ul>
 51  
  *  <li>Is constructed with unique name and {@link MuleContext}.
 52  
  *  <li>Uses a {@link MessageSource} as the source of messages.
 53  
  *  <li>Uses a chain of {@link MessageProcessor}s to process messages.
 54  
  *  <li>Has lifecycle and propagates this lifecycle to both {@link MessageSource} and
 55  
  *  {@link MessageProcessor}s in the correct order depending on the lifecycle phase.
 56  
  *  <li>Allows an {@link ExceptionListener} to be set.
 57  
  * </ul>
 58  
  * Implementations of <code>AbstractFlowConstuct</code> should implement
 59  
  * {@link #configureMessageProcessors(org.mule.api.processor.MessageProcessorChainBuilder)} and
 60  
  * {@link #validateConstruct()} to construct the processing chain required and
 61  
  * validate the resulting construct. Validation may include validation of the type of
 62  
  * attributes of the {@link MessageSource}.
 63  
  * <p/>
 64  
  * Implementations may also implement {@link #doInitialise()}, {@link #doStart()},
 65  
  * {@link #doStop()} and {@link #doDispose()} if they need to perform any action on
 66  
  * lifecycle transitions.
 67  
  */
 68  0
 public abstract class AbstractFlowConstruct implements FlowConstruct, Lifecycle
 69  
 {
 70  0
     protected transient Log logger = LogFactory.getLog(getClass());
 71  
 
 72  
     protected String name;
 73  
     protected MessageSource messageSource;
 74  
     protected MessageProcessorChain messageProcessorChain;
 75  
     protected MessagingExceptionHandler exceptionListener;
 76  
     protected final FlowConstructLifecycleManager lifecycleManager;
 77  
     protected final MuleContext muleContext;
 78  
     protected FlowConstructStatistics statistics;
 79  0
     protected MessageInfoMapping messageInfoMapping = new MuleMessageInfoMapping();
 80  
     protected ThreadingProfile threadingProfile;
 81  0
     private boolean canProcessMessage = false;
 82  
     
 83  
     /**
 84  
      * The initial states that the flow can be started in
 85  
      */
 86  
     public static final String INITIAL_STATE_STOPPED = "stopped";
 87  
     public static final String INITIAL_STATE_STARTED = "started";
 88  
     
 89  
     /**
 90  
      * Determines the initial state of this flow when the mule starts. Can be
 91  
      * 'stopped' or 'started' (default)
 92  
      */
 93  0
     protected String initialState = INITIAL_STATE_STARTED;
 94  
 
 95  
     public AbstractFlowConstruct(String name, MuleContext muleContext)
 96  0
     {
 97  0
         this.muleContext = muleContext;
 98  0
         this.name = name;
 99  0
         this.lifecycleManager = new FlowConstructLifecycleManager(this, muleContext);
 100  0
         this.exceptionListener = new DefaultServiceExceptionStrategy(muleContext);
 101  0
     }
 102  
 
 103  
     public final void initialise() throws InitialisationException
 104  
     {
 105  
         try
 106  
         {
 107  0
             lifecycleManager.fireInitialisePhase(new LifecycleCallback<FlowConstruct>()
 108  0
             {
 109  
                 public void onTransition(String phaseName, FlowConstruct object) throws MuleException
 110  
                 {
 111  0
                     createMessageProcessor();
 112  
 
 113  0
                     if (messageSource != null)
 114  
                     {
 115  
                         // Wrap chain to decouple lifecycle
 116  0
                         messageSource.setListener(new AbstractInterceptingMessageProcessor()
 117  0
                         {
 118  
                             public MuleEvent process(MuleEvent event) throws MuleException
 119  
                             {
 120  0
                                 return messageProcessorChain.process(event);
 121  
                             }
 122  
                         });
 123  
                     }
 124  
 
 125  0
                     injectFlowConstructMuleContext(messageSource);
 126  0
                     injectFlowConstructMuleContext(messageProcessorChain);
 127  0
                     injectFlowConstructMuleContext(exceptionListener);
 128  0
                     initialiseIfInitialisable(messageSource);
 129  0
                     initialiseIfInitialisable(messageProcessorChain);
 130  0
                     initialiseIfInitialisable(exceptionListener);
 131  
 
 132  0
                     doInitialise();
 133  
 
 134  0
                     validateConstruct();
 135  0
                 }
 136  
             });
 137  
 
 138  
         }
 139  0
         catch (InitialisationException e)
 140  
         {
 141  0
             throw e;
 142  
         }
 143  0
         catch (MuleException e)
 144  
         {
 145  0
             throw new InitialisationException(e, this);
 146  0
         }
 147  0
     }
 148  
 
 149  
     public final void start() throws MuleException
 150  
     {
 151  
         // Check if Initial State is Stopped
 152  0
         if(!isStopped() && initialState.equals(INITIAL_STATE_STOPPED))
 153  
         {
 154  0
             lifecycleManager.fireStartPhase(new EmptyLifecycleCallback<FlowConstruct>());
 155  0
             lifecycleManager.fireStopPhase(new EmptyLifecycleCallback<FlowConstruct>());
 156  
 
 157  0
             logger.info("Flow " + name + " has not been started (initial state = 'stopped')");
 158  0
             return;
 159  
         }
 160  
         
 161  0
         lifecycleManager.fireStartPhase(new LifecycleCallback<FlowConstruct>()
 162  0
         {
 163  
             public void onTransition(String phaseName, FlowConstruct object) throws MuleException
 164  
             {
 165  0
                 startIfStartable(messageProcessorChain);
 166  0
                 startIfStartable(exceptionListener);
 167  0
                 canProcessMessage = true;
 168  0
                 startIfStartable(messageSource);
 169  0
                 doStart();
 170  0
             }
 171  
         });
 172  0
     }
 173  
 
 174  
     public final void stop() throws MuleException
 175  
     {
 176  0
         lifecycleManager.fireStopPhase(new LifecycleCallback<FlowConstruct>()
 177  0
         {
 178  
             public void onTransition(String phaseName, FlowConstruct object) throws MuleException
 179  
             {
 180  
                 try
 181  
                 {
 182  0
                     stopIfStoppable(messageSource);
 183  
                 }
 184  
                 finally
 185  
                 {
 186  0
                     canProcessMessage = false;
 187  0
                 }
 188  0
                 stopIfStoppable(messageProcessorChain);
 189  0
                 stopIfStoppable(exceptionListener);
 190  0
                 doStop();
 191  0
             }
 192  
         });
 193  0
     }
 194  
 
 195  
     public final void dispose()
 196  
     {
 197  
         try
 198  
         {
 199  0
             if (isStarted())
 200  
             {
 201  0
                 stop();
 202  
             }
 203  
 
 204  0
             lifecycleManager.fireDisposePhase(new LifecycleCallback<FlowConstruct>()
 205  0
             {
 206  
                 public void onTransition(String phaseName, FlowConstruct object) throws MuleException
 207  
                 {
 208  0
                     disposeIfDisposable(messageProcessorChain);
 209  0
                     disposeIfDisposable(exceptionListener);
 210  0
                     disposeIfDisposable(messageSource);
 211  0
                     doDispose();
 212  0
                 }
 213  
             });
 214  
         }
 215  0
         catch (MuleException e)
 216  
         {
 217  0
             logger.error("Failed to stop service: " + name, e);
 218  0
         }
 219  0
     }
 220  
 
 221  
     public ThreadingProfile getThreadingProfile()
 222  
     {
 223  0
         return threadingProfile;
 224  
     }
 225  
 
 226  
     public boolean isStarted()
 227  
     {
 228  0
         return lifecycleManager.getState().isStarted();
 229  
     }
 230  
 
 231  
     public boolean isStopped()
 232  
     {
 233  0
         return lifecycleManager.getState().isStopped();
 234  
     }
 235  
 
 236  
     public boolean isStopping()
 237  
     {
 238  0
         return lifecycleManager.getState().isStopping();
 239  
     }
 240  
 
 241  
     /**
 242  
      * Creates a {@link MessageProcessor} that will process messages from the
 243  
      * configured {@link MessageSource}.
 244  
      * <p>
 245  
      * The default implementation of this methods uses a
 246  
      * {@link DefaultMessageProcessorChainBuilder} and allows a chain of
 247  
      * {@link MessageProcessor}s to be configured using the
 248  
      * {@link #configureMessageProcessors(org.mule.api.processor.MessageProcessorChainBuilder)}
 249  
      * method but if you wish to use another {@link MessageProcessorBuilder} or just
 250  
      * a single {@link MessageProcessor} then this method can be overridden and
 251  
      * return a single {@link MessageProcessor} instead.
 252  
      * 
 253  
      * @throws MuleException
 254  
      */
 255  
     protected void createMessageProcessor() throws MuleException
 256  
     {
 257  0
         DefaultMessageProcessorChainBuilder builder = new DefaultMessageProcessorChainBuilder(this);
 258  0
         builder.setName("'" + getName() + "' processor chain");
 259  0
         configureMessageProcessors(builder);
 260  0
         messageProcessorChain = builder.build();
 261  0
     }
 262  
 
 263  
     /**
 264  
      * Used to configure the processing chain for this <code>FlowConstuct</code by
 265  
      * adding {@link MessageProcessor}s to the chain using the builder provided.
 266  
      * <p>
 267  
      * To use a different builder of to construct a composite
 268  
      * {@link MessageProcessor} manually override {@link #createMessageProcessor()}
 269  
      * instead.
 270  
      * 
 271  
      *
 272  
      *
 273  
      *
 274  
      * @param builder instance of {@link org.mule.processor.chain.DefaultMessageProcessorChainBuilder}
 275  
      * @throws MuleException
 276  
      */
 277  
     protected abstract void configureMessageProcessors(MessageProcessorChainBuilder builder) throws MuleException;
 278  
 
 279  
     public String getName()
 280  
     {
 281  0
         return name;
 282  
     }
 283  
 
 284  
     public MessagingExceptionHandler getExceptionListener()
 285  
     {
 286  0
         return exceptionListener;
 287  
     }
 288  
 
 289  
     public void setExceptionListener(MessagingExceptionHandler exceptionListener)
 290  
     {
 291  0
         this.exceptionListener = exceptionListener;
 292  0
     }
 293  
     
 294  
     public String getInitialState()
 295  
     {
 296  0
         return initialState;
 297  
     }
 298  
 
 299  
     public void setInitialState(String initialState)
 300  
     {
 301  0
         this.initialState = initialState;
 302  0
     }    
 303  
 
 304  
     public LifecycleState getLifecycleState()
 305  
     {
 306  0
         return lifecycleManager.getState();
 307  
     }
 308  
 
 309  
     public MuleContext getMuleContext()
 310  
     {
 311  0
         return muleContext;
 312  
     }
 313  
 
 314  
     public MessageSource getMessageSource()
 315  
     {
 316  0
         return messageSource;
 317  
     }
 318  
 
 319  
     public void setMessageSource(MessageSource messageSource)
 320  
     {
 321  0
         this.messageSource = messageSource;
 322  0
     }
 323  
 
 324  
     public FlowConstructStatistics getStatistics()
 325  
     {
 326  0
         return statistics;
 327  
     }
 328  
 
 329  
     public MessageInfoMapping getMessageInfoMapping()
 330  
     {
 331  0
         return messageInfoMapping;
 332  
     }
 333  
 
 334  
     public void setMessageInfoMapping(MessageInfoMapping messageInfoMapping)
 335  
     {
 336  0
         this.messageInfoMapping = messageInfoMapping;
 337  0
     }
 338  
 
 339  
     protected void doInitialise() throws InitialisationException
 340  
     {
 341  0
         int threadPoolSize = threadingProfile == null ? 0 : threadingProfile.getMaxThreadsActive();
 342  0
         statistics = new FlowConstructStatistics(getConstructType(), name, threadPoolSize);
 343  0
         statistics.setEnabled(muleContext.getStatistics().isEnabled());
 344  0
         muleContext.getStatistics().add(statistics);
 345  0
     }
 346  
 
 347  
     protected void doStart() throws MuleException
 348  
     {
 349  
         // Empty template method
 350  0
     }
 351  
 
 352  
     protected void doStop() throws MuleException
 353  
     {
 354  
         // Empty template method
 355  0
     }
 356  
 
 357  
     protected void doDispose()
 358  
     {
 359  0
         muleContext.getStatistics().remove(statistics);
 360  0
     }
 361  
 
 362  
     /**
 363  
      * Validates configured flow construct
 364  
      * 
 365  
      * @throws FlowConstructInvalidException if the flow construct does not pass
 366  
      *             validation
 367  
      */
 368  
     protected void validateConstruct() throws FlowConstructInvalidException
 369  
     {
 370  
         // Empty template method
 371  0
     }
 372  
 
 373  
     protected void injectFlowConstructMuleContext(Object candidate)
 374  
     {
 375  0
         if (candidate instanceof FlowConstructAware)
 376  
         {
 377  0
             ((FlowConstructAware) candidate).setFlowConstruct(this);
 378  
         }
 379  0
         if (candidate instanceof MuleContextAware)
 380  
         {
 381  0
             ((MuleContextAware) candidate).setMuleContext(muleContext);
 382  
         }
 383  0
     }
 384  
 
 385  
     @Override
 386  
     public String toString()
 387  
     {
 388  0
         return String.format("%s{%s}", ClassUtils.getSimpleName(this.getClass()), getName());
 389  
     }
 390  
 
 391  
     protected void initialiseIfInitialisable(Object candidate) throws InitialisationException
 392  
     {
 393  0
         if (candidate instanceof Initialisable)
 394  
         {
 395  0
             ((Initialisable) candidate).initialise();
 396  
         }
 397  0
     }
 398  
 
 399  
     protected void startIfStartable(Object candidate) throws MuleException
 400  
     {
 401  0
         if (candidate instanceof Startable)
 402  
         {
 403  0
             ((Startable) candidate).start();
 404  
         }
 405  0
     }
 406  
 
 407  
     protected void stopIfStoppable(Object candidate) throws MuleException
 408  
     {
 409  0
         if (candidate instanceof Stoppable)
 410  
         {
 411  0
             ((Stoppable) candidate).stop();
 412  
         }
 413  0
     }
 414  
 
 415  
     protected void disposeIfDisposable(Object candidate)
 416  
     {
 417  0
         if (candidate instanceof Disposable)
 418  
         {
 419  0
             ((Disposable) candidate).dispose();
 420  
         }
 421  0
     }
 422  
     
 423  
     public MessageProcessorChain getMessageProcessorChain()
 424  
     {
 425  0
         return this.messageProcessorChain;
 426  
     }
 427  
 
 428  
     /**
 429  
      * @return the type of construct being created, e.g. "Flow"
 430  
      */
 431  
     public abstract String getConstructType();
 432  
 
 433  0
     public class ProcessIfPipelineStartedMessageProcessor extends AbstractFilteringMessageProcessor
 434  
     {
 435  
 
 436  
         @Override
 437  
         protected boolean accept(MuleEvent event)
 438  
         {
 439  0
             return canProcessMessage;
 440  
         }
 441  
 
 442  
         @Override
 443  
         protected MuleEvent handleUnaccepted(MuleEvent event) throws LifecycleException
 444  
         {
 445  0
             throw new LifecycleException(CoreMessages.isStopped(getName()), event.getMessage());
 446  
         }
 447  
     }
 448  
 }