[jboss-cvs] JBossAS SVN: r58158 - in trunk: testsuite/src/main/org/jboss/test/util/test varia/src/main/org/jboss/varia/scheduler varia/src/main/org/jboss/varia/scheduler/example

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Mon Nov 6 14:25:10 EST 2006


Author: genman
Date: 2006-11-06 14:25:06 -0500 (Mon, 06 Nov 2006)
New Revision: 58158

Modified:
   trunk/testsuite/src/main/org/jboss/test/util/test/SchedulerUnitTestCase.java
   trunk/varia/src/main/org/jboss/varia/scheduler/AbstractScheduleProvider.java
   trunk/varia/src/main/org/jboss/varia/scheduler/ScheduleManager.java
   trunk/varia/src/main/org/jboss/varia/scheduler/Scheduler.java
   trunk/varia/src/main/org/jboss/varia/scheduler/SchedulerMBean.java
   trunk/varia/src/main/org/jboss/varia/scheduler/example/SchedulableMBeanExample.java
   trunk/varia/src/main/org/jboss/varia/scheduler/example/SchedulableMBeanExampleMBean.java
Log:
JIRA-3126
Added tests of the scheduler feature
The tests do not include error cases or some configuration cases yet 
Cleaned up some of the scheduler classes: 
	Better logging (trace over debug), use MBean proxies, divided long methods 
	Addressed some potential race conditions in ScheduleManager


Modified: trunk/testsuite/src/main/org/jboss/test/util/test/SchedulerUnitTestCase.java
===================================================================
--- trunk/testsuite/src/main/org/jboss/test/util/test/SchedulerUnitTestCase.java	2006-11-06 19:24:43 UTC (rev 58157)
+++ trunk/testsuite/src/main/org/jboss/test/util/test/SchedulerUnitTestCase.java	2006-11-06 19:25:06 UTC (rev 58158)
@@ -22,9 +22,13 @@
 package org.jboss.test.util.test;
 
 import java.net.URL;
+import java.util.Date;
 import javax.management.ObjectName;
+import javax.management.MBeanServerInvocationHandler;
 
 import org.jboss.test.JBossTestCase;
+import org.jboss.varia.scheduler.ScheduleManager;
+import org.jboss.varia.scheduler.example.SchedulableMBeanExampleMBean;
 
 /**
  * Test case for the Scheduler Utility. The test
@@ -42,6 +46,9 @@
 public class SchedulerUnitTestCase
    extends JBossTestCase
 {
+
+   private String file = "../resources/util/test-default-scheduler-service.xml";
+
    /**
     * Constructor for the SchedulerUnitTestCase object
     *
@@ -52,52 +59,118 @@
       super(name);
    }
 
+   protected void setUp() throws Exception {
+	  super.setUp();
+   }
+
+   protected void tearDown() throws Exception {
+	  super.tearDown();
+   }
+
    // Public --------------------------------------------------------
 
+   private void registered(ObjectName on) throws Exception
+   {
+	  assertTrue(on + " isRegistered", getServer().isRegistered(on));
+   }
+
+   private SchedulableMBeanExampleMBean get(ObjectName on) throws Exception
+   {
+	  SchedulableMBeanExampleMBean ex = (SchedulableMBeanExampleMBean)
+		 MBeanServerInvocationHandler.newProxyInstance(getServer(), on,
+			   SchedulableMBeanExampleMBean.class, false);
+	  return ex;
+   }
+
+   private void check(ObjectName on, int hits, long remaining) throws Exception
+   {
+	  SchedulableMBeanExampleMBean ex = get(on);
+	  assertNotNull("name " + on, ex);
+
+	  assertEquals("hits", hits, ex.getHitCount());
+
+	  Date hd = ex.getHitDate();
+	  if (hits > 0)
+	  {
+		 Date now = new Date();
+		 assertNotNull("hit date", hd); 
+		 assertTrue("date " + hd + " " + now, !hd.after(now));
+		 assertTrue("note", ex.getHitNotification() != null);
+		 assertTrue("sched", ex.getSchedulerName() != null);
+		 assertEquals("remaining", remaining, ex.getRemainingRepetitions());
+	  }
+	  assertEquals(null, ex.getTestString());
+   }
+
    /**
-    * Checks if the Scheduler is deployed and if not then
-    * deployed the default one now.
+    * Tests the default scheduler.
     */
    public void testDefaultScheduler()
       throws Exception
    {
-      // The class loader used to locate the configuration file
-      ClassLoader lLoader = Thread.currentThread().getContextClassLoader();
-      assertTrue("ContextClassloader missing", lLoader != null);
-      //Get URL for deployable *service.xml file in resources
-      URL serviceURL = lLoader.getResource("util/test-default-scheduler-service.xml");
-      if (serviceURL == null)
-      {
-         //if we're running from the jmxtest.jar, it should be here instead
-         serviceURL = lLoader.getResource("test-default-scheduler-service.xml");
-      }
-      assertTrue("resource test-default-scheduler-service.xml not found", serviceURL != null);
+	  ObjectName ex1 = new ObjectName("test:name=SchedulableMBeanExample,instance=1");
+	  ObjectName ex2 = new ObjectName("test:name=SchedulableMBeanExample,instance=2");
+	  ObjectName ex3 = new ObjectName("test:name=SchedulableMBeanExample,instance=3");
+	  ObjectName scheduler0 = new ObjectName("test:service=Scheduler");
+	  ObjectName scheduler1 = new ObjectName("test:service=Scheduler,name=SchedulableMBeanExample,instance=1");
+	  ObjectName scheduler2 = new ObjectName("test:service=Scheduler,name=SchedulableMBeanExample,instance=2");
+	  ObjectName manager1 = new ObjectName("test:service=Scheduler,name=ScheduleManager");
+
+	  deploy(file);
       try
       {
-         deploy(serviceURL.toString());
-         ObjectName scheduler = new ObjectName("test:service=Scheduler");
-         assertTrue("test:service=Scheduler isRegistered",
-            getServer().isRegistered(scheduler));
-         ObjectName ex1 = new ObjectName("test:name=SchedulableMBeanExample");
-         assertTrue("test:name=SchedulableMBeanExample isRegistered",
-            getServer().isRegistered(ex1));
-         ObjectName scheduler2 = new ObjectName("test:service=Scheduler,name=SchedulableMBeanExample");
-         assertTrue("test:service=Scheduler,name=SchedulableMBeanExample isRegistered",
-            getServer().isRegistered(scheduler2));
+		 registered(new ObjectName(ScheduleManager.DEFAULT_TIMER_NAME));
+		 registered(ex1);
+		 registered(ex2);
+		 registered(ex3);
+		 registered(scheduler0);
+		 registered(scheduler1);
+		 registered(scheduler2);
+		 registered(manager1);
+		 check(ex1, 0, 0);
+		 check(ex2, 0, 0);
+		 check(ex3, 0, 0);
+
+		 Thread.sleep(1100); // NOW == one second
+		 check(ex1, 1, 0);
+		 check(ex2, 0, 0); // StartAtStartup is false
+		 check(ex3, 1, 2);
+		 invoke(scheduler2, "startSchedule", null, null);
+
+		 Thread.sleep(400); // one period
+		 check(ex1, 1, 0); // done
+		 check(ex2, 0, 0); // wait 500 more
+		 check(ex3, 2, 1); // last 
+
+		 Thread.sleep(500); // one period
+		 check(ex1, 1, 0); // done
+		 check(ex2, 1, -1); // first
+		 check(ex3, 3, 0); // done
+
+		 Thread.sleep(500); // one period
+		 check(ex2, 2, -1); // first
+		 invoke(scheduler2, "stopSchedule", new Object[] { Boolean.TRUE }, new String[] { boolean.class.getName() });
+
+		 Thread.sleep(500); // one period
+		 check(ex2, 2, -1); // no more
+		 invoke(scheduler2, "startSchedule", null, null);
+
+		 Thread.sleep(1001); // one period
+		 check(ex2, 3, -1); // restated
       }
       finally
       {
-         undeploy(serviceURL.toString());
-      } // end of try-finally
+         undeploy(file);
+      }
    }
 
-   /** Test the deployment of a ear containing a sar which creates an
+   /** 
+	* Test the deployment of a ear containing a sar which creates an
     * instance of the org.jboss.varia.scheduler.Scheduler service with a
     * Schedulable class that exists in an external jar referenced by the
     * sar manifest.
     *
     * @throws Exception
-    */
    public void testExternalServiceJar() throws Exception
    {
       // Deploy the external jar containg the Schedulable
@@ -117,4 +190,5 @@
          undeploy("scheduler.jar");
       }
    }
+    */
 }

Modified: trunk/varia/src/main/org/jboss/varia/scheduler/AbstractScheduleProvider.java
===================================================================
--- trunk/varia/src/main/org/jboss/varia/scheduler/AbstractScheduleProvider.java	2006-11-06 19:24:43 UTC (rev 58157)
+++ trunk/varia/src/main/org/jboss/varia/scheduler/AbstractScheduleProvider.java	2006-11-06 19:25:06 UTC (rev 58158)
@@ -28,6 +28,7 @@
 import javax.management.MBeanException;
 import javax.management.ObjectName;
 import javax.management.ReflectionException;
+import javax.management.MBeanServerInvocationHandler;
 
 import org.jboss.system.ServiceMBeanSupport;
 
