2 * Copyright (C) 2001, 2002 The Mir-coders group
4 * This file is part of Mir.
6 * Mir is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Mir is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Mir; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * In addition, as a special exception, The Mir-coders gives permission to link
21 * the code of this program with any library licensed under the Apache Software License,
22 * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
23 * (or with modified versions of the above that use the same license as the above),
24 * and distribute linked combinations including the two. You must obey the
25 * GNU General Public License in all respects for all of the code used other than
26 * the above mentioned libraries. If you modify this file, you may extend this
27 * exception to your version of the file, but you are not obligated to do so.
28 * If you do not wish to do so, delete this exception statement from your version.
31 package mircoders.global;
34 import java.util.Date;
35 import java.util.GregorianCalendar;
36 import java.util.HashMap;
37 import java.util.Iterator;
38 import java.util.List;
44 // important: objects passed as data must not be altered once put into a job
46 public class JobQueue {
47 private Vector jobHandlers;
48 private Map identifierToJobHandler;
50 private int jobCleanupTreshold;
51 private JobQueueRunner queueRunner;
52 private Thread thread;
53 private LoggerWrapper logger;
55 public static final int STATUS_CREATED = -1;
56 public static final int STATUS_PENDING = 0;
57 public static final int STATUS_PROCESSING = 1;
58 public static final int STATUS_PROCESSED = 2;
59 public static final int STATUS_CANCELLED = 3;
60 public static final int STATUS_ABORTED = 4;
62 public static final int PRIORITY_NORMAL = 100;
63 public static final int PRIORITY_LOW = 10;
64 public static final int PRIORITY_HIGH = 1000;
66 public static final int FINISHEDJOBS_LOGSIZE = 10;
68 public JobQueue(LoggerWrapper aLogger) {
70 jobHandlers = new Vector();
71 identifierToJobHandler = new HashMap();
73 jobCleanupTreshold = 1000;
74 queueRunner = new JobQueueRunner(logger);
75 thread = new Thread(queueRunner);
79 public String appendJob(Job aJob, String aDescription) {
80 synchronized (jobHandlers) {
81 JobHandler jobHandler = new JobHandler(aJob, Integer.toString(nrJobs), aDescription);
83 jobHandlers.add(jobHandler);
84 identifierToJobHandler.put(jobHandler.getIdentifier(), jobHandler);
85 jobHandler.setPending();
87 return jobHandler.getIdentifier();
91 public List getJobsInfo() {
92 List result = new Vector();
94 synchronized (jobHandlers) {
95 Iterator i = jobHandlers.iterator();
98 result.add(((JobHandler) i.next()).getJobInfo());
105 private void cleanupJobList() {
106 synchronized (jobHandlers) {
107 Iterator i = jobHandlers.iterator();
109 Calendar tresholdCalendar = new GregorianCalendar();
110 tresholdCalendar.add(Calendar.SECOND, -jobCleanupTreshold);
111 Date treshold = tresholdCalendar.getTime();
113 while (i.hasNext()) {
114 JobHandler jobHandler = (JobHandler) i.next();
116 synchronized (jobHandler) {
117 if (jobHandler.isFinished() && jobHandler.getLastChange().before(treshold)) {
118 jobHandlers.remove(jobHandler);
125 private JobHandler acquirePendingJob() {
126 synchronized (jobHandlers) {
127 int priorityFound= 0;
131 Iterator i = jobHandlers.iterator();
132 while (i.hasNext()) {
133 JobHandler job = (JobHandler) i.next();
135 if (job.isPending() && (jobFound==null || priorityFound<job.getPriority())) {
137 priorityFound = job.getPriority();
145 public void cancelJobs(List aJobs) {
146 synchronized (jobHandlers) {
147 Iterator i = aJobs.iterator();
149 while (i.hasNext()) {
150 ((JobHandler) identifierToJobHandler.get(i.next())).cancelOrAbortJob();
155 public interface Job {
161 * @return <code>true</code> if terminated normally, <code>false</code> if aborted
166 public static class JobInfo {
167 private String identifier;
168 private Date lastChange;
170 private long runningTime;
171 private int priority;
172 private String description;
174 private JobInfo(String aDescription, int aStatus, Date aLastChange, String anIdentifier, long aRunningTime, int aPriority) {
175 description = aDescription;
176 lastChange = aLastChange;
178 identifier = anIdentifier;
179 priority = aPriority;
180 runningTime = aRunningTime;
183 public String getDescription() {
187 public int getStatus() {
191 public int getPriority() {
195 public Date getLastChange() {
199 public String getIdentifier() {
203 public long getRunningTime() {
208 public class JobHandler {
210 private String identifier;
211 private String description;
213 private Date lastChange;
214 private long starttime;
215 private long endtime;
217 private int priority;
218 private boolean hasRun;
220 public JobHandler(Job aJob, String anIdentifier, String aDescription, int aPriority) {
222 description = aDescription;
223 identifier = anIdentifier;
224 priority = aPriority;
225 status = STATUS_CREATED;
228 public JobHandler(Job aJob, String anIdentifier, String aDescription) {
229 this(aJob, anIdentifier, aDescription, PRIORITY_NORMAL);
232 public JobInfo getJobInfo() {
233 return new JobInfo(getDescription(), getStatus(), getLastChange(), getIdentifier(), getRunningTime(), priority);
236 private void runJob() {
237 if (setProcessing()) {
245 private void cancelOrAbortJob() {
246 synchronized (this) {
254 public int getStatus() {
260 public String getIdentifier() {
264 public String getDescription() {
268 public long getRunningTime() {
276 result = System.currentTimeMillis();
278 result = result - starttime;
285 public int getPriority() {
289 private boolean setProcessing() {
290 return setStatus(STATUS_PENDING, STATUS_PROCESSING);
293 private void setProcessed() {
294 setStatus(STATUS_PROCESSING, STATUS_PROCESSED);
297 private void setAborted() {
298 setStatus(STATUS_PROCESSING, STATUS_ABORTED);
301 private void setPending() {
302 setStatus(STATUS_CREATED, STATUS_PENDING);
305 private boolean setCancelled() {
306 return setStatus(STATUS_PENDING, STATUS_CANCELLED);
309 public boolean hasBeenProcessed() {
310 return getStatus() == STATUS_PROCESSED;
313 public boolean hasBeenAborted() {
314 return getStatus() == STATUS_ABORTED;
317 public boolean isCancelled() {
318 return getStatus() == STATUS_CANCELLED;
321 public boolean isFinished() {
322 return hasBeenProcessed() || hasBeenAborted() || isCancelled();
325 public boolean isProcessing() {
326 return getStatus() == STATUS_PROCESSING;
329 public boolean isPending() {
330 return getStatus() == STATUS_PENDING;
333 public Date getLastChange() {
334 synchronized (this) {
339 private boolean setStatus(int anOldStatus, int aNewStatus) {
341 if (status == anOldStatus) {
343 lastChange = (new GregorianCalendar()).getTime();
344 if (isProcessing()) {
345 starttime = System.currentTimeMillis();
350 endtime = System.currentTimeMillis();
361 private class JobQueueRunner implements Runnable {
362 private LoggerWrapper logger;
364 public JobQueueRunner(LoggerWrapper aLogger) {
369 logger.debug("starting JobQueueRunner");
373 JobHandler job = acquirePendingJob();
375 logger.debug(" starting job ("+job.getIdentifier()+"): " +job.getDescription());
377 logger.debug(" finished job ("+job.getIdentifier()+"): " +job.getDescription());
383 catch (InterruptedException e) {
389 logger.warn("JobQueueRunner terminated");