| JobManager.java |
1 /**
2 * Distribution License:
3 * JSword is free software; you can redistribute it and/or modify it under
4 * the terms of the GNU Lesser General Public License, version 2.1 as published by
5 * the Free Software Foundation. This program is distributed in the hope
6 * that it will be useful, but WITHOUT ANY WARRANTY; without even the
7 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8 * See the GNU Lesser General Public License for more details.
9 *
10 * The License is available on the internet at:
11 * http://www.gnu.org/copyleft/lgpl.html
12 * or by writing to:
13 * Free Software Foundation, Inc.
14 * 59 Temple Place - Suite 330
15 * Boston, MA 02111-1307, USA
16 *
17 * Copyright: 2005
18 * The copyright to this program is held by it's authors.
19 *
20 * ID: $Id: JobManager.java 2053 2010-12-10 19:34:53Z dmsmith $
21 */
22 package org.crosswire.common.progress;
23
24 import java.util.ArrayList;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28
29 import org.crosswire.common.util.Logger;
30
31 /**
32 * JobManager is responsible for creating jobs and informing listeners about the
33 * progress they make to completion.
34 *
35 * <p>
36 * Example code:
37 *
38 * <pre>
39 * final Thread worker = new Thread("DisplayPreLoader")
40 * {
41 * public void run()
42 * {
43 * URL predictURI = Project.instance().getWritablePropertiesURI("save-name");
44 * Progress job = JobManager.createJob("Job Title", predictURI, this, true);
45 * try
46 * {
47 * job.setProgress("Step 1");
48 * ...
49 * job.setProgress("Step 2");
50 * ...
51 * }
52 * catch (Exception ex)
53 * {
54 * ...
55 * job.ignoreTimings();
56 * }
57 * finally
58 * {
59 * job.done();
60 * }
61 * }
62 * };
63 * worker.setPriority(Thread.MIN_PRIORITY);
64 * worker.start();
65 * </pre>
66 *
67 * @see gnu.lgpl.License for license details.<br>
68 * The copyright to this program is held by it's authors.
69 * @author Joe Walker [joe at eireneh dot com]
70 */
71 public final class JobManager {
72 /**
73 * Prevent instantiation
74 */
75 private JobManager() {
76 }
77
78 /**
79 * Create a new Job that cannot be canceled.
80 *
81 * @param jobName the name of the Job
82 */
83 public static Progress createJob(String jobName) {
84 return createJob(jobName, null);
85 }
86
87 /**
88 * Create a new Job that can be canceled.
89 *
90 * @param jobName the name of the Job
91 * @param workerThread the thread on which this job runs
92 */
93 public static Progress createJob(String jobName, Thread workerThread) {
94 Progress job = new Job(jobName, workerThread);
95 jobs.add(job);
96
97 log.debug("job starting: " + job.getJobName());
98
99 return job;
100 }
101
102 /**
103 * Add a listener to the list
104 */
105 public static synchronized void addWorkListener(WorkListener li) {
106 List<WorkListener> temp = new ArrayList<WorkListener>();
107 temp.addAll(listeners);
108
109 if (!temp.contains(li)) {
110 temp.add(li);
111 listeners = temp;
112 }
113 }
114
115 /**
116 * Remote a listener from the list
117 */
118 public static synchronized void removeWorkListener(WorkListener li) {
119 if (listeners.contains(li)) {
120 List<WorkListener> temp = new ArrayList<WorkListener>();
121 temp.addAll(listeners);
122 temp.remove(li);
123 listeners = temp;
124 }
125 }
126
127 /**
128 * Accessor for the currently known jobs
129 */
130 public static synchronized Set<Progress> getJobs() {
131 Set<Progress> reply = new HashSet<Progress>();
132 reply.addAll(jobs);
133 return reply;
134 }
135
136 /**
137 * Inform the listeners that a title has changed.
138 */
139 protected static void fireWorkProgressed(Progress job) {
140 final WorkEvent ev = new WorkEvent(job);
141
142 // we need to keep the synchronized section very small to avoid deadlock
143 // certainly keep the event dispatch clear of the synchronized block or
144 // there will be a deadlock
145 final List<WorkListener> temp = new ArrayList<WorkListener>();
146 synchronized (JobManager.class) {
147 temp.addAll(listeners);
148 }
149
150 // We ought only to tell listeners about jobs that are in our
151 // list of jobs so we need to fire before delete.
152 if (listeners != null) {
153 for (WorkListener worker : temp) {
154 worker.workProgressed(ev);
155 }
156 }
157
158 // Do we need to remove the job? Note that the section above will
159 // probably execute after this so we will be firing events for jobs
160 // that are no longer in our list of jobs. ho hum.
161 synchronized (JobManager.class) {
162 if (job.isFinished()) {
163 log.debug("job finished: " + job.getJobName());
164 jobs.remove(job);
165 }
166 }
167 }
168
169 /**
170 * List of listeners
171 */
172 private static List<WorkListener> listeners = new ArrayList<WorkListener>();
173
174 /**
175 * List of current jobs
176 */
177 private static Set<Progress> jobs = new HashSet<Progress>();
178
179 /**
180 * The log stream
181 */
182 private static final Logger log = Logger.getLogger(JobManager.class);
183 }
184