@@ -49,6 +50,7 @@
 {
    /** The schedule manager ObjectName */
    private ObjectName scheduleManagerName = ScheduleManagerMBean.OBJECT_NAME;
+   private ScheduleManagerMBean manager;
 
    // ------------------------------------------------------------------------
    // Constructors
@@ -127,30 +129,13 @@
          ObjectName pTarget, String pMethodName, String[] pMethodSignature,
          Date pStart, long pPeriod, int pRepetitions) throws JMException
    {
-      return (
-            (Integer) server.invoke(
-                  scheduleManagerName,
-                  "addSchedule",
-                  new Object[] {
-                        serviceName,
+	  return manager.addSchedule(serviceName,
                         pTarget,
                         pMethodName,
                         pMethodSignature,
                         pStart,
-                        new Long(pPeriod),
-                        new Integer((int) pRepetitions)
-                        },
-                  new String[] {
-                        ObjectName.class.getName(),
-                        ObjectName.class.getName(),
-                        String.class.getName(),
-                        String[].class.getName(),
-                        Date.class.getName(),
-                        Long.TYPE.getName(),
-                        Integer.TYPE.getName()
-                        }
-                  )
-              ).intValue();
+                        pPeriod,
+                        pRepetitions);
    }
 
    /**
@@ -160,12 +145,7 @@
     */
    protected void removeSchedule(int pID) throws JMException
    {
-      server.invoke(
-            scheduleManagerName,
-            "removeSchedule",
-            new Object[] { new Integer(pID)},
-            new String[] { Integer.TYPE.getName()}
-            );
+	  manager.removeSchedule(pID);
    }
 
    // -------------------------------------------------------------------------
@@ -184,6 +164,8 @@
     */   
    protected void startService() throws Exception
    {
+	  this.manager = (ScheduleManagerMBean)MBeanServerInvocationHandler.newProxyInstance(
+			getServer(), scheduleManagerName, ScheduleManagerMBean.class, false);
       startScheduleProviderService();
    }
 
@@ -208,12 +190,7 @@
    protected void startScheduleProviderService()
       throws InstanceNotFoundException, MBeanException, ReflectionException
    {
-      server.invoke(
-            scheduleManagerName,
-            "registerProvider",
-            new Object[] { serviceName.toString()},
-            new String[] { String.class.getName()}
-            );
+	  manager.registerProvider(serviceName.toString());
    }
 
    /**
@@ -222,19 +199,7 @@
    protected void stopScheduleProviderService()
       throws InstanceNotFoundException, MBeanException, ReflectionException
    {
-      try
-      {
-         server.invoke(
-               scheduleManagerName,
-               "unregisterProvider",
-               new Object[] { serviceName.toString()},
-               new String[] { String.class.getName()}
-            );
-      }
-      catch (JMException jme)
-      {
-         log.error("Could not unregister the Provider from the Schedule Manager", jme);
-      }
+	  manager.unregisterProvider(serviceName.toString());
    }
    
 }

Modified: trunk/varia/src/main/org/jboss/varia/scheduler/ScheduleManager.java
===================================================================
--- trunk/varia/src/main/org/jboss/varia/scheduler/ScheduleManager.java	2006-11-06 19:24:43 UTC (rev 58157)
+++ trunk/varia/src/main/org/jboss/varia/scheduler/ScheduleManager.java	2006-11-06 19:25:06 UTC (rev 58158)
@@ -22,30 +22,43 @@
 package org.jboss.varia.scheduler;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 import java.util.Date;
-import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.Map;
 
 import javax.management.InstanceNotFoundException;
 import javax.management.JMException;
 import javax.management.MBeanException;
 import javax.management.MBeanServer;
+import javax.management.MBeanServerInvocationHandler;
 import javax.management.MalformedObjectNameException;
 import javax.management.Notification;
 import javax.management.NotificationListener;
+import javax.management.NotificationEmitter;
 import javax.management.ObjectName;
 import javax.management.timer.TimerNotification;
+import javax.management.timer.TimerMBean;
+import javax.management.timer.Timer;
 
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedInt;
+import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
+import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
 import org.jboss.logging.Logger;
 import org.jboss.system.ServiceMBeanSupport;
 
 /**
- * Schedule Manager which manage the Schedule and their matching Timer notifications
- * and notification listeners.
- * Each provider has to register when it is started where in turn their startProviding()
- * method is called which allows him to add its Schedules because the Manager is now
- * ready.
+ * ScheduleManager manages multiple scheduled timer listeners.
+ * These are registered using the {@link #addSchedule} operation.
+ * Providers (basically MBean lifecycle listeners) can be registered using the
+ * {@link #registerProvider} operation.
  *
+ * Because of the way the JBoss deployment model works (no way to readily
+ * invoke operations at deployment time), prefer to use the {@link Scheduler}
+ * MBean instead.
+ *
  * @author <a href="mailto:andreas at jboss.org">Andreas Schaefer</a>
  * @author <a href="mailto:dimitris at jboss.org">Dimitris Andreadis</a>
  * @version $Revision$
@@ -58,11 +71,15 @@
    // Constants
    // -------------------------------------------------------------------------
 
-   /** Default Timer Object Name **/
+   /** 
+	* Default Timer Object Name
+	*/
    public static String DEFAULT_TIMER_NAME = "jboss:service=Timer";
 
-   /** Counter for the Schedule Instance **/
-   private static int sCounter = 0;
+   /** 
+	* Counter for the number of scheduled instances.
+	*/
+   private static SynchronizedInt sCounter = new SynchronizedInt(0);
 
    private static final int NOTIFICATION = 0;
    private static final int DATE = 1;
@@ -77,21 +94,24 @@
    // -------------------------------------------------------------------------
 
    private String mTimerName = DEFAULT_TIMER_NAME;
-   private ObjectName mTimer;
+   private ObjectName mTimerObjectName;
+   private TimerMBean mTimer;
+   private NotificationEmitter mTimerEmitter;
 
-   private boolean mWaitForNextCallToStop = false;
-   private boolean mStartOnStart = false;
+   private boolean mStartOnStart = true;
    private boolean mFixedRate = false;
-   private boolean mIsPaused = false;
+   private SynchronizedBoolean mIsPaused = new SynchronizedBoolean(false);
 
    /**
-    * List of registered providers to inform them when the
-    * Schedule is stop / started or destroyed
+	* List of registered AbstractScheduleProvider ObjectNames to inform 
+	* when the this manager is stop or started.
     */
-   private ArrayList mProviders = new ArrayList();
+   private List mProviders = Collections.synchronizedList(new ArrayList());
    
-   /** List of added Schedules */
-   private Hashtable mSchedules = new Hashtable();
+   /** 
+	* Maps Integer to registered ScheduleInstance.
+	*/
+   private Map mSchedules = new ConcurrentReaderHashMap();
 
    // -------------------------------------------------------------------------
    // Constructors
@@ -115,6 +135,7 @@
     */
    public void startSchedules()
    {
+      log.debug("startSchedules()");
       // Check if not already started
       if (!isStarted())
       {
@@ -127,9 +148,9 @@
             {
                lInstance.start();
             }
-            catch (JMException jme)
+            catch (JMException e)
             {
-               log.error("Could not start a Schedule", jme);
+               log.error("Could not start: " + lInstance, e);
             }
          }
       }
@@ -158,16 +179,16 @@
             {
                lInstance.stop();
             }
-            catch (JMException jme)
+            catch (JMException e)
             {
-               log.error("Could not stop a Schedule", jme);
+               log.error("Could not stop: " + lInstance, e);
             }
          }
       }
    }
 
    /**
-    * Stops the server right now and starts it right now.
+    * Stops existing schedules immediately and restarts them right away.
     *
     * @jmx:managed-operation
     */
