source: main/trunk/gli/src/org/greenstone/gatherer/download/DownloadScrollPane.java@ 31720

Last change on this file since 31720 was 31692, checked in by ak19, 7 years ago

Major changes to SafeProcess and classes of the download package, by bringing the final GLI (and final Greenstone) class DownloadJob over to use SafeProcess. Significant changes to SafeProcess: 1. Introduction of cancelRunningProcess as a new method, so that callers don't need to know how cancelling a process is implemented (as an interrupt) nor do they need to know what thread they ought to interrupt (which should be the thread that launched SafeProcess), nor do they need to know of the complexity surrounding the join() blocking call which should not be interrupted. 2. Introduction of the SafeProcess.MainHandler interface that provides methods that allow implementers to write hooks to various stages of the SafeProcess' internal process' life cycle. 3. moved process cleanUp() code into a reusable method within SafeProcess. Significant changes to DownloadJob and its associated DownloadProgressBar and DownloadScrollPane classes: 1. Unused member vars removed or commented out and those that can be declared final are now declared so, as a programming pricinple for thread safety, since DownloadJob and the other download classes will have to interact with multiple threads and could be called by different threads. 2. Replaced existing actionPerformed() and callDownload() of DownloadJob with SafeProcess and implemented the necessary Hooks in the SafeProcess.MainHandler() interface to ensure that perl is still told to terminate wget on a cancel action. 3. Replaced DownloadScrollPane's deleteDownloadJob() with a new version that now more responsively removes its DownloadProgressBar (with controls) for a DownloadJob. It's called by the SafeProcess.MainHandler interface hooks implemented by DownloadJob, so DownloadScrollPane no longer needs to wait() to be notify()ed when a process has cleaned up on premature termination by a cancel action. 4. Made the necessary methods in DownloadProgressBar synchronized for thread safety. 5. GShell now uses SafeProcess' new cancelRunningProcess() method in place of directly calling interrupt on the (GShell) thread that launched SafeProcess.

  • Property svn:keywords set to Author Date Id Revision
