001package com.hfg.util.scheduler; 002 003import java.util.Date; 004import java.util.logging.Level; 005import java.util.logging.Logger; 006 007import com.hfg.util.StringUtil; 008 009//------------------------------------------------------------------------------ 010/** 011 Runs specified job on a specified schedule. 012 <div> 013 @author J. Alex Taylor, hairyfatguy.com 014 </div> 015 */ 016//------------------------------------------------------------------------------ 017// com.hfg Library 018// 019// This library is free software; you can redistribute it and/or 020// modify it under the terms of the GNU Lesser General Public 021// License as published by the Free Software Foundation; either 022// version 2.1 of the License, or (at your option) any later version. 023// 024// This library is distributed in the hope that it will be useful, 025// but WITHOUT ANY WARRANTY; without even the implied warranty of 026// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 027// Lesser General Public License for more details. 028// 029// You should have received a copy of the GNU Lesser General Public 030// License along with this library; if not, write to the Free Software 031// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 032// 033// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 034// jataylor@hairyfatguy.com 035//------------------------------------------------------------------------------ 036 037public class ScheduledJob implements Runnable 038{ 039 private String mName; 040 private Runnable mJob; 041 private Schedule mSchedule; 042 private Thread mThread; 043 private boolean mIsActive = true; // Should this job still be managed by the Scheduler 044 private boolean mIsPaused = false; 045 private boolean mIsCurrentlyExecuting = false; 046 private boolean mExecuteNow = false; 047 private Date mLastExecutionStartDate; 048 049 private final static Logger LOGGER = Logger.getLogger(Scheduler.class.getPackage().getName()); 050 051 //########################################################################### 052 // CONSTRUCTORS 053 //########################################################################### 054 055 //------------------------------------------------------------------------ 056 public ScheduledJob(Runnable inJob, Schedule inSchedule) 057 { 058 mJob = inJob; 059 mSchedule = inSchedule; 060 } 061 062 //########################################################################### 063 // PUBLIC METHODS 064 //########################################################################### 065 066 //------------------------------------------------------------------------ 067 public ScheduledJob setName(String inValue) 068 { 069 mName = inValue; 070 return this; 071 } 072 073 //------------------------------------------------------------------------ 074 public String name() 075 { 076 return (StringUtil.isSet(mName) ? mName : mJob.getClass().getSimpleName()); 077 } 078 079 //------------------------------------------------------------------------ 080 @Override 081 public String toString() 082 { 083 return name(); 084 } 085 086 //------------------------------------------------------------------------ 087 public Runnable getJob() 088 { 089 return mJob; 090 } 091 092 //------------------------------------------------------------------------ 093 public Schedule getSchedule() 094 { 095 return mSchedule; 096 } 097 098 //------------------------------------------------------------------------ 099 public Thread getThread() 100 { 101 return mThread; 102 } 103 104 //------------------------------------------------------------------------ 105 public Date getLastExecutionStartDate() 106 { 107 return mLastExecutionStartDate; 108 } 109 110 //------------------------------------------------------------------------ 111 public void start() 112 { 113 if (null == mThread) 114 { 115 mThread = new Thread(this); 116 mThread.setName(name()); 117 mThread.start(); 118 } 119 120 mIsActive = true; 121 } 122 123 //------------------------------------------------------------------------ 124 public void stop() 125 { 126 mIsActive = false; 127 mThread.interrupt(); 128 } 129 130 //------------------------------------------------------------------------ 131 public void pause() 132 { 133 mIsPaused = true; 134 } 135 136 //------------------------------------------------------------------------ 137 public void resume() 138 { 139 mIsPaused = false; 140 } 141 142 //------------------------------------------------------------------------ 143 public void executeNow() 144 { 145 if (! mIsCurrentlyExecuting) 146 { 147 mExecuteNow = true; 148 mThread.interrupt(); 149 } 150 } 151 152 //------------------------------------------------------------------------ 153 public void run() 154 { 155 while (mIsActive) 156 { 157 try 158 { 159 Date nextScheduledExecutionTime = mSchedule.next(); 160 if (nextScheduledExecutionTime != null) 161 { 162 if (! mExecuteNow) 163 { 164 LOGGER.log(Level.FINE, "Next scheduled execution time: " + nextScheduledExecutionTime); 165 166 // Just sleep until it is time to execute this job again 167 Thread.sleep(nextScheduledExecutionTime.getTime() - System.currentTimeMillis()); 168 169 } 170 171 if (mIsPaused 172 && ! mExecuteNow) 173 { 174 LOGGER.log(Level.FINE, "Skipping this execution instance since this job is currently paused."); 175 } 176 else 177 { 178 mExecuteNow = false; 179 mIsCurrentlyExecuting = true; 180 mLastExecutionStartDate = new Date(); 181 182 mJob.run(); 183 } 184 } 185 } 186 catch (InterruptedException e) 187 { 188 // Ignore 189 } 190 catch (Throwable e2) 191 { 192 e2.printStackTrace(); 193 //TODO: Have the scheduler log the exception 194 } 195 } 196 197 LOGGER.log(Level.INFO, "Scheduled job " + mJob.getClass().getSimpleName() + " is exiting and will no longer be run."); 198 } 199 200}