@@ -178,7 +199,7 @@
    }
 
    /**
-    * Register a Provider to make him available. In turn this
+    * Register a Provider to make it available. In turn this
     * method calls "startProviding()" method on the Provider
     * to indicate that the Provider can start adding Schedules.
     *
@@ -188,35 +209,43 @@
     */
    public void registerProvider(String pProviderObjectName)
    {
-      if (pProviderObjectName == null)
+	  try
+	  {
+		 registerProvider(new ObjectName(pProviderObjectName));
+	  }
+      catch (JMException jme)
       {
-         throw new RuntimeException("Provider must not be null");
+         log.error("Could not call startProviding() on " + pProviderObjectName, jme);
       }
-      int lIndex = mProviders.indexOf(pProviderObjectName);
-      if (lIndex >= 0)
+   }
+
+   /**
+    * Register a Provider to make it available. In turn this
+    * method calls "startProviding()" method on the Provider
+    * to indicate that the Provider can start adding Schedules.
+    *
+    * @param pProviderObjectName Object Name of the Provider
+    *
+    * @jmx:managed-operation
+    */
+   public void registerProvider(ObjectName pProviderObjectName)
+	  throws JMException
+   {
+      if (pProviderObjectName == null)
       {
-         // Provider found then do nothing
-         return;
+         throw new MalformedObjectNameException("Provider must not be null");
       }
-      // No provider found ==> a new provider
-      mProviders.add(pProviderObjectName);
-      // Initiate the Provider to provide schedules
-      try
-      {
-         ObjectName lProviderName = new ObjectName(pProviderObjectName);
-         //log.debug( "calling startProviding(): " + lProviderName + ", based on: " + pProviderObjectName );
-         server.invoke(
-                 lProviderName,
-                 "startProviding",
-                 new Object[]{},
-                 new String[]{}
-         );
-      }
-      catch (JMException jme)
-      {
-         log.error("Could not call startProviding() on the provider", jme);
-         // Ignore Exceptions
-      }
+	  synchronized (mProviders) {
+		 if (mProviders.contains(pProviderObjectName))
+			throw new JMException("Already registered: " + pProviderObjectName);
+		 mProviders.add(pProviderObjectName);
+	  }
+	  server.invoke(
+			  pProviderObjectName,
+			  "startProviding",
+			  new Object[]{},
+			  new String[]{}
+	  );
    }
 
    /**
@@ -229,36 +258,38 @@
     */
    public void unregisterProvider(String pProviderObjectName)
    {
-      int lIndex = mProviders.indexOf(pProviderObjectName);
-      if (lIndex < 0)
-      {
-         // Provider not found then do nothing
-         return;
-      }
-      // Stop the Provider from providing schedules
       try
       {
-         ObjectName lProviderName = new ObjectName(pProviderObjectName);
-         server.invoke(
-                 lProviderName,
-                 "stopProviding",
-                 new Object[]{},
-                 new String[]{}
-         );
+		 unregisterProvider(new ObjectName(pProviderObjectName));
       }
       catch (JMException jme)
       {
-         log.error("Could not call stopProviding() on the provider", jme);
-         // Ignore Exceptions
+         log.error("Could not call stopProviding() on " + pProviderObjectName, jme);
       }
-      finally
-      {
-         // Finally remove the provider
-         mProviders.remove(pProviderObjectName);
-      }
    }
 
    /**
+    * Unregister a Provider which in turn calls "stopProviding()"
+    * indicating to the Provider to remove all the Schedules.
+    *
+    * @param pProviderObjectName Object Name of the Provider
+    *
+    * @jmx:managed-operation
+    */
+   public void unregisterProvider(ObjectName pProviderObjectName)
+	  throws JMException
+   {
+      if (!mProviders.remove(pProviderObjectName))
+		 return;
+	  server.invoke(
+			  pProviderObjectName,
+			  "stopProviding",
+			  new Object[]{},
+			  new String[]{}
+	  );
+   }
+
+   /**
     * Adds a new Schedule to the Scheduler
     *
     * @param pTarget Object Name of the Target MBean
@@ -283,12 +314,6 @@
            int pRepetitions
            )
    {
-      /*
-      String sig = "{";
-      for (int i = 0; i < pMethodSignature.length; i++) sig += pMethodSignature[i];
-      sig += "}";
-      log.info( "ScheduleManager.addScheduler(" + pProvider + ", " + pTarget + ", " + pMethodName + ","  + sig + ", " + pStartDate + ", " + pPeriod + ", " + pRepetitions);
-      */
       ScheduleInstance lInstance = new ScheduleInstance(
               pProvider,
               pTarget,
@@ -298,7 +323,6 @@
               pRepetitions,
               pPeriod
       );
-      // Start it now if the Schedule Manager is started
       if (isStarted())
       {
          try
@@ -307,7 +331,7 @@
          }
          catch (JMException jme)
          {
-            log.error("Could not start the Schedule", jme);
+            log.error("Could not start " + lInstance, jme);
          }
       }
       int lID = lInstance.getID();
@@ -329,11 +353,13 @@
       ScheduleInstance lInstance = (ScheduleInstance) mSchedules.get(new Integer(pIdentification));
       try
       {
+		 if (lInstance == null)
+			throw new InstanceNotFoundException();
          lInstance.stop();
       }
-      catch (JMException jme)
+      catch (JMException e)
       {
-         log.error("Could not stop a Schedule", jme);
+         log.error("Could not stop " + lInstance, e);
       }
       mSchedules.remove(new Integer(pIdentification));
    }
@@ -353,12 +379,12 @@
          ScheduleInstance lInstance = (ScheduleInstance) i.next();
          if (lFirst)
          {
-            lReturn.append(lInstance.mIdentification + "");
+            lReturn.append(lInstance.mIdentification);
             lFirst = false;
          }
          else
          {
-            lReturn.append("," + lInstance.mIdentification);
+            lReturn.append(",").append(lInstance.mIdentification);
          }
       }
       return lReturn.toString();
@@ -371,7 +397,7 @@
     */
    public boolean isPaused()
    {
-      return mIsPaused;
+      return mIsPaused.get();
    }
 
    /**
@@ -382,7 +408,7 @@
     */
    public void setPaused(boolean pIsPaused)
    {
-      mIsPaused = pIsPaused;
+      mIsPaused.set(pIsPaused);
    }
 
    /**
@@ -483,40 +509,26 @@
     */
    protected void startService() throws Exception
    {
-      // Create Timer MBean if necessary
-      try
+	  mTimerObjectName = new ObjectName(mTimerName);
+      if (!getServer().isRegistered(mTimerObjectName))
       {
-         mTimer = new ObjectName(mTimerName);
+         getServer().createMBean(Timer.class.getName(), mTimerObjectName);
       }
-      catch (MalformedObjectNameException mone)
+	  mTimer = (TimerMBean)MBeanServerInvocationHandler.newProxyInstance(getServer(),
+			mTimerObjectName, TimerMBean.class, true);
+	  mTimerEmitter = (NotificationEmitter)mTimer;
+      if (!mTimer.isActive())
       {
-         mTimer = new ObjectName(DEFAULT_TIMER_NAME);
+		 mTimer.start();
       }
-
-      if (!getServer().isRegistered(mTimer))
-      {
-         getServer().createMBean("javax.management.timer.Timer", mTimer);
-      }
-      if (!((Boolean) getServer().getAttribute(mTimer, "Active")).booleanValue())
-      {
-         // Now start the Timer
-         getServer().invoke(
-                 mTimer,
-                 "start",
-                 new Object[]{},
-                 new String[]{}
-         );
-      }
-      log.debug("Start Schedules when Service is (re) started");
       startSchedules();
    }
 
    /**
-    * Stops all available Schedules.
-    **/
+    * Stops all Schedules.
+    */
    protected void stopService()
    {
-      // Stop the schedules right now !!
       stopSchedules(true);
    }
 
@@ -558,105 +570,105 @@
 
       public void handleNotification(Notification pNotification, Object pHandback)
       {
-         log.debug("MBeanListener.handleNotification(), notification: " + pNotification);
-         try
-         {
-            // If schedule is started invoke the schedule method on the Schedulable instance
-            log.debug("Scheduler is started: " + isStarted());
-            Date lTimeStamp = new Date(pNotification.getTimeStamp());
-            if (isStarted())
-            {
-               if (mSchedule.mRemainingRepetitions > 0 || mSchedule.mRemainingRepetitions < 0)
-               {
-                  if (mSchedule.mRemainingRepetitions > 0)
-                  {
-                     mSchedule.mRemainingRepetitions--;
-                  }
-                  if (!mIsPaused)
-                  {
-                     Object[] lArguments = new Object[mSchedule.mSchedulableMBeanArguments.length];
-                     for (int i = 0; i < lArguments.length; i++)
-                     {
-                        switch (mSchedule.mSchedulableMBeanArguments[i])
-                        {
-                           case ID:
-                              lArguments[i] = pNotification.getUserData();
-                              break;
-                           case NOTIFICATION:
-                              lArguments[i] = pNotification;
-                              break;
-                           case DATE:
-                              lArguments[i] = lTimeStamp;
-                              break;
-                           case REPETITIONS:
-                              lArguments[i] = new Long(mSchedule.mRemainingRepetitions);
-                              break;
-                           case SCHEDULER_NAME:
-                              lArguments[i] = getServiceName();
-                              break;
-                           case NEXT_DATE:
-                              lArguments[i] = new Date(lTimeStamp.getTime() + mSchedule.mPeriod);
-                              break;
-                           default:
-                              lArguments[i] = null;
-                        }
-                     }
-                     log.debug("MBean Arguments are: " + java.util.Arrays.asList(lArguments));
-                     log.debug("MBean Arguments Types are: " + java.util.Arrays.asList(mSchedule.mSchedulableMBeanArgumentTypes));
-                     try
-                     {
-                        log.debug("invoke(" + mSchedule.mTarget + ", " + mSchedule.mMethodName);
-                        getServer().invoke(
-                                mSchedule.mTarget,
-                                mSchedule.mMethodName,
-                                lArguments,
-                                mSchedule.mSchedulableMBeanArgumentTypes
-                        );
-                     }
-                     catch (javax.management.JMRuntimeException jmre)
-                     {
-                        log.error("Invoke of the Schedulable MBean failed", jmre);
-                     }
-                     catch (javax.management.JMException jme)
-                     {
-                        log.error("Invoke of the Schedulable MBean failed", jme);
-                     }
-                     log.debug("Remaining Repititions: " + mSchedule.mRemainingRepetitions +
-                             ", wait for next call to stop: " + mWaitForNextCallToStop);
-                     if (mSchedule.mRemainingRepetitions == 0 || mWaitForNextCallToStop)
-                     {
-                        mSchedule.stop();
-                     }
-                  }
-               }
-            }
-            else
-            {
-               mSchedule.stop();
-            }
-         }
-         catch (Exception e)
-         {
-            log.error("Handling a Scheduler call failed", e);
-         }
+		 boolean trace = log.isTraceEnabled();
+		 if (trace) {
+			log.trace("MBeanListener.handleNotification: " + pNotification);
+		 }
+
+		 try
+		 {
+			if (!isStarted()) {
+			   log.trace("Scheduler not started");
+			   mSchedule.stop();
+			   return;
+			}
+			if (mSchedule.mRemainingRepetitions == 0)
+			{
+			   log.trace("No more repetitions");
+			   mSchedule.stop();
+			   return;
+			}
+			if (mIsPaused.get())
+			{
+			   log.trace("Paused");
+			   return;
+			}
+			if (mSchedule.mRemainingRepetitions > 0)
+			{
+			   mSchedule.mRemainingRepetitions--;
+			   if (trace)
+				  log.trace("Remaining repetitions: " + mSchedule.mRemainingRepetitions);
+			}
+			Object[] lArguments = getArguments(pNotification);
+			if (trace)
+			{
+			   log.trace("invoke " + mSchedule);
+			   log.trace("arguments are: " + Arrays.asList(lArguments));
+			}
+			
+			ObjectName on = mSchedule.mTarget;
+			String mn = mSchedule.mMethodName;
+			getServer().invoke(on, mn, lArguments,
+					mSchedule.mSchedulableMBeanArgumentTypes
+			);
+		 }
+		 catch (Exception e)
+		 {
+			log.error("Invoke failed: " + mSchedule.getTargetString(), e);
+		 }
       }
