source: trunk/gli/src/org/greenstone/gatherer/shell/GImportProgressMonitor.java@ 11068

Last change on this file since 11068 was 11068, checked in by mdewsnip, 18 years ago

Hacked in a compensation for metadata_read now outputting <File> tags also (thus messing up the progress bar).

  • Property svn:keywords set to Author Date Id Revision
File size: 19.5 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.shell;
38
39import java.awt.Component;
40import java.util.*;
41import javax.swing.JProgressBar;
42import org.greenstone.gatherer.Configuration;
43import org.greenstone.gatherer.DebugStream;
44import org.greenstone.gatherer.Dictionary;
45import org.greenstone.gatherer.Gatherer;
46import org.greenstone.gatherer.util.StaticStrings;
47
48/** This implementation of <i>GShellProgressMonitor</i> is designed to parse and translate the progress of a import.pl call.
49 * @author John Thompson, Greenstone Digital Library, University of Waikato
50 * @version 2.1
51 */
52public class GImportProgressMonitor
53 implements GShellProgressMonitor {
54 /** Indicates if the progress bar is currently showing a string. */
55 private boolean showing_string = false;
56 /** Indicates if the GUI has asked the process this object monitors to stop. */
57 private boolean stop = false;
58 /** A count of the extracted files processed so far. */
59 private int extracted_file_count;
60 /** The number of documents processed (or rejected) so far. */
61 private int file_count;
62 /** The next value to be set for the progress bar - I use this rather than a compounding progress measure to try to limit rounding inaccuracies (nothing looks worse than the progress bar having to jump the last 10-15%) */
63 private int next_progress_value;
64 /** The number of files expected to be scanned by this import process. */
65 private int num_expected_docs;
66 /** This holds the number of documents actually processed by the import command, as garnered from the final block of text output. */
67 private int num_docs;
68
69 private int threshold = Configuration.SYSTEMS_MODE;
70 /** The progress bar this monitor updates. */
71 private JProgressBar progress_bar;
72
73 /** The progress bar that is shared with build monitor. */
74 private JProgressBar shared_progress_bar;
75
76 /** */
77 static final private String BLOCKED_ATTRIBUTE = "blocked";
78 static final private String CONSIDERED_ATTRIBUTE = "considered";
79 static final private String FAILED_ATTRIBUTE = "failed";
80 static final private String IGNORED_ATTRIBUTE = "ignored";
81 static final private String IMPORT_ELEMENT = "Import";
82 static final private String PROCESSED_ATTRIBUTE = "processed";
83
84 static final private String ARGUMENT_ATTRIBUTE = "a";
85 /** */
86 static final private String NAME_ATTRIBUTE = "n";
87 /** */
88 static final private String PLUGIN_ATTRIBUTE = "p";
89 static final private String REASON_ATTRIBUTE = "r";
90 /** The fixed portion of the progress bar used for the calculating of file size and other pre-import functions. */
91 static final private int CALCULATION = 50000;
92 /** The fixed portion of the progress bar used for extracted metadata. */
93 static final private int EXTRACTED = 200000;
94 /** The fixed portion of the progress bar used for processed documents. */
95 static final private int PROCESSED = 750000;
96 /** The maximum value for this progress bar. */
97 static final private int MAXIMUM = CALCULATION + EXTRACTED + PROCESSED;
98 /** The minimum value for this progress bar. */
99 static final private int MINIMUM = 0;
100 /** The element name of a file detected message. */
101 static final private String FILE_ELEMENT = "File";
102 /** The element name of a file processing message. */
103 static final private String PROCESSING_ELEMENT = "Processing";
104 /** The element name of a processing error message. */
105 static final private String PROCESSINGERROR_ELEMENT = "ProcessingError";
106 /** The element name of an import complete message. */
107 static final private String IMPORTCOMPLETE_ELEMENT = "ImportComplete";
108 /** The element name of a file not processed. */
109 static final private String NONPROCESSEDFILE_ELEMENT = "NonProcessedFile";
110 /** The element name of a file not recognised. */
111 static final private String NONRECOGNISEDFILE_ELEMENT = "NonRecognisedFile";
112 /** The element name of a BadArgument message */
113 static final private String BADARGUMENT_ELEMENT = "BadArgument";
114 static final private String BADARGUMENTVALUE_ELEMENT = "BadArgumentValue";
115 static final private String BADPLUGIN_ELEMENT = "BadPlugin";
116
117 public GImportProgressMonitor() {
118 progress_bar = new JProgressBar();
119 progress_bar.setIndeterminate(false);
120 progress_bar.setMaximum(MAXIMUM);
121 progress_bar.setMinimum(MINIMUM);
122 progress_bar.setString(null);
123 progress_bar.setStringPainted(true);
124 next_progress_value = CALCULATION;
125 shared_progress_bar = new JProgressBar();
126 shared_progress_bar.setIndeterminate(false);
127 shared_progress_bar.setMaximum(MAXIMUM * 2);
128 shared_progress_bar.setMinimum(MINIMUM);
129 shared_progress_bar.setString(null); // Default string
130 shared_progress_bar.setStringPainted(true);
131 setValue(MINIMUM);
132 }
133
134 /** Method to register a new progress bar with this monitor.
135 * @param progress_bar The new <strong>JProgressBar</strong>.
136 */
137 public void addProgressBar(JProgressBar progress_bar) {
138 this.progress_bar = progress_bar;
139 progress_bar.setMaximum(MAXIMUM);
140 progress_bar.setMinimum(MINIMUM);
141 setValue(MINIMUM);
142 next_progress_value = CALCULATION;
143 }
144
145 /** Determine the script exit value according to the progress monitor. This gets around a problem where several script failures actually result with a successful exit value.
146 * @return A <i>int</i> with a value of zero if and only if the script was successful.
147 */
148 public int exitValue() {
149 if(num_docs > 0) {
150 return 0;
151 }
152 return 1;
153 }
154
155 /** Retrieve the number of documents recorded by the import monitor during the execution of the import scripts.
156 * @return An <i>int</i> giving the document number.
157 */
158 public int getNumberOfDocuments() {
159 return num_docs;
160 }
161
162 /** Method to retrieve whatever control is being used as the progress indicator. Usually a <strong>JProgressBar</strong> but there may be others implemented later.
163 * @return A <strong>Component</strong> on which the progress of the process is being displayed.
164 */
165 public Component getProgress() {
166 return progress_bar;
167 }
168
169 public JProgressBar getSharedProgress() {
170 return shared_progress_bar;
171 }
172
173 public void messageOnProgressBar(String message)
174 {
175 if ((message!=null) & (message!="")) {
176 progress_bar.setString(message);
177 shared_progress_bar.setString(message);
178 showing_string = true;
179 }
180 else {
181 progress_bar.setString(null);
182 shared_progress_bar.setString(null);
183 showing_string = false;
184 }
185 }
186
187 /** Method to determine the state of the stop flag, which may be set by the visual component that created this monitor.
188 * @return A <strong>boolean</strong> indicating if the process has been asked to stop.
189 */
190 public synchronized boolean hasSignalledStop() {
191 return stop;
192 }
193
194 /** Inform the progress bar that it should programatically increment progress by one step. This is only called during the metadata archive extraction so each step should be (1000000 / 5) / num_docs. */
195 public void increment() {
196 extracted_file_count++;
197 // The current progress is calculated to be:
198 // The fixed calculation value plus the fixed processed value plus some portion of the fixed extracted value. This portion is the extracted_file_count over the total number of documents available. Note that this breaks badly for bibliographical files (for now).
199 setValue(CALCULATION + PROCESSED + ((EXTRACTED * extracted_file_count) / num_docs));
200 }
201
202 /** This method is used to 'feed in' a line of text captured from the process.
203 * @param queue a queue which at the moment should contain a single GShellEvent
204 */
205 public void process(ArrayList queue) {
206 // Retrieve the first event.
207 GShellEvent event = (GShellEvent) queue.get(0);
208 // Remove 'import.pl> ' bit
209 String line = event.getMessage();
210 line = line.substring(line.indexOf(StaticStrings.GREATER_THAN_CHARACTER) + 1);
211 line = line.trim();
212 // System.err.println("**** line = " + line);
213
214 ///ystem.err.println("Process: " + line);
215 if(line.startsWith(StaticStrings.LESS_THAN_CHARACTER) && line.endsWith(StaticStrings.GREATER_THAN_CHARACTER)) {
216 // No original event is passed on, even in the lower modes
217 event.veto();
218 // Create a new element from it
219 GShellElement element = new GShellElement(line);
220 String name = element.getElementName();
221 ///ystem.err.println("Gatherer tag: " + name);
222 // We may be reading a file. Remember we have to offset process as we recieve this message 'before' a document is processed. Hence the use of 'next_progress_value'
223 if(name.equals(IMPORT_ELEMENT)) {
224 ///ystem.err.println("#Import");
225 // We're into parsing output, so we don't need the 'calculating file size' etc string.
226 if(showing_string) {
227 progress_bar.setString(null);
228 showing_string = false;
229 }
230 if(Configuration.getMode() <= threshold) {
231 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportBegun1"), event.getStatus()));
232 }
233 }
234 else if(name.equals(FILE_ELEMENT)) {
235 ///ystem.err.println("#File");
236 file_count++;
237 // Set the next progress
238 if(next_progress_value > 0) {
239 setValue(next_progress_value);
240 }
241 // Now we calculate the next progress value
242 next_progress_value = CALCULATION + ((PROCESSED * file_count) / num_expected_docs);
243 event.veto(); // Unconditional veto
244 }
245 // Or we're being told what plugin is actually processing the file
246 else if(name.equals(PROCESSING_ELEMENT)) {
247 ///ystem.err.println("#FileProcessing");
248 // If we are at lower mode settings fire a new 'dumbed down' event
249 if(Configuration.getMode() <= threshold) {
250 String args[] = new String[2];
251 args[0] = element.getAttribute(NAME_ATTRIBUTE);
252 args[1] = element.getAttribute(PLUGIN_ATTRIBUTE);
253 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileProcessing", args), event.getStatus()));
254 args = null;
255 }
256 }
257 // processing error
258 else if (name.equals(PROCESSINGERROR_ELEMENT)) {
259 if(Configuration.getMode() <= threshold) {
260 String args[] = new String[1];
261 args[0] = element.getAttribute(NAME_ATTRIBUTE);
262 String reason = element.getAttribute(REASON_ATTRIBUTE);
263 if (reason == null || reason.equals("")) {
264 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileProcessingError", args), event.getStatus()));
265 }
266 else {
267 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileProcessingError", args) + " (" + reason + ")", event.getStatus()));
268 }
269 args = null;
270 }
271 }
272 // unrecognised file
273 else if (name.equals(NONRECOGNISEDFILE_ELEMENT)) {
274 if(Configuration.getMode() <= threshold) {
275 String args[] = new String[1];
276 args[0] =element.getAttribute(NAME_ATTRIBUTE);
277 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileNotRecognised", args), event.getStatus()));
278 args = null;
279 }
280 }
281 // unprocessed file
282 else if (name.equals(NONPROCESSEDFILE_ELEMENT)) {
283 if(Configuration.getMode() <= threshold) {
284 String args[] = new String[1];
285 args[0] =element.getAttribute(NAME_ATTRIBUTE);
286 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.FileNotProcessed", args), event.getStatus()));
287 args = null;
288 }
289 }
290 // We had a bad argument to a plugin
291 else if (name.equals(BADARGUMENT_ELEMENT)) {
292 if(Configuration.getMode() <= threshold) {
293 String args[] = new String[1];
294 args[0] = element.getAttribute(ARGUMENT_ATTRIBUTE);
295 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.BadArgument", args), event.getStatus()));
296 args = null;
297 }
298 }
299 // We had a bad argument value to a plugin
300 else if (name.equals(BADARGUMENTVALUE_ELEMENT)) {
301 if(Configuration.getMode() <= threshold) {
302 String args[] = new String[1];
303 args[0] = element.getAttribute(ARGUMENT_ATTRIBUTE);
304 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.BadArgumentValue", args), event.getStatus()));
305 args = null;
306 }
307 }
308 // And this one tellsa us the plugin
309 else if (name.equals(BADPLUGIN_ELEMENT)) {
310 if(Configuration.getMode() <= threshold) {
311 String args[] = new String[1];
312 args[0] = element.getAttribute(PLUGIN_ATTRIBUTE);
313 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.BadPluginOptions", args), event.getStatus()));
314 args = null;
315 }
316 }
317 // Or the import complete element
318 else if(name.equals(IMPORTCOMPLETE_ELEMENT)) {
319 // Set the next progress
320 setValue(next_progress_value);
321 // If we are at lower mode settings fire a new 'dumbed down' event
322 if(Configuration.getMode() <= threshold) {
323 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportComplete1"), event.getStatus()));
324 String considered_str = element.getAttribute(CONSIDERED_ATTRIBUTE);
325
326 if (considered_str.equals(StaticStrings.ONE_CHARACTER)) {
327 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportComplete2.1"), event.getStatus()));
328 } else {
329 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportComplete2", considered_str), event.getStatus()));
330 }
331 considered_str = null;
332 // The number of documents processed
333 String processed_str = element.getAttribute(PROCESSED_ATTRIBUTE);
334 if(!processed_str.equals(StaticStrings.ZERO_CHARACTER)) {
335 if(processed_str.equals(StaticStrings.ONE_CHARACTER)) {
336 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), " "+Dictionary.get("GShell.Import.ImportComplete.Processed.1"), event.getStatus()));
337 }
338 else {
339 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), " "+Dictionary.get("GShell.Import.ImportComplete.Processed", processed_str), event.getStatus()));
340 }
341 }
342 // Try to set num docs
343 try {
344 num_docs = Integer.parseInt(processed_str);
345 }
346 catch(Exception exception) {
347 num_docs = 0;
348 }
349 processed_str = null;
350
351 // The number of documents blocked
352 String blocked_str = element.getAttribute(BLOCKED_ATTRIBUTE);
353 if(!blocked_str.equals(StaticStrings.ZERO_CHARACTER)) {
354 if (blocked_str.equals(StaticStrings.ONE_CHARACTER)) {
355 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), " "+Dictionary.get("GShell.Import.ImportComplete.Blocked.1"), event.getStatus()));
356 } else {
357 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), " "+Dictionary.get("GShell.Import.ImportComplete.Blocked", blocked_str), event.getStatus()));
358 }
359 }
360 blocked_str = null;
361
362 // The number of documents ignored
363 String ignored_str = element.getAttribute(IGNORED_ATTRIBUTE);
364 if(!ignored_str.equals(StaticStrings.ZERO_CHARACTER)) {
365 if(ignored_str.equals(StaticStrings.ONE_CHARACTER)) {
366 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), " "+Dictionary.get("GShell.Import.ImportComplete.Ignored.1"), event.getStatus()));
367 } else {
368 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), " "+Dictionary.get("GShell.Import.ImportComplete.Ignored", ignored_str), event.getStatus()));
369 }
370 }
371 ignored_str = null;
372
373 // The number of documents failed
374 String failed_str = element.getAttribute(FAILED_ATTRIBUTE);
375 if(!failed_str.equals(StaticStrings.ZERO_CHARACTER)) {
376 if(failed_str.equals(StaticStrings.ONE_CHARACTER)) {
377 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), " "+Dictionary.get("GShell.Import.ImportComplete.Failed.1"), event.getStatus()));
378 } else {
379 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), " "+Dictionary.get("GShell.Import.ImportComplete.Failed", failed_str), event.getStatus()));
380 }
381 }
382 failed_str = null;
383 // Message is finally ready
384 queue.add(new GShellEvent(event.getSource(), 0, event.getType(), Dictionary.get("GShell.Import.ImportComplete3"), event.getStatus()));
385 } // if mode below threshhold
386 else {
387 // Try to set num docs
388 String processed_str = element.getAttribute(PROCESSED_ATTRIBUTE);
389 try {
390 num_docs = Integer.parseInt(processed_str);
391 }
392 catch(Exception exception) {
393 num_docs = 0;
394 }
395 }
396 }
397 else {
398 // Veto it
399 event.veto();
400 }
401 } // GLI output
402 else if(Configuration.getMode() <= threshold) {
403 event.veto();
404 }
405 }
406
407 public void reset() {
408 setValue(MINIMUM);
409 progress_bar.setString(null);
410 progress_bar.updateUI();
411 }
412
413 public void saving() {
414 progress_bar.setString(Dictionary.get("SaveProgressDialog.Title"));
415 showing_string = true;
416 }
417
418 /** Since the creator of this process monitor is actually in the GUI, this class provides the simpliest way to send a cancel process message between the two.
419 * @param state The desired state of the stop flag as a <strong>boolean</strong>.
420 */
421 public synchronized void setStop(boolean state) {
422 this.stop = state;
423 }
424
425 /** This method resets this monitor to the start, reseting the process parsing and progress bar.
426 */
427 public void start() {
428 stop = false;
429 setValue(MINIMUM);
430 progress_bar.setString(Dictionary.get("FileActions.Calculating_Size"));
431 showing_string = true;
432 extracted_file_count = 0;
433 file_count = 0;
434 next_progress_value = -1;
435 num_docs = -1;
436 // !! HACK: This is multiplied by 2 because the metadata_read now outputs a <File> tag also
437 // Ideally the metadata read pass would be completely separate and the GLI could work out the number
438 // of documents accurately and provide a much better progress bar
439 num_expected_docs = Gatherer.c_man.getCollection().getCount() * 2;
440 }
441
442 /** This method indicates the process is complete.
443 */
444 public void stop() {
445 setValue(MAXIMUM);
446 }
447
448 int previous_value = -1;
449
450 private void setValue(int value)
451 {
452 // Don't let the value go higher than the maximum
453 if (value > MAXIMUM) {
454 DebugStream.println("Error: Tried to set progress bar higher than maximum!\n");
455 return;
456 }
457 // Don't let the value go backwards
458 if (value != 0 && value < previous_value) {
459 DebugStream.println("Error: Tried to set progress bar smaller than previous!\n");
460 return;
461 }
462
463 progress_bar.setValue(value);
464 shared_progress_bar.setValue(value);
465 previous_value = value;
466 }
467}
468
Note: See TracBrowser for help on using the repository browser.