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

Last change on this file since 4482 was 4482, checked in by mdewsnip, 21 years ago

Now chooses a sensible default location and size if none can be found from the configuration files.

  • Property svn:keywords set to Author Date Id Revision
File size: 33.9 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
208 // Size and place the frame on the screen
209 Rectangle bounds = config.getBounds("general.bounds", true);
210 if (bounds == null) {
211 // Choose a sensible default value
212 bounds = new Rectangle(0, 0, 640, 480);
213 }
214
215 // Ensure width and height are reasonable
216 size = bounds.getSize();
217 if (size.width < 640) {
218 size.width = 640;
219 }
220 else if (size.width > config.screen_size.width) {
221 size.width = config.screen_size.width;
222 }
223 if (size.height < 480) {
224 size.height = 480;
225 }
226 else if (size.height > config.screen_size.height) {
227 size.height = config.screen_size.height;
228 }
229 // Set default font
230 setUIFont(config.getFont("general.font", true), config.getFont("general.tooltip_font", true));
231 // Set up proxy
232 setProxy();
233 // Now we set up an Authenticator
234 Authenticator.setDefault(new GAuthenticator());
235
236 assoc_man = new FileAssociationManager();
237 // Create File Manager
238 f_man = new FileManager();
239 // Create Collection Manager
240 c_man = new CollectionManager();
241 // If there was an open collection last session, reopen it.
242 if(open_collection == null) {
243 open_collection = config.getString("general.open_collection", true);
244 }
245 if(!no_load && open_collection.length() > 0) {
246 c_man.loadCollection(open_collection);
247 }
248 // Create GUI Manager (last) or else suffer the death of a thousand NPE's
249 splash.toFront();
250 g_man = new GUIManager(size);
251 g_man.display();
252
253 // 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).
254 // g_man.setLocation((config.screen_size.width - size.width) / 2, (config.screen_size.height - size.height) / 2);
255 g_man.setBounds(bounds);
256 g_man.setVisible(true);
257 // 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.
258 g_man.afterDisplay();
259 // Hide the splash.
260 splash.hide();
261 splash.destroy();
262 splash = null;
263 }
264 catch (Exception error) {
265 error.printStackTrace();
266 }
267 }
268 /** Writes a message to the debug filestream.
269 * @param message The message as a <strong>String</strong>.
270 */
271 public void debug(String message) {
272 debug(null, message);
273 }
274 /** Writes a message to the debug filestream.
275 * @param error The <strong>Exception</strong> associated with this message, or <i>null</i> for no exception.
276 * @param message The message as a <strong>String</strong>.
277 * @see java.io.FileOutputStream
278 * @see java.io.PrintStream
279 * @see java.lang.Exception
280 */
281 public void debug(Exception exception, String message) {
282 if(message != null) {
283 Gatherer.println(message);
284 }
285 if(exception != null) {
286 Gatherer.printStackTrace(exception);
287 }
288 }
289 /** Exits the Gatherer after ensuring that things needing saving are saved.
290 * @see java.io.FileOutputStream
291 * @see java.io.PrintStream
292 * @see java.lang.Exception
293 * @see javax.swing.JOptionPane
294 * @see org.greenstone.gatherer.Configuration
295 * @see org.greenstone.gatherer.collection.CollectionManager
296 * @see org.greenstone.gatherer.gui.GUIManager
297 */
298 public void exit() {
299 exit = true;
300 // If we have an open collection make note of it.
301 config.setString("general.open_collection", true, null);
302 if(c_man.ready()) {
303 ///ystem.err.println("Collection open.");
304 if(c_man.saved()) {
305 ///ystem.err.println("Collection has been recently saved, so I'll remember it for next time.");
306 config.setString("general.open_collection", true, c_man.getCollectionFilename());
307 }
308 c_man.closeCollection();
309 }
310 if(assoc_man != null) {
311 assoc_man.destroy();
312 assoc_man = null;
313 }
314
315 // Store the current position and size (if reasonable) of the Gatherer for next time
316 Rectangle bounds = g_man.getBounds();
317 config.setBounds("general.bounds", true, bounds);
318
319 // Save configuration.
320 saveConfig();
321 // Flush debug
322 if(debug != null) {
323 try {
324 debug.flush();
325 debug.close();
326 }
327 catch (Exception error) {
328 error.printStackTrace();
329 }
330 }
331
332 // If we started a server, we should try to stop it.
333 if(gsdlsite_cfg != null) {
334 stopServerEXE();
335 }
336
337 if(apps.size() == 0) {
338 System.exit(0);
339 }
340 else {
341 JOptionPane.showMessageDialog(g_man, get("General.Outstanding_Processes"), get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
342 g_man.hide();
343 }
344 }
345 /** Overloaded to call get with both a key and an empty argument array.
346 * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
347 * @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.
348 */
349 public String get(String key) {
350 return dictionary.get(key, (String[])null);
351 }
352 /** Overloaded to call get with both a key and an argument array with one element.
353 * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
354 * @param arg A single argument as a <strong>String</strong>.
355 * @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.
356 */
357 public String get(String key, String arg) {
358 String args[] = new String[1];
359 args[0] = arg;
360 return dictionary.get(key, args);
361 }
362 /** 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>
363 * 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>.
364 * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
365 * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
366 * @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.
367 * @see org.greenstone.gatherer.Gatherer
368 * @see org.greenstone.gatherer.Dictionary
369 */
370 public String get(String key, String args[]) {
371 return dictionary.get(key, args);
372 }
373 /** Retrieve the metadata directory, as required by any MSMCaller implementation.
374 * @return The currently active collection metadata directory as a <strong>String</strong>.
375 * @see org.greenstone.gatherer.collection.CollectionManager
376 */
377 public String getCollectionMetadata() {
378 if(c_man != null && c_man.ready()) {
379 return c_man.getCollectionMetadata();
380 }
381 return "";
382 }
383 /** Retrieve a reference to the frame that any dialog boxes will appear relative to, as required by any MSMCaller or CDMCaller implementation.
384 * @return A <strong>JFrame</strong>.
385 * @see org.greenstone.gatherer.gui.GUIManager
386 */
387 public JFrame getFrame() {
388 return g_man;
389 }
390 /** 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.
391 * @return A reference to the <Strong>MetadataSetManager</strong>.
392 * @see org.greenstone.gatherer.collection.CollectionManager
393 */
394 public MetadataSetManager getMSM() {
395 if(c_man != null && c_man.getCollection() != null && c_man.getCollection().msm != null) {
396 return c_man.getCollection().msm;
397 }
398 return null;
399 }
400 /** Used to 'spawn' a new child application when a file is double clicked.
401 * @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>.
402 * @see java.util.Vector
403 * @see org.greenstone.gatherer.Gatherer.ExternalApplication
404 */
405 public void spawnApplication(File file) {
406 String command = assoc_man.getCommand(file);
407 if(command != null) {
408 ExternalApplication app = new ExternalApplication(command);
409 apps.add(app);
410 app.start();
411 }
412 else {
413 ///ystem.err.println("No open command available.");
414 }
415 }
416
417 /** 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.
418 * @param encoded An encoded <strong>String</strong>.
419 * @return The decoded <strong>String</strong>.
420 */
421 static public String decode(String encoded) {
422 return encoded.replace('%', ' ');
423 }
424 /** The entry point into the Gatherer. Parses arguments.
425 * @param args A collection of arguments that may include: initial screen size, dictionary, path to the GSDL etc.
426 * @see java.io.File
427 * @see java.io.FileInputStream
428 * @see java.lang.Exception
429 * @see java.util.Properties
430 * @see org.greenstone.gatherer.Dictionary
431 * @see org.greenstone.gatherer.Gatherer
432 * @see org.greenstone.gatherer.gui.Splash
433 */
434 static public void main(String[] args) {
435 // A serious hack, but its good enough to stop crappy 'Could not lock user prefs' error messages.
436 // Thanks to Walter Schatz from the java forums.
437 System.setProperty("java.util.prefs.syncInterval","2000000"); // One message every 600 hours!
438
439 Gatherer gatherer = new Gatherer();
440
441 boolean debug = false;
442 boolean no_load = false;
443 Dictionary dictionary = new Dictionary(null, null); // Default dictionary. Only used for starting error messages.
444 Dimension size = new Dimension(800, 540);
445 String exec_path = null;
446 String extra = null;
447 String filename = null;
448 String gsdl_path = null;
449 String perl_path = null;
450 // Parse arguments
451 for(int i = 0; i < args.length; i++) {
452 if(args[i].equals("-gsdl")) {
453 gsdl_path = decode(args[i+1]);
454 if(!gsdl_path.endsWith(File.separator)) {
455 gsdl_path = gsdl_path + File.separator;
456 }
457 }
458 if(args[i].equals("-load")) {
459 filename = decode(args[i+1]);
460 }
461 else if(args[i].equals("-library") && (i + 1) < args.length) {
462 exec_path = args[i+1];
463 // If we are on a non-windows system, and thus the local server is unavailable, we can append http:// if no protocol found.
464 if(exec_path.lastIndexOf(":", 5) == -1) {
465 exec_path = "http://" + exec_path;
466 }
467 // If the user has given us an address, but it ends with a '/' we assume we're using the greenstone library.cgi
468 if(exec_path.startsWith("http://") && exec_path.endsWith("/")) {
469 exec_path = exec_path + "library";
470 }
471 }
472 else if(args[i].equals("-perl")) {
473 perl_path = decode(args[i+1]);
474 // Test whether this points to the Perl bin directory or the Perl executable itself.
475 File perl_file = new File(perl_path);
476 if(perl_file.isDirectory()) {
477 // If this is windows we create a child file perl.exe, otherwise we create perl
478 if(Utility.isWindows()) {
479 perl_file = new File(perl_file, Utility.PERL_EXECUTABLE_WINDOWS);
480 }
481 else {
482 perl_file = new File(perl_file, Utility.PERL_EXECUTABLE_UNIX);
483 }
484 // And store this new path.
485 perl_path = perl_file.getAbsolutePath();
486 perl_file = null;
487 }
488 // Otherwise its fine as it is
489 ///ystem.err.println("Perl executable is: " + perl_path);
490 }
491 else if(args[i].equals("--help") || args[i].equals("-help") || args[i].equals("?") || args[i].equals("/?") || args[i].equals("/help")) {
492 printUsage(dictionary);
493 System.exit(0);
494 }
495 else if(args[i].equals("--debug") || args[i].equals("-debug")) {
496 debug = true;
497 }
498 // Don't load any previous collection. Convenient for me
499 else if(args[i].equals("-no_load")) {
500 no_load = true;
501 }
502 // Check if they want it skinned.
503 else if(args[i].equals("-skinlf")) {
504 // SkinLF
505 try {
506 SkinLookAndFeel.setSkin(SkinLookAndFeel.loadThemePackDefinition(SkinUtils.toURL(new File("lib/greenaqua/greenaqua.xml"))));
507 SkinLookAndFeel.enable();
508 }
509 catch (Exception error) {
510 ///ystem.err.println("Error: " + error);
511 error.printStackTrace();
512 }
513 }
514 }
515
516 // Splash screen.
517 Splash splash = new Splash();
518
519 // We take appropriate action when an empty gsdl_path is detected.
520 if(gsdl_path == null) {
521 // Check for the presence of the path.cfg file.
522 File path_file = new File("path.cfg");
523 if(path_file.exists()) {
524 try {
525 // Read in then add each property to the Java Environment.
526 FileInputStream prop_file = new FileInputStream(path_file);
527 Properties p = new Properties();
528 p.load(prop_file);
529 extra = p.getProperty(KEY);
530 }
531 catch (Exception error) {
532 System.out.println("Error in main():");
533 error.printStackTrace();
534 System.exit(1);
535 }
536 }
537 else {
538 missingGSDL(dictionary);
539 }
540 }
541 // We take appropriate action when an empty bin_path is detected.
542 gatherer.run(size, gsdl_path, exec_path, debug, perl_path, no_load, splash, filename);
543 }
544 /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
545 */
546 static public void missingEXEC(Dictionary dictionary) {
547 WarningDialog dialog = new WarningDialog("warning.MissingEXEC", false);
548 dialog.display();
549 dialog.dispose();
550 dialog = null;
551 ///ystem.out.println(dictionary.get("General.Missing_EXEC"));
552 }
553 /** Prints a warning message about a missing GSDL path, which although not fatal pretty much ensures nothing will work properly in the Gatherer.
554 */
555 static public void missingGSDL(Dictionary dictionary) {
556 WarningDialog dialog = new WarningDialog("warning.MissingGSDL", false);
557 dialog.display();
558 dialog.dispose();
559 dialog = null;
560 ///ystem.out.println(dictionary.get("General.Missing_GSDL"));
561 }
562 /** 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. */
563 static public void missingPERL(Dictionary dictionary) {
564 WarningDialog dialog = new WarningDialog("warning.MissingPERL", false);
565 dialog.display();
566 dialog.dispose();
567 dialog = null;
568 ///ystem.out.println(dictionary.get("General.Missing_PERL"));
569 }
570 /** Print a message to the debug stream. */
571 static synchronized public void println(String message) {
572 if(debug != null) {
573 debug.println(message);
574 }
575 else {
576 System.err.println(message);
577 }
578 }
579 /** Print a stack trace to the debug stream. */
580 static synchronized public void printStackTrace(Exception exception) {
581 if(debug != null) {
582 exception.printStackTrace(debug);
583 }
584 else {
585 exception.printStackTrace();
586 }
587 }
588 /** Prints a usage message to screen.
589 */
590 static public void printUsage(Dictionary dictionary) {
591 System.out.println(dictionary.get("General.Usage"));
592 }
593
594 /** Sets up the proxy connection by setting JVM Environment flags and creating a new Authenticator.
595 * @see java.lang.Exception
596 * @see java.lang.System
597 * @see java.net.Authenticator
598 * @see org.greenstone.gatherer.Configuration
599 * @see org.greenstone.gatherer.GAuthenticator
600 */
601 static public void setProxy() {
602 try {// Can throw several exceptions
603 if(Gatherer.config.get("general.use_proxy", true)) {
604 System.setProperty("http.proxyType", "4");
605 System.setProperty("http.proxyHost", Gatherer.config.getString("general.proxy_host", true));
606 System.setProperty("http.proxyPort", Gatherer.config.getString("general.proxy_port", true));
607 System.setProperty("http.proxySet", "true");
608 } else {
609 System.setProperty("http.proxySet", "false");
610 }
611 } catch (Exception error) {
612 Gatherer.println("Error in Gatherer.initProxy(): " + error);
613 Gatherer.printStackTrace(error);
614 }
615 }
616
617 /** Set all the default fonts of the program to a choosen font, except the tooltip font which should be some fixed width font.
618 * @param f The default font to use in the Gatherer as a <strong>FontUIResource</strong>.
619 * @param ttf The tooltip font to use also as a <strong>FontUIResource</strong>.
620 * @see java.util.Enumeration
621 * @see javax.swing.UIManager
622 */
623 static public void setUIFont (FontUIResource f, FontUIResource ttf){
624 // sets the default font for all Swing components.
625 // ex.
626 // setUIFont (new FontUIResource("Serif",Font.ITALIC,12));
627 //
628 Enumeration keys = UIManager.getDefaults().keys();
629 while (keys.hasMoreElements()) {
630 Object key = keys.nextElement();
631 Object value = UIManager.get (key);
632 if (value instanceof FontUIResource)
633 UIManager.put (key, f);
634 }
635 // Now set the tooltip font to some fixed width font
636 UIManager.put("ToolTip.font", ttf);
637 }
638
639 /** Loads the configuration file if one exists. Otherwise it creates a new one. Currently uses serialization.
640 * @param size The desired size of the Gatherer window as a <strong>Dimension</strong>.
641 * @param gsdl_path The path to the gsdl directory, gathered from the startup arguments, and presented as a <strong>String</strong>.
642 * @param exec_path The path to the library executable, gathered from the startup arguments, and presented as a <strong>String</strong>.
643 * @param perl_path The path to the PERL compiler as a <strong>String</strong>. Necessary for windows platform versions.
644 * @see java.io.FileInputStream
645 * @see java.io.ObjectInputStream
646 * @see java.lang.Exception
647 * @see org.greenstone.gatherer.Configuration
648 */
649 private void loadConfig(String gsdl_path, String exec_path, String perl_path) {
650 try {
651 config = new Configuration(gsdl_path, exec_path, perl_path);
652 }
653 catch (Exception error) {
654 Gatherer.println("config.xml is not a well formed XML document.");
655 Gatherer.printStackTrace(error);
656 }
657 }
658
659 /** Creates and dispatches a message given the initial details.
660 * @param level An <i>int</i> indicating the message level for this message.
661 * @param message A <strong>String</strong> which contains the payload of this message.
662 * @see org.greenstone.gatherer.Message
663 * @see org.greenstone.gatherer.Log
664 */
665 private void message(int level, String message) {
666 Message msg = new Message(Message.GENERAL, level, message);
667 log.add(msg);
668 }
669
670 /** 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). */
671 private void saveConfig() {
672 try {
673 config.save();
674 } catch (Exception error) {
675 Gatherer.printStackTrace(error);
676 }
677 }
678
679 private void startServerEXE() {
680 if(config.exec_file != null && config.exec_address == null && Utility.isWindows()) {
681 // First of all we create a GSDLSiteCFG object and check if a URL is already present, in which case the server is already running.
682 gsdlsite_cfg = new GSDLSiteConfig(config.exec_file);
683 String url = gsdlsite_cfg.getURL();
684 // If its already running then set exec address.
685 if(url != null) {
686 try {
687 config.exec_address = new URL(url);
688 }
689 catch(Exception error) {
690 }
691 }
692 // Otherwise its time to run the server in a spawned process.
693 if(config.exec_address == null && config.exec_file.exists()) {
694 // Configure for immediate entry. Note that this only works if the gsdlsite.cfg file exists.
695 gsdlsite_cfg.set();
696 // Spawn server
697 server = new ExternalApplication(config.exec_file.getAbsolutePath());
698 server.start();
699 // Now we have to wait until program has started. We do this by reloading and checking
700 try {
701 gsdlsite_cfg.load();
702 while((url = gsdlsite_cfg.getURL()) == null) {
703 synchronized(this) {
704 wait(1000);
705 }
706 gsdlsite_cfg.load();
707 }
708 // Ta-da. Now the url should be available.
709 config.exec_address = new URL(url);
710 }
711 catch (Exception error) {
712 error.printStackTrace();
713 }
714 }
715 // Can't do a damb thing.
716 }
717 System.err.println("Having started server.exe, exec_address is: " + config.exec_address);
718 }
719
720 private void stopServerEXE() {
721 if(server != null) {
722 // See if its already exited for some reason.
723 gsdlsite_cfg.load();
724 if(gsdlsite_cfg.getURL() != null) {
725 // Send the command for it to exit.
726 Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.QUIT_COMMAND);
727 // Wait until it exits.
728 try {
729 gsdlsite_cfg.load();
730 int try_again = JOptionPane.YES_OPTION;
731 while(try_again == JOptionPane.YES_OPTION) {
732 int attempt_count = 0;
733 while(gsdlsite_cfg.getURL() != null && attempt_count < 60) {
734 synchronized(this) {
735 wait(1000); // Wait one second (give or take)
736 }
737 gsdlsite_cfg.load();
738 attempt_count++;
739 }
740 if(attempt_count == 60) {
741 try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, dictionary.get("Server.QuitTimeOut"), dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
742 }
743 else {
744 try_again = JOptionPane.NO_OPTION;
745 }
746 }
747 if(gsdlsite_cfg.getURL() != null) {
748 JOptionPane.showMessageDialog(Gatherer.g_man, dictionary.get("Server.QuitManual"), dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
749 }
750 }
751 catch (Exception error) {
752 error.printStackTrace();
753 }
754 }
755 // Restore the gsdlsite_cfg.
756 if(gsdlsite_cfg != null) {
757 gsdlsite_cfg.restore();
758 }
759 // If the local server is still running then our changed values will get overwritten.
760 if(gsdlsite_cfg.getURL() != null) {
761 JOptionPane.showMessageDialog(Gatherer.g_man, dictionary.get("Server.QuitFailed"), dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
762 }
763 gsdlsite_cfg = null;
764 server = null;
765 }
766 }
767
768 /** 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. */
769 private class ExternalApplication
770 extends Thread {
771 private Process process = null;
772 /** The initial command string given to this sub-process. */
773 private String command = null;
774 /** Constructor.
775 * @param command The initial command <strong>String</strong>.
776 */
777 public ExternalApplication(String command) {
778 this.command = command;
779 }
780 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
781 * @see java.lang.Exception
782 * @see java.lang.Process
783 * @see java.lang.Runtime
784 * @see java.lang.System
785 * @see java.util.Vector
786 */
787 public void run() {
788 // Call an external process using the args.
789 try {
790 debug("Running " + command);
791 Runtime rt = Runtime.getRuntime();
792 process = rt.exec(command);
793 process.waitFor();
794 }
795 catch (Exception error) {
796 debug(error, "Error in ExternalApplication.run(): " + error);
797 }
798 // Remove ourself from Gatherer list of threads.
799 apps.remove(this);
800 // Call exit if we were the last outstanding child process thread.
801 if(apps.size() == 0 && exit == true) {
802 stopServerEXE();
803 System.exit(0);
804 }
805 }
806 public void stopExternalApplication() {
807 if(process != null) {
808 process.destroy();
809 }
810 }
811 }
812 /** 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. */
813 private class CTRLCHandler
814 implements SignalHandler {
815 /** <i>true</i> if we ignore any other signals we receive, most likely because we are already dealing with one, <i>false</i> otherwise. */
816 private boolean ignore = false;
817 /** The method called by the system to inform us a signal has occured.
818 * @param sig The <strong>Signal</strong> itself.
819 * @see org.greenstone.gatherer.collection.CollectionManager
820 */
821 public void handle(Signal sig) {
822 if(!ignore) {
823 ignore = true;
824 // handle SIGINT
825 System.out.println("Caught Ctrl-C...");
826 if(c_man != null && c_man.ready()) {
827 c_man.closeCollection();
828 }
829 exit();
830 ignore = false;
831 }
832 }
833 }
834
835 private class PerlTest {
836
837 private String[] command = new String[2];
838
839 public PerlTest() {
840 if(Utility.isWindows()) {
841 command[0] = Utility.PERL_EXECUTABLE_WINDOWS;
842 }
843 else {
844 command[0] = Utility.PERL_EXECUTABLE_UNIX;
845 }
846 command[1] = "-version";
847 }
848
849 public boolean found() {
850 boolean found = false;
851 try {
852 Process prcs = Runtime.getRuntime().exec(command);
853 prcs.waitFor();
854 found = (prcs.exitValue() == 0);
855 prcs = null;
856 }
857 catch(Exception error) {
858 }
859 return found;
860 }
861
862 public String toString() {
863 return command[0];
864 }
865 }
866}
867
868
869
870
871
Note: See TracBrowser for help on using the repository browser.