+
+	  private Object[] getArguments(Notification pNotification)
+	  {
+		 Object[] lArguments = new Object[mSchedule.mSchedulableMBeanArguments.length];
+		 Date lTimeStamp = new Date(pNotification.getTimeStamp());
+		 for (int i = 0; i < lArguments.length; i++)
+		 {
+			switch (mSchedule.mSchedulableMBeanArguments[i])
+			{
+			   case ID:
+				  lArguments[i] = pNotification.getUserData();
+				  break;
+			   case NOTIFICATION:
+				  lArguments[i] = pNotification;
+				  break;
+			   case DATE:
+				  lArguments[i] = lTimeStamp;
+				  break;
+			   case REPETITIONS:
+				  lArguments[i] = new Long(mSchedule.mRemainingRepetitions);
+				  break;
+			   case SCHEDULER_NAME:
+				  lArguments[i] = getServiceName();
+				  break;
+			   case NEXT_DATE:
+				  lArguments[i] = new Date(lTimeStamp.getTime() + mSchedule.mPeriod);
+				  break;
+			   default:
+				  lArguments[i] = null;
+			}
+		 }
+		 return lArguments;
+	  }
+
    }
 
    /**
     * Filter to ensure that each Scheduler only gets notified when it is supposed to.
     */
-   private static class NotificationFilter implements javax.management.NotificationFilter
+   static class IdNotificationFilter implements javax.management.NotificationFilter
    {
+      private static final Logger log = Logger.getLogger(IdNotificationFilter.class);
 
-      private Integer mId;
+      private Integer filterId;
 
       /**
        * Create a Filter.
        * @param pId the Scheduler id
        */
-      public NotificationFilter(Integer pId)
+      public IdNotificationFilter(int filterId)
       {
-         mId = pId;
+         this.filterId = new Integer(filterId);
       }
 
       /**
@@ -664,12 +676,17 @@
        */
       public boolean isNotificationEnabled(Notification pNotification)
       {
-         if (pNotification instanceof TimerNotification)
-         {
-            TimerNotification lTimerNotification = (TimerNotification) pNotification;
-            return lTimerNotification.getNotificationID().equals(mId);
-         }
-         return false;
+         if (!(pNotification instanceof TimerNotification))
+			return false;
+		 TimerNotification lTimerNotification = (TimerNotification) pNotification;
+		 if (log.isTraceEnabled())
+			log.trace("isNotificationEnabled(), filterId=" + filterId +
+			   ", notification=" + pNotification +
+			   ", notificationId=" + lTimerNotification.getNotificationID() +
+			   ", timestamp=" + lTimerNotification.getTimeStamp() +
+			   ", message=" + lTimerNotification.getMessage()
+			);
+		 return lTimerNotification.getNotificationID().equals(filterId);
       }
    }
 
@@ -753,7 +770,7 @@
                mSchedulableMBeanArgumentTypes[i] = lToken;
             }
          }
-         mIdentification = (sCounter++);
+         mIdentification = sCounter.increment();
       }
 
       /**
@@ -805,36 +822,20 @@
             lStartDate = mStartDate;
             mRemainingRepetitions = mInitialRepetitions;
          }
-         mNotificationID = ((Integer) getServer().invoke(
-                 mTimer,
-                 "addNotification",
-                 new Object[]{
-                    "Schedule",
-                    "Scheduler Notification",
-                    new Integer(getID()), // User Object
-                    lStartDate,
-                    new Long(mPeriod),
-                    mRemainingRepetitions < 0 ? new Long(0) : new Long(mRemainingRepetitions),
-                    new Boolean(mFixedRate)
-                 },
-                 new String[]{
-                    String.class.getName(),
-                    String.class.getName(),
-                    Object.class.getName(),
-                    Date.class.getName(),
-                    Long.TYPE.getName(),
-                    Long.TYPE.getName(),
-                    Boolean.TYPE.getName()
-                 }
-         )).intValue();
-         // Register the notification listener at the MBeanServer
+         mNotificationID = mTimer.addNotification(
+			   "Schedule", "Scheduler Notification",
+			   new Integer(getID()), // User Object
+			   lStartDate,
+			   new Long(mPeriod),
+			   mRemainingRepetitions < 0 ? new Long(0) : new Long(mRemainingRepetitions),
+			   Boolean.valueOf(mFixedRate)
+		 );
          mListener = new MBeanListener(this);
-         getServer().addNotificationListener(
-                 mTimer,
-                 mListener,
-                 new NotificationFilter(new Integer(mNotificationID)),
-                 // No object handback necessary
-                 null
+		 mTimerEmitter.addNotificationListener(
+			   mListener,
+               new IdNotificationFilter(mNotificationID),
+               // No object handback necessary
+               null
          );
          log.debug("start(), add Notification to Timer with ID: " + mNotificationID);
       }
@@ -847,38 +848,31 @@
               throws JMException
       {
          log.debug("stopSchedule(), notification id: " + mNotificationID);
-         getServer().removeNotificationListener(
-                 mTimer,
-                 mListener
-         );
-         try
-         {
-            getServer().invoke(
-                    mTimer,
-                    "removeNotification",
-                    new Object[]{
-                       new Integer(mNotificationID)
-                    },
-                    new String[]{
-                       Integer.class.getName()
-                    }
-            );
-         }
-         catch (MBeanException mbe)
-         {
-            Exception e = mbe.getTargetException();
-            // If target exception is InstanceNotFoundException then
-            // the notification is already removed so ignore it
-            if (!(e instanceof InstanceNotFoundException))
-            {
-               throw mbe;
-            }
-         }
+		 mTimerEmitter.removeNotificationListener(mListener);
+		 try
+		 {
+			mTimer.removeNotification(mNotificationID);
+		 }
+		 catch (InstanceNotFoundException e)
+		 {
+		     log.trace(e);
+		 }
       }
 
       public int getID()
       {
          return mIdentification;
       }
+
+	  public String toString()
+	  {
+		 return "Schedule target=" + getTargetString();
+	  }
+
+	  public String getTargetString()
+	  {
+		 return mTarget + " " + mMethodName + "" + Arrays.asList(mSchedulableMBeanArgumentTypes);
+	  }
+
    }
 }

Modified: trunk/varia/src/main/org/jboss/varia/scheduler/Scheduler.java
===================================================================
--- trunk/varia/src/main/org/jboss/varia/scheduler/Scheduler.java	2006-11-06 19:24:43 UTC (rev 58157)
+++ trunk/varia/src/main/org/jboss/varia/scheduler/Scheduler.java	2006-11-06 19:25:06 UTC (rev 58158)
@@ -27,11 +27,17 @@
 import java.util.Date;
 import java.util.StringTokenizer;
 import java.util.Vector;
+import java.util.Arrays;
 
+import javax.management.InstanceNotFoundException;
 import javax.management.MalformedObjectNameException;
 import javax.management.Notification;
+import javax.management.NotificationEmitter;
 import javax.management.NotificationListener;
 import javax.management.ObjectName;
+import javax.management.MBeanServerInvocationHandler;
+import javax.management.timer.Timer;
+import javax.management.timer.TimerMBean;
 import javax.management.timer.TimerNotification;
 
 import org.jboss.logging.Logger;
@@ -39,14 +45,21 @@
 import org.jboss.util.Classes;
 
 /**
- * Scheduler Instance to allow clients to run this as a scheduling service for
- * any Schedulable instances.
- * <br>
- * ATTENTION: The scheduler instance only allows to run one schedule at a time.
- * Therefore when you want to run two schedules create to instances with this
- * MBean. Suggested Object Name for the MBean are:<br>
- * :service=Scheduler,schedule=<you schedule name><br>
+ * Schedules a timer task that calls an MBean or Object instance.
+ * Any MBean operation can be called.  Object instances must implement the
+ * {@link Schedulable} interface.
+ * <p />
+ * Create a separate Scheduler MBean for every MBean or Object you wish to call.
+ * One example naming strategy for calling an MBean named:
+ <code>example:type=HelloWorld</code>
+ * is to create a similarly named:
+ <code>example:type=Scheduler,call=HelloWorld</code> MBean.
  * This way you should not run into a name conflict.
+ * <p>
+ * This MBean registers a notification listener with an
+ * javax.management.timer.Timer MBean. If the Timer does not exist, this MBean
+ * will create it.  Each Timer can handle multiple Scheduler instances.
+ * </p>
  *
  * @author <a href="mailto:andreas at jboss.org">Andreas Schaefer</a>
  * @author Cameron (camtabor)
@@ -62,8 +75,7 @@
 
    public static String JNDI_NAME = "scheduler:domain";
    public static String JMX_NAME = "scheduler";
-   /** Default Timer Object Name **/
-   public static String DEFAULT_TIMER_NAME = "jboss:service=Timer";
+   public static String DEFAULT_TIMER_NAME = ScheduleManager.DEFAULT_TIMER_NAME;
 
    private static final int NOTIFICATION = 0;
    private static final int DATE = 1;
