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

Last change on this file since 4397 was 4397, checked in by jmt12, 21 years ago

Forgot to increment attempt counter for server.exe close down so attempt never timed out.

  • Property svn:keywords set to Author Date Id Revision
File size: 33.7 KB
Line 
1package org.greenstone.gatherer;
2/**
3 *#########################################################################
4 *
5 * A component of the Gatherer application, part of the Greenstone digital
6 * library suite from the New Zealand Digital Library Project at the
7 * University of Waikato, New Zealand.
8 *
9 * <BR><BR>
10 *
11 * Author: John Thompson, Greenstone Digital Library, University of Waikato
12 *
13 * <BR><BR>
14 *
15 * Copyright (C) 1999 New Zealand Digital Library Project
16 *
17 * <BR><BR>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * <BR><BR>
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * <BR><BR>
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 *########################################################################
37 */
38import com.l2fprod.gui.*;
39import com.l2fprod.gui.plaf.skin.*;
40import com.l2fprod.util.*;
41
42import java.awt.*;
43import java.io.*;
44import java.lang.*;
45import java.net.*;
46import java.util.*;
47import javax.swing.*;
48import javax.swing.plaf.*;
49import org.greenstone.gatherer.Configuration;
50import org.greenstone.gatherer.GAuthenticator;
51import org.greenstone.gatherer.collection.CollectionManager;
52import org.greenstone.gatherer.file.FileManager;
53import org.greenstone.gatherer.file.FileAssociationManager;
54import org.greenstone.gatherer.gui.Coloring;
55import org.greenstone.gatherer.gui.GUIManager;
56import org.greenstone.gatherer.gui.Splash;
57import org.greenstone.gatherer.gui.WarningDialog;
58import org.greenstone.gatherer.msm.MetadataSetManager;
59import org.greenstone.gatherer.util.ArrayTools;
60import org.greenstone.gatherer.util.GSDLSiteConfig;
61import org.greenstone.gatherer.util.Utility;
62import sun.misc.*;
63/** Containing the main() method for the Gatherer, this class is the starting point for the rest of the application. It first parses the command line arguments, preparing to update the configuration as required. Next it loads several important support classes such as the Configuration and Dictionary. Finally it creates the other important managers and sends them on their way.
64 * @author John Thompson, Greenstone Digital Library, University of Waikato
65 * @version 2.3
66 */
67public class Gatherer {
68 /** Has the exit flag been set? <i>true</i> if so, <i>false</i> otherwise. */
69 public boolean exit = false;
70 /** The size of the Gatherer window. */
71 public Dimension frame_size = null;
72 /** A temporary shared memory area to store HIndexes to speed up metadata.xml writing. */
73 public Hashtable known_indexes = null;
74 /** Legacy copy of the debug_ps. */
75 public PrintStream debug_ps;
76 /** All of the external applications that must exit before we close the Gatherer. */
77 public Vector apps = new Vector();
78 /** Messages that have been issued before we have anyway to show them, ie prior to Log initialization. */
79 public Vector waiting_messages = new Vector();
80 /** The manager in charge of remembering what file extension gets opened with what program. */
81 static public FileAssociationManager assoc_man;
82 /** A public reference to the CollectionManager. */
83 static public CollectionManager c_man;
84 /** A public reference to the Gatherer's configuration. */
85 static public Configuration config;
86 /** A public reference to the Dictionary. */
87 static public Dictionary dictionary;
88 /** A public reference to the FileManager. */
89 static public FileManager f_man;
90 /** A public reference to the GUIManager. */
91 static public GUIManager g_man;
92 /** A static reference to ourselves. */
93 static public Gatherer self;
94 /** A public reference to the message log. */
95 static public Log log;
96 /** The debug print stream. */
97 static public PrintStream debug;
98 /** The name of the necessary environment variable to check for in the programs environment. */
99 static public String KEY = "GSDLPATH";
100 /** Extra environment information which must be set before shell processes will run properly. Should always be null if the startup script/program has done its job properly. */
101 static public String extra_env[] = null;
102 private GSDLSiteConfig gsdlsite_cfg = null;
103 private ExternalApplication server = null;
104 /** The name of the Gatherers configuration file. */
105 static private String CONFIG_FILE_NAME = "gatherer.cfg";
106 /** Constructor. Make the three main modules, c_man, f_man and g_man, and any other necessary classes such as Dictionary.
107 * @param size The desired size of the Gatherer window as a <strong>Dimension</strong>.
108 * @param gsdl_path The path to the gsdl directory, gathered from the startup arguments, and presented as a <strong>String</strong>.
109 * @param exec_path The path to the library executable, gathered from the startup arguments, and presented as a <strong>String</strong>.
110 * @param debug <i>true</i> to print verbose debug messages to "debug.txt", <i>false</i> otherwise.
111 * @param perl_path The path to the PERL compiler as a <strong>String</strong>. Necessary for windows platform versions.
112 * @param splash A reference to the splash screen.
113 * @param no_load <i>true</i> to prevent the previously opened collection from reopening.
114 * @see java.io.FileOutputStream
115 * @see java.io.PrintStream
116 * @see java.lang.Exception
117 * @see java.lang.StringBuffer
118 * @see java.util.Calendar
119 * @see org.greenstone.gatherer.Configuration
120 * @see org.greenstone.gatherer.Dictionary
121 * @see org.greenstone.gatherer.Gatherer.CTRLCHandler
122 * @see org.greenstone.gatherer.GAuthenticator
123 * @see org.greenstone.gatherer.collection.CollectionManager
124 * @see org.greenstone.gatherer.file.FileManager
125 * @see org.greenstone.gatherer.gui.GUIManager
126 * @see org.greenstone.gatherer.gui.Splash
127 */
128 public Gatherer() {
129 this.self = this;
130 }
131
132 public void run(Dimension size, String gsdl_path, String exec_path, boolean debug_enabled, String perl_path, boolean no_load, Splash splash, String open_collection) {
133
134 // This will hopefully catch ctrl-c and terminate, and exit gracefully. However it is platform specific, and may not be supported by some JVMs.
135 /** It does, but I get bloddy sick of it working when the Gatherer hangs.
136 CTRLCHandler handler = new CTRLCHandler();
137 Signal.handle(new Signal("INT"), handler);
138 Signal.handle(new Signal("TERM"), handler);
139 handler = null;
140 */
141 // Create the debug stream only if required.
142 if(debug_enabled) {
143 try {
144 Calendar now = Calendar.getInstance();
145 StringBuffer name = new StringBuffer("debug");
146 name.append(now.get(Calendar.DATE));
147 name.append("-");
148 name.append(now.get(Calendar.MONTH));
149 name.append("-");
150 name.append(now.get(Calendar.YEAR));
151 name.append(".txt");
152 this.debug = new PrintStream(new FileOutputStream(name.toString()));
153 Properties props = System.getProperties();
154 props.list(debug);
155 // Legacy
156 debug_ps = debug;
157 }
158 catch(Exception error) {
159 ///ystem.err.println("Error in Gatherer.init(): " + error);
160 error.printStackTrace();
161 System.exit(1);
162 }
163 }
164 try {
165 // Create log
166 log = new Log();
167 // Load Config
168 loadConfig(gsdl_path, exec_path, perl_path);
169
170 // Read Dictionary
171 dictionary = new Dictionary(config.getLocale("general.locale", true), config.getFont("general.font", true));
172
173 // If we were given a server run it if neccessary.
174 if(config.exec_file != null) {
175 startServerEXE();
176 }
177
178 // Having loaded the configuration (necessary to determine if certain warnings have been disabled) and dictionary, we now check if the necessary path variables have been provided.
179
180 if(config.exec_file == null && config.exec_address == null) {
181 missingEXEC(dictionary);
182 }
183 if(gsdl_path == null) {
184 missingGSDL(dictionary);
185 }
186 // Perl path is a little different as it is perfectly ok to start the Gatherer without providing a perl path
187 boolean found_perl = false;
188 if(config.perl_path != null) {
189 // See if the file pointed to actually exists
190 File perl_file = new File(config.perl_path);
191 found_perl = perl_file.exists();
192 perl_file = null;
193 }
194 if(config.perl_path == null || !found_perl) {
195 // Run test to see if we can run perl as is.
196 PerlTest perl_test = new PerlTest();
197 if(perl_test.found()) {
198 // If so replace the perl path with the system default (or null for unix).
199 config.perl_path = perl_test.toString();
200 found_perl = true;
201 }
202 }
203 if(!found_perl) {
204 // Time for an error message.
205 missingPERL(dictionary);
206 }
207 else {
208 ///ystem.err.println("Now perl_path = " + config.perl_path);
209 }
210
211 // Size the screen
212 Dimension temp = config.getDimension("general.size", true);
213 if(temp != null) {
214 size = temp;
215 }
216 if (size.height > config.screen_size.height) {
217 size.setSize(size.width, config.screen_size.height);
218 }
219 if (size.width > config.screen_size.width) {
220 size.setSize(config.screen_size.width, size.height);
221 }
222 // Set default font
223 setUIFont(config.getFont("general.font", true), config.getFont("general.tooltip_font", true));
224 // Set up proxy
225 setProxy();
226 // Now we set up an Authenticator
227 Authenticator.setDefault(new GAuthenticator());
228
229 assoc_man = new FileAssociationManager();
230 // Create File Manager
231 f_man = new FileManager();
232 // Create Collection Manager
233 c_man = new CollectionManager();
234 // If there was an open collection last session, reopen it.
235 if(open_collection == null) {
236 open_collection = config.getString("general.open_collection", true);
237 }
238 if(!no_load && open_collection.length() > 0) {
239 c_man.loadCollection(open_collection);
240 }
241 // Create GUI Manager (last) or else suffer the death of a thousand NPE's
242 splash.toFront();
243 g_man = new GUIManager(size);
244 g_man.display();
245
246 // Center 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).
247 g_man.setLocation((config.screen_size.width - size.width) / 2, (config.screen_size.height - size.height) / 2);
248 g_man.setVisible(true);
249 // 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.
250 g_man.afterDisplay();
251 // Hide the splash.
252 splash.hide();
253 splash.destroy();
254 splash = null;
255 }
256 catch (Exception error) {
257 error.printStackTrace();
258 }
259 }
260 /** Writes a message to the debug filestream.
261 * @param message The message as a <strong>String</strong>.
262 */
263 public void debug(String message) {
264 debug(null, message);
265 }
266 /** Writes a message to the debug filestream.
267 * @param error The <strong>Exception</strong> associated with this message, or <i>null</i> for no exception.
268 * @param message The message as a <strong>String</strong>.
269 * @see java.io.FileOutputStream
270 * @see java.io.PrintStream
271 * @see java.lang.Exception
272 */
273 public void debug(Exception exception, String message) {
274 if(message != null) {
275 Gatherer.println(message);
276 }
277 if(exception != null) {
278 Gatherer.printStackTrace(exception);
279 }
280 }
281 /** Exits the Gatherer after ensuring that things needing saving are saved.
282 * @see java.io.FileOutputStream
283 * @see java.io.PrintStream
284 * @see java.lang.Exception
285 * @see javax.swing.JOptionPane
286 * @see org.greenstone.gatherer.Configuration
287 * @see org.greenstone.gatherer.collection.CollectionManager
288 * @see org.greenstone.gatherer.gui.GUIManager
289 */
290 public void exit() {
291 exit = true;
292 // If we have an open collection make note of it.
293 config.setString("general.open_collection", true, null);
294 if(c_man.ready()) {
295 ///ystem.err.println("Collection open.");
296 if(c_man.saved()) {
297 ///ystem.err.println("Collection has been recently saved, so I'll remember it for next time.");
298 config.setString("general.open_collection", true, c_man.getCollectionFilename());
299 }
300 c_man.closeCollection();
301 }
302 if(assoc_man != null) {
303 assoc_man.destroy();
304 assoc_man = null;
305 }
306 // Check the current size of the Gatherer, and if its reasonable (ie greater than minsize) then store it for next time.
307 Dimension size = g_man.getSize();
308 if(size.width > 100 && size.height > 100) {
309 config.setDimension("general.size", true, size);
310 }
311
312 // Save configuration.
313 saveConfig();
314 // Flush debug
315 if(debug != null) {
316 try {
317 debug.flush();
318 debug.close();
319 }
320 catch (Exception error) {
321 error.printStackTrace();
322 }
323 }
324
325 // If we started a server, we should try to stop it.
326 if(gsdlsite_cfg != null) {
327 stopServerEXE();
328 }
329
330 if(apps.size() == 0) {
331 System.exit(0);
332 }
333 else {
334 JOptionPane.showMessageDialog(g_man, get("General.Outstanding_Processes"), get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
335 g_man.hide();
336 }
337 }
338 /** Overloaded to call get with both a key and an empty argument array.
339 * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
340 * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
341 */
342 public String get(String key) {
343 return dictionary.get(key, (String[])null);
344 }
345 /** Overloaded to call get with both a key and an argument array with one element.
346 * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
347 * @param arg A single argument as a <strong>String</strong>.
348 * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
349 */
350 public String get(String key, String arg) {
351 String args[] = new String[1];
352 args[0] = arg;
353 return dictionary.get(key, args);
354 }
355 /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
356 * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
357 * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
358 * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
359 * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatically populated with formatting Strings of with argument String provided in the get call.
360 * @see org.greenstone.gatherer.Gatherer
361 * @see org.greenstone.gatherer.Dictionary
362 */
363 public String get(String key, String args[]) {
364 return dictionary.get(key, args);
365 }
366 /** Retrieve the metadata directory, as required by any MSMCaller implementation.
367 * @return The currently active collection metadata directory as a <strong>String</strong>.
368 * @see org.greenstone.gatherer.collection.CollectionManager
369 */
370 public String getCollectionMetadata() {
371 if(c_man != null && c_man.ready()) {
372 return c_man.getCollectionMetadata();
373 }
374 return "";
375 }
376 /** Retrieve a reference to the frame that any dialog boxes will appear relative to, as required by any MSMCaller or CDMCaller implementation.
377 * @return A <strong>JFrame</strong>.
378 * @see org.greenstone.gatherer.gui.GUIManager
379 */
380 public JFrame getFrame() {
381 return g_man;
382 }
383 /** Method to retrieve a reference to the metadata set manager class. This is then used to create the 'metadataset' commands in the collection configuration file.
384 * @return A reference to the <Strong>MetadataSetManager</strong>.
385 * @see org.greenstone.gatherer.collection.CollectionManager
386 */
387 public MetadataSetManager getMSM() {
388 if(c_man != null && c_man.getCollection() != null && c_man.getCollection().msm != null) {
389 return c_man.getCollection().msm;
390 }
391 return null;
392 }
393 /** Used to 'spawn' a new child application when a file is double clicked.
394 * @param command The command to run in the child process to start the application, garnered from the registry of a default associations file, and presented as a <strong>String</strong>.
395 * @see java.util.Vector
396 * @see org.greenstone.gatherer.Gatherer.ExternalApplication
397 */
398 public void spawnApplication(File file) {
399 String command = assoc_man.getCommand(file);
400 if(command != null) {
401 ExternalApplication app = new ExternalApplication(command);
402 apps.add(app);
403 app.start();
404 }
405 else {
406 ///ystem.err.println("No open command available.");
407 }
408 }
409
410 /** Some startup arguments to the Gatherer have been encoded, where ' ' is replaced with '%', in order to allow arguments containing spaces to be parsed correctly by the JVM, and this method restores these arguments to thier original state.
411 * @param encoded An encoded <strong>String</strong>.
412 * @return The decoded <strong>String</strong>.
413 */
414 static public String decode(String encoded) {
415 return encoded.replace('%', ' ');
416 }
417 /** The entry point into the Gatherer. Parses arguments.
418 * @param args A collection of arguments that may include: initial screen size, dictionary, path to the GSDL etc.
419 * @see java.io.File
420 * @see java.io.FileInputStream
421 * @see java.lang.Exception
422 * @see java.util.Properties
423 * @see org.greenstone.gatherer.Dictionary
424 * @see org.greenstone.gatherer.Gatherer
425 * @see org.greenstone.gatherer.gui.Splash
426 */
427 static public void main(String[] args) {
428 // A serious hack, but its good enough to stop crappy 'Could not lock user prefs' error messages.
429 // Thanks to Walter Schatz from the java forums.
430 System.setProperty("java.util.prefs.syncInterval","2000000"); // One message every 600 hours!
431
432 Gatherer gatherer = new Gatherer();
433
434 boolean debug = false;
435 boolean no_load = false;
436 Dictionary dictionary = new Dictionary(null, null); // Default dictionary. Only used for starting error messages.
437 Dimension size = new Dimension(800, 540);
438 String exec_path = null;
439 String extra = null;
440 String filename = null;
441 String gsdl_path = null;
442 String perl_path = null;
443 // Parse arguments
444 for(int i = 0; i < args.length; i++) {
445 if(args[i].equals("-gsdl")) {
446 gsdl_path = decode(args[i+1]);
447 if(!gsdl_path.endsWith(File.separator)) {
448 gsdl_path = gsdl_path + File.separator;
449 }
450 }
451 if(args[i].equals("-load")) {
452 filename = decode(args[i+1]);
453 }
454 else if(args[i].equals("-library") && (i + 1) < args.length) {
455 exec_path = args[i+1];
456 // If we are on a non-windows system, and thus the local server is unavailable, we can append http:// if no protocol found.
457 if(exec_path.lastIndexOf(":", 5) == -1) {
458 exec_path = "http://" + exec_path;
459 }
460 // If the user has given us an address, but it ends with a '/' we assume we're using the greenstone library.cgi
461 if(exec_path.startsWith("http://") && exec_path.endsWith("/")) {
462 exec_path = exec_path + "library";
463 }
464 }
465 else if(args[i].equals("-perl")) {
466 perl_path = decode(args[i+1]);
467 // Test whether this points to the Perl bin directory or the Perl executable itself.
468 File perl_file = new File(perl_path);
469 if(perl_file.isDirectory()) {
470 // If this is windows we create a child file perl.exe, otherwise we create perl
471 if(Utility.isWindows()) {
472 perl_file = new File(perl_file, Utility.PERL_EXECUTABLE_WINDOWS);
473 }
474 else {
475 perl_file = new File(perl_file, Utility.PERL_EXECUTABLE_UNIX);
476 }
477 // And store this new path.
478 perl_path = perl_file.getAbsolutePath();
479 perl_file = null;
480 }
481 // Otherwise its fine as it is
482 ///ystem.err.println("Perl executable is: " + perl_path);
483 }
484 else if(args[i].equals("--help") || args[i].equals("-help") || args[i].equals("?") || args[i].equals("/?") || args[i].equals("/help")) {
485 printUsage(dictionary);
486 System.exit(0);
487 }
488 else if(args[i].equals("--debug") || args[i].equals("-debug")) {
489 debug = true;
490 }
491 // Don't load any previous collection. Convenient for me
492 else if(args[i].equals("-no_load")) {
493 no_load = true;
494 }
495 // Check if they want it skinned.
496 else if(args[i].equals("-skinlf")) {
497 // SkinLF
498 try {
499 SkinLookAndFeel.setSkin(SkinLookAndFeel.loadThemePackDefinition(SkinUtils.toURL(new File("lib/greenaqua/greenaqua.xml"))));
500 SkinLookAndFeel.enable();
501 }
502 catch (Exception error) {
503 ///ystem.err.println("Error: " + error);
504 error.printStackTrace();
505 }
506 }
507 }
508
509 // Splash screen.
510 Splash splash = new Splash();
511
512 // We take appropriate action when an empty gsdl_path is detected.
513 if(gsdl_path == null) {
514 // Check for the presence of the path.cfg file.
515 File path_file = new File("path.cfg");
516 if(path_file.exists()) {
517 try {
518 // Read in then add each property to the Java Environment.
519 FileInputStream prop_file = new FileInputStream(path_file);
520 Properties p = new Properties();
521 p.load(prop_file);
522 extra = p.getProperty(KEY);
523 }
524 catch (Exception error) {
525 System.out.println("Error in main():");
526 error.printStackTrace();
527 System.exit(1);
528 }
529 }
530 else {
531 missingGSDL(dictionary);
532 }
533 }
534 // We take appropriate action when an empty bin_path is detected.
535 gatherer.run(size, gsdl_path, exec_path, debug, perl_path, no_load, splash, filename);
536 }
537 /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
538 */
539 static public void missingEXEC(Dictionary dictionary) {
540 WarningDialog dialog = new WarningDialog("warning.MissingEXEC", false);
541 dialog.display();
542 dialog.dispose();
543 dialog = null;
544 ///ystem.out.println(dictionary.get("General.Missing_EXEC"));
545 }
546 /** Prints a warning message about a missing GSDL path, which although not fatal pretty much ensures nothing will work properly in the Gatherer.
547 */
548 static public void missingGSDL(Dictionary dictionary) {
549 WarningDialog dialog = new WarningDialog("warning.MissingGSDL", false);
550 dialog.display();
551 dialog.dispose();
552 dialog = null;
553 ///ystem.out.println(dictionary.get("General.Missing_GSDL"));
554 }
555 /** Prints a warning message about a missing PERL path, which although not fatal pretty much ensures no collection creation/building will work properly in the Gatherer. */
556 static public void missingPERL(Dictionary dictionary) {
557 WarningDialog dialog = new WarningDialog("warning.MissingPERL", false);
558 dialog.display();
559 dialog.dispose();
560 dialog = null;
561 ///ystem.out.println(dictionary.get("General.Missing_PERL"));
562 }
563 /** Print a message to the debug stream. */
564 static synchronized public void println(String message) {
565 if(debug != null) {
566 debug.println(message);
567 }
568 else {
569 System.err.println(message);
570 }
571 }
572 /** Print a stack trace to the debug stream. */
573 static synchronized public void printStackTrace(Exception exception) {
574 if(debug != null) {
575 exception.printStackTrace(debug);
576 }
577 else {
578 exception.printStackTrace();
579 }
580 }
581 /** Prints a usage message to screen.
582 */
583 static public void printUsage(Dictionary dictionary) {
584 System.out.println(dictionary.get("General.Usage"));
585 }
586
587 /** Sets up the proxy connection by setting JVM Environment flags and creating a new Authenticator.
588 * @see java.lang.Exception
589 * @see java.lang.System
590 * @see java.net.Authenticator
591 * @see org.greenstone.gatherer.Configuration
592 * @see org.greenstone.gatherer.GAuthenticator
593 */
594 static public void setProxy() {
595 try {// Can throw several exceptions
596 if(Gatherer.config.get("general.use_proxy", true)) {
597 System.setProperty("http.proxyType", "4");
598 System.setProperty("http.proxyHost", Gatherer.config.getString("general.proxy_host", true));
599 System.setProperty("http.proxyPort", Gatherer.config.getString("general.proxy_port", true));
600 System.setProperty("http.proxySet", "true");
601 } else {
602 System.setProperty("http.proxySet", "false");
603 }
604 } catch (Exception error) {
605 Gatherer.println("Error in Gatherer.initProxy(): " + error);
606 Gatherer.printStackTrace(error);
607 }
608 }
609
610 /** Set all the default fonts of the program to a choosen font, except the tooltip font which should be some fixed width font.
611 * @param f The default font to use in the Gatherer as a <strong>FontUIResource</strong>.
612 * @param ttf The tooltip font to use also as a <strong>FontUIResource</strong>.
613 * @see java.util.Enumeration
614 * @see javax.swing.UIManager
615 */
616 static public void setUIFont (FontUIResource f, FontUIResource ttf){
617 // sets the default font for all Swing components.
618 // ex.
619 // setUIFont (new FontUIResource("Serif",Font.ITALIC,12));
620 //
621 Enumeration keys = UIManager.getDefaults().keys();
622 while (keys.hasMoreElements()) {
623 Object key = keys.nextElement();
624 Object value = UIManager.get (key);
625 if (value instanceof FontUIResource)
626 UIManager.put (key, f);
627 }
628 // Now set the tooltip font to some fixed width font
629 UIManager.put("ToolTip.font", ttf);
630 }
631
632 /** Loads the configuration file if one exists. Otherwise it creates a new one. Currently uses serialization.
633 * @param size The desired size of the Gatherer window as a <strong>Dimension</strong>.
634 * @param gsdl_path The path to the gsdl directory, gathered from the startup arguments, and presented as a <strong>String</strong>.
635 * @param exec_path The path to the library executable, gathered from the startup arguments, and presented as a <strong>String</strong>.
636 * @param perl_path The path to the PERL compiler as a <strong>String</strong>. Necessary for windows platform versions.
637 * @see java.io.FileInputStream
638 * @see java.io.ObjectInputStream
639 * @see java.lang.Exception
640 * @see org.greenstone.gatherer.Configuration
641 */
642 private void loadConfig(String gsdl_path, String exec_path, String perl_path) {
643 try {
644 config = new Configuration(gsdl_path, exec_path, perl_path);
645 }
646 catch (Exception error) {
647 Gatherer.println("config.xml is not a well formed XML document.");
648 Gatherer.printStackTrace(error);
649 }
650 }
651
652 /** Creates and dispatches a message given the initial details.
653 * @param level An <i>int</i> indicating the message level for this message.
654 * @param message A <strong>String</strong> which contains the payload of this message.
655 * @see org.greenstone.gatherer.Message
656 * @see org.greenstone.gatherer.Log
657 */
658 private void message(int level, String message) {
659 Message msg = new Message(Message.GENERAL, level, message);
660 log.add(msg);
661 }
662
663 /** 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). */
664 private void saveConfig() {
665 try {
666 config.save();
667 } catch (Exception error) {
668 Gatherer.printStackTrace(error);
669 }
670 }
671
672 private void startServerEXE() {
673 if(config.exec_file != null && config.exec_address == null && Utility.isWindows()) {
674 // First of all we create a GSDLSiteCFG object and check if a URL is already present, in which case the server is already running.
675 gsdlsite_cfg = new GSDLSiteConfig(config.exec_file);
676 String url = gsdlsite_cfg.getURL();
677 // If its already running then set exec address.
678 if(url != null) {
679 try {
680 config.exec_address = new URL(url);
681 }
682 catch(Exception error) {
683 }
684 }
685 // Otherwise its time to run the server in a spawned process.
686 if(config.exec_address == null && config.exec_file.exists()) {
687 // Configure for immediate entry. Note that this only works if the gsdlsite.cfg file exists.
688 gsdlsite_cfg.set();
689 // Spawn server
690 server = new ExternalApplication(config.exec_file.getAbsolutePath());
691 server.start();
692 // Now we have to wait until program has started. We do this by reloading and checking
693 try {
694 gsdlsite_cfg.load();
695 while((url = gsdlsite_cfg.getURL()) == null) {
696 synchronized(this) {
697 wait(1000);
698 }
699 gsdlsite_cfg.load();
700 }
701 // Ta-da. Now the url should be available.
702 config.exec_address = new URL(url);
703 }
704 catch (Exception error) {
705 error.printStackTrace();
706 }
707 }
708 // Can't do a damb thing.
709 }
710 System.err.println("Having started server.exe, exec_address is: " + config.exec_address);
711 }
712
713 private void stopServerEXE() {
714 if(server != null) {
715 // See if its already exited for some reason.
716 gsdlsite_cfg.load();
717 if(gsdlsite_cfg.getURL() != null) {
718 // Send the command for it to exit.
719 Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.QUIT_COMMAND);
720 // Wait until it exits.
721 try {
722 gsdlsite_cfg.load();
723 int try_again = JOptionPane.YES_OPTION;
724 while(try_again == JOptionPane.YES_OPTION) {
725 int attempt_count = 0;
726 while(gsdlsite_cfg.getURL() != null && attempt_count < 60) {
727 synchronized(this) {
728 wait(1000); // Wait one second (give or take)
729 }
730 gsdlsite_cfg.load();
731 attempt_count++;
732 }
733 if(attempt_count == 60) {
734 try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, dictionary.get("Server.QuitTimeOut"), dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
735 }
736 else {
737 try_again = JOptionPane.NO_OPTION;
738 }
739 }
740 if(gsdlsite_cfg.getURL() != null) {
741 JOptionPane.showMessageDialog(Gatherer.g_man, dictionary.get("Server.QuitManual"), dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
742 }
743 }
744 catch (Exception error) {
745 error.printStackTrace();
746 }
747 }
748 // Restore the gsdlsite_cfg.
749 if(gsdlsite_cfg != null) {
750 gsdlsite_cfg.restore();
751 }
752 // If the local server is still running then our changed values will get overwritten.
753 if(gsdlsite_cfg.getURL() != null) {
754 JOptionPane.showMessageDialog(Gatherer.g_man, dictionary.get("Server.QuitFailed"), dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
755 }
756 gsdlsite_cfg = null;
757 server = null;
758 }
759 }
760
761 /** 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. */
762 private class ExternalApplication
763 extends Thread {
764 private Process process = null;
765 /** The initial command string given to this sub-process. */
766 private String command = null;
767 /** Constructor.
768 * @param command The initial command <strong>String</strong>.
769 */
770 public ExternalApplication(String command) {
771 this.command = command;
772 }
773 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
774 * @see java.lang.Exception
775 * @see java.lang.Process
776 * @see java.lang.Runtime
777 * @see java.lang.System
778 * @see java.util.Vector
779 */
780 public void run() {
781 // Call an external process using the args.
782 try {
783 debug("Running " + command);
784 Runtime rt = Runtime.getRuntime();
785 process = rt.exec(command);
786 process.waitFor();
787 }
788 catch (Exception error) {
789 debug(error, "Error in ExternalApplication.run(): " + error);
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 stopServerEXE();
796 System.exit(0);
797 }
798 }
799 public void stopExternalApplication() {
800 if(process != null) {
801 process.destroy();
802 }
803 }
804 }
805 /** This class is intented to detect a specific SIGNAL, in this case SIGINT, and exit properly, rather than letting the Gatherer be interrupted which has the potential to leave erroneous lock files. */
806 private class CTRLCHandler
807 implements SignalHandler {
808 /** <i>true</i> if we ignore any other signals we receive, most likely because we are already dealing with one, <i>false</i> otherwise. */
809 private boolean ignore = false;
810 /** The method called by the system to inform us a signal has occured.
811 * @param sig The <strong>Signal</strong> itself.
812 * @see org.greenstone.gatherer.collection.CollectionManager
813 */
814 public void handle(Signal sig) {
815 if(!ignore) {
816 ignore = true;
817 // handle SIGINT
818 System.out.println("Caught Ctrl-C...");
819 if(c_man != null && c_man.ready()) {
820 c_man.closeCollection();
821 }
822 exit();
823 ignore = false;
824 }
825 }
826 }
827
828 private class PerlTest {
829
830 private String[] command = new String[2];
831
832 public PerlTest() {
833 if(Utility.isWindows()) {
834 command[0] = Utility.PERL_EXECUTABLE_WINDOWS;
835 }
836 else {
837 command[0] = Utility.PERL_EXECUTABLE_UNIX;
838 }
839 command[1] = "-version";
840 }
841
842 public boolean found() {
843 boolean found = false;
844 try {
845 Process prcs = Runtime.getRuntime().exec(command);
846 prcs.waitFor();
847 found = (prcs.exitValue() == 0);
848 prcs = null;
849 }
850 catch(Exception error) {
851 }
852 return found;
853 }
854
855 public String toString() {
856 return command[0];
857 }
858 }
859}
860
861
862
863
864
Note: See TracBrowser for help on using the repository browser.