View Javadoc

1   /***
2    * @(#)TaskScheduler.java
3    * 
4    * JFoxSOAF, Service-Oriented Application Framework
5    * 
6    * Copyright(c) JFoxSOAF Team
7    * 
8    * Licensed under the GNU LGPL, Version 2.1 (the "License"); 
9    * you may not use this file except in compliance with the License. 
10   * You may obtain a copy of the License at  
11   * 
12   * http://www.gnu.org/copyleft/lesser.html
13   * 
14   * Unless required by applicable law or agreed to in writing, software
15   * distributed under the License is distributed on an "AS IS" BASIS, 
16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
17   * See the License for the specific language governing permissions and 
18   * limitations under the License. 
19   * 
20   * For more information, please visit:
21   * http://www.jfox.cn/confluence/display/JFoxSOAF/Home
22   * http://www.huihoo.org/jfox/jfoxsoaf
23   */
24  
25  package org.huihoo.jfox.soaf.services.timer;
26  
27  import java.util.ArrayList;
28  import java.util.Date;
29  import java.util.Timer;
30  import java.util.TimerTask;
31  
32  /***
33   * Class for running Tasks with scheduling/thread pooling etc. <br>
34   * <p>
35   * The tasks are Task objects. A user would extend the Task class and override
36   * the abstract methods ( e.g. its run() method ).
37   * </p>
38   * <p>
39   * Persistence of the Task objects allows the TaskScheduler to be shutdown and
40   * restarted with all the scheduled tasks read from storage.
41   * </p>
42   * 
43   * @author <a href="mailto:founder_chen@yahoo.com.cn">Peter Cheng </a>
44   * @author <a href="mailto:berkovichnyc@hotmail.com">Efraim Berkovich </a>
45   * @version $Revision: 1.1 $ $Date: 2005/05/22 06:52:07 $
46   * @version Revision: 1.0
47   */
48  
49  public class SimpleTimerServiceImpl implements SimpleTimerService {
50  
51      // instance variables
52      private Timer schedulerThread;
53  
54      private ArrayList taskList;
55  
56      private long initTime;
57  
58      private TaskPersistStrategy persistStrategy = null;
59  
60      //  static variables
61      private static Boolean semaphore = new Boolean(true);
62  
63      /***
64       * Shutdown the scheduler
65       */
66      public void shutdown() {
67          synchronized (semaphore) {
68              this.schedulerThread.cancel();
69          }
70      }
71  
72      /***
73       * Create a task scheduler with a default thread pool size.
74       */
75      public SimpleTimerServiceImpl() {
76          schedulerThread = new Timer(false);
77          initTime = System.currentTimeMillis();
78          taskList = new ArrayList();
79      }
80  
81      /***
82       * Set the particular methodology for persisting Tasks
83       * 
84       * @param strategy The TaskPersistStrategy to use
85       */
86      public void setPersistStrategy(TaskPersistStrategy strategy) {
87          synchronized (this) {
88              persistStrategy = strategy;
89          }
90      }
91  
92      /***
93       * Get the time the TaskScheduler was started.
94       * 
95       * @return the time (in millis) when the Scheduler was started.
96       */
97      public long getSchedulerStartTime() {
98          return initTime;
99      }
100 
101     /***
102      * Schedules the specified task for execution according to the task's
103      * scheduling properties.
104      * 
105      * @param task The task to schedule for execution.
106      * @exception IllegalStateException if task was already scheduled or
107      *                cancelled, timer was cancelled, or timer thread
108      *                terminated.
109      * @exception Exception if cannot persist task
110      */
111     public void schedule(Task task) throws IllegalStateException, Exception {
112         synchronized (this) {
113             cleanupAll();
114             if (taskList.contains(task))
115                 throw new IllegalStateException("Task was already scheduled");
116 
117             Date time = new Date(task.getScheduledFirstTime());
118 
119             RunTask runTask = new RunTask(task);
120 
121             if (task.getScheduledInterval() <= 0) {
122                 schedulerThread.schedule(runTask, time);
123             } else {
124                 schedulerThread.scheduleAtFixedRate(runTask, time, task
125                         .getScheduledInterval());
126             }
127 
128             task.scheduler = this;
129             taskList.add(task);
130 
131             this.persist(task);
132         }
133     }
134 
135     /***
136      * Cancel all executing tasks and timer threads.
137      * 
138      * @param withRestart if true, all timer threads will restart; however, all
139      *            scheduled task will have been cancelled.
140      */
141     public void cancelAll(boolean withRestart) {
142         synchronized (this) {
143             taskList.clear();
144             schedulerThread.cancel();
145 
146             if (withRestart)
147                 schedulerThread = new Timer(false);
148         }
149     }
150 
151     /***
152      * Fetch all non-cancelled tasks at the time the method is called. If tasks
153      * are cancelling during this time, some cancelled tasks may be returned.
154      * 
155      * @return array of Tasks which are not cancelled
156      */
157     public Task[] getRunningTasks() {
158         ArrayList list = new ArrayList();
159         cleanupAll();
160 
161         synchronized (this) {
162             for (int i = 0; i < taskList.size(); i++) {
163                 Task task = (Task) taskList.get(i);
164                 if (!task.isCancelled()) {
165                     list.add(task);
166                 }
167             }
168         }
169         Task[] out = new Task[list.size()];
170         for (int i = 0; i < out.length; i++)
171             out[i] = (Task) list.get(i);
172 
173         return out;
174     }
175 
176     /***
177      * Find a particular task by its ID
178      * 
179      * @param taskID The task to find
180      * @return Task for this ID or null if not found
181      */
182     public Task findTaskByID(long taskID) {
183         synchronized (this) {
184             for (int i = 0; i < taskList.size(); i++) {
185                 Task task = (Task) taskList.get(i);
186                 if (task.getID() == taskID) {
187                     return task;
188                 }
189             }
190         }
191         return null;
192     }
193 
194     /***
195      * Check and remove a particular task
196      * 
197      * @param Task the potentially cancelled task to remove
198      */
199     void cleanup(Task task) {
200         synchronized (this) {
201             if (taskList.contains(task)) {
202                 if (task.isCancelled()) {
203                     taskList.remove(task);
204                     if (persistStrategy != null)
205                         persistStrategy.delete(task);
206                 }
207             }
208         }
209     }
210 
211     /***
212      * Persists the task by telling the persist strategy to do so
213      * 
214      * @exception various possible depending on strategy
215      */
216     void persist(Task task) throws Exception {
217         synchronized (this) {
218             if (persistStrategy != null)
219                 persistStrategy.write(task);
220         }
221     }
222 
223     /***
224      * Go through the taskList and eliminate cancelled tasks
225      */
226     private void cleanupAll() {
227         synchronized (this) {
228             for (int i = 0; i < taskList.size(); i++) {
229                 Task task = (Task) taskList.get(i);
230                 if (task.isCancelled()) {
231                     taskList.remove(i);
232                     if (persistStrategy != null)
233                         persistStrategy.delete(task);
234                     i--;
235                 }
236             }
237         }
238     }
239 
240     /***
241      * RunTask class is scheduler to on the Timer and is associated with a Task
242      * which it runs.
243      */
244     private class RunTask extends TimerTask {
245         // instance variables
246         private Task task;
247 
248         /***
249          * Create a new RunTask
250          * 
251          * @param task The Task to run
252          */
253         public RunTask(Task task) {
254             this.task = task;
255         }
256 
257         /***
258          * Run the Task
259          */
260         public void run() {
261             if (task.isCancelled()) {
262                 this.cancel();
263                 return;
264             }
265 
266             // NOTE: TBD
267             //    For now we just launch a thread to do the task.
268             //    This is potentially not scaleable. In the future,
269             //    we will pick threads from a pool.
270 
271             Thread runner = new Thread(task);
272             runner.start();
273             task.setLastRunTime(System.currentTimeMillis());
274         }
275 
276     }
277 
278 }