@@ -77,9 +89,11 @@
 
    private long mActualSchedulePeriod;
    private long mRemainingRepetitions = 0;
-   private int mActualSchedule = -1;
+   private int mNotificationID = -1;
    private String mTimerName = DEFAULT_TIMER_NAME;
-   private ObjectName mTimer;
+   private ObjectName mTimerObjectName;
+   private TimerMBean mTimer;
+   private NotificationEmitter mTimerEmitter;
    private Schedulable mSchedulable;
 
    private boolean mScheduleIsStarted = false;
@@ -110,22 +124,35 @@
    private long mInitialRepetitions;
    private boolean mFixedRate = false;
    
-   private NotificationListener listener;
+   private NotificationListener mListener;
 
    // -------------------------------------------------------------------------
    // Constructors
    // -------------------------------------------------------------------------
 
    /**
-    * Default (no-args) Constructor
+    * Constructs a new Scheduler instance.
     **/
    public Scheduler()
    {
    }
 
    /**
-    * 
+    * Constructs a new Scheduler instance.
     * @param pSchedulableClass
+    * @param pSchedulePeriod
+    */ 
+   public Scheduler(String pSchedulableClass,
+      long pSchedulePeriod)
+   {
+      setStartAtStartup(true);
+      setSchedulableClass(pSchedulableClass);
+      setSchedulePeriod(pSchedulePeriod);
+   }
+
+   /**
+    * Constructs a new Scheduler instance.
+    * @param pSchedulableClass
     * @param pInitArguments
     * @param pInitTypes
     * @param pInitialStartDate
@@ -150,7 +177,7 @@
    }
 
    /**
-    * 
+    * Constructs a new Scheduler instance.
     * @param pSchedulableClass
     * @param pInitArguments
     * @param pInitTypes
@@ -182,7 +209,145 @@
    // -------------------------------------------------------------------------
    // SchedulerMBean Methods
    // -------------------------------------------------------------------------
+   //
 
+   private void checkMBean() {
+	  if (mSchedulableMBean == null)
+	  {
+		 log.debug("Schedulable MBean Object Name is not set");
+		 throw new InvalidParameterException(
+			"Schedulable MBean must be set"
+		 );
+	  }
+	  if (mSchedulableMBeanMethodName == null)
+	  {
+		 mSchedulableMBeanMethodName = "perform";
+		 mSchedulableMBeanArguments = new int[]{DATE, REPETITIONS};
+		 mSchedulableMBeanArgumentTypes = new String[]{
+			Date.class.getName(),
+			Integer.TYPE.getName()
+		 };
+	  }
+   }
+
+   private void createSchedulable() {
+	  if (mSchedulableClass == null)
+	  {
+		 throw new InvalidParameterException("Schedulable Class not set");
+	  }
+	  if (mSchedulableArgumentList.length != mSchedulableArgumentTypeList.length)
+	  {
+		 throw new InvalidParameterException(
+			"Schedulable Class Arguments and Types do not match in length"
+		 );
+	  }
+	  // Create all the Objects for the Constructor to be called
+	  Object[] lArgumentList = new Object[mSchedulableArgumentTypeList.length];
+	  try
+	  {
+		 for (int i = 0; i < mSchedulableArgumentTypeList.length; i++)
+		 {
+			Class lClass = mSchedulableArgumentTypeList[i];
+			if (lClass == Boolean.TYPE)
+			{
+			   lArgumentList[i] = new Boolean(mSchedulableArgumentList[i]);
+			}
+			else if (lClass == Integer.TYPE)
+			{
+			   lArgumentList[i] = new Integer(mSchedulableArgumentList[i]);
+			}
+			else if (lClass == Long.TYPE)
+			{
+			   lArgumentList[i] = new Long(mSchedulableArgumentList[i]);
+			}
+			else if (lClass == Short.TYPE)
+			{
+			   lArgumentList[i] = new Short(mSchedulableArgumentList[i]);
+			}
+			else if (lClass == Float.TYPE)
+			{
+			   lArgumentList[i] = new Float(mSchedulableArgumentList[i]);
+			}
+			else if (lClass == Double.TYPE)
+			{
+			   lArgumentList[i] = new Double(mSchedulableArgumentList[i]);
+			}
+			else if (lClass == Byte.TYPE)
+			{
+			   lArgumentList[i] = new Byte(mSchedulableArgumentList[i]);
+			}
+			else if (lClass == Character.TYPE)
+			{
+			   lArgumentList[i] = new Character(mSchedulableArgumentList[i].charAt(0));
+			}
+			else
+			{
+			   Constructor lConstructor = lClass.getConstructor(new Class[]{String.class});
+			   lArgumentList[i] = lConstructor.newInstance(new Object[]{mSchedulableArgumentList[i]});
+			}
+		 }
+	  }
+	  catch (Exception e)
+	  {
+		 log.error("Could not load or create constructor argument", e);
+		 throw new InvalidParameterException("Could not load or create a constructor argument");
+	  }
+	  try
+	  {
+		 // Check if constructor is found
+		 Constructor lSchedulableConstructor = mSchedulableClass.getConstructor(mSchedulableArgumentTypeList);
+		 // Create an instance of it
+		 mSchedulable = (Schedulable) lSchedulableConstructor.newInstance(lArgumentList);
+	  }
+	  catch (Exception e)
+	  {
+		 log.error("Could not find the constructor or create Schedulable instance", e);
+		 throw new InvalidParameterException("Could not find the constructor or create the Schedulable Instance");
+	  }
+   }
+
+   private Date getNow() {
+	  long now = System.currentTimeMillis();
+	  return new Date(now + 1000);
+   }
+
+   private void initStartDate() {
+	  // Register the Schedule at the Timer
+	  // If start date is NOW then take the current date
+	  if (mStartDateIsNow)
+	  {
+		 mStartDate = getNow();
+	  }
+	  else
+	  {
+		 // Check if initial start date is in the past
+		 if (mStartDate.before(new Date()))
+		 {
+			// If then first check if a repetition is in the future
+			long lNow = new Date().getTime() + 100;
+			long lSkipRepeats = ((lNow - mStartDate.getTime()) / mActualSchedulePeriod) + 1;
+			log.debug("Old start date: " + mStartDate + ", now: " + new Date(lNow) + ", Skip repeats: " + lSkipRepeats);
+			if (mRemainingRepetitions > 0)
+			{
+			   // If not infinit loop
+			   if (lSkipRepeats >= mRemainingRepetitions)
+			   {
+				  // No repetition left -> exit
+				  log.info("No repetitions left because start date is in the past and could " +
+					 "not be reached by Initial Repetitions * Schedule Period");
+				  return;
+			   }
+			   else
+			   {
+				  // Reduce the missed hits
+				  mRemainingRepetitions -= lSkipRepeats;
+			   }
+			}
+			mStartDate = new Date(mStartDate.getTime() + (lSkipRepeats * mActualSchedulePeriod));
+		 }
+	  }
+   }
+
    /**
     * Starts the schedule if the schedule is stopped otherwise nothing will happen.
     * The Schedule is immediately set to started even the first call is in the
@@ -196,215 +361,54 @@
     */
    public void startSchedule()
    {
-      // Check if not already started
-      if (!isStarted())
+      if (isStarted())
       {
-         try
-         {
-            // Check the given attributes if correct
-            if (mUseMBean)
-            {
-               if (mSchedulableMBean == null)
-               {
-                  log.debug("Schedulable MBean Object Name is not set");
-                  throw new InvalidParameterException(
-                     "Schedulable MBean must be set"
-                  );
-               }
-               if (mSchedulableMBeanMethodName == null)
-               {
-                  mSchedulableMBeanMethodName = "perform";
-                  mSchedulableMBeanArguments = new int[]{DATE, REPETITIONS};
-                  mSchedulableMBeanArgumentTypes = new String[]{
-                     Date.class.getName(),
-                     Integer.TYPE.getName()
-                  };
-               }
-            }
-            else
-            {
-               if (mSchedulableClass == null)
-               {
-                  log.debug("Schedulable Class is not set");
-                  throw new InvalidParameterException(
-                     "Schedulable Class must be set"
-                  );
-               }
-               if (mSchedulableArgumentList.length != mSchedulableArgumentTypeList.length)
-               {
-                  log.debug("Schedulable Class Arguments and Types do not match in length");
-                  throw new InvalidParameterException(
-                     "Schedulable Class Arguments and Types do not match in length"
-                  );
-               }
-            }
-            if (mSchedulePeriod <= 0)
-            {
-               log.debug("Schedule Period is less than 0 (ms)");
-               throw new InvalidParameterException(
-                  "Schedule Period must be set and greater than 0 (ms)"
-               );
-            }
-            if (!mUseMBean)
-            {
-               // Create all the Objects for the Constructor to be called
-               Object[] lArgumentList = new Object[mSchedulableArgumentTypeList.length];
-               try
-               {
-                  for (int i = 0; i < mSchedulableArgumentTypeList.length; i++)
-                  {
-                     Class lClass = mSchedulableArgumentTypeList[i];
-                     if (lClass == Boolean.TYPE)
-                     {
-                        lArgumentList[i] = new Boolean(mSchedulableArgumentList[i]);
-                     }
-                     else if (lClass == Integer.TYPE)
-                     {
-                        lArgumentList[i] = new Integer(mSchedulableArgumentList[i]);
-                     }
-                     else if (lClass == Long.TYPE)
-                     {
-                        lArgumentList[i] = new Long(mSchedulableArgumentList[i]);
-                     }
-                     else if (lClass == Short.TYPE)
-                     {
-                        lArgumentList[i] = new Short(mSchedulableArgumentList[i]);
-                     }
-                     else if (lClass == Float.TYPE)
-                     {
-                        lArgumentList[i] = new Float(mSchedulableArgumentList[i]);
-                     }
-                     else if (lClass == Double.TYPE)
-                     {
-                        lArgumentList[i] = new Double(mSchedulableArgumentList[i]);
-                     }
-                     else if (lClass == Byte.TYPE)
-                     {
-                        lArgumentList[i] = new Byte(mSchedulableArgumentList[i]);
-                     }
-                     else if (lClass == Character.TYPE)
-                     {
-                        lArgumentList[i] = new Character(mSchedulableArgumentList[i].charAt(0));
-                     }
-                     else
-                     {
-                        Constructor lConstructor = lClass.getConstructor(new Class[]{String.class});
-                        lArgumentList[i] = lConstructor.newInstance(new Object[]{mSchedulableArgumentList[i]});
-                     }
-                  }
-               }
-               catch (Exception e)
-               {
-                  log.error("Could not load or create constructor argument", e);
-                  throw new InvalidParameterException("Could not load or create a constructor argument");
-               }
-               try
-               {
-                  // Check if constructor is found
-                  Constructor lSchedulableConstructor = mSchedulableClass.getConstructor(mSchedulableArgumentTypeList);
-                  // Create an instance of it
-                  mSchedulable = (Schedulable) lSchedulableConstructor.newInstance(lArgumentList);
-               }
-               catch (Exception e)
-               {
-                  log.error("Could not find the constructor or create Schedulable instance", e);
-                  throw new InvalidParameterException("Could not find the constructor or create the Schedulable Instance");
-               }
-            }
+		 log.debug("already started");
+		 return;
+	  }
 
-            mRemainingRepetitions = mInitialRepetitions;
-            mActualSchedulePeriod = mSchedulePeriod;
-            Date lStartDate = null;
-            // Register the Schedule at the Timer
-            // If start date is NOW then take the current date
-            if (mStartDateIsNow)
-            {
-               mStartDate = new Date(new Date().getTime() + 1000);
-               lStartDate = mStartDate;
-            }
-            else
-            {
-               // Check if initial start date is in the past
-               if (mStartDate.getTime() < new Date().getTime())
-               {
-                  // If then first check if a repetition is in the future
-                  long lNow = new Date().getTime() + 100;
-                  long lSkipRepeats = ((lNow - mStartDate.getTime()) / mActualSchedulePeriod) + 1;
-                  log.debug("Old start date: " + mStartDate + ", now: " + new Date(lNow) + ", Skip repeats: " + lSkipRepeats);
-                  if (mRemainingRepetitions > 0)
-                  {
-                     // If not infinit loop
-                     if (lSkipRepeats >= mRemainingRepetitions)
-                     {
-                        // No repetition left -> exit
-                        log.info("No repetitions left because start date is in the past and could " +
-                           "not be reached by Initial Repetitions * Schedule Period");
-                        return;
-                     }
-                     else
-                     {
-                        // Reduce the missed hits
-                        mRemainingRepetitions -= lSkipRepeats;
-                     }
-                  }
-                  lStartDate = new Date(mStartDate.getTime() + (lSkipRepeats * mActualSchedulePeriod));
-               }
-               else
-               {
-                  lStartDate = mStartDate;
-               }
-            }
-            log.debug("Schedule initial call to: " + lStartDate + ", remaining repetitions: " + mRemainingRepetitions);
-            // Add an initial call
-            mActualSchedule = ((Integer) getServer().invoke(
-               mTimer,
-               "addNotification",
-               new Object[]{
-                  "Schedule",
-                  "Scheduler Notification",
-                  null, // User Object
-                  lStartDate,
-                  new Long(mActualSchedulePeriod),
-                  mRemainingRepetitions < 0 ? new Long(0) : new Long(mRemainingRepetitions),
-                  new Boolean(mFixedRate)
-               },
-               new String[]{
-                  String.class.getName(),
-                  String.class.getName(),
-                  Object.class.getName(),
-                  Date.class.getName(),
-                  Long.TYPE.getName(),
-                  Long.TYPE.getName(),
-                  Boolean.TYPE.getName()
-               }
-            )).intValue();
-            if (mUseMBean)
-            {
-               listener = new MBeanListener(mSchedulableMBean);
-            }
-            else
-            {
-               listener = new Listener(mSchedulable);
-            }
-            // Register the notification listener at the MBeanServer
-            getServer().addNotificationListener(
-               mTimer,
-               listener,
-               new Scheduler.NotificationFilter(new Integer(mActualSchedule)),
-               // No object handback necessary
-               null
-            );
-            mScheduleIsStarted = true;
-            mIsRestartPending = false;
-         }
-         catch (Exception e)
-         {
-            log.error("operation failed", e);
-         }
-      }
+	  if (mUseMBean)
+	  {
+		 checkMBean();
+	  }
+	  else
+	  {
+		 createSchedulable();
+	  }
+
+	  mRemainingRepetitions = mInitialRepetitions;
+	  mActualSchedulePeriod = mSchedulePeriod;
+	  initStartDate();
+
+	  log.debug("Schedule initial call to: " + mStartDate + ", remaining repetitions: " + mRemainingRepetitions);
+	  mNotificationID = mTimer.addNotification(
+			"Schedule", "Scheduler Notification",
+			null, // new Integer(getID()), // User Object
+			mStartDate,
+			new Long(mActualSchedulePeriod),
+			mRemainingRepetitions < 0 ? new Long(0) : new Long(mRemainingRepetitions),
+			Boolean.valueOf(mFixedRate)
+	  );
+	  mListener = mUseMBean ? new MBeanListener() : new PojoScheduler();
+	  mTimerEmitter.addNotificationListener(
+			mListener,
+			new ScheduleManager.IdNotificationFilter(mNotificationID),
+			null
+	  );
+	  mScheduleIsStarted = true;
+	  mIsRestartPending = false;
    }
 
    /**
+    * Stops the schedule immediately.
+    * @jmx:managed-operation
+    */
+   public void stopSchedule()
+   {
+	  stopSchedule(true);
+   }
+
+   /**
     * Stops the schedule because it is either not used anymore or to restart it with
     * new values.
     *
@@ -416,9 +420,10 @@
     */
    public void stopSchedule(boolean pDoItNow)
    {
+	  log.debug("stopSchedule(" + pDoItNow + ")");
       try
       {
-         if (mActualSchedule < 0)
+         if (mNotificationID < 0)
          {
             mScheduleIsStarted = false;
             mWaitForNextCallToStop = false;
@@ -426,29 +431,22 @@
          }
          if (pDoItNow)
          {
+            log.debug("stopSchedule(), removing schedule id: " + mNotificationID);
             mWaitForNextCallToStop = false;
-            // Remove notification listener now
-            if (listener != null)
+            if (mListener != null)
             {
-               getServer().removeNotificationListener(
-                  mTimer,
-                  listener
-               );
-               listener = null;
+			   mTimerEmitter.removeNotificationListener(mListener);
+			   try
+			   {
+				  mTimer.removeNotification(mNotificationID);
+			   }
+			   catch (InstanceNotFoundException e)
+			   {
+			      log.trace(e);
+			   }
+               mListener = null;
             }
-            log.debug("stopSchedule(), schedule id: " + mActualSchedule);
-            getServer().invoke(
-               mTimer,
-               "removeNotification",
-               new Object[]{
-                  new Integer(mActualSchedule)
-               },
-               new String[]{
-                  Integer.class.getName()
-               }
-            );
-            log.debug("stopSchedule(), removed schedule id: " + mActualSchedule);
-            mActualSchedule = -1;
+			mNotificationID = -1;
             mScheduleIsStarted = false;
          }
          else
@@ -458,7 +456,7 @@
       }
       catch (Exception e)
       {
-         log.error("operation failed", e);
+         log.error("stopSchedule failed", e);
       }
    }
 
