/* * Weblounge: Web Content Management System * Copyright (c) 2003 - 2011 The Weblounge Team * http://entwinemedia.com/weblounge * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package ch.entwine.weblounge.common.impl.scheduler; import ch.entwine.weblounge.common.scheduler.JobTrigger; import java.util.Date; /** * This trigger will fire a job periodically. The next period starts when the * job's last execution finished. */ public class PeriodicJobTrigger implements JobTrigger { /** The start time */ private long startTime = -1; /** The end time */ private long endTime = -1; /** Number of times to fire */ private long repeatCount = -1; /** Number of times the trigger has been fired */ private long triggerCount = 0; /** The period in milliseconds */ private long period = -1; /** Flag indicating whether to wait a period for the first execution */ private boolean startImmediately = false; /** True if this is the first execution */ private boolean firstExecution = true; /** * Creates a new <code>PeriodicJob</code> with the given name and period. The * job starts <code>period</code> milliseconds from now. * * @param period * the period in milliseconds at which the job should be executed * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public PeriodicJobTrigger(long period) throws IllegalArgumentException { this(period, new Date(), null, false); } /** * Creates a new <code>PeriodicJob</code> with the given name and period. The * job starts <code>period</code> milliseconds from now. * * @param period * the period in milliseconds at which the job should be executed * @param startImmediately * <code>true</code> if the first execution should be right now * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public PeriodicJobTrigger(long period, boolean startImmediately) throws IllegalArgumentException { this(period, new Date(), null, startImmediately); } /** * Creates a new <code>PeriodicJob</code> with the given name and period. The * job starts execution at the given time. * * @param name * the name of the job * @param period * the period in milliseconds at which the job should be executed * @param startTime * the start time of the job * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public PeriodicJobTrigger(long period, Date startTime) throws IllegalArgumentException { this(period, startTime, null, -1, false); } /** * Creates a new <code>PeriodicJob</code> with the given name and period. The * job starts execution at the given time. * * @param name * the name of the job * @param period * the period in milliseconds at which the job should be executed * @param startTime * the start time of the job * @param startImmediately * <code>true</code> if the first execution should be right now * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public PeriodicJobTrigger(long period, Date startTime, boolean startImmediately) throws IllegalArgumentException { this(period, startTime, null, -1, startImmediately); } /** * Creates a new <code>PeriodicJob</code> with the given name and period. The * job starts execution at the given time and ends at or before * <code>endTime</code>. If <code>endTime</code> is set to <code>null</code>, * this trigger will fire forever or until it has reached the repeat count set * using <code>setRepeatCount()</code>. * * @param name * the name of the job * @param period * the period in milliseconds at which the job should be executed * @param startTime * the start time of the job * @param endTime * the end time of the job * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public PeriodicJobTrigger(long period, Date startTime, Date endTime) throws IllegalArgumentException { this(period, startTime, endTime, -1, false); } /** * Creates a new <code>PeriodicJob</code> with the given name and period. The * job starts execution at the given time and ends at or before * <code>endTime</code>. If <code>endTime</code> is set to <code>null</code>, * this trigger will fire forever or until it has reached the repeat count set * using <code>setRepeatCount()</code>. * * @param name * the name of the job * @param period * the period in milliseconds at which the job should be executed * @param startTime * the start time of the job * @param endTime * the end time of the job * @param startImmediately * <code>true</code> if the first execution should be right now * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public PeriodicJobTrigger(long period, Date startTime, Date endTime, boolean startImmediately) throws IllegalArgumentException { this(period, startTime, endTime, -1, startImmediately); } /** * Creates a new <code>PeriodicJob</code> with the given name and period. The * job starts execution at the given time and ends at or before * <code>endTime</code>. If <code>endTime</code> is set to <code>null</code>, * this trigger will fire forever or until it has reached the repeat count set * using <code>setRepeatCount()</code>. * * @param name * the name of the job * @param period * the period in milliseconds at which the job should be executed * @param startTime * the start time of the job * @param endTime * the end time of the job * @param repeat * number of times that this trigger should be executed * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public PeriodicJobTrigger(long period, Date startTime, Date endTime, long repeat) throws IllegalArgumentException { this(period, startTime, endTime, repeat, false); } /** * Creates a new <code>PeriodicJob</code> with the given name and period. The * job starts execution at the given time and ends at or before * <code>endTime</code>. If <code>endTime</code> is set to <code>null</code>, * this trigger will fire forever or until it has reached the repeat count set * using <code>setRepeatCount()</code>. * * @param name * the name of the job * @param period * the period in milliseconds at which the job should be executed * @param startTime * the start time of the job * @param endTime * the end time of the job * @param repeat * number of times that this trigger should be executed * @param startImmediately * <code>true</code> if the first execution should be right now * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public PeriodicJobTrigger(long period, Date startTime, Date endTime, long repeat, boolean startImmediately) throws IllegalArgumentException { if (period <= 1) throw new IllegalArgumentException("Period needs to be a positive integer"); this.period = period; this.startTime = startTime != null ? startTime.getTime() : System.currentTimeMillis(); this.endTime = endTime != null ? endTime.getTime() : -1; this.repeatCount = repeat; this.startImmediately = startImmediately; } /** * {@inheritDoc} * * @see java.lang.Object#clone() */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * {@inheritDoc} * * @see ch.entwine.weblounge.common.scheduler.JobTrigger#getNextExecutionAfter(Date) */ public Date getNextExecutionAfter(Date date) { if (endTime != -1 && date.getTime() >= endTime) return null; if (repeatCount != -1 && triggerCount >= repeatCount) return null; if (date.getTime() < startTime) return new Date(startTime); long nextExecution = 0; long triggerCount = (long) Math.floor((date.getTime() - startTime) / period); if (triggerCount == 0 && startImmediately && firstExecution) nextExecution = startTime; else nextExecution = startTime + (triggerCount + 1) * period; firstExecution = false; return new Date(nextExecution); } /** * {@inheritDoc} * * @see ch.entwine.weblounge.common.scheduler.JobTrigger#triggered(java.util.Date) */ public void triggered(Date date) { triggerCount++; if (endTime > -1 && date.getTime() > date.getTime()) throw new IllegalStateException("Trigger was not supposed to be fired after " + new Date(endTime)); if (repeatCount > -1 && triggerCount > repeatCount) throw new IllegalStateException("Trigger was not supposed to called more than " + repeatCount + " times"); } /** * Returns the period in milliseconds. * * @return the period */ public long getPeriod() { return period; } /** * Sets the period for this trigger. * * @param period * the new period for this periodic job in milliseconds * @throws IllegalArgumentException * if the period is smaller are equal to zero */ public void setPeriod(long period) { if (period <= 1) throw new IllegalArgumentException("Period needs to be a positive integer"); this.period = period; } /** * Sets the number of times that this trigger will fire, given that it doesn't * reach the end time. * * @param repeatCount * number of times to fire */ public void setRepeatCount(long repeatCount) { this.repeatCount = repeatCount; } /** * Returns the number of times that this trigger will fire or <code>-1</code> * if it should fire indefinitely or until it reaches the end time. * * @return the number of times to fire */ public long getRepeatCount() { return repeatCount; } /** * Returns <code>true</code> if the first execution is right now rather than * after the first period of time has passed. * * @return the startImmediately <code>true</code> if the trigger fires right * now for the first time */ public boolean getStartsImmediately() { return startImmediately; } /** * Sets the first trigger execution to either <code>now</code> or * <code>now + period</code>. * * @param startImmediately * <code>true</code> to execute the trigger right now for the first * time */ public void setStartImmediately(boolean startImmediately) { this.startImmediately = startImmediately; } /** * {@inheritDoc} * * @see ch.entwine.weblounge.common.scheduler.JobTrigger#reset() */ public void reset() { triggerCount = 0; firstExecution = true; } /** * {@inheritDoc} * * @see java.lang.Object#toString() */ @Override public String toString() { return "Periodic job trigger [period=" + period + " ms]"; } }