File size: 9.2 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37package org.greenstone.gatherer.download;
38
39import java.awt.*;
40import java.io.*;
41import java.net.*;
42import java.util.*;
43import javax.swing.*;
44import javax.swing.tree.*;
45import org.greenstone.gatherer.*;
46import org.greenstone.gatherer.util.SafeProcess;
47
48/** This class provides access to the functionality of the WGet program, either by calling it via a shell script or by the JNI. It maintains a queue of pending jobs, and the component for showing these tasks to the user.
49 * @author John Thompson, Greenstone Digital Library, University of Waikato
50 * @version 2.3
51 */
52public class DownloadScrollPane
53 extends Thread {
54
55 /** <i>true</i> if verbose debug messages should be displayed, <i>false</i> otherwise. */
56 private boolean debug = false;
57 /** <i>true</i> if successfully completed tasks should be automatically removed from the job queue. */
58 private boolean remove_complete_jobs = true;
59
60 private JPanel filler_pane = null;
61 /** The panel that the task list will be shown in. */
62 private JPanel list_pane;
63 /** The job currently underway. */
64 private DownloadJob job;
65 /** A scroll pane which will be used to display the list of pending tasks. */
66 private JScrollPane list_scroll;
67 /** A queue of download tasks. */
68 private Vector job_queue;
69 static final private boolean simple = true;
70
71
72 public DownloadScrollPane() {
73 job = null;
74 job_queue = new Vector();
75 filler_pane = new JPanel();
76 list_pane = new JPanel();
77 list_pane.setLayout(new BoxLayout(list_pane, BoxLayout.Y_AXIS));
78 list_scroll = new JScrollPane(list_pane);
79 }
80
81 /**
82 * To be used with DownloadJob.java's old_callDownload() and old_actionPerformed()
83 * OR by uncommenting the "synchronized(this)" section in Download.java at the end of
84 * its new callDownload() along with commenting out "mummy.deleteCurrentDownloadJob(this);"
85 * in Download.java's doneCleanup().
86 */
87 public void old_deleteDownloadJob(DownloadJob delete_me) {
88 if (delete_me == job) {
89 try {
90 // Wait for the job to finish cleaning up, before we can continue cleaning up here.
91 // But sometimes the job has completed (terminated naturally) and in that case there's
92 // nothing to wait for.
93 synchronized(delete_me) {
94 if (!delete_me.hasSignalledStop()) { // don't wait if DownloadJob.COMPLETED
95 ///SafeProcess.log("**************** download scrollpane waiting for downloadjob to stop");
96 delete_me.wait();
97 }
98 }
99 } catch (Exception e) {
100 e.printStackTrace();
101 }
102 }
103
104 ///System.err.println("**************** Deleting job from download scroll pane");
105 // Close button pressed, get rid of this download's dedicated pane
106 finishedDownloadJob(delete_me, true);
107 }
108
109 /**
110 * If called to delete the current download job, this method won't do anything.
111 * But if called on any inactive download job, its display is removed.
112 */
113 public void deleteDownloadJob(DownloadJob delete_me) {
114 if (delete_me != job) {
115
116 SafeProcess.log("**************** Deleting job from download scroll pane");
117 // Close button pressed, get rid of this download's dedicated pane
118 finishedDownloadJob(delete_me, true);
119 } // else don't do anything, we'll be contacted again when the current job can be deleted
120
121 }
122
123 /**
124 * To be called when we're ready to delete the current download job,
125 * else this method won't do anything
126 */
127 public void deleteCurrentDownloadJob(DownloadJob delete_me) {
128 if (delete_me == job) {
129 SafeProcess.log("**************** Deleting current job from download scroll pane");
130 // Close button pressed, get rid of this download's dedicated pane
131 finishedDownloadJob(delete_me, true);
132 }
133 }
134
135
136 /** To be called when a download job has terminated naturally or was prematurely stopped
137 * via the close button.
138 * Gets rid of this download's pane with buttons and progress bar if prematurely stopped. */
139 protected void finishedDownloadJob(DownloadJob delete_me, boolean removeDisplay) {
140 if (delete_me.hasSignalledStop()) {
141 if(removeDisplay) {
142 list_pane.remove(delete_me.getProgressBar());
143 list_pane.remove(filler_pane);
144 }
145 job_queue.remove(delete_me);
146 if(job_queue.size() > 0) {
147 Dimension progress_bar_size = delete_me.getProgressBar().getPreferredSize();
148 Dimension list_pane_size = list_pane.getSize();
149 int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
150 progress_bar_size = null;
151 if(height > 0) {
152 filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
153 list_pane.add(filler_pane);
154 }
155 list_pane_size = null;
156 }
157 list_pane.updateUI();
158 }
159 else {
160 DebugStream.println("Somehow we're trying to delete a job that is still running.");
161 }
162 }
163
164 public synchronized void downloadComplete() {
165 job.downloadComplete();
166 }
167
168 public synchronized void downloadFailed() {
169 job.downloadFailed();
170 }
171
172 public synchronized void downloadWarning() {
173 job.downloadWarning();
174 }
175
176 public JScrollPane getDownloadJobList() {
177 return list_scroll;
178 }
179
180 public synchronized boolean hasSignalledStop() {
181 return job.hasSignalledStop();
182 }
183
184 public void newDownloadJob(Download download, String mode, String proxy_url) {
185 // Create the job and fill in the details from gatherer.config.
186
187 DebugStream.println("About to create a new job");
188
189 DownloadJob new_job = new DownloadJob(download, Configuration.proxy_pass, Configuration.proxy_user, this, mode, proxy_url);
190 // Tell it to run as soon as possible
191
192 new_job.setState(DownloadJob.RUNNING);
193
194 // Add to job_queue job list.
195 job_queue.add(new_job);
196
197 // Now add it to the visual component, job list.
198
199 list_pane.remove(filler_pane);
200
201 Dimension progress_bar_size = new_job.getProgressBar().getPreferredSize();
202
203 Dimension list_pane_size = list_pane.getSize();
204
205 int height = list_pane_size.height - (job_queue.size() * progress_bar_size.height);
206
207 progress_bar_size = null;
208
209 list_pane.add(new_job.getProgressBar());
210
211 if(height > 0) {
212 filler_pane.setPreferredSize(new Dimension(list_pane_size.width, height));
213 list_pane.add(filler_pane);
214 }
215
216 list_pane_size = null;
217 //list_pane.setAlignmentX(Component.LEFT_ALIGNMENT);
218 list_pane.updateUI();
219 new_job = null; //job = (DownloadJob) job_queue.get(index);
220
221 synchronized(this) {
222 notify(); // Just incase its sleeping.
223 }
224 }
225
226 public synchronized void updateProgress(long current, long expected) {
227 job.updateProgress(current, expected);
228 }
229
230 /* There may be times when the download thread is sleeping, but the
231 * user has indicated that a previously paused job should now begin
232 * again. The flag within the job will change, so we tell the thread
233 * to start again.
234 */
235 public void resumeThread() {
236 synchronized(this) {
237 notify(); // Just incase its sleeping.
238 }
239 }
240
241 public void run() {
242 while(true) {
243 if(job_queue.size() > 0) {
244 while(!job_queue.isEmpty()) {
245 job = (DownloadJob) job_queue.firstElement();
246
247 if(job.getState() == DownloadJob.RUNNING) {
248 DownloadJob delete_me = job;
249 String jobDisplayString = job.toString();
250 DebugStream.println("DownloadJob " + jobDisplayString + " Begun.");
251 System.err.println("DownloadJob " + job.port + " " + job.toString() + " Begun.");
252 job.callDownload();
253 // Job is done. Ended naturally, don't get rid of this download's separate display panel
254 finishedDownloadJob(delete_me, false);
255 System.err.println("DownloadJob " + jobDisplayString + " complete.");
256 DebugStream.println("DownloadJob " + jobDisplayString + " complete."); // by this point job is null!
257 job = null;
258 delete_me = null;
259 }
260 }
261 try {
262 synchronized(this) {
263 DebugStream.println("WGet thread is waiting for DownloadJobs.");
264 wait();
265 }
266 } catch (InterruptedException e) {
267 // Time to get going again.
268 }
269 }
270 else {
271 try {
272 synchronized(this) {
273 DebugStream.println("WGet thread is waiting for DownloadJobs.");
274 wait();
275 }
276 } catch (InterruptedException e) {
277 // Time to get going again.
278 }
279 }
280 }
281 }
282}
Note: See TracBrowser for help on using the repository browser.