@@ -469,7 +467,7 @@
     */
    public void restartSchedule()
    {
-      stopSchedule(true);
+      stopSchedule();
       startSchedule();
    }
 
@@ -687,7 +685,7 @@
    /**
     * @jmx:managed-attribute
     *
-    * @return Object Name if a Schedulalbe MBean is set
+    * @return Object Name if a Schedulable MBean is set
     */
    public String getSchedulableMBean()
    {
@@ -725,10 +723,9 @@
          mSchedulableMBean = new ObjectName(pSchedulableMBean);
          mUseMBean = true;
       }
-      catch (MalformedObjectNameException mone)
+      catch (MalformedObjectNameException e)
       {
-         log.error("Schedulable MBean Object Name is malformed", mone);
-         throw new InvalidParameterException("Schedulable MBean is not correctly formatted");
+         throw new InvalidParameterException("Schedulable MBean name invalid " + pSchedulableMBean);
       }
    }
 
@@ -780,14 +777,14 @@
          return;
       }
       int lIndex = pSchedulableMBeanMethod.indexOf('(');
-      String lMethodName = "";
-      if (lIndex < 0)
+	  String lMethodName;
+      if (lIndex == -1)
       {
          lMethodName = pSchedulableMBeanMethod.trim();
          mSchedulableMBeanArguments = new int[0];
          mSchedulableMBeanArgumentTypes = new String[0];
       }
-      else if (lIndex > 0)
+      else
       {
          lMethodName = pSchedulableMBeanMethod.substring(0, lIndex).trim();
       }
