Coverage Report - org.mule.impl.model.seda.SedaComponent
 
Classes in this File Line Coverage Branch Coverage Complexity
SedaComponent
0%
0/222
0%
0/53
3.357
 
 1  
 /*
 2  
  * $Id: SedaComponent.java 7976 2007-08-21 14:26:13Z dirk.olmes $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.impl.model.seda;
 12  
 
 13  
 import org.mule.MuleManager;
 14  
 import org.mule.MuleRuntimeException;
 15  
 import org.mule.config.PoolingProfile;
 16  
 import org.mule.config.QueueProfile;
 17  
 import org.mule.config.ThreadingProfile;
 18  
 import org.mule.config.i18n.CoreMessages;
 19  
 import org.mule.impl.FailedToQueueEventException;
 20  
 import org.mule.impl.MuleDescriptor;
 21  
 import org.mule.impl.MuleEvent;
 22  
 import org.mule.impl.model.AbstractComponent;
 23  
 import org.mule.impl.model.DefaultMuleProxy;
 24  
 import org.mule.impl.model.MuleProxy;
 25  
 import org.mule.management.stats.ComponentStatistics;
 26  
 import org.mule.management.stats.SedaComponentStatistics;
 27  
 import org.mule.umo.ComponentException;
 28  
 import org.mule.umo.UMOEvent;
 29  
 import org.mule.umo.UMOException;
 30  
 import org.mule.umo.UMOMessage;
 31  
 import org.mule.umo.lifecycle.InitialisationException;
 32  
 import org.mule.umo.lifecycle.LifecycleException;
 33  
 import org.mule.umo.manager.UMOWorkManager;
 34  
 import org.mule.util.ObjectPool;
 35  
 import org.mule.util.queue.QueueSession;
 36  
 
 37  
 import java.util.ArrayList;
 38  
 import java.util.List;
 39  
 import java.util.NoSuchElementException;
 40  
 
 41  
 import javax.resource.spi.work.Work;
 42  
 import javax.resource.spi.work.WorkEvent;
 43  
 import javax.resource.spi.work.WorkException;
 44  
 import javax.resource.spi.work.WorkListener;
 45  
 import javax.resource.spi.work.WorkManager;
 46  
 
 47  
 /**
 48  
  * A Seda component runs inside a Seda Model and is responsible for managing a Seda
 49  
  * Queue and thread pool for a Mule sevice component. In Seda terms this is
 50  
  * equivilent to a stage.
 51  
  */
 52  
 public class SedaComponent extends AbstractComponent implements Work, WorkListener
 53  
 {
 54  
     public static final String QUEUE_PROFILE_PROPERTY = "queueProfile";
 55  
     public static final String POOLING_PROFILE_PROPERTY = "poolingProfile";
 56  
     /**
 57  
      * Serial version/
 58  
      */
 59  
     private static final long serialVersionUID = 7711976708670893015L;
 60  
 
 61  
     /**
 62  
      * A pool of available Mule proxies. If component pooling has been disabled on the
 63  
      * SEDAModel, this pool will be null and the 'componentProxy' will be used.
 64  
      */
 65  
     protected ObjectPool proxyPool;
 66  
 
 67  
     /**
 68  
      * Is created only if component pooling is turned off on the SEDAModel. In this
 69  
      * scenario all requests are serviced by this component, unless
 70  
      * {@link #componentPerRequest} flag is set on the model.
 71  
      */
 72  
     protected MuleProxy componentProxy;
 73  
 
 74  
     protected UMOWorkManager workManager;
 75  
 
 76  
     protected String descriptorQueueName;
 77  
 
 78  
     /**
 79  
      * The time out used for taking from the Seda Queue.
 80  
      */
 81  0
     protected int queueTimeout = 0;
 82  
 
 83  
     /**
 84  
      * Whether component objects should be pooled or a single instance should be
 85  
      * used.
 86  
      */
 87  0
     protected boolean enablePooling = true;
 88  
 
 89  
     /**
 90  
      * If this is set to true a new component will be created for every request.
 91  
      */
 92  0
     protected boolean componentPerRequest = false;
 93  
 
 94  
     /**
 95  
      * The pooling configuration used when initialising the component described by
 96  
      * this descriptor.
 97  
      */
 98  
     protected PoolingProfile poolingProfile;
 99  
 
 100  
     /**
 101  
      * The queuing profile for events received for this component.
 102  
      */
 103  
     protected QueueProfile queueProfile;
 104  
 
 105  
     /**
 106  
      * Creates a new SEDA component.
 107  
      * 
 108  
      * @param descriptor The descriptor of the component to creat
 109  
      * @param model the model in which the component is registered
 110  
      */
 111  
     public SedaComponent(MuleDescriptor descriptor, SedaModel model)
 112  
     {
 113  0
         super(descriptor, model);
 114  
 
 115  0
         descriptorQueueName = descriptor.getName() + ".component";
 116  0
         queueTimeout = model.getQueueTimeout();
 117  0
         enablePooling = model.isEnablePooling();
 118  0
         componentPerRequest = model.isComponentPerRequest();
 119  0
         poolingProfile = model.getPoolingProfile();
 120  0
         queueProfile = model.getQueueProfile();
 121  0
     }
 122  
 
 123  
     /**
 124  
      * Initialise the component. The component will first create a Mule UMO from the
 125  
      * UMODescriptor and then initialise a pool based on the attributes in the
 126  
      * UMODescriptor.
 127  
      * 
 128  
      * @throws org.mule.umo.lifecycle.InitialisationException if the component fails
 129  
      *             to initialise
 130  
      * @see org.mule.umo.UMODescriptor
 131  
      */
 132  
     public synchronized void doInitialise() throws InitialisationException
 133  
     {
 134  
         // Create thread pool
 135  0
         ThreadingProfile tp = descriptor.getThreadingProfile();
 136  0
         workManager = tp.createWorkManager(descriptor.getName());
 137  
 
 138  0
         queueProfile = descriptor.getQueueProfile();
 139  0
         if (queueProfile == null)
 140  
         {
 141  0
             queueProfile = ((SedaModel) model).getQueueProfile();
 142  
         }
 143  
 
 144  0
         poolingProfile = descriptor.getPoolingProfile();
 145  0
         if (poolingProfile == null)
 146  
         {
 147  0
             poolingProfile = ((SedaModel) model).getPoolingProfile();
 148  
         }
 149  
 
 150  
         try
 151  
         {
 152  
             // Setup event Queue (used for VM execution)
 153  0
             queueProfile.configureQueue(descriptor.getName());
 154  
         }
 155  0
         catch (InitialisationException e)
 156  
         {
 157  0
             throw e;
 158  
         }
 159  0
         catch (Throwable e)
 160  
         {
 161  0
             throw new InitialisationException(
 162  
                 CoreMessages.objectFailedToInitialise("Component Queue"), e, this);
 163  0
         }
 164  0
     }
 165  
 
 166  
     protected ComponentStatistics createStatistics()
 167  
     {
 168  0
         return new SedaComponentStatistics(getName(), descriptor.getThreadingProfile().getMaxThreadsActive(),
 169  
             poolingProfile.getMaxActive());
 170  
     }
 171  
 
 172  
     protected ObjectPool createPool() throws InitialisationException
 173  
     {
 174  0
         return getPoolingProfile().getPoolFactory().createPool(descriptor, model,
 175  
             getPoolingProfile());
 176  
     }
 177  
 
 178  
     protected void initialisePool() throws InitialisationException
 179  
     {
 180  
         try
 181  
         {
 182  0
             int initPolicy = getPoolingProfile().getInitialisationPolicy();
 183  0
             if (initPolicy == PoolingProfile.INITIALISE_ALL)
 184  
             {
 185  0
                 int numToBorrow = getPoolingProfile().getMaxActive();
 186  0
                 List holderList = new ArrayList(numToBorrow);
 187  
 
 188  
                 try
 189  
                 {
 190  0
                     for (int t = 0; t < numToBorrow; t++)
 191  
                     {
 192  0
                         holderList.add(proxyPool.borrowObject());
 193  
                     }
 194  0
                 }
 195  
                 finally
 196  
                 {
 197  0
                     for (int t = 0; t < holderList.size(); t++)
 198  
                     {
 199  0
                         Object obj = holderList.get(t);
 200  0
                         if (obj != null)
 201  
                         {
 202  
                             try
 203  
                             {
 204  0
                                 proxyPool.returnObject(obj);
 205  
                             }
 206  
                             finally
 207  0
                             {
 208  
                                 // ignore - nothing we can do
 209  0
                             }
 210  
                         }
 211  
                     }
 212  0
                 }
 213  
             }
 214  0
             else if (initPolicy == PoolingProfile.INITIALISE_ONE)
 215  
             {
 216  0
                 Object obj = null;
 217  
                 try
 218  
                 {
 219  0
                     obj = proxyPool.borrowObject();
 220  0
                 }
 221  
                 finally
 222  
                 {
 223  0
                     if (obj != null)
 224  
                     {
 225  0
                         proxyPool.returnObject(obj);
 226  
                     }
 227  0
                 }
 228  
             }
 229  
 
 230  0
             poolInitialised.set(true);
 231  
         }
 232  0
         catch (Exception e)
 233  
         {
 234  0
             throw new InitialisationException(
 235  
                 CoreMessages.objectFailedToInitialise("Proxy Pool"), e, this);
 236  0
         }
 237  0
     }
 238  
 
 239  
     protected MuleProxy createComponentProxy() throws InitialisationException
 240  
     {
 241  
         try
 242  
         {
 243  0
             Object component = lookupComponent();
 244  0
             MuleProxy componentProxy = new DefaultMuleProxy(component, descriptor, model, null);
 245  0
             ((SedaComponentStatistics) getStatistics()).setComponentPoolSize(-1);
 246  0
             componentProxy.setStatistics(getStatistics());
 247  0
             componentProxy.start();
 248  0
             return componentProxy;
 249  
         }
 250  0
         catch (UMOException e)
 251  
         {
 252  0
             throw new InitialisationException(e, this);
 253  
         }
 254  
     }
 255  
 
 256  
     public void doForceStop() throws UMOException
 257  
     {
 258  0
         doStop();
 259  0
     }
 260  
 
 261  
     public void doStop() throws UMOException
 262  
     {
 263  0
         workManager.stop();
 264  0
         if (proxyPool != null)
 265  
         {
 266  
             try
 267  
             {
 268  0
                 proxyPool.stop();
 269  0
                 proxyPool.clearPool();
 270  
             }
 271  0
             catch (Exception e)
 272  
             {
 273  
                 // TODO MULE-863: If this is an error, do something about it
 274  0
                 logger.error("Failed to stop component pool: " + e.getMessage(), e);
 275  0
             }
 276  0
             poolInitialised.set(false);
 277  
         }
 278  0
         else if (componentProxy != null)
 279  
         {
 280  0
             componentProxy.stop();
 281  
         }
 282  0
     }
 283  
 
 284  
     public void doStart() throws UMOException
 285  
     {
 286  
 
 287  
         try
 288  
         {
 289  
             // Need to initialise the pool only after all listerner have
 290  
             // been registered and initialised so we need to delay until now
 291  0
             if (!poolInitialised.get() && enablePooling)
 292  
             {
 293  0
                 proxyPool = this.createPool();
 294  0
                 this.initialisePool();
 295  0
                 proxyPool.start();
 296  
             }
 297  0
             else if (!componentPerRequest)
 298  
             {
 299  0
                 componentProxy = createComponentProxy();
 300  
             }
 301  0
             workManager.start();
 302  0
             workManager.scheduleWork(this, WorkManager.INDEFINITE, null, this);
 303  
         }
 304  0
         catch (Exception e)
 305  
         {
 306  0
             throw new LifecycleException(
 307  
                 CoreMessages.failedToStart("Component: " + descriptor.getName()), e, this);
 308  0
         }
 309  0
     }
 310  
 
 311  
     protected void doDispose()
 312  
     {
 313  
 
 314  
         try
 315  
         {
 316  
             // threadPool.awaitTerminationAfterShutdown();
 317  0
             if (workManager != null)
 318  
             {
 319  0
                 workManager.dispose();
 320  
             }
 321  
         }
 322  0
         catch (Exception e)
 323  
         {
 324  
             // TODO MULE-863: So what are we going to do about it?
 325  0
             logger.error("Component Thread Pool did not close properly: " + e);
 326  0
         }
 327  
         try
 328  
         {
 329  0
             if (proxyPool != null)
 330  
             {
 331  0
                 proxyPool.clearPool();
 332  
             }
 333  0
             else if (componentProxy != null)
 334  
             {
 335  0
                 componentProxy.dispose();
 336  
             }
 337  
         }
 338  0
         catch (Exception e)
 339  
         {
 340  
             // TODO MULE-863: So what are we going to do about it?
 341  0
             logger.error("Proxy Pool did not close properly: " + e);
 342  0
         }
 343  0
     }
 344  
 
 345  
     protected void doDispatch(UMOEvent event) throws UMOException
 346  
     {
 347  
         // Dispatching event to the component
 348  0
         if (stats.isEnabled())
 349  
         {
 350  0
             stats.incReceivedEventASync();
 351  
         }
 352  0
         if (logger.isDebugEnabled())
 353  
         {
 354  0
             logger.debug("Component: " + descriptor.getName() + " has received asynchronous event on: "
 355  
                             + event.getEndpoint().getEndpointURI());
 356  
         }
 357  
 
 358  
         // Block until we can queue the next event
 359  
         try
 360  
         {
 361  0
             enqueue(event);
 362  0
             if (stats.isEnabled())
 363  
             {
 364  0
                 stats.incQueuedEvent();
 365  
             }
 366  
         }
 367  0
         catch (Exception e)
 368  
         {
 369  0
             FailedToQueueEventException e1 = 
 370  
                 new FailedToQueueEventException(
 371  
                     CoreMessages.interruptedQueuingEventFor(this.getName()), 
 372  
                     event.getMessage(), this, e);
 373  0
             handleException(e1);
 374  0
         }
 375  
 
 376  0
         if (logger.isTraceEnabled())
 377  
         {
 378  0
             logger.trace("Event added to queue for: " + descriptor.getName());
 379  
         }
 380  0
     }
 381  
 
 382  
     public UMOMessage doSend(UMOEvent event) throws UMOException
 383  
     {
 384  0
         UMOMessage result = null;
 385  0
         MuleProxy proxy = null;
 386  
         try
 387  
         {
 388  0
             proxy = getProxy();
 389  0
             if (logger.isDebugEnabled())
 390  
             {
 391  0
                 logger.debug(this + " : got proxy for " + event.getId() + " = " + proxy);
 392  
             }
 393  0
             result = (UMOMessage) proxy.onCall(event);
 394  0
         }
 395  0
         catch (UMOException e)
 396  
         {
 397  0
             throw e;
 398  
         }
 399  0
         catch (Exception e)
 400  
         {
 401  0
             throw new ComponentException(event.getMessage(), this, e);
 402  
         }
 403  
         finally
 404  
         {
 405  0
             try
 406  
             {
 407  0
                 if (proxy != null)
 408  
                 {
 409  0
                     if (proxyPool != null)
 410  
                     {
 411  0
                         proxyPool.returnObject(proxy);
 412  
                     }
 413  0
                     else if (componentPerRequest)
 414  
                     {
 415  0
                         proxy.dispose();
 416  
                     }
 417  
                 }
 418  
             }
 419  0
             catch (Exception e)
 420  
             {
 421  
                 // noinspection ThrowFromFinallyBlock
 422  0
                 throw new ComponentException(event.getMessage(), this, e);
 423  0
             }
 424  
 
 425  0
             if (proxyPool != null)
 426  
             {
 427  0
                 ((SedaComponentStatistics) getStatistics()).setComponentPoolSize(proxyPool.getSize());
 428  
             }
 429  0
         }
 430  0
         return result;
 431  
     }
 432  
 
 433  
     /**
 434  
      * @return the pool of Mule UMOs initialised in this component
 435  
      */
 436  
     ObjectPool getProxyPool()
 437  
     {
 438  0
         return proxyPool;
 439  
     }
 440  
 
 441  
     public int getQueueSize()
 442  
     {
 443  0
         QueueSession queueSession = MuleManager.getInstance().getQueueManager().getQueueSession();
 444  0
         return queueSession.getQueue(descriptor.getName()).size();
 445  
     }
 446  
 
 447  
     /**
 448  
      * While the component isn't stopped this runs a continuous loop checking for new
 449  
      * events in the queue.
 450  
      */
 451  
     public void run()
 452  
     {
 453  0
         MuleEvent event = null;
 454  0
         MuleProxy proxy = null;
 455  0
         QueueSession queueSession = MuleManager.getInstance().getQueueManager().getQueueSession();
 456  
 
 457  0
         while (!stopped.get())
 458  
         {
 459  
             try
 460  
             {
 461  
                 // Wait if the component is paused
 462  0
                 paused.whenFalse(null);
 463  
 
 464  
                 // If we're doing a draining stop, read all events from the queue
 465  
                 // before stopping
 466  0
                 if (stopping.get())
 467  
                 {
 468  0
                     if (queueSession == null || queueSession.getQueue(descriptorQueueName).size() == 0)
 469  
                     {
 470  0
                         stopping.set(false);
 471  0
                         break;
 472  
                     }
 473  
                 }
 474  
 
 475  0
                 event = (MuleEvent) dequeue();
 476  0
                 if (event != null)
 477  
                 {
 478  0
                     if (stats.isEnabled())
 479  
                     {
 480  0
                         stats.decQueuedEvent();
 481  
                     }
 482  
 
 483  0
                     if (logger.isDebugEnabled())
 484  
                     {
 485  0
                         logger.debug("Component: " + descriptor.getName() + " dequeued event on: "
 486  
                                         + event.getEndpoint().getEndpointURI());
 487  
                     }
 488  
 
 489  0
                     proxy = getProxy();
 490  0
                     proxy.start();
 491  0
                     proxy.onEvent(queueSession, event);
 492  0
                     workManager.scheduleWork(proxy, WorkManager.INDEFINITE, null, this);
 493  
                 }
 494  0
             }
 495  0
             catch (Exception e)
 496  
             {
 497  0
                 if (proxy != null && proxyPool != null)
 498  
                 {
 499  
                     try
 500  
                     {
 501  0
                         proxyPool.returnObject(proxy);
 502  
                     }
 503  0
                     catch (Exception e2)
 504  
                     {
 505  
                         // TODO MULE-863: What should we do here? Die?
 506  0
                         logger.info("Failed to return proxy to pool", e2);
 507  0
                     }
 508  
                 }
 509  
 
 510  0
                 if (e instanceof InterruptedException)
 511  
                 {
 512  0
                     stopping.set(false);
 513  0
                     break;
 514  
                 }
 515  0
                 else if (e instanceof NoSuchElementException)
 516  
                 {
 517  0
                     handleException(new ComponentException(CoreMessages.proxyPoolTimedOut(),
 518  
                         (event == null ? null : event.getMessage()), this, e));
 519  
                 }
 520  0
                 else if (e instanceof UMOException)
 521  
                 {
 522  0
                     handleException(e);
 523  
                 }
 524  0
                 else if (e instanceof WorkException)
 525  
                 {
 526  0
                     handleException(
 527  
                         new ComponentException(
 528  
                             CoreMessages.eventProcessingFailedFor(descriptor.getName()),
 529  
                             (event == null ? null : event.getMessage()), this, e));
 530  
                 }
 531  
                 else
 532  
                 {
 533  0
                     handleException(
 534  
                         new ComponentException(
 535  
                             CoreMessages.failedToGetPooledObject(),
 536  
                             (event == null ? null : event.getMessage()), this, e));
 537  
                 }
 538  0
             }
 539  
             finally
 540  
             {
 541  0
                 stopping.set(false);
 542  0
                 if (proxy != null && componentPerRequest)
 543  
                 {
 544  0
                     proxy.dispose();
 545  
                 }
 546  0
             }
 547  
         }
 548  0
     }
 549  
 
 550  
     /**
 551  
      * The proxy may be one of three types: 1. pooled 2. not pooled 3. per-request
 552  
      */
 553  
     protected MuleProxy getProxy() throws Exception
 554  
     {
 555  
         MuleProxy proxy;
 556  0
         if (proxyPool != null)
 557  
         {
 558  0
             proxy = (MuleProxy) proxyPool.borrowObject();
 559  0
             ((SedaComponentStatistics) getStatistics()).setComponentPoolSize(proxyPool.getSize());
 560  
         }
 561  0
         else if (componentPerRequest)
 562  
         {
 563  0
             proxy = createComponentProxy();
 564  
         }
 565  
         else
 566  
         {
 567  0
             proxy = componentProxy;
 568  
         }
 569  0
         proxy.setStatistics(getStatistics());
 570  0
         return proxy;
 571  
     }
 572  
     
 573  
     public void release()
 574  
     {
 575  0
         stopping.set(false);
 576  0
     }
 577  
 
 578  
     protected void enqueue(UMOEvent event) throws Exception
 579  
     {
 580  0
         QueueSession session = MuleManager.getInstance().getQueueManager().getQueueSession();
 581  0
         session.getQueue(descriptorQueueName).put(event);
 582  0
     }
 583  
 
 584  
     protected UMOEvent dequeue() throws Exception
 585  
     {
 586  
         // Wait until an event is available
 587  0
         QueueSession queueSession = MuleManager.getInstance().getQueueManager().getQueueSession();
 588  0
         return (UMOEvent) queueSession.getQueue(descriptorQueueName).poll(queueTimeout);
 589  
     }
 590  
 
 591  
     public void workAccepted(WorkEvent event)
 592  
     {
 593  0
         handleWorkException(event, "workAccepted");
 594  0
     }
 595  
 
 596  
     public void workRejected(WorkEvent event)
 597  
     {
 598  0
         handleWorkException(event, "workRejected");
 599  0
     }
 600  
 
 601  
     public void workStarted(WorkEvent event)
 602  
     {
 603  0
         handleWorkException(event, "workStarted");
 604  0
     }
 605  
 
 606  
     public void workCompleted(WorkEvent event)
 607  
     {
 608  0
         handleWorkException(event, "workCompleted");
 609  0
     }
 610  
 
 611  
     protected void handleWorkException(WorkEvent event, String type)
 612  
     {
 613  
         Throwable e;
 614  
 
 615  0
         if (event != null && event.getException() != null)
 616  
         {
 617  0
             e = event.getException();
 618  
         }
 619  
         else
 620  
         {
 621  0
             return;
 622  
         }
 623  
 
 624  0
         if (event.getException().getCause() != null)
 625  
         {
 626  0
             e = event.getException().getCause();
 627  
         }
 628  
 
 629  0
         logger.error("Work caused exception on '" + type + "'. Work being executed was: "
 630  
                         + event.getWork().toString());
 631  
 
 632  0
         if (e instanceof Exception)
 633  
         {
 634  0
             handleException((Exception) e);
 635  
         }
 636  
         else
 637  
         {
 638  0
             throw new MuleRuntimeException(
 639  
                 CoreMessages.componentCausedErrorIs(this.getName()), e);
 640  
         }
 641  0
     }
 642  
 
 643  
     public PoolingProfile getPoolingProfile()
 644  
     {
 645  0
         return poolingProfile;
 646  
     }
 647  
 
 648  
     public void setPoolingProfile(PoolingProfile poolingProfile)
 649  
     {
 650  0
         this.poolingProfile = poolingProfile;
 651  0
     }
 652  
 
 653  
     public QueueProfile getQueueProfile()
 654  
     {
 655  0
         return queueProfile;
 656  
     }
 657  
 
 658  
     public void setQueueProfile(QueueProfile queueProfile)
 659  
     {
 660  0
         this.queueProfile = queueProfile;
 661  0
     }
 662  
 }