Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » ejb » txtimer » [javadoc | source]
    1   /*
    2    * JBoss, Home of Professional Open Source
    3    * Copyright 2005, JBoss Inc., and individual contributors as indicated
    4    * by the @authors tag. See the copyright.txt in the distribution for a
    5    * full listing of individual contributors.
    6    *
    7    * This is free software; you can redistribute it and/or modify it
    8    * under the terms of the GNU Lesser General Public License as
    9    * published by the Free Software Foundation; either version 2.1 of
   10    * the License, or (at your option) any later version.
   11    *
   12    * This software is distributed in the hope that it will be useful,
   13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15    * Lesser General Public License for more details.
   16    *
   17    * You should have received a copy of the GNU Lesser General Public
   18    * License along with this software; if not, write to the Free
   19    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21    */
   22   package org.jboss.ejb.txtimer;
   23   
   24   // $Id: EJBTimerServiceImpl.java 66679 2007-11-02 14:29:49Z wolfc $
   25   
   26   import java.lang.reflect.Constructor;
   27   import java.util.Collection;
   28   import java.util.Collections;
   29   import java.util.HashMap;
   30   import java.util.Iterator;
   31   import java.util.List;
   32   import java.util.Map;
   33   import java.util.Date;
   34   import java.io.Serializable;
   35   
   36   import javax.ejb.TimerService;
   37   import javax.ejb.Timer;
   38   import javax.ejb.EJBException;
   39   import javax.management.ObjectName;
   40   import javax.transaction.TransactionManager;
   41   
   42   import org.jboss.ejb.Container;
   43   import org.jboss.ejb.ContainerMBean;
   44   import org.jboss.logging.Logger;
   45   import org.jboss.mx.util.MBeanProxyExt;
   46   import org.jboss.system.ServiceMBeanSupport;
   47   import org.jboss.tm.TransactionManagerFactory;
   48   import org.jboss.tm.TransactionManagerLocator;
   49   
   50   /**
   51    * A service that implements this interface provides an Tx aware EJBTimerService.
   52    *
   53    * @author Thomas.Diesler@jboss.org
   54    * @author Dimitris.Andreadis@jboss.org
   55    * @version $Revision: 66679 $
   56    * @since 07-Apr-2004
   57    */
   58   public class EJBTimerServiceImpl extends ServiceMBeanSupport
   59      implements EJBTimerServiceImplMBean
   60   {
   61      // Logging support
   62      private static Logger log = Logger.getLogger(EJBTimerServiceImpl.class);
   63   
   64      /**
   65       * Used for objects that don't implement javax.ejb.TimedObject but still call getTimerService()
   66       * According to the CTS, it's allowed (jbcts-381).
   67       */
   68      public static TimerService FOR_NON_TIMED_OBJECT = new TimerService()
   69      {
   70         public Timer createTimer(long duration, Serializable info) throws IllegalArgumentException,
   71            IllegalStateException,
   72            EJBException
   73         {
   74            throw new IllegalStateException("The object does not implement javax.ejb.TimedObject interface!");
   75         }
   76   
   77         public Timer createTimer(long initialDuration, long intervalDuration, Serializable info)
   78            throws IllegalArgumentException, IllegalStateException, EJBException
   79         {
   80            throw new IllegalStateException("The object does not implement javax.ejb.TimedObject interface!");
   81         }
   82   
   83         public Timer createTimer(Date expiration, Serializable info) throws IllegalArgumentException,
   84            IllegalStateException,
   85            EJBException
   86         {
   87            throw new IllegalStateException("The object does not implement javax.ejb.TimedObject interface!");
   88         }
   89   
   90         public Timer createTimer(Date initialExpiration, long intervalDuration, Serializable info)
   91            throws IllegalArgumentException, IllegalStateException, EJBException
   92         {
   93            throw new IllegalStateException("The object does not implement javax.ejb.TimedObject interface!");
   94         }
   95   
   96         public Collection getTimers() throws IllegalStateException, EJBException
   97         {
   98            return Collections.EMPTY_LIST;
   99         }
  100      };
  101   
  102      // Attributes
  103      
  104      // The object name of the retry policy
  105      private ObjectName retryPolicyName;
  106      // The object name of the persistence policy
  107      private ObjectName persistencePolicyName;
  108      // The TimerIdGenerator class name
  109      private String timerIdGeneratorClassName;
  110      // The TimedObjectInvoker class name
  111      private String timedObjectInvokerClassName;
  112      // The TransactionManagerFactory
  113      private TransactionManagerFactory transactionManagerFactory;
  114      
  115      // Plug-ins
  116   
  117      // The tx manager plug-in
  118      private TransactionManager transactionManager;   
  119      // The retry policy plug-in
  120      private RetryPolicy retryPolicy;
  121      // The persistence policy plug-in
  122      private PersistencePolicy persistencePolicy;
  123      // The timerId generator plug-in
  124      private TimerIdGenerator timerIdGenerator;   
  125      
  126      // Maps the timedObjectId to TimerServiceImpl objects
  127      private Map timerServiceMap = Collections.synchronizedMap(new HashMap());
  128   
  129      // Attributes ----------------------------------------------------
  130      
  131      /**
  132       * Get the object name of the retry policy.
  133       *
  134       * @jmx.managed-attribute
  135       */
  136      public ObjectName getRetryPolicy()
  137      {
  138         return retryPolicyName;
  139      }
  140   
  141      /**
  142       * Set the object name of the retry policy.
  143       *
  144       * @jmx.managed-attribute
  145       */
  146      public void setRetryPolicy(ObjectName retryPolicyName)
  147      {
  148         this.retryPolicyName = retryPolicyName;
  149      }
  150   
  151      /**
  152       * Get the object name of the persistence policy.
  153       *
  154       * @jmx.managed-attribute
  155       */
  156      public ObjectName getPersistencePolicy()
  157      {
  158         return persistencePolicyName;
  159      }
  160   
  161      /**
  162       * Set the object name of the persistence policy.
  163       *
  164       * @jmx.managed-attribute
  165       */
  166      public void setPersistencePolicy(ObjectName persistencePolicyName)
  167      {
  168         this.persistencePolicyName = persistencePolicyName;
  169      }
  170   
  171      /**
  172       * Get the TimerIdGenerator class name
  173       *
  174       * @jmx.managed-attribute
  175       */
  176      public String getTimerIdGeneratorClassName()
  177      {
  178         return timerIdGeneratorClassName;
  179      }
  180   
  181      /**
  182       * Get the TimerIdGenerator class name
  183       *
  184       * @jmx.managed-attribute
  185       */
  186      public void setTimerIdGeneratorClassName(String timerIdGeneratorClassName)
  187      {
  188         this.timerIdGeneratorClassName = timerIdGeneratorClassName;
  189      }
  190   
  191      /**
  192       * Get the TimedObjectInvoker class name
  193       *
  194       * @jmx.managed-attribute
  195       */
  196      public String getTimedObjectInvokerClassName()
  197      {
  198         return timedObjectInvokerClassName;
  199      }
  200   
  201      /**
  202       * Set the TimedObjectInvoker class name
  203       *
  204       * @jmx.managed-attribute
  205       */
  206      public void setTimedObjectInvokerClassName(String timedObjectInvokerClassName)
  207      {
  208         this.timedObjectInvokerClassName = timedObjectInvokerClassName;
  209      }
  210   
  211      /**
  212       * Set the TransactionManagerFactory
  213       */
  214      public void setTransactionManagerFactory(TransactionManagerFactory factory)
  215      {
  216         this.transactionManagerFactory = factory;
  217      }
  218      
  219      // ServiceMBeanSupport Lifecycle ---------------------------------
  220      
  221      protected void startService() throws Exception
  222      {
  223         // Setup plugins, fall back to safe defaults
  224   
  225         // Get the TransactionManager from the factory, fall-back to the locator
  226         if (transactionManagerFactory != null)
  227            transactionManager = transactionManagerFactory.getTransactionManager();
  228         else
  229            transactionManager = TransactionManagerLocator.getInstance().locate();
  230         
  231         // Get a proxy to the retry policy
  232         try
  233         {
  234            retryPolicy = (RetryPolicy)MBeanProxyExt.create(RetryPolicy.class, getRetryPolicy(), server);
  235         }
  236         catch (Exception e)
  237         {
  238            log.error("Cannot obtain the implementation of a RetryPolicy", e);
  239         }
  240         
  241         // Get a proxy to the persistence policy
  242         try
  243         {
  244            persistencePolicy = (PersistencePolicy)MBeanProxyExt.create(PersistencePolicy.class, persistencePolicyName, server);
  245         }
  246         catch (Exception e)
  247         {
  248            log.warn("Cannot obtain the implementation of a PersistencePolicy, using NoopPersistencePolicy: " + e.toString());
  249            persistencePolicy = new NoopPersistencePolicy();
  250         }
  251   
  252         // Get the timerId generator
  253         try
  254         {
  255            Class timerIdGeneratorClass = getClass().getClassLoader().loadClass(timerIdGeneratorClassName);
  256            timerIdGenerator = (TimerIdGenerator)timerIdGeneratorClass.newInstance();
  257         }
  258         catch (Exception e)
  259         {
  260            log.warn("Cannot obtain the implementation of a TimerIdGenerator, using BigIntegerTimerIdGenerator: " + e.toString());
  261            timerIdGenerator = new BigIntegerTimerIdGenerator();
  262         }
  263      }
  264      
  265      protected void stopService()
  266      {
  267         // Cleanup plugins
  268         transactionManager = null;
  269         retryPolicy = null;
  270         persistencePolicy = null;
  271         timerIdGenerator = null;
  272      }
  273      
  274      // EJBTimerService Operations ------------------------------------
  275      
  276      /**
  277       * Create a TimerService for a given TimedObjectId that lives in a JBoss Container.
  278       * The TimedObjectInvoker is constructed from the invokerClassName.
  279       *
  280       * @param containerId The string identifier for a class of TimedObjects
  281       * @param instancePk  The rimary key for an instance of a TimedObject, may be null
  282       * @param container   The Container that is associated with the TimerService
  283       * @return the TimerService
  284       */
  285      public TimerService createTimerService(ObjectName containerId, Object instancePk, Container container)
  286      {
  287         TimedObjectInvoker invoker = null;
  288         try
  289         {
  290            TimedObjectId timedObjectId = new TimedObjectId(containerId, instancePk);
  291            Class invokerClass = getClass().getClassLoader().loadClass(timedObjectInvokerClassName);
  292            Constructor constr = invokerClass.getConstructor(new Class[]{TimedObjectId.class, Container.class});
  293            invoker = (TimedObjectInvoker)constr.newInstance(new Object[]{timedObjectId, container});
  294         }
  295         catch (Exception e)
  296         {
  297            log.error("Cannot create TimedObjectInvoker: " + timedObjectInvokerClassName, e);
  298            return null;
  299         }
  300   
  301         return createTimerService(containerId, instancePk, invoker);
  302      }
  303   
  304      /**
  305       * Create a TimerService for a given TimedObjectId that is invoked through the given invoker
  306       *
  307       * @param containerId The string identifier for a class of TimedObjects
  308       * @param instancePk  The rimary key for an instance of a TimedObject, may be null
  309       * @param invoker     The TimedObjectInvoker
  310       * @return the TimerService
  311       */
  312      public TimerService createTimerService(ObjectName containerId, Object instancePk, TimedObjectInvoker invoker)
  313      {
  314         TimedObjectId timedObjectId = new TimedObjectId(containerId, instancePk);
  315         TimerServiceImpl timerService = (TimerServiceImpl)timerServiceMap.get(timedObjectId);
  316         if (timerService == null)
  317         {
  318            timerService = new TimerServiceImpl(timedObjectId, invoker,
  319                  transactionManager, persistencePolicy, retryPolicy, timerIdGenerator);
  320            log.debug("createTimerService: " + timerService);
  321            timerServiceMap.put(timedObjectId, timerService);
  322         }
  323         return timerService;
  324      }
  325   
  326      /**
  327       * Get the TimerService for a given TimedObjectId
  328       *
  329       * @param containerId The string identifier for a class of TimedObjects
  330       * @param instancePk  The rimary key for an instance of a TimedObject, may be null
  331       * @return The TimerService, or null if it does not exist
  332       */
  333      public TimerService getTimerService(ObjectName containerId, Object instancePk)
  334      {
  335         TimedObjectId timedObjectId = new TimedObjectId(containerId, instancePk);
  336         return (TimerServiceImpl)timerServiceMap.get(timedObjectId);
  337      }
  338   
  339      /**
  340       * Remove the TimerService for a given containerId/pKey (TimedObjectId),
  341       * along with any persisted timer information.
  342       * 
  343       * This should be used for removing the TimerService and Timers
  344       * associated with a particular entity bean, when it gets removed.
  345       * 
  346       * @param containerId The string identifier for a class of TimedObjects
  347       * @param pKey        The primary key for an instance of a TimedObject, may be null
  348       */
  349      public void removeTimerService(ObjectName containerId, Object instancePk)
  350      {
  351         TimedObjectId timedObjectId = new TimedObjectId(containerId, instancePk);
  352         // remove a single timer service
  353         if (timedObjectId.getInstancePk() != null)
  354         {
  355            TimerServiceImpl timerService = (TimerServiceImpl)getTimerService(containerId, instancePk);
  356            if (timerService != null)
  357            {
  358               log.debug("removeTimerService: " + timerService);
  359               // don't keep persistent state about the timer
  360               // this is really an entity->remove()
  361               timerService.shutdown(false);
  362               timerServiceMap.remove(timedObjectId);
  363            }
  364         }      
  365         else
  366         {
  367            // assume we don't want to keep timer state when the container
  368            // gets undeployed, this is the legacy behaviour
  369            removeTimerService(containerId, false);
  370         }
  371      }
  372   
  373      /**
  374       * Remove the TimerService for a given containerId.
  375       * 
  376       * This should be used to remove the timer service and timers for
  377       * any type of container (session, entity, message) at the time of
  378       * undeployment.
  379       *
  380       * @param containerId The string identifier for a class of TimedObjects
  381       * @param keepState   Flag indicating whether timer persistent state should be kept or removed 
  382       */
  383      public void removeTimerService(ObjectName containerId, boolean keepState) throws IllegalStateException
  384      {
  385         // remove all timers with the given containerId
  386         Iterator it = timerServiceMap.entrySet().iterator();
  387         while (it.hasNext())
  388         {
  389            Map.Entry entry = (Map.Entry)it.next();
  390            TimedObjectId key = (TimedObjectId)entry.getKey();
  391            TimerServiceImpl timerService = (TimerServiceImpl)entry.getValue();
  392            if (containerId.equals(key.getContainerId()))
  393            {
  394               log.debug("removeTimerService: " + timerService);
  395               timerService.shutdown(keepState);
  396               it.remove();
  397            }
  398         }
  399      }
  400      
  401      /**
  402       * Remove the TimerService for a given containerId/pKey (TimedObjectId).
  403       *
  404       * @param containerId The string identifier for a class of TimedObjects
  405       * @param pKey        The primary key for an instance of a TimedObject, may be null
  406       * @param keepState   Flag indicating whether timer persistent state should be kept or removed 
  407       */
  408      public void removeTimerService(ObjectName containerId, Object instancePk, boolean keepState) throws IllegalStateException   
  409      {
  410         // remove a single timer service
  411         TimedObjectId timedObjectId = new TimedObjectId(containerId, instancePk);
  412         if (timedObjectId.getInstancePk() != null)
  413         {
  414            TimerServiceImpl timerService = (TimerServiceImpl)getTimerService(containerId, instancePk);
  415            if (timerService != null)
  416            {
  417               log.debug("removeTimerService: " + timerService);
  418               timerService.shutdown(false);
  419               timerServiceMap.remove(timedObjectId);
  420            }
  421         }
  422         // remove all timers with the given containerId
  423         else
  424         {
  425            Iterator it = timerServiceMap.entrySet().iterator();
  426            while (it.hasNext())
  427            {
  428               Map.Entry entry = (Map.Entry)it.next();
  429               TimedObjectId key = (TimedObjectId)entry.getKey();
  430               TimerServiceImpl timerService = (TimerServiceImpl)entry.getValue();
  431               if (containerId.equals(key.getContainerId()))
  432               {
  433                  log.debug("removeTimerService: " + timerService);
  434                  timerService.shutdown(keepState);
  435                  it.remove();
  436               }
  437            }
  438         }      
  439      }
  440      
  441      /**
  442       * Restore the persisted timers for a given ejb container
  443       * 
  444       * @param containerId The ejb container id
  445       * @param loader      The classloader to use for loading the timers
  446       */
  447      public void restoreTimers(ObjectName containerId, ClassLoader loader) throws IllegalStateException
  448      {
  449         assert persistencePolicy != null : "persistencePolicy is not set";
  450         
  451         // find out all the persisted handles, for the specified container
  452         List handles = persistencePolicy.listTimerHandles(containerId, loader);
  453         
  454         if (handles.isEmpty() == false)
  455         {
  456            // first remove the persisted handles from the db
  457            for (Iterator i = handles.iterator(); i.hasNext(); )
  458            {
  459               TimerHandleImpl handle = (TimerHandleImpl)i.next();
  460               persistencePolicy.deleteTimer(handle.getTimerId(), handle.getTimedObjectId());
  461            }
  462   
  463            // make a second pass to re-create the timers; use the container
  464            // itself to retrieve the correct TimerService/ for each handle,
  465            // then use the standard ejb timer API to recreate the timer
  466            for (Iterator i = handles.iterator(); i.hasNext(); )
  467            {
  468               TimerHandleImpl handle = (TimerHandleImpl)i.next();
  469               try
  470               {
  471                  TimedObjectId targetId = handle.getTimedObjectId();
  472                  ContainerMBean container = (ContainerMBean)MBeanProxyExt.create(ContainerMBean.class, containerId, server);               
  473                  TimerService timerService = container.getTimerService(targetId.getInstancePk());
  474                  timerService.createTimer(handle.getFirstTime(), handle.getPeriode(), handle.getInfo());
  475               }
  476               catch (Exception e)
  477               {
  478                  log.warn("Unable to restore timer record: " + handle, e);
  479               }
  480            }
  481         }      
  482      }
  483      
  484      // EJBTimerServiceImplMbean operations ---------------------------
  485      
  486      /**
  487       * List the timers registered with all TimerService objects
  488       *
  489       * @jmx.managed-operation
  490       */
  491      public String listTimers()
  492      {
  493         StringBuffer retBuffer = new StringBuffer();
  494         Iterator it = timerServiceMap.entrySet().iterator();
  495         while (it.hasNext())
  496         {
  497            Map.Entry entry = (Map.Entry)it.next();
  498            TimedObjectId timedObjectId = (TimedObjectId)entry.getKey();
  499            retBuffer.append(timedObjectId + "\n");
  500   
  501            TimerServiceImpl timerService = (TimerServiceImpl)entry.getValue();
  502            Collection col = timerService.getAllTimers();
  503            for (Iterator iterator = col.iterator(); iterator.hasNext();)
  504            {
  505               TimerImpl timer = (TimerImpl)iterator.next();
  506               TimerHandleImpl handle = new TimerHandleImpl(timer);
  507               retBuffer.append("   handle: " + handle + "\n");
  508               retBuffer.append("      " + timer + "\n");
  509            }
  510         }
  511         return retBuffer.toString();
  512      }
  513    
  514   }

Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » ejb » txtimer » [javadoc | source]