@@ -818,7 +815,7 @@
          }
          else
          {
-            StringTokenizer lTokenizer = new StringTokenizer(lArguments, ",");
+            StringTokenizer lTokenizer = new StringTokenizer(lArguments, ", ");
             mSchedulableMBeanArguments = new int[lTokenizer.countTokens()];
             mSchedulableMBeanArgumentTypes = new String[lTokenizer.countTokens()];
             for (int i = 0; lTokenizer.hasMoreTokens(); i++)
@@ -974,7 +971,7 @@
       }
       else if (mStartDateString.equals("NOW"))
       {
-         mStartDate = new Date(new Date().getTime() + 1000);
+         mStartDate = getNow();
          mStartDateIsNow = true;
       }
       else
@@ -985,7 +982,7 @@
             mStartDate = new Date(lDate);
             mStartDateIsNow = false;
          }
-         catch (Exception e)
+         catch (NumberFormatException e)
          {
             try
             {
@@ -999,7 +996,7 @@
             catch (Exception e2)
             {
                log.error("Could not parse given date string: " + mStartDateString, e2);
-               throw new InvalidParameterException("Schedulable Date is not of correct format");
+               throw new InvalidParameterException("Schedulable Date is not of correct format: " + mStartDateString);
             }
          }
       }
@@ -1022,7 +1019,7 @@
     * @jmx:managed-attribute
     *
     * @param pNumberOfCalls Initial Number of scheduled calls. If -1 then the number
-    *                       is unlimted.
+    *                       is infinite
     *
     * @throws InvalidParameterException If the given value is less or equal than 0
     */
