You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by mc...@apache.org on 2004/03/16 13:49:52 UTC

cvs commit: avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler BinaryHeap.java DefaultTimeScheduler.java DefaultTimeScheduler.xinfo MonitorableTimeScheduler.java MonitorableTimeSchedulerMBean.java PriorityQueue.java SynchronizedPriorityQueue.java TimeScheduledEntry.java package.html

mcconnell    2004/03/16 04:49:52

  Added:       cornerstone/scheduler/api .cvsignore project.xml
               cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler
                        CronTimeTrigger.java PeriodicTimeTrigger.java
                        Target.java TimeScheduler.java TimeTrigger.java
                        TimeTriggerFactory.java Trigger.java
                        TriggerFailureListener.java package.html
               cornerstone/scheduler/impl .cvsignore project.xml
               cornerstone/scheduler/impl/conf block.xml
               cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler
                        BinaryHeap.java DefaultTimeScheduler.java
                        DefaultTimeScheduler.xinfo
                        MonitorableTimeScheduler.java
                        MonitorableTimeSchedulerMBean.java
                        PriorityQueue.java SynchronizedPriorityQueue.java
                        TimeScheduledEntry.java package.html
  Log:
  Add avalon tags to scheduler component (while maintaining phoenix legacy descriptors).  Bumped impl version to SNAPSHOT (reflecting link to threads API which is bumped in relation to excalibur threads interface change).
  
  Revision  Changes    Path
  1.1                  avalon-components/cornerstone/scheduler/api/.cvsignore
  
  Index: .cvsignore
  ===================================================================
  maven.log
  velocity.log
  build.properties
  target
  maven.log
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/project.xml
  
  Index: project.xml
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <project>
  
    <extend>${basedir}/../../project.xml</extend>
  
    <groupId>cornerstone-scheduler</groupId>
    <id>cornerstone-scheduler-api</id>
    <name>Cornerstone Scheduler API</name>
    <currentVersion>1.0</currentVersion>
    <package>org.apache.avalon.cornerstone.services.scheduler</package>
    <inceptionYear>2001</inceptionYear>
    <shortDescription>Cornerstone Scheduler API</shortDescription>
    
    <dependencies>
  
      <!-- avalon dependencies -->
  
      <dependency>
        <groupId>avalon-framework</groupId>
        <artifactId>avalon-framework-api</artifactId>
        <version>4.1.5</version>
      </dependency>
  
      <!-- pre JDK 1.4 dependencies -->
  
      <dependency>
        <id>xml-apis</id>
        <version>1.0.b2</version>
        <url>http://xml.apache.org/xerces2-j/</url>
      </dependency>
  
      <dependency>
        <id>xerces</id>
        <version>2.2.1</version>
        <url>http://xml.apache.org/xerces2-j/</url>
      </dependency>
  
    </dependencies>
    
  </project>
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/CronTimeTrigger.java
  
  Index: CronTimeTrigger.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.services.scheduler;
  
  import java.util.Calendar;
  import java.util.Date;
  import java.util.GregorianCalendar;
  
  /**
   * This is the holder triggers based on standard crontabs format.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public class CronTimeTrigger
      implements TimeTrigger
  {
      protected final int m_minute;
      protected final int m_hour;
      protected final int m_dayOfMonth;
      protected final int m_month;
      protected final int m_dayOfWeek;
      protected final int m_year;
  
      /**
       * Constructor for CronTimeTrigger.
       * Day is either day of week or day of month depending on value of isDayOfWeek.
       * if (isDayOfWeek == true) then valid values are 1-7 otherwise the values
       * are 1-31
       *
       * @param minute the minute at which job is scheduled. (0-59)
       * @param hour hour at which job is scheduled. (0-23 or -1 for every hour)
       * @param month the month at which job is scheduled. (0-11 or -1 for every month)
       * @param year the year when job is scheduled (-1 implies every year)
       * @param day the day
       * @param isDayOfWeek true if day is a day of week or false if day is day of month
       */
      public CronTimeTrigger( final int minute,
                              final int hour,
                              final int day,
                              final int month,
                              final int year,
                              final boolean isDayOfWeek )
      {
          m_minute = minute;
          m_hour = hour;
          m_month = month;
          m_year = year;
  
          if( isDayOfWeek )
          {
              m_dayOfMonth = -1;
              m_dayOfWeek = day;
          }
          else
          {
              m_dayOfMonth = day;
              m_dayOfWeek = -1;
          }
      }
  
      /**
       * Returns the next time after the given <tt>moment</tt> when
       * this trigger goes off.
       *
       * @param moment base point in milliseconds
       * @return the time in milliseconds when this trigger goes off
       */
      public long getTimeAfter( final long moment )
      {
          //first create calendars
          final Date timeMarker = new Date( moment );
          final GregorianCalendar relativeTo = new GregorianCalendar();
          relativeTo.setTime( timeMarker );
          relativeTo.set( Calendar.SECOND, 0 );
  
          final GregorianCalendar next = (GregorianCalendar)relativeTo.clone();
  
          if( -1 != m_minute )
              next.set( Calendar.MINUTE, m_minute );
          else
          {
              if( -1 == m_hour && -1 == m_month && -1 == m_year )
              {
                  //roll minutes if all other values -1
                  next.add( Calendar.MINUTE, 1 );
              }
              else
              {
                  next.set( Calendar.MINUTE, 0 );
              }
          }
  
          if( -1 != m_hour )
          {
              next.set( Calendar.HOUR_OF_DAY, m_hour );
              if( -1 == m_minute ) next.set( Calendar.MINUTE, 0 );
          }
  
          if( -1 != m_month )
          {
              next.set( Calendar.MONTH, m_month );
              if( -1 == m_hour ) next.set( Calendar.HOUR_OF_DAY, 0 );
              if( -1 == m_minute ) next.set( Calendar.MINUTE, 0 );
          }
  
          if( -1 != m_year )
          {
              next.set( Calendar.YEAR, m_year );
              if( -1 == m_month ) next.set( Calendar.MONTH, 0 );
              if( -1 == m_hour ) next.set( Calendar.HOUR_OF_DAY, 0 );
              if( -1 == m_minute ) next.set( Calendar.MINUTE, 0 );
          }
  
          //use zeroed constant to make if statements easier to read
          final int minute = ( -1 != m_minute ) ? m_minute : 0;
          final int rminute = relativeTo.get( Calendar.MINUTE );
  
          if( -1 == m_year && -1 == m_month && -1 == m_hour &&
              -1 != m_minute && rminute >= minute )
          {
              //for every hour jobs and job is done this hour
              next.add( Calendar.HOUR_OF_DAY, 1 );
          }
  
          //use zeroed constant to make if statements easier to read
          final int hour = ( -1 != m_hour ) ? m_hour : 0;
          final int rhour = relativeTo.get( Calendar.HOUR_OF_DAY );
  
          if( -1 == m_dayOfMonth && -1 == m_dayOfWeek &&
              (
              //for when past hour that was scheduled to run
              ( -1 != m_hour && rhour > hour ) ||
  
              //for the case where you have to wrap over day
              //when hour is not specified
              ( -1 == m_hour && rhour == 24 && rminute >= minute ) ||
  
              //for when you are past time of day where both minute and
              //hour are specified
              ( -1 != m_hour && rhour == hour && rminute >= minute )
              )
          )
          {
              //for jobs scheduled everyday and job is done this day
              next.add( Calendar.DAY_OF_YEAR, 1 );
          }
  
          int realDayOfMonth = m_dayOfMonth;
          {
              //This block will update day of month if it is out of bounds
              //For instance if you ask to schedule on 30th of everymonth
              //this section will set the day to 28th (or 29th) in febuary
              //as there is no 30th
              final Calendar targetMonth = (GregorianCalendar)next.clone();
              targetMonth.set( Calendar.DAY_OF_MONTH, 1 );
              targetMonth.set( Calendar.MONTH, m_month );
  
              final int maxDayCount = targetMonth.getActualMaximum( Calendar.DAY_OF_MONTH );
              if( maxDayCount < realDayOfMonth )
              {
                  realDayOfMonth = maxDayCount;
                  next.add( Calendar.MONTH, -1 );
              }
          }
  
          final int month = ( -1 != m_month ) ? m_month : 0;
          final int dayOfMonth = ( -1 != m_dayOfMonth ) ? m_dayOfMonth : 0;
  
          //update the year if ran job for this year
          if( -1 != m_month && -1 == m_year &&
              ( relativeTo.get( Calendar.MONTH ) > month ||
              ( relativeTo.get( Calendar.MONTH ) == month &&
              ( relativeTo.get( Calendar.DAY_OF_MONTH ) > dayOfMonth ||
              ( relativeTo.get( Calendar.DAY_OF_MONTH ) == dayOfMonth &&
              ( relativeTo.get( Calendar.HOUR_OF_DAY ) > hour ||
              ( relativeTo.get( Calendar.HOUR_OF_DAY ) == hour &&
              ( relativeTo.get( Calendar.MINUTE ) >= minute ) ) ) ) ) ) ) )
          {
              next.add( Calendar.YEAR, 1 );
          }
  
          if( -1 != m_year )
          {
              //if past current year or already executed job this year then
              //bail out
              if( relativeTo.get( Calendar.YEAR ) > m_year ||
                  ( relativeTo.get( Calendar.YEAR ) == m_year &&
                  ( relativeTo.get( Calendar.MONTH ) > month ||
                  ( relativeTo.get( Calendar.MONTH ) == month &&
                  ( relativeTo.get( Calendar.DAY_OF_MONTH ) > dayOfMonth ||
                  ( relativeTo.get( Calendar.DAY_OF_MONTH ) == dayOfMonth &&
                  ( relativeTo.get( Calendar.HOUR_OF_DAY ) > hour ||
                  ( relativeTo.get( Calendar.HOUR_OF_DAY ) == hour &&
                  ( relativeTo.get( Calendar.MINUTE ) >= minute ) ) ) ) ) ) ) ) )
              {
                  return -1;
              }
          }
  
          //schedule weekly jobs
          if( -1 != m_dayOfWeek )
          {
              final int dayWait =
                  ( 7 + m_dayOfWeek - relativeTo.get( Calendar.DAY_OF_WEEK ) ) % 7;
  
              if( 0 != dayWait )
              {
                  next.add( Calendar.DAY_OF_YEAR, dayWait );
              }
              else if( relativeTo.get( Calendar.HOUR_OF_DAY ) > hour ||
                  ( relativeTo.get( Calendar.HOUR_OF_DAY ) == hour &&
                  relativeTo.get( Calendar.MINUTE ) >= minute ) )
              {
                  //if job scheduled for today has passed then schedule on next week
                  next.add( Calendar.DAY_OF_YEAR, 7 );
              }
          }
          // Schedule monthly jobs
          else if( -1 != m_dayOfMonth )
          {
              //System.out.println( "Setting to maxday: " + realDayOfMonth );
              next.set( Calendar.DAY_OF_MONTH, realDayOfMonth );
              //next.set( Calendar.DAY_OF_MONTH, m_dayOfMonth );
  
              //if this months job has already run then schedule next week
              if( m_month == -1 &&
                  ( relativeTo.get( Calendar.DAY_OF_MONTH ) > m_dayOfMonth ||
                  ( relativeTo.get( Calendar.DAY_OF_MONTH ) == m_dayOfMonth &&
                  ( relativeTo.get( Calendar.HOUR_OF_DAY ) > hour ||
                  ( relativeTo.get( Calendar.HOUR_OF_DAY ) == hour &&
                  relativeTo.get( Calendar.MINUTE ) >= minute ) ) ) ) )
              {
                  next.roll( Calendar.MONTH, true );
              }
          }
  
          //return time in millis
          return next.getTime().getTime();
      }
  
      /**
       * Reset the cron-trigger.
       */
      public void reset()
      {
          // nothing to reset for CronTimeTrigger
      }
  
      public String toString()
      {
          final StringBuffer sb = new StringBuffer();
          sb.append( "CronTimeTrigger[ " );
  
          if( -1 != m_minute )
          {
              sb.append( "minute=" );
              sb.append( m_minute );
              sb.append( " " );
          }
  
          if( -1 != m_hour )
          {
              sb.append( "hour=" );
              sb.append( m_hour );
              sb.append( " " );
          }
  
          if( -1 != m_month )
          {
              sb.append( "month=" );
              sb.append( m_month );
              sb.append( " " );
          }
  
          if( -1 != m_year )
          {
              sb.append( "year=" );
              sb.append( m_year );
              sb.append( " " );
          }
  
          if( -1 != m_dayOfMonth )
          {
              sb.append( "dayOfMonth=" );
              sb.append( m_dayOfMonth );
              sb.append( " " );
          }
  
          if( -1 != m_dayOfWeek )
          {
              sb.append( "dayOfWeek=" );
              sb.append( m_dayOfWeek );
              sb.append( " " );
          }
  
          sb.append( "]" );
  
          return sb.toString();
      }
  }
  
  
  
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/PeriodicTimeTrigger.java
  
  Index: PeriodicTimeTrigger.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.services.scheduler;
  
  /**
   * Goes off every <tt>period</tt> milliseconds after waiting for
   * <tt>offset</tt> milliseconds from the moment the trigger was
   * <tt>reset</tt>.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public class PeriodicTimeTrigger
      implements TimeTrigger
  {
      protected final long m_offset;
      protected final long m_period;
      private long m_triggerTime;
  
      /**
       * Creates a periodic trigger. It goes off the first time after
       * <tt>offset</tt> milliseconds from the time it was
       * <tt>reset</tt> and then every <tt>period</tt>
       * milliseconds. The trigger is <tt>reset</tt> as
       * part of its construction.
       *
       * @param offset initial delay in milliseconds, -1 means fire immediately
       * @param period after initial delay in milliseconds, -1 means fire only once after initial delay
       */
      public PeriodicTimeTrigger( final int offset, final int period )
      {
          m_offset = offset;
          m_period = period;
  
          reset();
      }
  
      /**
       * Returns the next time after the given <tt>moment</tt> when
       * this trigger goes off.
       *
       * @param moment base point in milliseconds
       * @return the time in milliseconds when this trigger goes off
       */
      public long getTimeAfter( final long moment )
      {
          if( moment <= m_triggerTime )
          {
              return m_triggerTime;
          }
          else
          {
              if( -1 == m_period )
              {
                  return -1;
              }
  
              final long over = moment - m_triggerTime;
              final long remainder = over % m_period;
  
              return moment + ( m_period - remainder );
          }
      }
  
      public long getOffset()
      {
          return m_offset;
      }
  
      public long getPeriod()
      {
          return m_period;
      }
  
      /**
       * Reset the original TimeTrigger.
       * This will recalculate the activation time for this trigger.
       */
      public void reset()
      {
          final long current = System.currentTimeMillis();
  
          if( -1 == m_offset )
          {
              m_triggerTime = current;
          }
          else
          {
              m_triggerTime = current + m_offset;
          }
      }
  
      public String toString()
      {
          final StringBuffer sb = new StringBuffer();
          sb.append( "PeriodicTimeTrigger[ " );
  
          sb.append( "trigger time=" );
          sb.append( m_triggerTime );
          sb.append( " " );
  
          sb.append( "offset=" );
          sb.append( m_offset );
          sb.append( " " );
  
          if( -1 != m_period )
          {
              sb.append( "period=" );
              sb.append( m_period );
              sb.append( " " );
          }
  
          sb.append( "]" );
  
          return sb.toString();
      }
  }
  
  
  
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/Target.java
  
  Index: Target.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.services.scheduler;
  
  /**
   * This is the interface to implement to receive notification trigger.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public interface Target
  {
      /**
       * Notify target that trigger has occured.
       *
       * @param triggerName the name of trigger
       */
      void targetTriggered( String triggerName );
  }
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/TimeScheduler.java
  
  Index: TimeScheduler.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.services.scheduler;
  
  import java.util.NoSuchElementException;
  
  /**
   * This service provides a way to regularly schedule jobs.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public interface TimeScheduler
  {
      String ROLE = TimeScheduler.class.getName();
  
      /**
       * Schedule a time based trigger.
       * Note that if a TimeTrigger already has same name then it is removed.
       *
       * @param name the name of the trigger
       * @param trigger the trigger
       * @param target the target
       */
      void addTrigger( String name, TimeTrigger trigger, Target target );
  
      /**
       * Remove a scheduled trigger by name.
       *
       * @param name the name of the trigger
       * @exception NoSuchElementException if no trigger exists with that name
       */
      void removeTrigger( String name )
          throws NoSuchElementException;
  
      /**
       * Force a trigger time to be recalculated.
       *
       * @param name the name of the trigger
       * @exception NoSuchElementException if no trigger exists with that name
       */
      void resetTrigger( String name )
          throws NoSuchElementException;
  
      /**
       * Add a trigger failure listener
       * @param listener the listener
       */
      void addTriggerFailureListener( TriggerFailureListener listener );
  
      /**
       * Remove a trigger failure listener
       * @param listener the listener
       */
      void removeTriggerFailureListener( TriggerFailureListener listener );
  
  }
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/TimeTrigger.java
  
  Index: TimeTrigger.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.services.scheduler;
  
  /**
   * A kind of trigger that makes the determination to go off based
   * on time.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public interface TimeTrigger
      extends Trigger
  {
      /**
       * Returns the next time after the given <tt>moment</tt> when
       * this trigger goes off.
       *
       * @param moment base point in milliseconds
       * @return the time in milliseconds when this trigger goes off
       */
      long getTimeAfter( long moment );
  }
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/TimeTriggerFactory.java
  
  Index: TimeTriggerFactory.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.services.scheduler;
  
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  
  /**
   * Factory for <code>TimeTrigger</code>s.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public class TimeTriggerFactory
  {
      /**
       * Create <code>TimeTrigger</code> from configuration.
       *
       * @param conf configuration for time trigger
       */
      public TimeTrigger createTimeTrigger( final Configuration conf )
          throws ConfigurationException
      {
          final String type = conf.getAttribute( "type" );
  
          TimeTrigger trigger;
          if( "periodic".equals( type ) )
          {
              final int offset =
                  conf.getChild( "offset", true ).getValueAsInteger( 0 );
              final int period =
                  conf.getChild( "period", true ).getValueAsInteger( -1 );
  
              trigger = new PeriodicTimeTrigger( offset, period );
          }
          else if( "cron".equals( type ) )
          {
              final int minute =
                  conf.getChild( "minute" ).getValueAsInteger( -1 );
              final int hour =
                  conf.getChild( "hour" ).getValueAsInteger( -1 );
              final int day =
                  conf.getChild( "day" ).getValueAsInteger( -1 );
              final int month =
                  conf.getChild( "month" ).getValueAsInteger( -1 );
              final int year =
                  conf.getChild( "year" ).getValueAsInteger( -1 );
              final boolean dayOfWeek =
                  conf.getChild( "day" ).getAttributeAsBoolean( "week", false );
  
              trigger = new CronTimeTrigger( minute, hour, day, month, year,
                                             dayOfWeek );
          }
          else
          {
              throw new ConfigurationException( "Unknown trigger type" );
          }
  
          return trigger;
      }
  }
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/Trigger.java
  
  Index: Trigger.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.services.scheduler;
  
  /**
   * This is the marker interface for Triggers.
   * Triggers can be time-based, event-based or other.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public interface Trigger
  {
      /**
       * Reset the Trigger. The Triggers can be time-based,
       * event-based or other.
       */
      void reset();
  }
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/TriggerFailureListener.java
  
  Index: TriggerFailureListener.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.services.scheduler;
  
  /**
   * A callback mechanism for failures on triggering of targets.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public interface TriggerFailureListener
  {
      void triggerFailure( Throwable throwable );
  }
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/api/src/java/org/apache/avalon/cornerstone/services/scheduler/package.html
  
  Index: package.html
  ===================================================================
  <body>
  Defintion of the scheduler service.
  </body>
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/.cvsignore
  
  Index: .cvsignore
  ===================================================================
  maven.log
  velocity.log
  build.properties
  target
  maven.log
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/project.xml
  
  Index: project.xml
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  
  <project>
  
    <extend>${basedir}/../../project.xml</extend>
  
    <groupId>cornerstone-scheduler</groupId>
    <id>cornerstone-scheduler-impl</id>
    <name>Cornerstone Scheduler Implementation</name>
  
    <!-- candidate 2.0 due to reference to threads -->
  
    <currentVersion>SNAPSHOT</currentVersion> 
    <package>org.apache.avalon.cornerstone.blocks.scheduler</package>
  
    <inceptionYear>2001</inceptionYear>
    <shortDescription>Cornerstone Scheduler</shortDescription>
  
    <dependencies>
  
      <!-- cornerstone api dependencies -->
  
      <dependency>
        <groupId>cornerstone-scheduler</groupId>
        <artifactId>cornerstone-scheduler-api</artifactId>
        <version>1.0</version>
      </dependency>
  
      <dependency>
        <groupId>cornerstone-threads</groupId>
        <artifactId>cornerstone-threads-api</artifactId>
        <version>SNAPSHOT</version>
      </dependency>
  
      <!-- excalibur api dependencies -->
  
      <dependency>
        <groupId>excalibur-thread</groupId>
        <artifactId>excalibur-thread-api</artifactId>
        <version>SNAPSHOT</version>
      </dependency>
  
      <!-- avalon dependencies -->
  
      <dependency>
        <groupId>avalon-framework</groupId>
        <artifactId>avalon-framework-api</artifactId>
        <version>4.1.5</version>
      </dependency>
      <dependency>
        <groupId>avalon-framework</groupId>
        <artifactId>avalon-framework-impl</artifactId>
        <version>4.1.5</version>
      </dependency>
  
      <!-- pre JDK 1.4 dependencies -->
  
      <dependency>
        <id>xml-apis</id>
        <version>1.0.b2</version>
        <url>http://xml.apache.org/xerces2-j/</url>
      </dependency>
  
      <dependency>
        <id>xerces</id>
        <version>2.2.1</version>
        <url>http://xml.apache.org/xerces2-j/</url>
      </dependency>
  
    </dependencies>
    
  </project>
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/conf/block.xml
  
  Index: block.xml
  ===================================================================
  
  <!--
  Thread Block deployment directive.
  -->
  
  <container name="scheduler">
  
     <services>
       <service type="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler">
         <source>manager</source>
       </service>
     </services>
  
     <classloader>
       <classpath>
         <repository>
           <resource id="avalon-framework:avalon-framework-impl" version="4.1.5"/>
           <resource id="cornerstone-scheduler:cornerstone-scheduler-api" version="1.0"/>
           <resource id="cornerstone-threads:cornerstone-threads-api" version="SNAPSHOT"/>
           <resource id="excalibur-thread:excalibur-thread-api" version="SNAPSHOT"/>
         </repository>
       </classpath>
     </classloader>
  
     <component name="manager" 
          class="org.apache.avalon.cornerstone.blocks.scheduler.DefaultTimeScheduler" 
          activation="true">
     </component>
  
  </container>
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/BinaryHeap.java
  
  Index: BinaryHeap.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.blocks.scheduler;
  
  import java.util.Comparator;
  import java.util.NoSuchElementException;
  
  /**
   * BinaryHeap implementation of priority queue.
   * The heap is either a minimum or maximum heap as determined
   * by parameters passed to constructor.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   * @version CVS $Revision: 1.1 $ $Date: 2004/03/16 12:49:52 $
   * @since 4.0
   */
  public final class BinaryHeap
      implements PriorityQueue
  {
      private static final class MinComparator
          implements Comparator
      {
          public final int compare( final Object lhs, final Object rhs )
          {
              return ( (Comparable)lhs ).compareTo( rhs );
          }
      }
  
      private static final class MaxComparator
          implements Comparator
      {
          public final int compare( final Object lhs, final Object rhs )
          {
              return ( (Comparable)rhs ).compareTo( lhs );
          }
      }
  
      /**
       * Comparator used to instantiate a min heap - assumes contents implement
       * the Comparable interface.
       */
      public static final Comparator MIN_COMPARATOR = new MinComparator();
  
      /**
       * Comparator used to instantiate a max heap - assumes contents implement
       * the Comparable interface.
       */
      public static final Comparator MAX_COMPARATOR = new MaxComparator();
  
      private static final int DEFAULT_CAPACITY = 13;
      private static final Comparator DEFAULT_COMPARATOR = MIN_COMPARATOR;
      private int m_size;
      private Object[] m_elements;
      private Comparator m_comparator;
  
      /**
       * Instantiates a new min binary heap with the default initial capacity.
       */
      public BinaryHeap()
      {
          this( DEFAULT_CAPACITY, DEFAULT_COMPARATOR );
      }
  
      /**
       * Instantiates a new min binary heap with the given initial capacity.
       *
       * @param capacity the size of the heap
       */
      public BinaryHeap( final int capacity )
      {
          this( capacity, DEFAULT_COMPARATOR );
      }
  
      /**
       * Instantiates a new binary heap with the default initial capacity and
       * ordered using the given Comparator.
       *
       * @param comparator to order the contents of the heap
       */
      public BinaryHeap( final Comparator comparator )
      {
          this( DEFAULT_CAPACITY, comparator );
      }
  
      /**
       * Instantiates a new binary heap with the given initial capacity and
       * ordered using the given Comparator.
       *
       * @param capacity the size of the heap
       * @param comparator to order the contents of the heap
       */
      public BinaryHeap( final int capacity, final Comparator comparator )
      {
          //+1 as 0 is noop
          m_elements = new Object[ capacity + 1 ];
          m_comparator = comparator;
      }
  
      /**
       * Create a binary heap of Comparables. Takes a parameter
       * to specify whether it is a minimum or maximum heap.
       *
       * @param isMinHeap true to make it a minimum heap, false to make it a max heap
       */
      public BinaryHeap( final boolean isMinHeap )
      {
          this( DEFAULT_CAPACITY, isMinHeap );
      }
  
      /**
       * Create a binary heap of Comparables. Takes a parameter
       * to specify whether it is a minimum or maximum heap and another
       * parameter to specify the size of the heap.
       *
       * @param capacity the size of the heap
       * @param isMinHeap true to make it a minimum heap, false to make it a max heap
       */
      public BinaryHeap( final int capacity, final boolean isMinHeap )
      {
          this( capacity, isMinHeap ? MIN_COMPARATOR : MAX_COMPARATOR );
      }
  
      /**
       * Clear all elements from queue.
       */
      public void clear()
      {
          m_size = 0;
      }
  
      /**
       * Test if queue is empty.
       *
       * @return true if queue is empty else false.
       */
      public boolean isEmpty()
      {
          return ( 0 == m_size );
      }
  
      /**
       * Test if queue is full.
       *
       * @return true if queue is full else false.
       */
      public boolean isFull()
      {
          //+1 as element 0 is noop
          return ( m_elements.length == m_size + 1 );
      }
  
      /**
       * Returns the number of elements currently on the heap.
       *
       * @return the size of the heap.
       */
      public int size()
      {
          return m_size;
      }
  
      /**
       * Insert an element into queue.
       *
       * @param element the element to be inserted
       */
      public void insert( final Object element )
      {
          if( isFull() )
          {
              grow();
          }
  
          percolateUpHeap( element );
      }
  
      /**
       * Return element on top of heap but don't remove it.
       *
       * @return the element at top of heap
       * @throws NoSuchElementException if isEmpty() == true
       */
      public Object peek() throws NoSuchElementException
      {
          if( isEmpty() )
          {
              throw new NoSuchElementException();
          }
          else
          {
              return m_elements[ 1 ];
          }
      }
  
      /**
       * Return element on top of heap and remove it.
       *
       * @return the element at top of heap
       * @throws NoSuchElementException if isEmpty() == true
       */
      public Object pop() throws NoSuchElementException
      {
          final Object result = peek();
          m_elements[ 1 ] = m_elements[ m_size-- ];
  
          //set the unused element to 'null' so that the garbage collector
          //can free the object if not used anywhere else.(remove reference)
          m_elements[ m_size + 1 ] = null;
  
          if( m_size != 0 )
          {
              percolateDownHeap( 1 );
          }
  
          return result;
      }
  
      /**
       * Percolate element down heap from top.
       *
       * @param index the index of element
       */
      private void percolateDownHeap( final int index )
      {
          final Object element = m_elements[ index ];
  
          int hole = index;
          int child = hole << 1;
  
          while( child <= m_size )
          {
              //if we have a right child and that child can not be percolated
              //up then move onto other child
              if( child != m_size &&
                  m_comparator.compare( m_elements[ child + 1 ], m_elements[ child ] ) < 0 )
              {
                  child++;
              }
  
              //if we found resting place of bubble then terminate search
              if( m_comparator.compare( m_elements[ child ], element ) >= 0 )
              {
                  break;
              }
  
              m_elements[ hole ] = m_elements[ child ];
              hole = child;
              child = hole << 1;
          }
  
          m_elements[ hole ] = element;
      }
  
      /**
       * Percolate element up heap from bottom.
       *
       * @param element the element
       */
      private void percolateUpHeap( final Object element )
      {
          int hole = ++m_size;
          int next = hole >> 1;
  
          m_elements[ hole ] = element;
  
          while( hole > 1 &&
              m_comparator.compare( element, m_elements[ next ] ) < 0 )
          {
              m_elements[ hole ] = m_elements[ next ];
              hole = next;
              next = hole >> 1;
          }
  
          m_elements[ hole ] = element;
      }
  
      /**
       * Grows the heap by a factor of 2.
       */
      private void grow()
      {
          final Object[] elements =
              new Object[ m_elements.length * 2 ];
          System.arraycopy( m_elements, 0, elements, 0, m_elements.length );
          m_elements = elements;
      }
  
      /**
       * Create a string representing heap
       * and all elements in heap.
       *
       * @return the string representing heap
       */
      public String toString()
      {
          final StringBuffer sb = new StringBuffer();
  
          sb.append( "[ " );
  
          for( int i = 1; i < m_size + 1; i++ )
          {
              if( i != 1 )
              {
                  sb.append( ", " );
              }
              sb.append( m_elements[ i ] );
          }
  
          sb.append( " ]" );
  
          return sb.toString();
      }
  }
  
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/DefaultTimeScheduler.java
  
  Index: DefaultTimeScheduler.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.blocks.scheduler;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.Hashtable;
  import java.util.Iterator;
  import java.util.NoSuchElementException;
  import java.util.Vector;
  import java.util.List;
  import java.util.Map;
  
  import org.apache.avalon.cornerstone.services.scheduler.Target;
  import org.apache.avalon.cornerstone.services.scheduler.TimeScheduler;
  import org.apache.avalon.cornerstone.services.scheduler.TimeTrigger;
  import org.apache.avalon.cornerstone.services.scheduler.TriggerFailureListener;
  import org.apache.avalon.cornerstone.services.threads.ThreadManager;
  
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.activity.Startable;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.service.ServiceException;
  import org.apache.avalon.framework.service.ServiceManager;
  import org.apache.avalon.framework.service.Serviceable;
  
  /**
   * Default implementation of TimeScheduler service.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   * @avalon.component name="time-scheduler" lifestyle="singleton"
   * @avalon.service type="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler"
   */
  public class DefaultTimeScheduler
      extends AbstractLogEnabled
      implements TimeScheduler, Serviceable, Startable, Disposable, Runnable, MonitorableTimeSchedulerMBean
  {
      // ----------------------------------------------------------------------
      //  Properties
      // ----------------------------------------------------------------------
      private final Hashtable m_entries = new Hashtable();
      private final PriorityQueue m_priorityQueue =
          new SynchronizedPriorityQueue( new BinaryHeap() );
      private ThreadManager m_threadManager;
      private boolean m_running;
      private ArrayList m_triggerFailureListeners = new ArrayList();
  
      // ----------------------------------------------------------------------
      //  Getter/Setter methods
      // ----------------------------------------------------------------------
      //
      // LSD: these have been added in to allow subclasses of the
      // DefaultScheduler to override implementation behaviour.
      // You should *not* make these public in subclasses (hence
      // they are final); they're here for convenience implementation
      // only.
  
      protected final ThreadManager getThreadManager()
      {
          return m_threadManager;
      }
  
      protected final boolean isRunning()
      {
          return m_running;
      }
  
      protected final void setRunning( boolean running )
      {
          m_running = running;
      }
  
      protected final List getTriggerFailureListeners()
      {
          return m_triggerFailureListeners;
      }
  
      protected final Map getEntryMap()
      {
          return m_entries;
      }
  
      protected final PriorityQueue getPriorityQueue()
      {
          return m_priorityQueue;
      }
  
      // ----------------------------------------------------------------------
      //  Avalon Lifecycle
      // ----------------------------------------------------------------------
  
     /**
      * Supply of the service manager to the component.
      * @param serviceManager the service manager
      * @avalon.dependency type="org.apache.avalon.cornerstone.services.threads.ThreadManager"
      */
      public void service( final ServiceManager serviceManager )
          throws ServiceException
      {
          m_threadManager = (ThreadManager)serviceManager.lookup( ThreadManager.ROLE );
      }
  
      public void dispose()
      {
          if( getLogger().isDebugEnabled() )
          {
              getLogger().debug( "disposal" );
          }
          m_entries.clear();
          m_priorityQueue.clear();
      }
  
      public void start()
          throws Exception
      {
          //this should suck threads from a named pool
          getThreadManager().getDefaultThreadPool().execute( this );
      }
  
      public void stop()
      {
          m_running = false;
          synchronized( this )
          {
              notifyAll();
          }
      }
  
      // ----------------------------------------------------------------------
      //  Work Interface: Runnable
      // ----------------------------------------------------------------------
      /**
       * Entry point for thread that monitors entrys and triggers
       * entrys when necessary.
       */
      public void run()
      {
          m_running = true;
  
          while( m_running )
          {
              long duration = 0;
  
              if( !getPriorityQueue().isEmpty() )
              {
                  TimeScheduledEntry entry = null;
                  synchronized( this )
                  {
                      entry = getNextEntry();
                      if( null == entry ) continue;
  
                      duration = entry.getNextTime() - System.currentTimeMillis();
  
                      if( duration < 0 )
                      {
                          //time to run job so remove it from priority queue
                          //and run it
                          getPriorityQueue().pop();
  
                          //Note that we need the pop to occur in a
                          //synchronized section while the runEntry
                          //does not need to be synchronized
                          //hence why there is to if statements
                          //structured in this ugly way
                      }
                  }
  
                  if( duration < 0 )
                  {
                      // runs and reschedules the entry
                      runEntry( entry );                    
                      continue;
                  }
                  else if( 0 == duration )
                  {
                      //give a short duration that will sleep
                      // so that next loop will definetly be below 0.
                      //Can not act on zero else multiple runs could go through
                      //at once
                      duration = 1;
                  }
              }
  
              //wait/sleep until monitor is signalled which occurs when
              //next jobs is likely to occur or when a new job gets added to
              //top of heap
              try
              {
                  synchronized( this )
                  {
                      wait( duration );
                  }
              }
              catch( final InterruptedException ie )
              {
              }
          }
      }
  
      // ----------------------------------------------------------------------
      //  Work Interface: Time Scheduler
      // ----------------------------------------------------------------------
      /**
       * Add a trigger failure listener
       * @param listener The listener
       */
      public void addTriggerFailureListener( TriggerFailureListener listener )
      {
          getTriggerFailureListeners().add( listener );
      }
  
      /**
       * Remove a trigger failure listener
       * @param listener The listener
       */
      public void removeTriggerFailureListener( TriggerFailureListener listener )
      {
          getTriggerFailureListeners().remove( listener );
      }
  
      /**
       * Schedule a time based trigger.
       * Note that if a TimeTrigger already has same name then it is removed.
       *
       * @param name the name of the trigger
       * @param trigger the trigger
       * @param target the target
       */
      public synchronized void addTrigger( final String name,
                                           final TimeTrigger trigger,
                                           final Target target )
      {
          try
          {
              removeTrigger( name );
          }
          catch( final NoSuchElementException nse )
          {
          }
  
          final TimeScheduledEntry entry = new TimeScheduledEntry( name, trigger, target );
          getEntryMap().put( name, entry );
          final boolean added = rescheduleEntry( entry, false );
  
          if( !added ) return;
  
          try
          {
              if( entry == getPriorityQueue().peek() )
              {
                  notifyAll();
              }
          }
          catch( final NoSuchElementException nse )
          {
              final String message =
                  "Unexpected exception when peek() on priority queue for " +
                  entry.getName();
              getLogger().warn( message, nse );
          }
      }
  
      /**
       * Remove a scheduled trigger by name.
       *
       * @param name the name of the trigger
       * @exception NoSuchElementException if no trigger exists with that name
       */
      public synchronized void removeTrigger( String name )
          throws NoSuchElementException
      {
          //use the kill-o-matic against any entry with same name
          final TimeScheduledEntry entry = getEntry( name );
          entry.invalidate();
          getEntryMap().remove( name );
      }
  
      /**
       * Force a trigger time to be recalculated.
       *
       * @param name the name of the trigger
       * @exception NoSuchElementException if no trigger exists with that name
       */
      public synchronized void resetTrigger( final String name )
          throws NoSuchElementException
      {
          final TimeScheduledEntry entry = getEntry( name );
          entry.getTimeTrigger().reset();
          rescheduleEntry( entry, true );
      }
  
      // ----------------------------------------------------------------------
      //  Work Interface: MonitorableTimeSchedulerMBean
      // ----------------------------------------------------------------------
  
      /**
       * Return a collection of the triggerable names.
       * @return
       */
      public synchronized Collection getEntries()
      {
          Collection coll = getEntryMap().keySet();
          Vector retval = new Vector();
          for( Iterator iterator = coll.iterator(); iterator.hasNext(); )
          {
              TimeScheduledEntry tse = (TimeScheduledEntry)getEntryMap().get( iterator.next() );
              retval.add( tse.toString() );
          }
          return retval;
      }
  
      // ----------------------------------------------------------------------
      //  Helper methods
      // ----------------------------------------------------------------------
  
      /**
       * Reschedule an entry.
       * if clone is true then invalidate old version and create a new entry to
       * insert into queue.
       *
       * @param timeEntry the entry
       * @param clone true if new entry is to be created
       * @return true if added to queue, false if not added
       */
      protected synchronized boolean rescheduleEntry( final TimeScheduledEntry timeEntry,
                                                    final boolean clone )
      {
          TimeScheduledEntry entry = timeEntry;
  
          if( clone )
          {
              entry = new TimeScheduledEntry( timeEntry.getName(),
                                              timeEntry.getTimeTrigger(),
                                              timeEntry.getTarget() );
              timeEntry.invalidate();
  
              // remove old refernce to the entry..so that next time
              // somebody calls getEntry( name ), we will get the new valid entry.
              getEntryMap().remove( timeEntry.getName() );
              getEntryMap().put( timeEntry.getName(), entry );
          }
  
          //reschedule if appropriate
          final long next = entry.getTimeTrigger().getTimeAfter( System.currentTimeMillis() );
  
          if( 0 < next )
          {
              entry.setNextTime( next );
              getPriorityQueue().insert( entry );
  
              if( entry == getPriorityQueue().peek() )
              {
                  notify();
              }
  
              return true;
          }
          else
          {
              return false;
          }
      }
  
      /**
       * Retrieve entry from set.
       *
       * @param name the name of entry
       * @return the entry
       * @exception NoSuchElementException if no entry is found with that name
       */
      protected TimeScheduledEntry getEntry( final String name )
          throws NoSuchElementException
      {
          //use the kill-o-matic against any entry with same name
          final TimeScheduledEntry entry = (TimeScheduledEntry)getEntryMap().get( name );
          if( null != entry )
          {
              return entry;
          }
          else
          {
              throw new NoSuchElementException();
          }
      }
  
      /**
       * Run entry in a separate thread and reschedule it.
       *
       * @param entry the entry to run
       */
      protected void runEntry( final TimeScheduledEntry entry )
      {
          final Runnable runnable = new Runnable()
          {
              public void run()
              {
                  doRunEntry( entry );
                  // Stefan Seifert:
                  // rescheduleEntry( entry, false );
                  //
                  // and then don't reschedule at the end of runEntry
                  // this will ensure long-running events are
                  // queued
                  //
                  // LSD:
                  // that might break other apps. No-can-do.
              }
          };
  
          //this should suck threads from a named pool
          try
          {
              getThreadManager().getDefaultThreadPool().execute( runnable );
          }
          catch( final Exception e )
          {
              final String message = "Error executing trigger " + entry.getName();
              getLogger().warn( message, e );
          }
          
  				// reschedule entry
  				rescheduleEntry( entry, false );
      }
  
      /**
       * Helper method delegated to to run in a separate thread.
       *
       * @param entry the entry to run
       */
      protected void doRunEntry( final TimeScheduledEntry entry )
      {
          try
          {
              entry.getTarget().targetTriggered( entry.getName() );
          }
          catch( final Error e )
          {
              final String message = "Error occured executing trigger " + entry.getName();
              getLogger().error( message, e );
              notifyFailedTriggers( e );
  
          }
          catch( final Exception e )
          {
              final String message = "Exception occured executing trigger " + entry.getName();
              getLogger().warn( message, e );
              notifyFailedTriggers( e );
          }
      }
  
      /**
       * Retrieve next valid entry. It will pop off any
       * invalid entrys until the heap is empty or a valid entry
       * is found.
       *
       * @return the next valid entry or null if none
       */
      protected synchronized TimeScheduledEntry getNextEntry()
      {
          TimeScheduledEntry entry =
              (TimeScheduledEntry)getPriorityQueue().peek();
  
          //if job has been invalidated then remove it and continue
          while( !entry.isValid() )
          {
              getPriorityQueue().pop();
  
              if( getPriorityQueue().isEmpty() )
              {
                  return null;
              }
  
              entry = (TimeScheduledEntry)getPriorityQueue().peek();
          }
  
          return entry;
      }
  
      protected void notifyFailedTriggers( Throwable t )
      {
          for( int i = 0; i < getTriggerFailureListeners().size(); i++ )
          {
              TriggerFailureListener triggerFailureListener = (TriggerFailureListener)m_triggerFailureListeners.get( i );
              triggerFailureListener.triggerFailure( t );
          }
  
      }
  }
  
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/DefaultTimeScheduler.xinfo
  
  Index: DefaultTimeScheduler.xinfo
  ===================================================================
  <?xml version="1.0"?>
  <!DOCTYPE blockinfo PUBLIC "-//PHOENIX/Block Info DTD Version 1.0//EN"
                    "http://jakarta.apache.org/avalon/dtds/phoenix/blockinfo_1_0.dtd">
  
  <blockinfo>
    <block>
      <version>1.0</version>
    </block>
    <services>
      <service name="org.apache.avalon.cornerstone.services.scheduler.TimeScheduler"/>
    </services>
    <management-access-points>
       <service name="org.apache.avalon.cornerstone.blocks.scheduler.MonitorableTimeSchedulerMBean"/>
    </management-access-points>
    <dependencies>
      <dependency>
        <service name="org.apache.avalon.cornerstone.services.threads.ThreadManager"/>
      </dependency>
    </dependencies>
  </blockinfo>
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/MonitorableTimeScheduler.java
  
  Index: MonitorableTimeScheduler.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.blocks.scheduler;
  
  /**
   * A JMX Monitorable TimeScheduler.
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public class MonitorableTimeScheduler extends DefaultTimeScheduler
      implements MonitorableTimeSchedulerMBean
  {
  }
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/MonitorableTimeSchedulerMBean.java
  
  Index: MonitorableTimeSchedulerMBean.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.blocks.scheduler;
  
  import java.util.Collection;
  
  /**
   */
  public interface MonitorableTimeSchedulerMBean
  {
  
      /**
       * The triggerable names.
       * @return The triggerable names
       */
      Collection getEntries();
  }
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/PriorityQueue.java
  
  Index: PriorityQueue.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.blocks.scheduler;
  
  import java.util.NoSuchElementException;
  
  /**
   * Iterface for priority queues.
   * This interface does not dictate whether it is min or max heap.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   * @version CVS $Revision: 1.1 $ $Date: 2004/03/16 12:49:52 $
   * @since 4.0
   */
  public interface PriorityQueue
  {
      /**
       * Clear all elements from queue.
       */
      void clear();
  
      /**
       * Test if queue is empty.
       *
       * @return true if queue is empty else false.
       */
      boolean isEmpty();
  
      /**
       * Insert an element into queue.
       *
       * @param element the element to be inserted
       */
      void insert( Object element );
  
      /**
       * Return element on top of heap but don't remove it.
       *
       * @return the element at top of heap
       * @throws NoSuchElementException if isEmpty() == true
       */
      Object peek() throws NoSuchElementException;
  
      /**
       * Return element on top of heap and remove it.
       *
       * @return the element at top of heap
       * @throws NoSuchElementException if isEmpty() == true
       */
      Object pop() throws NoSuchElementException;
  }
  
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/SynchronizedPriorityQueue.java
  
  Index: SynchronizedPriorityQueue.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.blocks.scheduler;
  
  import java.util.NoSuchElementException;
  
  /**
   * A thread safe version of the PriorityQueue.
   * Provides synchronized wrapper methods for all the methods
   * defined in the PriorityQueue interface.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   * @version CVS $Revision: 1.1 $ $Date: 2004/03/16 12:49:52 $
   * @since 4.0
   */
  public final class SynchronizedPriorityQueue
      implements PriorityQueue
  {
      private final PriorityQueue m_priorityQueue;
  
      public SynchronizedPriorityQueue( final PriorityQueue priorityQueue )
      {
          if( null == priorityQueue )
          {
              throw new NullPointerException( "priorityQueue" );
          }
          m_priorityQueue = priorityQueue;
      }
  
      /**
       * Clear all elements from queue.
       */
      public void clear()
      {
          synchronized( m_priorityQueue )
          {
              m_priorityQueue.clear();
          }
      }
  
      /**
       * Test if queue is empty.
       *
       * @return true if queue is empty else false.
       */
      public boolean isEmpty()
      {
          synchronized( m_priorityQueue )
          {
              return m_priorityQueue.isEmpty();
          }
      }
  
      /**
       * Insert an element into queue.
       *
       * @param element the element to be inserted
       */
      public void insert( final Object element )
      {
          synchronized( m_priorityQueue )
          {
              m_priorityQueue.insert( element );
          }
      }
  
      /**
       * Return element on top of heap but don't remove it.
       *
       * @return the element at top of heap
       * @throws NoSuchElementException if isEmpty() == true
       */
      public Object peek() throws NoSuchElementException
      {
          synchronized( m_priorityQueue )
          {
              return m_priorityQueue.peek();
          }
      }
  
      /**
       * Return element on top of heap and remove it.
       *
       * @return the element at top of heap
       * @throws NoSuchElementException if isEmpty() == true
       */
      public Object pop() throws NoSuchElementException
      {
          synchronized( m_priorityQueue )
          {
              return m_priorityQueue.pop();
          }
      }
  
      public String toString()
      {
          synchronized( m_priorityQueue )
          {
              return m_priorityQueue.toString();
          }
      }
  }
  
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/TimeScheduledEntry.java
  
  Index: TimeScheduledEntry.java
  ===================================================================
  /* 
   * Copyright 1999-2004 The Apache Software Foundation
   * Licensed  under the  Apache License,  Version 2.0  (the "License");
   * you may not use  this file  except in  compliance with the License.
   * You may obtain a copy of the License at 
   * 
   *   http://www.apache.org/licenses/LICENSE-2.0
   * 
   * Unless required by applicable law or agreed to in writing, software
   * distributed  under the  License is distributed on an "AS IS" BASIS,
   * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
   * implied.
   * 
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package org.apache.avalon.cornerstone.blocks.scheduler;
  
  import java.text.SimpleDateFormat;
  import java.util.Date;
  import org.apache.avalon.cornerstone.services.scheduler.Target;
  import org.apache.avalon.cornerstone.services.scheduler.TimeTrigger;
  
  /**
   * Class use internally to package to hold scheduled time entries.
   *
   * @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
   */
  public final class TimeScheduledEntry
      implements Comparable
  {
      private static final SimpleDateFormat DATEFORMAT = new SimpleDateFormat();
  
      private final String m_name;
      private final TimeTrigger m_trigger;
      private final Target m_target;
  
      //cached version of time from TimeTrigger class
      private long m_time;
      private boolean m_isValid;
  
      public TimeScheduledEntry( String name, TimeTrigger trigger, Target target )
      {
          m_name = name;
          m_trigger = trigger;
          m_target = target;
          //m_time = m_trigger.getTimeAfter( System.currentTimeMillis() );
          m_isValid = true;
      }
  
      /**
       * Return name of trigger.
       *
       * @return the name of trigger
       */
      public String getName()
      {
          return m_name;
      }
  
      public Target getTarget()
      {
          return m_target;
      }
  
      public TimeTrigger getTimeTrigger()
      {
          return m_trigger;
      }
  
      /**
       * Determine if this entry is valid
       *
       * @return true if trigger is valid, false otherwise
       */
      public boolean isValid()
      {
          return m_isValid;
      }
  
      /**
       * Invalidate trigger
       */
      public void invalidate()
      {
          m_isValid = false;
      }
  
      /**
       * Retrieve cached time when trigger should run next.
       *
       * @return the time in milliseconds when trigger should run
       */
      public long getNextTime()
      {
          return m_time;
      }
  
      /**
       * Set cached time in milliseconds when trigger should run
       *
       * @param time the time
       */
      public void setNextTime( long time )
      {
          m_time = time;
      }
  
      /**
       * Implement comparable interface used to help sort triggers.
       * Triggers are compared based on next time to run
       *
       * @param object the other trigger
       * @return -'ve value if other trigger occurs before this trigger
       */
      public int compareTo( final Object object )
      {
          final TimeScheduledEntry other = (TimeScheduledEntry)object;
          return (int)-( other.m_time - m_time );
      }
  
      public String toString()
      {
          return "TimeEntry[ name=" + m_name + " valid=" + m_isValid + " time=" + DATEFORMAT.format( new Date( m_time ) ) + " ]";
      }
  }
  
  
  
  
  1.1                  avalon-components/cornerstone/scheduler/impl/src/java/org/apache/avalon/cornerstone/blocks/scheduler/package.html
  
  Index: package.html
  ===================================================================
  <body>
  Default implementation of a scheduler manager.
  </body>
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: cvs-unsubscribe@avalon.apache.org
For additional commands, e-mail: cvs-help@avalon.apache.org