source: trunk/gli/src/org/greenstone/gatherer/Gatherer.java@ 9647

Last change on this file since 9647 was 9580, checked in by mdewsnip, 19 years ago

Added a check for ImageMagick when the GLI starts up.

  • Property svn:keywords set to Author Date Id Revision
File size: 29.0 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 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.io.*;
32import java.lang.*;
33import java.net.*;
34import java.util.*;
35import javax.swing.*;
36import javax.swing.plaf.*;
37import javax.swing.text.*;
38import org.greenstone.gatherer.Configuration;
39import org.greenstone.gatherer.GAuthenticator;
40import org.greenstone.gatherer.cdm.ClassifierManager;
41import org.greenstone.gatherer.cdm.PluginManager;
42import org.greenstone.gatherer.collection.CollectionManager;
43import org.greenstone.gatherer.feedback.ActionRecorderDialog;
44import org.greenstone.gatherer.file.FileManager;
45import org.greenstone.gatherer.file.FileAssociationManager;
46import org.greenstone.gatherer.gui.GUIManager;
47import org.greenstone.gatherer.gui.URLField;
48import org.greenstone.gatherer.gui.WarningDialog;
49import org.greenstone.gatherer.util.StaticStrings;
50import org.greenstone.gatherer.util.Utility;
51
52
53/** Containing the top-level "core" for the Gatherer, this class is the
54 * common core for the GLI application and applet. It first parses the
55 * command line arguments, preparing to update the configuration as
56 * required. Next it loads several important support classes such as the
57 * Configuration and Dictionary. Finally it creates the other important
58 * managers and sends them on their way.
59 * @author John Thompson, Greenstone Digital Library, University of Waikato
60 * @version 2.3
61 */
62public class Gatherer
63{
64 /** Has the exit flag been set? */
65 public boolean exit = false;
66
67 /** All of the external applications that must exit before we close the Gatherer. */
68 public Vector apps = new Vector();
69 static private String non_standard_collect_directory_path = null;
70 static public String open_collection_file_path = null;
71 /** A public reference to the FileAssociationManager. */
72 static public FileAssociationManager assoc_man;
73 /** A public reference to the CollectionManager. */
74 static public CollectionManager c_man;
75 /** a reference to the Servlet Configuration is GS3 */
76 static public ServletConfiguration servlet_config;
77 /** A public reference to the FileManager. */
78 static public FileManager f_man;
79 /** A public reference to the GUIManager. */
80 static public GUIManager g_man;
81 static private boolean g_man_built = false;
82
83 /** A static reference to ourselves. */
84 static public Gatherer self;
85 /** We are using the GLI for GS3 */
86 static public boolean GS3 = false;
87
88 static public boolean isGsdlRemote = false;
89 static public String cgiBase = "";
90
91 // feedback stuff
92 /** is the feedback feature enabled? */
93 static public boolean feedback_enabled = true;
94 /** the action recorder dialog */
95 static public ActionRecorderDialog feedback_dialog = null;
96
97 // Refresh reasons
98 static public final int COLLECTION_OPENED = 0;
99 static public final int COLLECTION_CLOSED = 1;
100 static public final int COLLECTION_REBUILT = 2;
101 static public final int PREFERENCES_CHANGED = 3;
102
103
104 /** Magic to allow Enter to fire the default button. */
105 static {
106 KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
107 Keymap map = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
108 map.removeKeyStrokeBinding(enter);
109 }
110
111
112 public Gatherer()
113 {
114 this.self = this;
115
116 Utility.initImages(this);
117 }
118
119
120 public GUIManager init(Dimension size, String gsdl_path, String gsdl3_path, String local_library_path,
121 String library_url_string, boolean debug_enabled, String perl_path,
122 boolean no_load, String open_collection,
123 String site_name, String servlet_path, String wget_path)
124 {
125 if (gsdl3_path != null && !gsdl3_path.equals("")) {
126 this.GS3 = true;
127 } else {
128 gsdl3_path = null;
129 }
130
131 // Create the debug stream if required
132 if (debug_enabled) {
133 DebugStream.enableDebugging();
134
135 Calendar now = Calendar.getInstance();
136 String debug_file_path = "debug" + now.get(Calendar.DATE) + "-" + now.get(Calendar.MONTH) + "-" + now.get(Calendar.YEAR) + ".txt";
137
138 // Debug file is created in the user's GLI directory
139 debug_file_path = Utility.getGLIUserFolder().toString() + File.separator + debug_file_path;
140 DebugStream.println("Debug file path: " + debug_file_path);
141 DebugStream.setDebugFile(debug_file_path);
142 DebugStream.print(System.getProperties());
143 }
144
145 try {
146 // Load GLI config file
147 new Configuration(gsdl_path, gsdl3_path, site_name);
148 if (Configuration.just_created_new_config_file) {
149 // Delete the plugins.dat and classifiers.dat files
150 PluginManager.clearPluginCache();
151 ClassifierManager.clearClassifierCache();
152 }
153
154 if (GS3) {
155 // Load Greenstone 3 servelt configuration
156 servlet_config = new ServletConfiguration(gsdl3_path);
157 }
158
159 // Check we know where Perl is
160 Configuration.perl_path = perl_path;
161 if (isGsdlRemote && Utility.isWindows() && Configuration.perl_path != null) {
162 if (Configuration.perl_path.toLowerCase().endsWith("perl.exe")) {
163 Configuration.perl_path = Configuration.perl_path.substring(0, Configuration.perl_path.length() - "perl.exe".length());
164 }
165 if (Configuration.perl_path.endsWith(File.separator)) {
166 Configuration.perl_path = Configuration.perl_path.substring(0, Configuration.perl_path.length() - File.separator.length());
167 }
168 }
169
170 if (GS3 && Configuration.servlet_path == null) {
171 Configuration.servlet_path = servlet_config.getServletPath(Configuration.site_name);
172 }
173
174 // the feedback dialog has been loaded with a default locale,
175 // now set the user specified one
176 if (feedback_enabled && feedback_dialog != null) {
177 feedback_dialog.setLocale(Configuration.getLocale("general.locale", true));
178 }
179
180 // Read Dictionary
181 new Dictionary(Configuration.getLocale("general.locale", true), Configuration.getFont("general.font", true));
182
183 // check that we are using Sun Java
184 String java_vendor = System.getProperty("java.vendor");
185 if (!java_vendor.equals("Sun Microsystems Inc.")) {
186 // is this the definitive string??
187 System.err.println(Dictionary.get("General.NotSunJava", java_vendor));
188 }
189
190 if (gsdl_path == null) {
191 missingGSDL();
192 }
193
194 // Start up the local library server, if that's what we want
195 if (Utility.isWindows() && local_library_path != null && !GS3) {
196 LocalLibraryServer.start(gsdl_path, local_library_path);
197 }
198
199 // The "-library_url" option overwrites anything in the config files
200 if (library_url_string != null && library_url_string.length() > 0) {
201 try {
202 System.err.println("Setting library_url to " + library_url_string + "...");
203 Configuration.library_url = new URL(library_url_string);
204 }
205 catch (MalformedURLException error) {
206 DebugStream.printStackTrace(error);
207 }
208 }
209
210 // Check that we now know the Greenstone library URL, since we need this for previewing collections
211 DebugStream.println("Configuration.library_url = " + Configuration.library_url);
212 if (Configuration.library_url == null) {
213 missingEXEC();
214 }
215
216 // Check for ImageMagick
217 if (Gatherer.isGsdlRemote) {
218 DebugStream.println("Not checking for ImageMagick.");
219 }
220 else if (!(new ImageMagickTest()).found()) {
221 // Time for a warning message
222 missingImageMagick();
223 }
224
225 if (Gatherer.isGsdlRemote) {
226 DebugStream.println("Not checking for perl path/exe");
227 }
228 else {
229 // Perl path is a little different as it is perfectly ok to
230 // start the Gatherer without providing a perl path
231 boolean found_perl = false;
232 if (Configuration.perl_path != null) {
233 // See if the file pointed to actually exists
234 File perl_file = new File(Configuration.perl_path);
235 found_perl = perl_file.exists();
236 perl_file = null;
237 }
238 if (Configuration.perl_path == null || !found_perl) {
239 // Run test to see if we can run perl as is.
240 PerlTest perl_test = new PerlTest();
241 if (perl_test.found()) {
242 // If so replace the perl path with the system
243 // default (or null for unix).
244 Configuration.perl_path = perl_test.toString();
245 found_perl = true;
246 }
247 }
248 if (!found_perl) {
249 // Time for an error message.
250 missingPERL();
251 }
252 }
253
254 boolean download_workflow = Configuration.get("workflow.download", false);
255 if (download_workflow) {
256 // If the WGet path hasn't been specified by the user, try the Greenstone one
257 if (wget_path == null) {
258 File wget_file = new File(Utility.getWGetPath(gsdl_path));
259 if (wget_file.exists()) {
260 wget_path = Utility.getWGetPath(gsdl_path);
261 }
262 }
263
264 // If we still don't have a WGet path, give up (there isn't anything else we can do)
265 String wget_version_str = null;
266 if (wget_path == null) {
267 wget_version_str = StaticStrings.NO_WGET_STR;
268 missingWGET();
269 }
270 // Otherwise check the version of WGet
271 else {
272 wget_version_str = testWGetVersion(wget_path);
273 if (wget_version_str.equals(StaticStrings.WGET_OLD_STR)) {
274 oldWGET();
275 }
276 }
277
278 // Store the new values in the configuration
279 DebugStream.println("WGet path: " + wget_path);
280 Configuration.setWGetPath(wget_path);
281 Configuration.setWGetVersion(wget_version_str);
282 }
283
284 // Set the default font for all Swing components.
285 FontUIResource default_font = Configuration.getFont("general.font", true);
286 Enumeration keys = UIManager.getDefaults().keys();
287 while (keys.hasMoreElements()) {
288 Object key = keys.nextElement();
289 Object value = UIManager.get(key);
290 if (value instanceof FontUIResource) {
291 UIManager.put(key, default_font);
292 }
293 }
294
295 // Set up proxy
296 setProxy();
297 // Now we set up an Authenticator
298 Authenticator.setDefault(new GAuthenticator());
299
300 assoc_man = new FileAssociationManager();
301 // Create File Manager
302 f_man = new FileManager();
303 // Create Collection Manager
304 c_man = new CollectionManager();
305
306 if (GS3) {
307 if (site_name==null) {
308 site_name = Configuration.site_name;
309 servlet_path = null; // need to reset this
310 }
311 if (servlet_path == null) {
312 servlet_path = Configuration.getServletPath();
313 }
314 }
315
316 open_collection_file_path = open_collection;
317 if (open_collection_file_path == null) {
318 open_collection_file_path = Configuration.getString("general.open_collection", true);
319 }
320 if (no_load || open_collection_file_path.equals("")) {
321 open_collection_file_path = null;
322 }
323 }
324 catch (Exception exception) {
325 DebugStream.printStackTrace(exception);
326 }
327
328 // Create GUI Manager (last) or else suffer the death of a thousand NPE's
329 g_man = new GUIManager(size);
330 return g_man;
331 }
332
333
334 public void run(Dimension size, GUIManager g_man)
335 {
336 // Size and place the frame on the screen
337 Rectangle bounds = Configuration.getBounds("general.bounds", true);
338 if (bounds == null) {
339 // Choose a sensible default value
340 bounds = new Rectangle(0, 0, 640, 480);
341 }
342
343 // Ensure width and height are reasonable
344 size = bounds.getSize();
345 if (size.width < 640) {
346 size.width = 640;
347 }
348 else if (size.width > Configuration.screen_size.width) {
349 size.width = Configuration.screen_size.width;
350 }
351 if (size.height < 480) {
352 size.height = 480;
353 }
354 else if (size.height > Configuration.screen_size.height) {
355 size.height = Configuration.screen_size.height;
356 }
357
358 if (!g_man_built) {
359
360 g_man.display();
361
362 // Place the window in the desired location on the screen, if this is do-able (not under most linux window managers apparently. In fact you're lucky if they listen to any of your screen size requests).
363 g_man.setLocation(bounds.x, bounds.y);
364 g_man.setVisible(true);
365
366 // After the window has been made visible, check that it is in the correct place
367 // sometimes java places a window not in the correct place,
368 // but with an offset. If so, we work out what the offset is
369 // and change the desired location to take that into account
370 Point location = g_man.getLocation();
371 int x_offset = bounds.x - location.x;
372 int y_offset = bounds.y - location.y;
373 // If not, offset the window to move it into the correct location
374 if (x_offset > 0 || y_offset > 0) {
375 ///ystem.err.println("changing the location to "+(bounds.x + x_offset)+" "+ (bounds.y + y_offset));
376 g_man.setLocation(bounds.x + x_offset, bounds.y + y_offset);
377 }
378
379 // The 'after-display' triggers several events which don't occur until after the visual components are actually available on screen. Examples of these would be the various html renderings, as they can't happen offscreen.
380 g_man.afterDisplay();
381 g_man_built = true;
382 }
383 else {
384 g_man.setVisible(true);
385 }
386 }
387
388
389 /** Exits the Gatherer after ensuring that things needing saving are saved.
390 * @see java.io.FileOutputStream
391 * @see java.io.PrintStream
392 * @see java.lang.Exception
393 * @see javax.swing.JOptionPane
394 * @see org.greenstone.gatherer.Configuration
395 * @see org.greenstone.gatherer.collection.CollectionManager
396 * @see org.greenstone.gatherer.gui.GUIManager
397 */
398 public void exit() {
399 exit = true;
400 // If we have an open collection make note of it.
401 Configuration.setString("general.open_collection", true, null);
402 if(c_man.ready()) {
403 ///ystem.err.println("Collection open.");
404 if(c_man.saved()) {
405 ///ystem.err.println("Collection has been recently saved, so I'll remember it for next time.");
406 Configuration.setString("general.open_collection", true, c_man.getCollectionFilePath());
407 }
408 c_man.closeCollection();
409 }
410 if(assoc_man != null) {
411 assoc_man.save();
412 assoc_man = null;
413 }
414
415 // Store the current position and size (if reasonable) of the Gatherer for next time
416 Rectangle bounds = g_man.getBounds();
417 Configuration.setBounds("general.bounds", true, bounds);
418
419 // Save configuration.
420 saveConfig();
421
422 // Get the gui to deallocate
423 g_man.setVisible(false);
424 g_man.destroy();
425 g_man_built = false;
426
427 // Flush debug
428 DebugStream.closeDebugStream();
429
430 // If we started a server, we should try to stop it.
431 if (LocalLibraryServer.isRunning() == true) {
432 LocalLibraryServer.stop();
433 }
434
435 if(apps.size() == 0) {
436 if (!Gatherer.isGsdlRemote) {
437 System.exit(0);
438 }
439 }
440 else {
441 JOptionPane.showMessageDialog(g_man, Dictionary.get("General.Outstanding_Processes"), Dictionary.get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
442 g_man.setVisible(false);
443 }
444 }
445
446
447 static public String getCollectDirectoryPath()
448 {
449 if (non_standard_collect_directory_path != null) {
450 return non_standard_collect_directory_path;
451 }
452
453 if (!GS3) {
454 return Configuration.gsdl_path + "collect" + File.separator;
455 }
456 else {
457 return getSitesDirectoryPath() + Configuration.site_name + File.separator + "collect" + File.separator;
458 }
459 }
460
461
462 static public String getSitesDirectoryPath()
463 {
464 return Configuration.gsdl3_path + File.separator + "web" + File.separator + "sites" + File.separator;
465 }
466
467
468 static public void setCollectDirectoryPath(String collect_directory_path)
469 {
470 non_standard_collect_directory_path = collect_directory_path;
471 if (!non_standard_collect_directory_path.endsWith(File.separator)) {
472 non_standard_collect_directory_path = non_standard_collect_directory_path + File.separator;
473 }
474 }
475
476
477 static public void refresh(int refresh_reason)
478 {
479 if (g_man != null) {
480 g_man.refresh(refresh_reason, c_man.ready());
481 }
482
483 // Now is a good time to force a garbage collect
484 System.gc();
485 }
486
487
488 // used to send reload coll messages to the tomcat server
489 static public void configGS3Server(String site, String command) {
490
491 try {
492 // need to add the servlet name to the exec address
493 String raw_url = Configuration.library_url.toString() + Configuration.getServletPath() + command;
494 URL url = new URL(raw_url);
495 DebugStream.println("Action: " + raw_url);
496 HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
497 int response_code = library_connection.getResponseCode();
498 if(HttpURLConnection.HTTP_OK <= response_code && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
499 DebugStream.println("200 - Complete.");
500 }
501 else {
502 DebugStream.println("404 - Failed.");
503 }
504 url = null;
505 }
506 catch (Exception exception) {
507 DebugStream.printStackTrace(exception);
508 }
509 }
510
511
512 /** Used to 'spawn' a new child application when a file is double clicked.
513 * @param file The file to open
514 * @see org.greenstone.gatherer.Gatherer.ExternalApplication
515 */
516 public void spawnApplication(File file) {
517 String [] commands = assoc_man.getCommand(file);
518 if(commands != null) {
519 ExternalApplication app = new ExternalApplication(commands);
520 apps.add(app);
521 app.start();
522 }
523 else {
524 ///ystem.err.println("No open command available.");
525 }
526 }
527
528
529 public void spawnApplication(String command)
530 {
531 ExternalApplication app = new ExternalApplication(command);
532 apps.add(app);
533 app.start();
534 }
535
536
537 /** Used to 'spawn' a new browser application or reset an existing one when the preview button is clicked
538 * @param url The url to open the browser at
539 * @see org.greenstone.gatherer.Gatherer.BrowserApplication
540 */
541 public void spawnBrowser(String url) {
542 String command = assoc_man.getBrowserCommand(url);
543 if (command != null) {
544 BrowserApplication app = new BrowserApplication(command, url);
545 apps.add(app);
546 app.start();
547 }
548 else {
549 ///ystem.err.println("No browser command available.");
550 }
551 }
552
553
554 /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
555 */
556 static public void missingEXEC() {
557 WarningDialog dialog;
558 if (GS3) {
559 dialog = new WarningDialog("warning.MissingEXEC_GS3", "MissingEXEC_GS3.Title", "MissingEXEC_GS3.Message", "general.library_url", false);
560 }
561 else {
562 dialog = new WarningDialog("warning.MissingEXEC", "MissingEXEC.Title", "MissingEXEC.Message", "general.library_url", false);
563 }
564 dialog.setValueField(new URLField(Configuration.getColor("coloring.editable_foreground", false), Configuration.getColor("coloring.editable_background", false), Configuration.getColor("coloring.error_foreground", false), Configuration.getColor("coloring.error_background", false)));
565 dialog.display();
566 dialog.dispose();
567 dialog = null;
568
569 String library_url_string = Configuration.getString("general.library_url", true);
570 if (!library_url_string.equals("")) {
571 try {
572 Configuration.library_url = new URL(library_url_string);
573 }
574 catch (MalformedURLException exception) {
575 DebugStream.printStackTrace(exception);
576 }
577 }
578 }
579
580
581 /** Prints a warning message about a missing GSDL path, which although not fatal pretty much ensures nothing will work properly in the GLI.
582 */
583 static public void missingGSDL() {
584 WarningDialog dialog = new WarningDialog("warning.MissingGSDL", "MissingGSDL.Title", "MissingGSDL.Message", null, false);
585 dialog.display();
586 dialog.dispose();
587 dialog = null;
588 }
589
590 /** Prints a warning message about missing a valid ImageMagick path, which although not fatal means building image collections won't work */
591 static public void missingImageMagick() {
592 WarningDialog dialog = new WarningDialog("warning.MissingImageMagick", "MissingImageMagick.Title", "MissingImageMagick.Message", null, false);
593 dialog.display();
594 dialog.dispose();
595 dialog = null;
596 }
597
598 /** Prints a warning message about missing a valid PERL path, which although not fatal pretty much ensures no collection creation/building will work properly in the GLI. */
599 static public void missingPERL() {
600 WarningDialog dialog = new WarningDialog("warning.MissingPERL", "MissingPERL.Title", "MissingPERL.Message", null, false);
601 dialog.display();
602 dialog.dispose();
603 dialog = null;
604 }
605
606 /** Prints a warning message about missing a valid WGet path, which although not fatal means mirroring won't work */
607 static public void missingWGET() {
608 WarningDialog dialog = new WarningDialog("warning.MissingWGET", "MissingWGET.Title", "MissingWGET.Message", null, false);
609 dialog.display();
610 dialog.dispose();
611 dialog = null;
612 }
613
614 /** Prints a warning message about having an old version of WGet. not fatal, but mirroring may not work properly */
615 static public void oldWGET() {
616 WarningDialog dialog = new WarningDialog("warning.OldWGET", "OldWGET.Title", "OldWGET.Message", null, false);
617 dialog.display();
618 dialog.dispose();
619 dialog = null;
620 }
621
622
623 /** Sets up the proxy connection by setting JVM Environment flags and creating a new Authenticator.
624 * @see java.lang.Exception
625 * @see java.lang.System
626 * @see java.net.Authenticator
627 * @see org.greenstone.gatherer.Configuration
628 * @see org.greenstone.gatherer.GAuthenticator
629 */
630 static public void setProxy() {
631 try {// Can throw several exceptions
632 if(Configuration.get("general.use_proxy", true)) {
633 System.setProperty("http.proxyType", "4");
634 System.setProperty("http.proxyHost", Configuration.getString("general.proxy_host", true));
635 System.setProperty("http.proxyPort", Configuration.getString("general.proxy_port", true));
636 System.setProperty("http.proxySet", "true");
637 } else {
638 System.setProperty("http.proxySet", "false");
639 }
640 } catch (Exception error) {
641 DebugStream.println("Error in Gatherer.initProxy(): " + error);
642 DebugStream.printStackTrace(error);
643 }
644 }
645
646
647 /** Causes the general configuration file to export itself to xml. Doesn't effect any remaining collection configuration, as its up to the collection manager to handle them (especially since we have no idea where they are going). */
648 private void saveConfig() {
649 try {
650 Configuration.save();
651 } catch (Exception exception) {
652 DebugStream.printStackTrace(exception);
653 }
654 }
655
656
657 // TODO fill this in
658 private String testWGetVersion(String wget_path) {
659 return StaticStrings.WGET_STR;
660 }
661
662 /** This private class contains an instance of an external application running within a JVM shell. It is important that this process sits in its own thread, but its more important that when we exit the Gatherer we don't actually System.exit(0) the Gatherer object until the user has volunteerily ended all of these child processes. Otherwise when we quit the Gatherer any changes the users may have made in external programs will be lost and the child processes are automatically deallocated. */
663 private class ExternalApplication
664 extends Thread {
665 private Process process = null;
666 /** The initial command string given to this sub-process. */
667 private String command = null;
668 private String[] commands = null;
669 /** Constructor.
670 * @param command The initial command <strong>String</strong>.
671 */
672 public ExternalApplication(String command) {
673 this.command = command;
674 }
675
676 public ExternalApplication(String[] commands) {
677 this.commands = commands;
678 }
679 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
680 * @see java.lang.Exception
681 * @see java.lang.Process
682 * @see java.lang.Runtime
683 * @see java.lang.System
684 * @see java.util.Vector
685 */
686 public void run() {
687 // Call an external process using the args.
688 try {
689 if(commands != null) {
690 StringBuffer whole_command = new StringBuffer();
691 for(int i = 0; i < commands.length; i++) {
692 whole_command.append(commands[i]);
693 whole_command.append(" ");
694 }
695 DebugStream.println("Running " + whole_command.toString());
696 Runtime rt = Runtime.getRuntime();
697 process = rt.exec(commands);
698 process.waitFor();
699 }
700 else {
701 DebugStream.println("Running " + command);
702 Runtime rt = Runtime.getRuntime();
703 process = rt.exec(command);
704 process.waitFor();
705 }
706 }
707 catch (Exception exception) {
708 DebugStream.printStackTrace(exception);
709 }
710 // Remove ourself from Gatherer list of threads.
711 apps.remove(this);
712 // Call exit if we were the last outstanding child process thread.
713 if (apps.size() == 0 && exit == true) {
714 System.exit(0);
715 }
716 }
717 public void stopExternalApplication() {
718 if(process != null) {
719 process.destroy();
720 }
721 }
722 }
723 /** This private class contains an instance of an external application running within a JVM shell. It is important that this process sits in its own thread, but its more important that when we exit the Gatherer we don't actually System.exit(0) the Gatherer object until the user has volunteerily ended all of these child processes. Otherwise when we quit the Gatherer any changes the users may have made in external programs will be lost and the child processes are automatically deallocated. */
724 private class BrowserApplication
725 extends Thread {
726 private Process process = null;
727 /** The initial command string given to this sub-process. */
728 private String command = null;
729 private String url = null;
730 private String[] commands = null;
731
732 public BrowserApplication(String command, String url) {
733 StringTokenizer st = new StringTokenizer(command);
734 int num_tokens = st.countTokens();
735 this.commands = new String [num_tokens];
736 int i=0;
737 while (st.hasMoreTokens()) {
738 commands[i] = st.nextToken();
739 i++;
740 }
741 //this.commands = commands;
742 this.url = url;
743 }
744 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
745 * @see java.lang.Exception
746 * @see java.lang.Process
747 * @see java.lang.Runtime
748 * @see java.lang.System
749 * @see java.util.Vector
750 */
751 public void run() {
752 // Call an external process using the args.
753 if(commands == null) {
754 apps.remove(this);
755 return;
756 }
757 try {
758 String prog_name = commands[0];
759 String lower_name = prog_name.toLowerCase();
760 if (lower_name.indexOf("mozilla") != -1 || lower_name.indexOf("netscape") != -1) {
761 DebugStream.println("found mozilla or netscape, trying remote it");
762 // mozilla and netscape, try using a remote command to get things in the same window
763 String [] new_commands = new String[] {prog_name, "-raise", "-remote", "openURL("+url+",new-tab)"};
764 printArray(new_commands);
765
766 Runtime rt = Runtime.getRuntime();
767 process = rt.exec(new_commands);
768 int exitCode = process.waitFor();
769 if (exitCode != 0) { // if Netscape or mozilla was not open
770 DebugStream.println("couldn't do remote, trying original command");
771 printArray(commands);
772 process = rt.exec(commands); // try the original command
773 }
774 } else {
775 // just run what we have been given
776 StringBuffer whole_command = new StringBuffer();
777 for(int i = 0; i < commands.length; i++) {
778 whole_command.append(commands[i]);
779 whole_command.append(" ");
780 }
781 DebugStream.println("Running " + whole_command.toString());
782 Runtime rt = Runtime.getRuntime();
783 process = rt.exec(commands);
784 process.waitFor();
785 }
786 }
787
788 catch (Exception exception) {
789 DebugStream.printStackTrace(exception);
790 }
791 // Remove ourself from Gatherer list of threads.
792 apps.remove(this);
793 // Call exit if we were the last outstanding child process thread.
794 if (apps.size() == 0 && exit == true) {
795 System.exit(0);
796 }
797 }
798 public void printArray(String [] array) {
799 for(int i = 0; i < array.length; i++) {
800 DebugStream.print(array[i]+" ");
801 System.err.println(array[i]+" ");
802 }
803 }
804 public void stopBrowserApplication() {
805 if(process != null) {
806 process.destroy();
807 }
808 }
809 }
810
811
812 private class ImageMagickTest
813 {
814 public boolean found()
815 {
816 try {
817 String command = (Utility.isWindows() ? "identify.exe" : "identify");
818 Process image_magick_process = Runtime.getRuntime().exec(command);
819 image_magick_process.waitFor();
820 return (image_magick_process.exitValue() == 0);
821 }
822 catch (Exception exception) {
823 return false;
824 }
825 }
826 }
827
828
829 private class PerlTest
830 {
831 private String[] command = new String[2];
832
833 public PerlTest()
834 {
835 command[0] = (Utility.isWindows() ? Utility.PERL_EXECUTABLE_WINDOWS : Utility.PERL_EXECUTABLE_UNIX);
836 command[1] = "-version";
837 }
838
839 public boolean found()
840 {
841 try {
842 Process perl_process = Runtime.getRuntime().exec(command);
843 perl_process.waitFor();
844 return (perl_process.exitValue() == 0);
845 }
846 catch (Exception exception) {
847 return false;
848 }
849 }
850
851 public String toString() {
852 return command[0];
853 }
854 }
855}
Note: See TracBrowser for help on using the repository browser.