@@ -1155,32 +1152,18 @@
    protected void startService()
       throws Exception
    {
-      // Create Timer MBean if need be
-
-      try
+	  mTimerObjectName = new ObjectName(mTimerName);
+      if (!getServer().isRegistered(mTimerObjectName))
       {
-         mTimer = new ObjectName(mTimerName);
+         getServer().createMBean(Timer.class.getName(), mTimerObjectName);
       }
-      catch (MalformedObjectNameException mone)
+	  mTimer = (TimerMBean)MBeanServerInvocationHandler.newProxyInstance(getServer(),
+			mTimerObjectName, TimerMBean.class, true);
+	  mTimerEmitter = (NotificationEmitter)mTimer;
+      if (!mTimer.isActive())
       {
-         mTimer = new ObjectName(DEFAULT_TIMER_NAME);
+		 mTimer.start();
       }
-
-      if (!getServer().isRegistered(mTimer))
-      {
-         getServer().createMBean("javax.management.timer.Timer", mTimer);
-      }
-      if (!((Boolean) getServer().getAttribute(mTimer, "Active")).booleanValue())
-      {
-         // Now start the Timer
-         getServer().invoke(
-            mTimer,
-            "start",
-            new Object[]{},
-            new String[]{}
-         );
-      }
-
       if (mStartOnStart)
       {
          log.debug("Start Scheduler on start up time");
@@ -1190,8 +1173,7 @@
 
    protected void stopService()
    {
-      // Stop the schedule right now !!
-      stopSchedule(true);
+      stopSchedule();
    }
 
    private static boolean isSchedulable(Class c)
@@ -1214,71 +1196,79 @@
       return lFound;
    }
 
+   /**
+	* Base class for listeners.
+	*/
+   public abstract class BaseListener
+      implements NotificationListener
+   {
+      final Logger log = Logger.getLogger(BaseListener.class);
+
+      public void handleNotification(
+         Notification notification,
+         Object handback
+         )
+      {
+		 boolean trace = log.isTraceEnabled();
+		 if (trace)
+		 {
+			log.trace("handleNotification: " + notification);
+		 }
+		 if (!isStarted())
+		 {
+			log.trace("Scheduler not started");
+			stopSchedule();
+			return;
+		 }
+		 if (mRemainingRepetitions == 0)
+		 {
+			log.trace("No more repetitions");
+			stopSchedule();
+			return;
+		 }
+		 if (mRemainingRepetitions > 0)
+		 {
+			mRemainingRepetitions--;
+			if (trace)
+			   log.trace("Remaining repetitions: " + mRemainingRepetitions);
+		 }
+		 invoke(notification);
+		 if (mWaitForNextCallToStop)
+		 {
+			stopSchedule();
+		 }
+      }
+
+	  /**
+	   * Invokes the scheduler method.
+	   */
+	  protected abstract void invoke(Notification notification);
+
+   }
+
    // -------------------------------------------------------------------------
    // Inner Classes
    // -------------------------------------------------------------------------
 
-   public class Listener
-      implements NotificationListener
+   /**
+	* Calls {@link Schedulable#perform} on a plain Java Object.
+	*/
+   public class PojoScheduler extends BaseListener
    {
-      private final Logger log = Logger.getLogger(Listener.class);
-      private Schedulable mDelegate;
 
-      public Listener(Schedulable pDelegate)
+	  protected void invoke(Notification notification)
       {
-         mDelegate = pDelegate;
-      }
-
-      public void handleNotification(Notification notification,Object handback)
-      {
-         log.debug("Listener.handleNotification(), notification: " + notification);
          ClassLoader currentTCL = TCLActions.getContextClassLoader();
          try
          {
-            ClassLoader loader = TCLActions.getClassLoader(mDelegate.getClass());
+            ClassLoader loader = TCLActions.getClassLoader(mSchedulable.getClass());
             TCLActions.setContextClassLoader(loader);
-            // If schedule is started invoke the schedule method on the Schedulable instance
-            log.debug("Scheduler is started: " + isStarted());
             Date lTimeStamp = new Date(notification.getTimeStamp());
-            if (isStarted())
-            {
-               if (getRemainingRepetitions() > 0 || getRemainingRepetitions() < 0)
-               {
-                  if (mRemainingRepetitions > 0)
-                  {
-                     mRemainingRepetitions--;
-                  }
-                  mDelegate.perform(
-                     lTimeStamp,
-                     getRemainingRepetitions()
-                  );
-                  log.debug("Remaining Repititions: " + getRemainingRepetitions() +
-                     ", wait for next call to stop: " + mWaitForNextCallToStop);
-                  if (getRemainingRepetitions() == 0 || mWaitForNextCallToStop)
-                  {
-                     stopSchedule(true);
-                  }
-               }
-            }
-            else
-            {
-               // Schedule is stopped therefore remove the Schedule
-               getServer().invoke(
-                  mTimer,
-                  "removeNotification",
-                  new Object[]{
-                     new Integer(mActualSchedule)
-                  },
-                  new String[]{
-                     Integer.class.getName()
-                  }
-               );
-               mActualSchedule = -1;
-            }
+			mSchedulable.perform(lTimeStamp, getRemainingRepetitions());
          }
          catch (Exception e)
          {
-            log.error("Handling a Scheduler call failed", e);
+            log.error("Scheduler.perform call failed", e);
          }
          finally
          {
@@ -1287,182 +1277,54 @@
       }
    }
 
-   public class MBeanListener
-      implements NotificationListener
-   {
-      private final Logger log = Logger.getLogger(Listener.class);
-
-      private ObjectName mDelegate;
-
-      public MBeanListener(ObjectName pDelegate)
-      {
-         mDelegate = pDelegate;
-      }
-
-      public void handleNotification(
-         Notification notification,
-         Object handback
-         )
-      {
-         log.debug("MBeanListener.handleNotification(), notification: " + notification);
-         try
-         {
-            // If schedule is started invoke the schedule method on the Schedulable instance
-            log.debug("Scheduler is started: " + isStarted());
-            Date lTimeStamp = new Date(notification.getTimeStamp());
-            if (isStarted())
-            {
-               if (getRemainingRepetitions() > 0 || getRemainingRepetitions() < 0)
-               {
-                  if (mRemainingRepetitions > 0)
-                  {
-                     mRemainingRepetitions--;
-                  }
-                  Object[] lArguments = new Object[mSchedulableMBeanArguments.length];
-                  for (int i = 0; i < lArguments.length; i++)
-                  {
-                     switch (mSchedulableMBeanArguments[i])
-                     {
-                        case NOTIFICATION:
-                           lArguments[i] = notification;
-                           break;
-                        case DATE:
-                           lArguments[i] = lTimeStamp;
-                           break;
-                        case REPETITIONS:
-                           lArguments[i] = new Long(mRemainingRepetitions);
-                           break;
-                        case SCHEDULER_NAME:
-                           lArguments[i] = getServiceName();
-                           break;
-                        default:
-                           lArguments[i] = null;
-                     }
-                  }
-                  log.debug("MBean Arguments are: " + java.util.Arrays.asList(lArguments));
-                  log.debug("MBean Arguments Types are: " + java.util.Arrays.asList(mSchedulableMBeanArgumentTypes));
-                  try
-                  {
-                     getServer().invoke(
-                        mDelegate,
-                        mSchedulableMBeanMethodName,
-                        lArguments,
-                        mSchedulableMBeanArgumentTypes
-                     );
-                  }
-                  catch (javax.management.JMRuntimeException jmre)
-                  {
-                     log.error("Invoke of the Schedulable MBean failed", jmre);
-                  }
-                  catch (javax.management.JMException jme)
-                  {
-                     log.error("Invoke of the Schedulable MBean failed", jme);
-                  }
-                  log.debug("Remaining Repititions: " + getRemainingRepetitions() +
-                     ", wait for next call to stop: " + mWaitForNextCallToStop);
-                  if (getRemainingRepetitions() == 0 || mWaitForNextCallToStop)
-                  {
-                     stopSchedule(true);
-                  }
-               }
-            }
-            else
-            {
-               // Schedule is stopped therefore remove the Schedule
-               getServer().invoke(
-                  mTimer,
-                  "removeNotification",
-                  new Object[]{
-                     new Integer(mActualSchedule)
-                  },
-                  new String[]{
-                     Integer.class.getName()
-                  }
-               );
-               mActualSchedule = -1;
-            }
-         }
-         catch (Exception e)
-         {
-            log.error("Handling a Scheduler call failed", e);
-         }
-      }
-   }
-
    /**
-    * Filter to ensure that each Scheduler only gets notified when it is supposed to.
-    */
-   private static class NotificationFilter implements javax.management.NotificationFilter
+	* Invokes an operation on an MBean.
+	*/
+   public class MBeanListener extends BaseListener
    {
-
-      /** Class logger. */
-      private static final Logger log = Logger.getLogger(NotificationFilter.class);
-
-      private Integer mId;
-
-      /**
-       * Create a Filter.
-       * @param id the Scheduler id
-       */
-      public NotificationFilter(Integer id)
+	  protected void invoke(Notification notification)
       {
-         mId = id;
+		 Object[] lArguments = new Object[mSchedulableMBeanArguments.length];
+		 for (int i = 0; i < lArguments.length; i++)
+		 {
+			switch (mSchedulableMBeanArguments[i])
+			{
+			   case NOTIFICATION:
+				  lArguments[i] = notification;
+				  break;
+			   case DATE:
+				  lArguments[i] = new Date(notification.getTimeStamp());
+				  break;
+			   case REPETITIONS:
+				  lArguments[i] = new Long(mRemainingRepetitions);
+				  break;
+			   case SCHEDULER_NAME:
+				  lArguments[i] = getServiceName();
+				  break;
+			   default:
+				  lArguments[i] = null;
+			}
+		 }
+		 if (log.isTraceEnabled())
+		 {
+			log.debug("invoke " + mSchedulableMBean + " " + mSchedulableMBeanMethodName);
+			log.debug("arguments: " + Arrays.asList(lArguments));
+			log.debug("argument types: " + Arrays.asList(mSchedulableMBeanArgumentTypes));
+		 }
+		 try
+		 {
+			getServer().invoke(
+			   mSchedulableMBean,
+			   mSchedulableMBeanMethodName,
+			   lArguments,
+			   mSchedulableMBeanArgumentTypes
+			);
+		 }
+		 catch (Exception e)
+		 {
+			log.error("Invoke failed for " + mSchedulableMBean + " " + mSchedulableMBeanMethodName, e);
+		 }
       }
-
-      /**
-       * Determine if the notification should be sent to this Scheduler
-       */
-      public boolean isNotificationEnabled(Notification notification)
-      {
-         if (notification instanceof TimerNotification)
-         {
-            TimerNotification lTimerNotification = (TimerNotification) notification;
-            if (log.isTraceEnabled())
-               log.trace("Scheduler.NotificationFilter.isNotificationEnabled(), Id: " + mId +
-                  ", notification: " + notification +
-                  ", notification Id: " + lTimerNotification.getNotificationID() +
-                  ", timestamp: " + lTimerNotification.getTimeStamp() +
-                  ", message: " + lTimerNotification.getMessage()
-               );
-            return lTimerNotification.getNotificationID().equals(mId);
-         }
-         return false;
-      }
    }
 
-   /**
-    * A test class for a Schedulable Class
-    **/
-   public static class SchedulableExample
-      implements Schedulable
-   {
-
-      /** Class logger. */
-      private static final Logger log = Logger.getLogger(Scheduler.SchedulableExample.class);
-
-      private String mName;
-      private int mValue;
-
-      public SchedulableExample(
-         String pName,
-         int pValue
-         )
-      {
-         mName = pName;
-         mValue = pValue;
-      }
-
-      /**
-       * Just log the call
-       **/
-      public void perform(
-         Date pTimeOfCall,
-         long pRemainingRepetitions
-         )
-      {
-         log.info("Schedulable Examples is called at: " + pTimeOfCall +
-            ", remaining repetitions: " + pRemainingRepetitions +
-            ", test, name: " + mName + ", value: " + mValue);
-      }
-   }
 }

Modified: trunk/varia/src/main/org/jboss/varia/scheduler/SchedulerMBean.java
===================================================================
--- trunk/varia/src/main/org/jboss/varia/scheduler/SchedulerMBean.java	2006-11-06 19:24:43 UTC (rev 58157)
+++ trunk/varia/src/main/org/jboss/varia/scheduler/SchedulerMBean.java	2006-11-06 19:25:06 UTC (rev 58158)
@@ -164,6 +164,11 @@
    void stopSchedule(boolean doItNow);
 
    /**
+    * Stops the schedule immediately.
+    */
+   void stopSchedule();
+
+   /**
     * Stops the server right now and starts it right now.
     */
    void restartSchedule();

Modified: trunk/varia/src/main/org/jboss/varia/scheduler/example/SchedulableMBeanExample.java
===================================================================
--- trunk/varia/src/main/org/jboss/varia/scheduler/example/SchedulableMBeanExample.java	2006-11-06 19:24:43 UTC (rev 58157)
+++ trunk/varia/src/main/org/jboss/varia/scheduler/example/SchedulableMBeanExample.java	2006-11-06 19:25:06 UTC (rev 58158)
@@ -38,9 +38,8 @@
 import org.jboss.varia.scheduler.Schedulable;
 
 /**
+ * A sample SchedulableMBean that records when an event is received.
  * 
- * A sample SchedulableMBean
- * 
  * @jmx:mbean extends="org.jboss.system.ServiceMBean"
  *
  * @author <a href="mailto:andreas at jboss.org">Andreas Schaefer</a>
@@ -52,39 +51,99 @@
    extends ServiceMBeanSupport
    implements SchedulableMBeanExampleMBean
 {
-   /**
-    * Default (no-args) Constructor
-    **/
-   public SchedulableMBeanExample()
-   {
-   }
+
+   private Notification notification;
+   private Date date;
+   private long repetitions;
+   private ObjectName name;
+   private String test;
+   private int hitCount;
    
    // -------------------------------------------------------------------------
    // SchedulableExampleMBean Methods
    // -------------------------------------------------------------------------
    
    /**
+	* Called by ScheduleManager.
     * @jmx:managed-operation
     */
-   public void hit( Notification lNotification, Date lDate, long lRepetitions, ObjectName lName, String lTest ) {
-      log.info( "got hit"
-         + ", notification: " + lNotification
-         + ", date: " + lDate
-         + ", remaining repetitions: " + lRepetitions
-         + ", scheduler name: " + lName
-         + ", test string: " + lTest
-      );
+   public void hit(Notification notification, Date date, long repetitions, ObjectName name, String test)
+   {
+      log.info("got hit");
+	  this.notification = notification;
+	  this.date = date;
+	  this.repetitions = repetitions;
+	  this.name = name;
+	  this.test = test;
       hitCount++;
+      log.info(this.toString());
    }
 
   /**
-   * @jmx:managed-operation
+   * Returns the number of hits.
+   * @jmx:managed-attribute
    */   
    public int getHitCount()
    {
      return hitCount;
    }
    
-   private int hitCount = 0;
+  /**
+   * Returns the last hit date.
+   * @jmx:managed-attribute
+   */   
+   public Date getHitDate()
+   {
+     return date;
+   }
    
+  /**
+   * Returns the last hit notification.
+   * @jmx:managed-attribute
+   */   
+   public Notification getHitNotification()
+   {
+     return notification;
+   }
+   
+  /**
+   * Returns the last hit date.
+   * @jmx:managed-attribute
+   */   
+   public long getRemainingRepetitions()
+   {
+     return repetitions;
+   }
+   
+  /**
+   * Returns the object name.
+   * @jmx:managed-attribute
+   */   
+   public ObjectName getSchedulerName()
+   {
+     return name;
+   }
+   
+  /**
+   * Returns the test string.
+   * @jmx:managed-attribute
+   */   
+   public String getTestString()
+   {
+     return test;
+   }
+   
+   /**
+	* Returns a debug string.
+	*/
+   public String toString() {
+      return super.toString() 
+		 + " name=" + getName()
+		 + " hitCount=" + hitCount
+         + " notification=" + notification
+         + " date=" + date
+         + " repetitions=" + repetitions
+         + " name=" + name
+         + " test string=" + test;
+   }
 }

Modified: trunk/varia/src/main/org/jboss/varia/scheduler/example/SchedulableMBeanExampleMBean.java
===================================================================
--- trunk/varia/src/main/org/jboss/varia/scheduler/example/SchedulableMBeanExampleMBean.java	2006-11-06 19:24:43 UTC (rev 58157)
+++ trunk/varia/src/main/org/jboss/varia/scheduler/example/SchedulableMBeanExampleMBean.java	2006-11-06 19:25:06 UTC (rev 58158)
@@ -26,8 +26,13 @@
  */
 public interface SchedulableMBeanExampleMBean extends org.jboss.system.ServiceMBean {
 
-  void hit(javax.management.Notification lNotification,java.util.Date lDate,long lRepetitions,javax.management.ObjectName lName,java.lang.String lTest) ;
+  void hit(javax.management.Notification lNotification, java.util.Date lDate, long lRepetitions, javax.management.ObjectName name, String test) ;
 
   int getHitCount() ;
+  javax.management.Notification getHitNotification() ;
+  java.util.Date getHitDate() ;
+  long getRemainingRepetitions() ;
+  String getTestString() ;
+  javax.management.ObjectName getSchedulerName() ;
 
 }




More information about the jboss-cvs-commits mailing list