22a6be789e3dbd98d9a35630413e823ce83521af
[mir.git] / source / mircoders / global / JobQueue.java
1 /*
2  * Copyright (C) 2001, 2002 The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
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.
10  *
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.
15  *
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
19  *
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.
29  */
30
31 package mircoders.global;
32
33
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;
39 import java.util.Map;
40 import java.util.Vector;
41
42 // important: objects passed as data must not be altered once put into a job
43
44 public class JobQueue {
45   private Vector jobs;
46   private Vector finishedJobs;
47   private Map dataToJob;
48   private Map identifierToJob;
49   private int nrJobs;
50
51   public static final int STATUS_PENDING = 0;
52   public static final int STATUS_PROCESSING = 1;
53   public static final int STATUS_PROCESSED = 2;
54   public static final int STATUS_CANCELLED = 3;
55   public static final int STATUS_ABORTED = 4;
56
57   public static final int PRIORITY_NORMAL = 100;
58   public static final int PRIORITY_LOW = 10;
59   public static final int PRIORITY_HIGH = 1000;
60
61   public static final int FINISHEDJOBS_LOGSIZE = 10;
62
63   public JobQueue() {
64     finishedJobs = new Vector();
65     jobs = new Vector();
66     dataToJob = new HashMap();
67     identifierToJob = new HashMap();
68     nrJobs = 0;
69   }
70
71   public String appendJob(Object aData) {
72     synchronized (jobs) {
73       Job job = new Job(aData, Integer.toString(nrJobs));
74       nrJobs++;
75       jobs.add(job);
76       dataToJob.put(aData, job);
77       identifierToJob.put(job.getIdentifier(), job);
78       return job.getIdentifier();
79     }
80   }
81
82   public Object acquirePendingJob() {
83     synchronized (jobs) {
84       int priorityFound= 0;
85       Job jobFound;
86
87       do {
88         jobFound = null;
89         Iterator i = jobs.iterator();
90         while (i.hasNext()) {
91           Job job = (Job) i.next();
92
93           if (job.isPending() && (jobFound==null || priorityFound<job.getPriority())) {
94             jobFound = job;
95             priorityFound = job.getPriority();
96           }
97         }
98       }
99       while (jobFound!=null && !jobFound.setProcessing());
100
101       if (jobFound!=null)
102         return jobFound.getData();
103       else
104         return null;
105     }
106   }
107
108   private void finishJob(Job aJob) {
109     synchronized (jobs) {
110       identifierToJob.remove(aJob.identifier);
111       jobs.remove(aJob);
112       finishedJobs.insertElementAt(aJob, 0);
113       if (finishedJobs.size()>FINISHEDJOBS_LOGSIZE)
114         finishedJobs.remove(finishedJobs.size()-1);
115     }
116   }
117
118   public void jobProcessed(Object aData) {
119     synchronized (jobs) {
120       Job job = (Job) dataToJob.get(aData);
121
122       if (job!=null) {
123         job.setProcessed();
124         finishJob(job);
125       }
126     }
127   }
128
129   public void jobAborted(Object aData) {
130     synchronized (jobs) {
131       Job job = (Job) dataToJob.get(aData);
132
133       if (job!=null) {
134         job.setAborted();
135         finishJob(job);
136       }
137     }
138   }
139
140   public void cancelJob(Object aData) {
141     synchronized (jobs) {
142       Job job = (Job) dataToJob.get(aData);
143
144       if (job!=null && job.setCancelled()) {
145         finishJob(job);
146       }
147     }
148   }
149
150   public void makeJobListSnapshots(List aJobList, List aFinishedJobList) {
151     synchronized (jobs) {
152       aJobList.addAll(makeJobListSnapshot());
153       aFinishedJobList.addAll(makeFinishedJobListSnapshot());
154     }
155   }
156
157   public List makeJobListSnapshot() {
158     synchronized (jobs) {
159       return (List) jobs.clone();
160     }
161   }
162
163   public List makeFinishedJobListSnapshot() {
164     synchronized (jobs) {
165       return (List) finishedJobs.clone();
166     }
167   }
168
169   public class Job implements Cloneable {
170     private Object data;
171     private Date lastChange;
172     private long starttime;
173     private long endtime;
174     private String identifier;
175     private int status;
176     private int priority;
177     private boolean hasRun;
178
179     public Job(Object aData, String anIdentifier, int aStatus, int aPriority, Date aLastChange) {
180       data = aData;
181       status = aStatus;
182       identifier = anIdentifier;
183       priority = aPriority;
184       lastChange = aLastChange;
185
186       hasRun = false;
187     }
188
189     public Job(Object aData, String anIdentifier, int aStatus, int aPriority) {
190       this(aData, anIdentifier, aStatus, aPriority, (new GregorianCalendar()).getTime());
191     }
192
193     public Job(Object aData, String anIdentifier) {
194       this(aData, anIdentifier, STATUS_PENDING, PRIORITY_NORMAL);
195     }
196
197     public Object getData() {
198       return data;
199     }
200
201     public int getStatus() {
202       synchronized(this) {
203         return status;
204       }
205     }
206
207     public Date getLastChange() {
208       return lastChange;
209     }
210
211     public String getIdentifier() {
212       return identifier;
213     }
214
215     public long getRunningTime() {
216       long result = 0;
217
218       if (hasRun) {
219         if (isFinished())
220           result = endtime;
221         else
222           result = System.currentTimeMillis();
223
224         result = result-starttime;
225       }
226
227       return result;
228     }
229
230     public int getPriority() {
231       return priority;
232     }
233
234     protected boolean setProcessing() {
235       return setStatus(STATUS_PENDING, STATUS_PROCESSING);
236     }
237
238     protected void setProcessed() {
239       setStatus(STATUS_PROCESSING, STATUS_PROCESSED);
240     }
241
242     protected void setAborted() {
243       setStatus(STATUS_PROCESSING, STATUS_ABORTED);
244     }
245
246     protected boolean setCancelled() {
247       return setStatus(STATUS_PENDING, STATUS_CANCELLED);
248     }
249
250     public boolean hasBeenProcessed() {
251       return getStatus() == STATUS_PROCESSED;
252     }
253
254     public boolean hasBeenAborted() {
255       return getStatus() == STATUS_ABORTED;
256     }
257
258     public boolean isCancelled() {
259       return getStatus() == STATUS_CANCELLED;
260     }
261
262     public boolean isFinished() {
263       return hasBeenProcessed() || hasBeenAborted() || isCancelled();
264     }
265
266     public boolean isProcessing() {
267       return getStatus() == STATUS_PROCESSING;
268     }
269
270     public boolean isPending() {
271       return getStatus() == STATUS_PENDING;
272     }
273
274     private boolean setStatus(int anOldStatus, int aNewStatus) {
275       synchronized(this) {
276         if (status == anOldStatus) {
277           status = aNewStatus;
278           lastChange = (new GregorianCalendar()).getTime();
279           if (isProcessing()) {
280             starttime = System.currentTimeMillis();
281             hasRun = true;
282           }
283
284           if (isFinished()) {
285             endtime = System.currentTimeMillis();
286           }
287           return true;
288         }
289         else {
290           return false;
291         }
292       }
293     }
294
295     protected Object clone() {
296       synchronized(this) {
297         return new Job(data, identifier, status, priority, lastChange);
298       }
299     }
300   }
301 }
302