Coverage Report - org.mule.processor.SedaStageInterceptingMessageProcessor
 
Classes in this File Line Coverage Branch Coverage Complexity
SedaStageInterceptingMessageProcessor
0%
0/110
0%
0/70
0
SedaStageInterceptingMessageProcessor$SedaStageWorker
0%
0/12
0%
0/2
0
 
 1  
 /*
 2  
  * $Id: SedaStageInterceptingMessageProcessor.java 20320 2010-11-24 15:03:31Z dfeist $
 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.processor;
 12  
 
 13  
 import org.mule.DefaultMuleEvent;
 14  
 import org.mule.api.MessagingException;
 15  
 import org.mule.api.MuleContext;
 16  
 import org.mule.api.MuleEvent;
 17  
 import org.mule.api.MuleException;
 18  
 import org.mule.api.NamedObject;
 19  
 import org.mule.api.context.WorkManager;
 20  
 import org.mule.api.context.WorkManagerSource;
 21  
 import org.mule.api.exception.MessagingExceptionHandler;
 22  
 import org.mule.api.exception.SystemExceptionHandler;
 23  
 import org.mule.api.lifecycle.InitialisationException;
 24  
 import org.mule.api.lifecycle.Lifecycle;
 25  
 import org.mule.api.lifecycle.LifecycleException;
 26  
 import org.mule.api.lifecycle.LifecycleState;
 27  
 import org.mule.api.processor.MessageProcessor;
 28  
 import org.mule.api.service.FailedToQueueEventException;
 29  
 import org.mule.config.QueueProfile;
 30  
 import org.mule.config.i18n.CoreMessages;
 31  
 import org.mule.config.i18n.MessageFactory;
 32  
 import org.mule.management.stats.QueueStatistics;
 33  
 import org.mule.service.Pausable;
 34  
 import org.mule.util.concurrent.WaitableBoolean;
 35  
 import org.mule.util.queue.Queue;
 36  
 import org.mule.util.queue.QueueSession;
 37  
 import org.mule.work.AbstractMuleEventWork;
 38  
 import org.mule.work.MuleWorkManager;
 39  
 
 40  
 import java.text.MessageFormat;
 41  
 
 42  
 import javax.resource.spi.work.Work;
 43  
 import javax.resource.spi.work.WorkException;
 44  
 import javax.resource.spi.work.WorkListener;
 45  
 
 46  
 /**
 47  
  * Processes {@link MuleEvent}'s asynchronously using a {@link MuleWorkManager} to
 48  
  * schedule asynchronous processing of the next {@link MessageProcessor}. 
 49  
  */
 50  
 public class SedaStageInterceptingMessageProcessor extends OptionalAsyncInterceptingMessageProcessor
 51  
     implements WorkListener, Work, Lifecycle
 52  
 {
 53  
     protected static final String QUEUE_NAME_PREFIX = "seda.queue";
 54  
 
 55  
     protected QueueProfile queueProfile;
 56  
     protected int queueTimeout;
 57  
     protected LifecycleState lifecycleState;
 58  
     protected QueueStatistics queueStatistics;
 59  
     protected MuleContext muleContext;
 60  
     protected String name;
 61  
 
 62  
     protected Queue queue;
 63  0
     private WaitableBoolean queueDraining = new WaitableBoolean(false);
 64  
 
 65  
     public SedaStageInterceptingMessageProcessor(String name,
 66  
                                                  QueueProfile queueProfile,
 67  
                                                  int queueTimeout,
 68  
                                                  WorkManagerSource workManagerSource,
 69  
                                                  LifecycleState lifecycleState,
 70  
                                                  QueueStatistics queueStatistics,
 71  
                                                  MuleContext muleContext)
 72  
     {
 73  0
         super(workManagerSource);
 74  0
         this.name = name;
 75  0
         this.queueProfile = queueProfile;
 76  0
         this.queueTimeout = queueTimeout;
 77  0
         this.lifecycleState = lifecycleState;
 78  0
         this.queueStatistics = queueStatistics;
 79  0
         this.muleContext = muleContext;
 80  0
     }
 81  
     
 82  
     @Deprecated
 83  
     public SedaStageInterceptingMessageProcessor(String name,
 84  
                                                  QueueProfile queueProfile,
 85  
                                                  int queueTimeout,
 86  
                                                  WorkManagerSource workManagerSource,
 87  
                                                  boolean doThreading,
 88  
                                                  LifecycleState lifecycleState,
 89  
                                                  QueueStatistics queueStatistics,
 90  
                                                  MuleContext muleContext)
 91  
     {
 92  0
         this(name, queueProfile, queueTimeout, workManagerSource, lifecycleState, queueStatistics,
 93  
             muleContext);
 94  0
         this.doThreading = doThreading;
 95  0
     }
 96  
 
 97  
     @Override
 98  
     protected void processNextAsync(MuleEvent event) throws MuleException
 99  
     {
 100  
         try
 101  
         {
 102  0
             if (isStatsEnabled())
 103  
             {
 104  0
                 queueStatistics.incQueuedEvent();
 105  
             }
 106  0
             enqueue(event);
 107  
         }
 108  0
         catch (Exception e)
 109  
         {
 110  0
             throw new FailedToQueueEventException(
 111  
                 CoreMessages.interruptedQueuingEventFor(getStageDescription()), event, e);
 112  0
         }
 113  
 
 114  0
         if (logger.isTraceEnabled())
 115  
         {
 116  0
             logger.trace("MuleEvent added to queue for: " + getStageDescription());
 117  
         }
 118  0
     }
 119  
 
 120  
     protected boolean isStatsEnabled()
 121  
     {
 122  0
         return queueStatistics != null && queueStatistics.isEnabled();
 123  
     }
 124  
 
 125  
     protected void enqueue(MuleEvent event) throws Exception
 126  
     {
 127  0
         if (logger.isDebugEnabled())
 128  
         {
 129  0
             logger.debug(MessageFormat.format("{1}: Putting event on queue {2}", queue.getName(),
 130  
                 getStageDescription(), event));
 131  
         }
 132  0
         queue.put(event);
 133  0
     }
 134  
 
 135  
     protected MuleEvent dequeue() throws Exception
 136  
     {
 137  0
         if (queue == null)
 138  
         {
 139  0
             return null;
 140  
         }
 141  0
         if (logger.isTraceEnabled())
 142  
         {
 143  0
             logger.trace(MessageFormat.format("{0}: Polling queue {1}, timeout = {2}", getStageName(),
 144  
                 getStageDescription(), queueTimeout));
 145  
         }
 146  
 
 147  0
         MuleEvent event = (MuleEvent)queue.poll(queueTimeout);
 148  
         //If the service has been paused why the poll was waiting for an event to arrive on the queue,
 149  
         //we put the object back on the queue
 150  0
         if(event!=null && lifecycleState.isPhaseComplete(Pausable.PHASE_NAME))
 151  
         {
 152  0
             queue.untake(event);
 153  0
             return null;
 154  
         }
 155  0
         return event;
 156  
     }
 157  
 
 158  
     private class SedaStageWorker extends AbstractMuleEventWork
 159  
     {
 160  
         public SedaStageWorker(MuleEvent event)
 161  0
         {
 162  0
             super(event);
 163  0
         }
 164  
 
 165  
         @Override
 166  
         protected void doRun()
 167  
         {
 168  
             try
 169  
             {
 170  0
                 processNextTimed(event);
 171  
             }
 172  0
             catch (Exception e)
 173  
             {
 174  0
                 event.getSession().setValid(false);
 175  0
                 MessagingExceptionHandler exceptionListener = event.getFlowConstruct().getExceptionListener();
 176  0
                 if (e instanceof MessagingException)
 177  
                 {
 178  0
                     exceptionListener.handleException(e, event);
 179  
                 }
 180  
                 else
 181  
                 {
 182  0
                     exceptionListener.handleException(new MessagingException(
 183  
                         CoreMessages.eventProcessingFailedFor(getStageDescription()), event, e), event);
 184  
                 }
 185  0
             }
 186  0
         }
 187  
     }
 188  
 
 189  
     /**
 190  
      * While the service isn't stopped this runs a continuous loop checking for new
 191  
      * events in the queue.
 192  
      */
 193  
     public void run()
 194  
     {
 195  0
         DefaultMuleEvent event = null; 
 196  0
         QueueSession queueSession = muleContext.getQueueManager().getQueueSession();
 197  
 
 198  0
         while (!lifecycleState.isStopped())
 199  
         {
 200  
             try
 201  
             {
 202  
                 // Wait if the service is paused
 203  0
                 if (lifecycleState.isPhaseComplete(Pausable.PHASE_NAME))
 204  
                 {
 205  0
                     waitIfPaused();
 206  
 
 207  
                     // If service is resumed as part of stopping
 208  0
                     if (lifecycleState.isStopping())
 209  
                     {
 210  0
                         queueDraining.set(true);
 211  0
                         if (!isQueuePersistent() && (queueSession != null && getQueueSize() > 0))
 212  
                         {
 213  
                             // Any messages in a non-persistent queue went paused
 214  
                             // service is stopped are lost
 215  0
                             logger.warn(CoreMessages.stopPausedSedaStageNonPeristentQueueMessageLoss(
 216  
                                 getQueueSize(), getQueueName()));
 217  
                         }
 218  0
                         queueDraining.set(false);
 219  0
                         break;
 220  
                     }
 221  
                 }
 222  
 
 223  
                 // If we're doing a draining stop, read all events from the queue
 224  
                 // before stopping
 225  0
                 if (lifecycleState.isStopping())
 226  
                 {
 227  0
                     if (isQueuePersistent() || queueSession == null || getQueueSize() <= 0)
 228  
                     {
 229  0
                         queueDraining.set(false);
 230  0
                         break;
 231  
                     }
 232  
                 }
 233  
 
 234  0
                 event = (DefaultMuleEvent) dequeue();
 235  
             }
 236  0
             catch (InterruptedException ie)
 237  
             {
 238  0
                 queueDraining.set(false);
 239  0
                 break;
 240  
             }
 241  0
             catch (Exception e)
 242  
             {
 243  0
                 SystemExceptionHandler exceptionListener = muleContext.getExceptionListener();
 244  0
                 if (e instanceof MuleException)
 245  
                 {
 246  0
                     exceptionListener.handleException(e);
 247  
                 }
 248  
                 else
 249  
                 {
 250  0
                     exceptionListener.handleException(new MessagingException(
 251  
                         CoreMessages.eventProcessingFailedFor(getStageDescription()),
 252  
                         event, e));
 253  
                 }
 254  0
             }
 255  
 
 256  0
             if (event != null)
 257  
             {
 258  
                 try
 259  
                 {
 260  0
                     if (isStatsEnabled())
 261  
                     {
 262  0
                         queueStatistics.decQueuedEvent();
 263  
                     }
 264  
 
 265  0
                     if (logger.isDebugEnabled())
 266  
                     {
 267  0
                         logger.debug(MessageFormat.format("{0}: Dequeued event from {1}",
 268  
                             getStageDescription(), getQueueName()));
 269  
                     }
 270  0
                     Work work = new SedaStageWorker(event);
 271  0
                     if (doThreading)
 272  
                     {
 273  0
                         workManagerSource.getWorkManager().scheduleWork(work, WorkManager.INDEFINITE, null,
 274  
                             this);
 275  
                     }
 276  
                     else
 277  
                     {
 278  0
                         work.run();
 279  
                     }
 280  
                 }
 281  0
                 catch (Exception e)
 282  
                 {
 283  0
                     event.getFlowConstruct().getExceptionListener().handleException(e, event);
 284  0
                 }
 285  
             }
 286  
         }
 287  0
     }
 288  
 
 289  
     /** Are the events in the SEDA queue persistent? */
 290  
     protected boolean isQueuePersistent()
 291  
     {
 292  0
         return queueProfile.isPersistent();
 293  
     }
 294  
 
 295  
     public int getQueueSize()
 296  
     {
 297  0
         return queue.size();
 298  
     }
 299  
 
 300  
     protected String getQueueName()
 301  
     {
 302  0
         return String.format("%s(%s)", QUEUE_NAME_PREFIX, getStageName());
 303  
     }
 304  
 
 305  
     protected String getStageName()
 306  
     {
 307  0
         if (name != null)
 308  
         {
 309  0
             return name;
 310  
         }
 311  0
         else if (next instanceof NamedObject)
 312  
         {
 313  0
             return ((NamedObject) next).getName();
 314  
         }
 315  
         else
 316  
         {
 317  0
             return String.format("%s.%s", next.getClass().getName(), next.hashCode());
 318  
         }
 319  
     }
 320  
 
 321  
     protected String getStageDescription()
 322  
     {
 323  0
         return "SEDA Stage " + getStageName();
 324  
     }
 325  
 
 326  
     protected void waitIfPaused() throws InterruptedException
 327  
     {
 328  0
         if (logger.isDebugEnabled() && lifecycleState.isPhaseComplete(Pausable.PHASE_NAME))
 329  
         {
 330  0
             logger.debug(getStageDescription() + " is paused. Polling halted until resumed is called");
 331  
         }
 332  0
         while (lifecycleState.isPhaseComplete(Pausable.PHASE_NAME) && !lifecycleState.isStopping())
 333  
         {
 334  0
             Thread.sleep(500);
 335  
         }
 336  0
     }
 337  
 
 338  
     public void release()
 339  
     {
 340  0
         queueDraining.set(false);
 341  0
     }
 342  
 
 343  
     public void initialise() throws InitialisationException
 344  
     {
 345  0
         if (next == null)
 346  
         {
 347  0
             throw new IllegalStateException(
 348  
                 "Next message processor cannot be null with this InterceptingMessageProcessor");
 349  
         }
 350  
         // Setup event Queue
 351  0
         queueProfile.configureQueue(getQueueName(), muleContext.getQueueManager());
 352  0
         queue = muleContext.getQueueManager().getQueueSession().getQueue(getQueueName());
 353  0
         if (queue == null)
 354  
         {
 355  0
             throw new InitialisationException(MessageFactory.createStaticMessage("Queue not created for "
 356  
                                                                                  + getStageDescription()),
 357  
                 this);
 358  
         }
 359  0
     }
 360  
 
 361  
     public void start() throws MuleException
 362  
     {
 363  0
         if (queue == null)
 364  
         {
 365  0
             throw new IllegalStateException("Not initialised");
 366  
         }
 367  
         try
 368  
         {
 369  0
             workManagerSource.getWorkManager().scheduleWork(this, WorkManager.INDEFINITE, null, this);
 370  
         }
 371  0
         catch (WorkException e)
 372  
         {
 373  0
             throw new LifecycleException(CoreMessages.failedToStart(getStageDescription()), e, this);
 374  
 
 375  0
         }
 376  0
     }
 377  
 
 378  
     public void stop() throws MuleException
 379  
     {
 380  0
         if (queue != null && queue.size() > 0)
 381  
         {
 382  
             try
 383  
             {
 384  0
                 queueDraining.whenFalse(null);
 385  
             }
 386  0
             catch (InterruptedException e)
 387  
             {
 388  
                 // we can ignore this
 389  0
             }
 390  
         }
 391  0
     }
 392  
 
 393  
     public void dispose()
 394  
     {
 395  0
         queue = null;
 396  0
     }
 397  
 
 398  
 }