KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > applications > crontab > CronDaemon


1 /*
2  This software is OSI Certified Open Source Software.
3 OSI Certified is a certification mark of the Open Source Initiative.
4
5 The license (Mozilla version 1.0) can be read at the MMBase site.
6 See http://www.MMBase.org/license
7  */

8 package org.mmbase.applications.crontab;
9
10 import java.util.*;
11 import org.mmbase.util.logging.*;
12
13 /**
14  * CronDaemon is a "crontab" clone written in java.
15  * The daemon starts a thread that wakes up every minute
16  *(it keeps sync by calculating the time to sleep)
17  *
18  * @author Kees Jongenburger
19  * @author Michiel Meeuwissen
20  */

21 public class CronDaemon {
22
23     private static final Logger log = Logging.getLoggerInstance(CronDaemon.class);
24
25     private TimerTask task;
26
27     private static CronDaemon cronDaemon;
28     private Timer cronTimer;
29     private Set cronEntries;
30     private Set removedCronEntries;
31     private Set addedCronEntries;
32
33     /**
34      * CronDaemon is a Singleton. This makes the one instance and starts the Thread.
35      */

36     private CronDaemon() {
37         cronEntries = Collections.synchronizedSet(new LinkedHashSet()); // predictable order
38
removedCronEntries = Collections.synchronizedSet(new HashSet());
39         addedCronEntries = Collections.synchronizedSet(new LinkedHashSet()); // predictable order
40
start();
41     }
42
43     /**
44      * Finds in given set the CronEntry with the given id.
45      * @return a CronEntry if found, <code>null</code> otherwise.
46      */

47     protected static CronEntry getById(Set set, String JavaDoc id) {
48         Iterator i = set.iterator();
49         while (i.hasNext()) {
50             CronEntry entry = (CronEntry)i.next();
51             if (entry.getId().equals(id))
52                 return entry;
53         }
54         return null;
55     }
56
57     /**
58      * Adds the given CronEntry to this daemon.
59      * @throws RuntimeException If an entry with the same id is present already (unless it is running and scheduled for removal already)
60      */

61
62     public void add(CronEntry entry) {
63         CronEntry containing = getById(cronEntries, entry.getId());
64         if (containing != null) {
65             if (removedCronEntries.contains(containing)) {
66                 addedCronEntries.add(entry);
67                 // do copy the 'crontime' allready.
68
containing.setCronTime(entry.getCronTime());
69                 return;
70             } else {
71                 throw new RuntimeException JavaDoc("There is an entry " + entry + " already");
72             }
73         } else {
74             addEntry(entry);
75         }
76
77     }
78
79     /**
80      * Actually adds, no checks for 'removedEntries' and so on.
81      */

82     protected void addEntry(CronEntry entry) {
83         entry.init();
84         cronEntries.add(entry);
85         log.service("Added entry " + entry);
86     }
87
88     public CronEntry getCronEntry(String JavaDoc id) {
89         return getById(cronEntries, id);
90     }
91     /**
92      * Remove the given CronEntry from this daemon. If the entry is currently running, it will be
93      * postponed until this job is ready.
94      */

95     public void remove(CronEntry entry) {
96         if (!entry.isAlive()) {
97             removeEntry(entry);
98         } else {
99             // it is alive, only schedule for removal.
100
removedCronEntries.add(entry);
101         }
102     }
103
104     /**
105      * Actually removes, nor checks for removedEntries' and so on.
106      */

107     protected void removeEntry(CronEntry entry) {
108         cronEntries.remove(entry);
109         entry.stop();
110         log.service("Removed entry " + entry);
111     }
112
113     /**
114      * Starts the daemon, which you might want to do if you have stopped if for some reason. The
115      * daemon is already started on default.
116      */

117     public void start() {
118         log.info("Starting CronDaemon");
119         cronTimer = new Timer(true);
120         cronTimer.scheduleAtFixedRate(new TimerTask() { public void run() {CronDaemon.this.run();} }, 0, 60 * 1000);
121     }
122
123     /**
124      * If you like to temporary stop the daemon, call this.
125      */

126     public void stop() {
127         log.info("Stopping CronDaemon");
128         cronTimer.cancel();
129         cronTimer = null;
130         Iterator i = cronEntries.iterator();
131         while (i.hasNext()) {
132             CronEntry entry = (CronEntry)i.next();
133             entry.stop();
134         }
135     }
136
137     public boolean isAlive() {
138         return cronTimer != null;
139     }
140
141     /**
142      * Singleton, Gets (and instantiates, and starts) the one CronDaemon instance.
143      */

144
145     public static synchronized CronDaemon getInstance() {
146         if (cronDaemon == null) {
147             cronDaemon = new CronDaemon();
148         }
149         return cronDaemon;
150     }
151
152     /**
153      * The main loop of the daemon, which of course is a Thread, implemented in run() to satisfy the
154      * 'Runnable' interface.
155      */

156     public void run() {
157         long now = System.currentTimeMillis();
158         try {
159             Date currentMinute = new Date(now / 60000 * 60000);
160
161             if (log.isDebugEnabled()) {
162                 log.debug("Checking for " + currentMinute);
163             }
164
165             // remove jobs which were scheduled for removal
166
Iterator z = removedCronEntries.iterator();
167             while (z.hasNext()) {
168                 CronEntry entry = (CronEntry)z.next();
169                 if (entry.isAlive()) {
170                     if (log.isDebugEnabled()) {
171                         log.debug("Job " + entry + " still running, so could not yet be removed");
172                     }
173                 } else {
174                     removeEntry(entry);
175                     z.remove();
176                     CronEntry added = getById(addedCronEntries, entry.getId());
177                     if (added != null) {
178                         addEntry(added);
179                         addedCronEntries.remove(added);
180                     }
181                 }
182             }
183             // start jobs which need starting on this minute
184
z = cronEntries.iterator();
185             while (z.hasNext()) {
186                 if (Thread.currentThread().isInterrupted()) return;
187                 CronEntry entry = (CronEntry)z.next();
188                 if (entry.mustRun(currentMinute)) {
189                     if (entry.kick()) {
190                         if (log.isDebugEnabled()) {
191                             log.debug("Started " + entry);
192                         }
193                     } else {
194                         log.warn("Job " + entry + " still running, so not restarting it again.");
195                     }
196                 }
197             }
198         } catch (Throwable JavaDoc t) {
199             log.error(t.getClass().getName() + " " + t.getMessage(), t);
200         }
201     }
202
203     /**
204      * @since MMBase-1.8
205      */

206     public Set getEntries() {
207         return Collections.unmodifiableSet(cronEntries);
208     }
209
210     /**
211      * main only for testing purposes
212      */

213
214     public static void main(String JavaDoc[] argv) throws Exception JavaDoc {
215         CronDaemon d = CronDaemon.getInstance();
216
217         //d.add(new CronEntry("20 10 31 8 *","happy birthday",null));
218
//d.add(new CronEntry("* * * * 1","monday",null));
219
//d.add(new CronEntry("* * * * 2","tuesday",null));
220

221         //d.add(new CronEntry("* * 19 * *","the 19'st day of the month",null));
222

223         //d.add(new CronEntry("* * * 1 *","the first month of the year",null));
224
//d.add(new CronEntry("*/2 * * * *","every 2 minutes stating from 0",null));
225
//d.add(new CronEntry("1-59/2 * * * *","every 2 minutes stating from 1",null));
226
d.add(new CronEntry("1", "*/2 5-23 * * *", "every 2 minute from 5 till 11 pm", "org.mmbase.applications.crontab.TestCronJob", null));
227         //d.add(new CronEntry("40-45,50-59 * * * *","test 40-45,50-60","Dummy",null));
228

229         try {
230             Thread.sleep(240 * 1000 * 60);
231         } catch (Exception JavaDoc e) {};
232         d.stop();
233     }
234 }
235
Popular Tags