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

Last change on this file since 8204 was 8196, checked in by mdewsnip, 20 years ago

Debug files are now written correctly when running as an applet.

  • Property svn:keywords set to Author Date Id Revision
File size: 37.7 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
29//import com.l2fprod.gui.*;
30//import com.l2fprod.gui.plaf.skin.*;
31//import com.l2fprod.util.*;
32import java.awt.*;
33import java.awt.event.*;
34import java.io.*;
35import java.lang.*;
36import java.net.*;
37import java.util.*;
38import javax.swing.*;
39import javax.swing.plaf.*;
40import javax.swing.text.*;
41import org.greenstone.gatherer.Configuration;
42import org.greenstone.gatherer.GAuthenticator;
43import org.greenstone.gatherer.collection.CollectionManager;
44import org.greenstone.gatherer.feedback.ActionRecorderDialog;
45import org.greenstone.gatherer.file.FileManager;
46import org.greenstone.gatherer.file.FileAssociationManager;
47import org.greenstone.gatherer.gui.GUIManager;
48import org.greenstone.gatherer.gui.ModalDialog;
49import org.greenstone.gatherer.gui.Splash;
50import org.greenstone.gatherer.gui.URLField;
51import org.greenstone.gatherer.gui.WarningDialog;
52import org.greenstone.gatherer.util.GSDLSiteConfig;
53import org.greenstone.gatherer.util.StaticStrings;
54import org.greenstone.gatherer.util.Utility;
55// import sun.misc.*;
56
57/** Containing the top-level "core" for the Gatherer, this class is the
58 * common core for the GLI application and applet. It first parses the
59 * command line arguments, preparing to update the configuration as
60 * required. Next it loads several important support classes such as the
61 * Configuration and Dictionary. Finally it creates the other important
62 * managers and sends them on their way.
63 * @author John Thompson, Greenstone Digital Library, University of Waikato
64 * @version 2.3
65 */
66
67// How to catch All Exceptions including those from the AWT Event thread.
68// Step 1: register a handler class in your main()
69//
70// System.setProperty("sun.awt.exception.handler", "YourHandler");
71//
72// Step 2: implement your handler class.
73//
74// public class YourHandler {
75// public void handle(Throwable thrown) {
76// eat the exception without dumping to the console.
77// }
78// }
79
80public class Gatherer
81{
82 static public Hashtable authentications = new Hashtable();
83
84 static final private String SKIN_DEFINITION_FILE = "lib/greenaqua/greenaqua.xml";
85
86 static public boolean always_show_exceptions = true;
87 /** Has the exit flag been set? <i>true</i> if so, <i>false</i> otherwise. */
88 public boolean exit = false;
89 /** The size of the Gatherer window. */
90 public Dimension frame_size = null;
91
92 /** All of the external applications that must exit before we close the Gatherer. */
93 public Vector apps = new Vector();
94 /** A public reference to the FileAssociationManager. */
95 static public FileAssociationManager assoc_man;
96 /** A public reference to the CollectionManager. */
97 static public CollectionManager c_man;
98 /** A public reference to the Gatherer's configuration. */
99 static public Configuration config;
100 /** a reference to the Servlet Configuration is GS3 */
101 static public ServletConfiguration servlet_config;
102 /** The current modal dialog being shown on screen, if any. */
103 static public ModalDialog current_modal = null;
104 /** A public reference to the Dictionary. */
105 static public Dictionary dictionary;
106 /** A public reference to the FileManager. */
107 static public FileManager f_man;
108 /** A public reference to the GUIManager. */
109 static public GUIManager g_man;
110 static public boolean g_man_built = false;
111
112 /** A static reference to ourselves. */
113 static public Gatherer self;
114 /** The debug print stream. */
115 static public PrintStream debug;
116 /** We are using the GLI for GS3 */
117 static public boolean GS3 = false;
118
119 static public boolean isGsdlRemote = false;
120 static public String cgiBase = "";
121
122 // feedback stuff
123 /** is the feedback feature enabled? */
124 static public boolean feedback_enabled = true;
125 /** the action recorder dialog */
126 static public ActionRecorderDialog feedback_dialog = null;
127 /** 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. */
128 static public String extra_env[] = null;
129 private GSDLSiteConfig gsdlsite_cfg = null;
130 private ExternalApplication server = null;
131
132 /** Magic to allow Enter to fire the default button. */
133 static {
134 KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
135 Keymap map = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
136 map.removeKeyStrokeBinding(enter);
137 }
138
139 public Gatherer()
140 {
141 this.self = this;
142
143 init_images();
144 }
145
146 protected void init_images()
147 {
148 Class base = this.getClass();
149 Utility.BLANK_ICON = new ImageIcon(base.getResource("/images/blank.gif"));
150 Utility.ERROR_ICON = new ImageIcon(base.getResource("/images/error.gif"));
151 Utility.HELP_ICON = new ImageIcon(base.getResource("/images/help.gif"));
152 Utility.ON_ICON = new ImageIcon(base.getResource("/images/check.gif"));
153 Utility.OFF_ICON = new ImageIcon(base.getResource("/images/cross.gif"));
154
155 Utility.base = base;
156 }
157
158
159 public GUIManager init(Dimension size, String gsdl_path, String gsdl3_path,
160 String exec_path, boolean debug_enabled, String perl_path,
161 boolean no_load, String open_collection,
162 String site_name, String servlet_path,
163 boolean mirroring_enabled, String wget_version_str,
164 String wget_path)
165 {
166
167 // This will hopefully catch ctrl-c and terminate, and exit gracefully. However it is platform specific, and may not be supported by some JVMs.
168 /** It does, but I get bloody sick of it working when the Gatherer hangs.
169 CTRLCHandler handler = new CTRLCHandler();
170 Signal.handle(new Signal("INT"), handler);
171 Signal.handle(new Signal("TERM"), handler);
172 handler = null;
173 */
174 if (gsdl3_path != null && !gsdl3_path.equals("")) {
175 this.GS3 = true;
176 } else {
177 gsdl3_path = null;
178 }
179 // Create the debug stream only if required.
180 if(debug_enabled) {
181 try {
182 Calendar now = Calendar.getInstance();
183 StringBuffer name = new StringBuffer("debug");
184 name.append(now.get(Calendar.DATE));
185 name.append("-");
186 name.append(now.get(Calendar.MONTH));
187 name.append("-");
188 name.append(now.get(Calendar.YEAR));
189 name.append(".txt");
190
191 // Debug file is created in the GLI directory, unless the GLI is running as an applet
192 String debug_file_path = name.toString();
193 if (isGsdlRemote) {
194 debug_file_path = Utility.getGLIUserFolder().toString() + File.separator + debug_file_path;
195 }
196 Gatherer.println("Debug file path: " + debug_file_path);
197 this.debug = new PrintStream(new FileOutputStream(debug_file_path));
198
199 Properties props = System.getProperties();
200 props.list(debug);
201 }
202 catch(Exception error) {
203 ///ystem.err.println("Error in Gatherer.init(): " + error);
204 error.printStackTrace();
205 System.exit(1);
206 }
207 }
208 try {
209 // Load Config
210 loadConfig(gsdl_path, gsdl3_path, exec_path, perl_path, mirroring_enabled, site_name);
211
212 // the feedback dialog has been loaded with a default locale,
213 // now set the user specified one
214 if (feedback_enabled && feedback_dialog != null) {
215 feedback_dialog.setLocale(config.getLocale("general.locale", true));
216 }
217
218 // Read Dictionary
219 dictionary = new Dictionary(config.getLocale("general.locale", true), config.getFont("general.font", true));
220
221
222 if (gsdl_path == null) {
223 missingGSDL();
224 }
225
226 // If we were given a server run it if neccessary.
227 if (!GS3 && config.exec_file != null) {
228 startServerEXE();
229 }
230
231 // 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.
232 if (config.exec_file == null && config.exec_address == null) {
233 if (config.exec_file == null) {
234 Gatherer.println("config.exec_file is null");
235 }
236 if (config.exec_address == null) {
237 Gatherer.println("config.exec_address is null");
238 }
239 missingEXEC();
240 }
241
242 if (Gatherer.isGsdlRemote) {
243 Gatherer.println("Not checking for perl path/exe");
244 }
245 else {
246 // Perl path is a little different as it is perfectly ok to
247 // start the Gatherer without providing a perl path
248 boolean found_perl = false;
249 if (config.perl_path != null) {
250 // See if the file pointed to actually exists
251 File perl_file = new File(config.perl_path);
252 found_perl = perl_file.exists();
253 perl_file = null;
254 }
255 if (config.perl_path == null || !found_perl) {
256 // Run test to see if we can run perl as is.
257 PerlTest perl_test = new PerlTest();
258 if (perl_test.found()) {
259 // If so replace the perl path with the system
260 // default (or null for unix).
261 config.perl_path = perl_test.toString();
262 found_perl = true;
263 }
264 }
265 if (!found_perl) {
266 // Time for an error message.
267 missingPERL();
268 }
269 }
270
271 // also check for wget
272 boolean mirror_workflow = config.get(StaticStrings.WORKFLOW_MIRROR, false);
273 if (mirror_workflow) {
274 wget_version_str = StaticStrings.NO_WGET_STR;
275 // has the user specified a path?
276 if (wget_path != null && !wget_path.equals("")) {
277 File wget_file = new File(wget_path);
278 if (wget_file.exists()) {
279 // we assume its ok if its there
280 wget_version_str = StaticStrings.WGET_STR;
281 }
282 }
283
284 // it hasn't been set by the user so we use the greenstone one
285 if (wget_version_str.equals(StaticStrings.NO_WGET_STR)) {
286 // TODO fix for gs3
287 wget_path = Utility.getWGetPath(gsdl_path);
288 File wget_file = new File(wget_path);
289 if (!wget_file.exists()) {
290 // we give up trying to find one
291 missingWGET();
292 } else {
293 // we have found one
294 wget_version_str = StaticStrings.WGET_STR;
295 }
296 }
297
298 if (wget_version_str.equals(StaticStrings.WGET_STR)) {
299 // we have found one, should we check the version??
300 wget_version_str = testWGetVersion(wget_path);
301 if (wget_version_str.equals(StaticStrings.WGET_OLD_STR)) {
302 oldWGET();
303 }
304 }
305
306 // tell the config the new values
307 config.setWGetPath(wget_path);
308 config.setWGetVersion(wget_version_str);
309 }
310
311 // Set default font
312 setUIFont(config.getFont("general.font", true), config.getFont("general.tooltip_font", true));
313 // Set up proxy
314 setProxy();
315 // Now we set up an Authenticator
316 Authenticator.setDefault(new GAuthenticator());
317
318 assoc_man = new FileAssociationManager();
319 // Create File Manager
320 f_man = new FileManager();
321 // Create Collection Manager
322 c_man = new CollectionManager();
323
324 if (GS3) {
325 if (site_name==null) {
326 site_name = config.site_name;
327 servlet_path = null; // need to reset this
328 }
329 if (servlet_path == null) {
330 servlet_path = config.getServletPath();
331 }
332 }
333
334 // If there was an open collection last session, reopen it.
335 if (open_collection == null) {
336 open_collection = config.getString("general.open_collection", true);
337 }
338 if (!no_load && open_collection.length() > 0) {
339 c_man.loadCollection(open_collection);
340 }
341
342 }
343 catch (Exception error) {
344 error.printStackTrace();
345 }
346
347 // Create GUI Manager (last) or else suffer the death of a thousand NPE's
348 g_man = new GUIManager(size);
349
350 return g_man;
351 }
352
353
354
355 public void run(Dimension size, Splash splash, GUIManager g_man)
356 {
357 // Size and place the frame on the screen
358 Rectangle bounds = config.getBounds("general.bounds", true);
359 if (bounds == null) {
360 // Choose a sensible default value
361 bounds = new Rectangle(0, 0, 640, 480);
362 }
363
364 // Ensure width and height are reasonable
365 size = bounds.getSize();
366 if (size.width < 640) {
367 size.width = 640;
368 }
369 else if (size.width > config.screen_size.width) {
370 size.width = config.screen_size.width;
371 }
372 if (size.height < 480) {
373 size.height = 480;
374 }
375 else if (size.height > config.screen_size.height) {
376 size.height = config.screen_size.height;
377 }
378
379 if (splash != null) { splash.toFront(); }
380
381 if (!g_man_built) {
382
383 g_man.display();
384
385 // 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).
386 g_man.setLocation(bounds.x, bounds.y);
387 g_man.setVisible(true);
388
389 // After the window has been made visible, check that it is in the correct place
390 // sometimes java places a window not in the correct place,
391 // but with an offset. If so, we work out what the offset is
392 // and change the desired location to take that into account
393 Point location = g_man.getLocation();
394 int x_offset = bounds.x - location.x;
395 int y_offset = bounds.y - location.y;
396 // If not, offset the window to move it into the correct location
397 if (x_offset > 0 || y_offset > 0) {
398 ///ystem.err.println("changing the location to "+(bounds.x + x_offset)+" "+ (bounds.y + y_offset));
399 g_man.setLocation(bounds.x + x_offset, bounds.y + y_offset);
400 }
401
402 // 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.
403 g_man.afterDisplay();
404 g_man_built = true;
405 }
406 else {
407 g_man.setVisible(true);
408 }
409
410 if (splash != null) {
411 // Hide the splash screen
412 splash.hide();
413 splash.destroy();
414 splash = null;
415 }
416 }
417
418
419 /** Exits the Gatherer after ensuring that things needing saving are saved.
420 * @see java.io.FileOutputStream
421 * @see java.io.PrintStream
422 * @see java.lang.Exception
423 * @see javax.swing.JOptionPane
424 * @see org.greenstone.gatherer.Configuration
425 * @see org.greenstone.gatherer.collection.CollectionManager
426 * @see org.greenstone.gatherer.gui.GUIManager
427 */
428 public void exit() {
429 exit = true;
430 // If we have an open collection make note of it.
431 config.setString("general.open_collection", true, null);
432 if(c_man.ready()) {
433 ///ystem.err.println("Collection open.");
434 if(c_man.saved()) {
435 ///ystem.err.println("Collection has been recently saved, so I'll remember it for next time.");
436 config.setString("general.open_collection", true, c_man.getCollectionFilename());
437 }
438 c_man.closeCollection();
439 }
440 if(assoc_man != null) {
441 assoc_man.save();
442 assoc_man = null;
443 }
444
445 // Store the current position and size (if reasonable) of the Gatherer for next time
446 Rectangle bounds = g_man.getBounds();
447 config.setBounds("general.bounds", true, bounds);
448
449 // Save configuration.
450 saveConfig();
451
452 // Get the gui to deallocate
453 g_man.hide();
454 g_man.destroy();
455 g_man_built = false;
456
457
458 // Flush dictionary
459 // dictionary.destroy();
460
461 // Flush debug
462 if(debug != null) {
463 try {
464 debug.flush();
465 debug.close();
466 }
467 catch (Exception error) {
468 error.printStackTrace();
469 }
470 }
471
472 // If we started a server, we should try to stop it.
473 if(!GS3 && gsdlsite_cfg != null) {
474 stopServerEXE();
475 }
476
477 if(apps.size() == 0) {
478 if (!Gatherer.isGsdlRemote) {
479 System.exit(0);
480 }
481 }
482 else {
483 JOptionPane.showMessageDialog(g_man, Dictionary.get("General.Outstanding_Processes"), Dictionary.get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
484 g_man.hide();
485 }
486 }
487
488 // Used to send messages to the local library
489 // Warning: this has a lot of potential for nasty race conditions
490 // The response code is returned immediately -- but this does not mean the local
491 // library action has finished!
492 public void configServer(String command)
493 {
494 try {
495 String raw_url = config.exec_address.toString() + command;
496 URL url = new URL(raw_url);
497 Gatherer.println("Action: " + raw_url);
498 HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
499 int response_code = library_connection.getResponseCode();
500 if(HttpURLConnection.HTTP_OK <= response_code && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
501 Gatherer.println("200 - Complete.");
502 }
503 else {
504 Gatherer.println("404 - Failed.");
505 }
506 url = null;
507 }
508 catch (Exception ex) {
509 ex.printStackTrace();
510 Gatherer.printStackTrace(ex);
511 }
512 }
513
514 // used to send reload coll messages to the tomcat server
515 public void configGS3Server(String site, String command) {
516
517 try {
518 // need to add the servlet name to the exec address
519 String raw_url = config.exec_address.toString() + config.getServletPath() + command;
520 URL url = new URL(raw_url);
521 Gatherer.println("Action: " + raw_url);
522 HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
523 int response_code = library_connection.getResponseCode();
524 if(HttpURLConnection.HTTP_OK <= response_code && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
525 Gatherer.println("200 - Complete.");
526 }
527 else {
528 Gatherer.println("404 - Failed.");
529 }
530 url = null;
531 }
532 catch(Exception exception) {
533 Gatherer.printStackTrace(exception);
534 ///ystem.err.println("Bad URL.");
535 }
536 }
537
538 /** Retrieve the metadata directory, as required by any MSMCaller implementation.
539 * @return The currently active collection metadata directory as a <strong>String</strong>.
540 * @see org.greenstone.gatherer.collection.CollectionManager
541 */
542 public String getCollectionMetadata() {
543 if (c_man != null && c_man.ready()) {
544 return c_man.getCollectionMetadata();
545 }
546 return "";
547 }
548
549 /** Used to 'spawn' a new child application when a file is double clicked.
550 * @param file The file to open
551 * @see org.greenstone.gatherer.Gatherer.ExternalApplication
552 */
553 public void spawnApplication(File file) {
554 String [] commands = assoc_man.getCommand(file);
555 if(commands != null) {
556 ExternalApplication app = new ExternalApplication(commands);
557 apps.add(app);
558 app.start();
559 }
560 else {
561 ///ystem.err.println("No open command available.");
562 }
563 }
564
565 /** Used to 'spawn' a new browser application or reset an existing one when the preview button is clicked
566 * @param url The url to open the browser at
567 * @see org.greenstone.gatherer.Gatherer.BrowserApplication
568 */
569 public void spawnBrowser(String url) {
570 String command = assoc_man.getBrowserCommand(url);
571 if (command != null) {
572 BrowserApplication app = new BrowserApplication(command, url);
573 apps.add(app);
574 app.start();
575 }
576 else {
577 ///ystem.err.println("No browser command available.");
578 }
579 }
580
581 /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
582 */
583 static public void missingEXEC() {
584 String message_name;
585 if (GS3) {
586 message_name = "warning.MissingEXEC_GS3";
587 } else {
588 message_name = "warning.MissingEXEC";
589 }
590 WarningDialog dialog = new WarningDialog(message_name, "general.exec_address" );
591 dialog.setValueField(new URLField(Gatherer.config.getColor("coloring.editable_foreground", false), Gatherer.config.getColor("coloring.editable_background", false), Gatherer.config.getColor("coloring.error_foreground", false), Gatherer.config.getColor("coloring.error_background", false)));
592 dialog.display();
593 dialog.dispose();
594 dialog = null;
595
596 String library_path_string = Gatherer.config.getString("general.exec_address", true);
597 if (!library_path_string.equals("")) {
598 try {
599 Gatherer.config.exec_address = new URL(library_path_string);
600 }
601 catch (MalformedURLException error) {
602 ///ystem.err.println("Error: Bad address: " + exec_address_string);
603 }
604 }
605 }
606
607 /** Prints a warning message about a missing GSDL path, which although not fatal pretty much ensures nothing will work properly in the Gatherer.
608 */
609 static public void missingGSDL() {
610 WarningDialog dialog = new WarningDialog("warning.MissingGSDL", false);
611 dialog.display();
612 dialog.dispose();
613 dialog = null;
614 }
615
616 /** 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. */
617 static public void missingPERL() {
618 WarningDialog dialog = new WarningDialog("warning.MissingPERL", false);
619 dialog.display();
620 dialog.dispose();
621 dialog = null;
622 }
623
624 /** Prints a warning message about a missing a valid WGet path. not fatal, but mirroring won't work */
625 static public void missingWGET() {
626 WarningDialog dialog = new WarningDialog("warning.MissingWGET", false);
627 dialog.display();
628 dialog.dispose();
629 dialog = null;
630 }
631 /** Prints a warning message about having an old version of WGet. not fatal, but mirroring may not work properly */
632 static public void oldWGET() {
633 WarningDialog dialog = new WarningDialog("warning.OldWGET", false);
634 dialog.display();
635 dialog.dispose();
636 dialog = null;
637 }
638 /** Print a message to the debug stream. */
639 static synchronized public void print(String message) {
640 if(debug != null) {
641 debug.print(message);
642 System.err.print(message);
643 }
644 }
645 /** Print a message to the debug stream. */
646 static synchronized public void println(String message) {
647 if(debug != null) {
648 debug.println(message);
649 System.err.println(message);
650 }
651 }
652
653 /** Print a stack trace to the debug stream. */
654 static synchronized public void printStackTrace(Exception exception) {
655 if(debug != null) {
656 exception.printStackTrace(debug);
657 exception.printStackTrace();
658 }
659 }
660 /** Prints a usage message to screen.
661 */
662 static public void printUsage(Dictionary dictionary) {
663 System.out.println(Dictionary.get("General.Usage"));
664 }
665
666 /** Sets up the proxy connection by setting JVM Environment flags and creating a new Authenticator.
667 * @see java.lang.Exception
668 * @see java.lang.System
669 * @see java.net.Authenticator
670 * @see org.greenstone.gatherer.Configuration
671 * @see org.greenstone.gatherer.GAuthenticator
672 */
673 static public void setProxy() {
674 try {// Can throw several exceptions
675 if(Gatherer.config.get("general.use_proxy", true)) {
676 System.setProperty("http.proxyType", "4");
677 System.setProperty("http.proxyHost", Gatherer.config.getString("general.proxy_host", true));
678 System.setProperty("http.proxyPort", Gatherer.config.getString("general.proxy_port", true));
679 System.setProperty("http.proxySet", "true");
680 } else {
681 System.setProperty("http.proxySet", "false");
682 }
683 } catch (Exception error) {
684 Gatherer.println("Error in Gatherer.initProxy(): " + error);
685 Gatherer.printStackTrace(error);
686 }
687 }
688
689 /** Set all the default fonts of the program to a choosen font, except the tooltip font which should be some fixed width font.
690 * @param f The default font to use in the Gatherer as a <strong>FontUIResource</strong>.
691 * @param ttf The tooltip font to use also as a <strong>FontUIResource</strong>.
692 * @see java.util.Enumeration
693 * @see javax.swing.UIManager
694 */
695 static private void setUIFont(FontUIResource f, FontUIResource ttf) {
696 // sets the default font for all Swing components.
697 // ex.
698 // setUIFont (new FontUIResource("Serif",Font.ITALIC,12));
699 //
700 Enumeration keys = UIManager.getDefaults().keys();
701 while (keys.hasMoreElements()) {
702 Object key = keys.nextElement();
703 Object value = UIManager.get (key);
704 if (value instanceof FontUIResource)
705 UIManager.put (key, f);
706 }
707 // Now set the tooltip font to some fixed width font
708 UIManager.put("ToolTip.font", ttf);
709 }
710
711 /** Loads the configuration file if one exists. Otherwise it creates a new one. Currently uses serialization.
712 * @param gsdl_path The path to the gsdl directory, gathered from the startup arguments, and presented as a <strong>String</strong>.
713 * @param exec_path The path to the library executable, gathered from the startup arguments, and presented as a <strong>String</strong>.
714 * @param perl_path The path to the PERL compiler as a <strong>String</strong>. Necessary for windows platform versions.
715 * @param mirroring_enabled
716 * @param wget_version_str
717 * @param wget_path
718 * @see java.io.FileInputStream
719 * @see java.io.ObjectInputStream
720 * @see java.lang.Exception
721 * @see org.greenstone.gatherer.Configuration
722 */
723 private void loadConfig(String gsdl_path, String gsdl3_path, String exec_path, String perl_path, boolean mirroring_enabled, String site_name) {
724 try {
725 config = new Configuration(gsdl_path, gsdl3_path, exec_path, perl_path, mirroring_enabled, site_name);
726 }
727 catch (Exception error) {
728 Gatherer.println(Configuration.CONFIG_XML+" is not a well formed XML document.");
729 Gatherer.printStackTrace(error);
730 }
731 if (GS3) {
732 try {
733 servlet_config = new ServletConfiguration(gsdl3_path);
734 } catch (Exception error) {
735 error.printStackTrace();
736 }
737 }
738 }
739
740 /** 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). */
741 private void saveConfig() {
742 try {
743 config.save();
744 } catch (Exception error) {
745 Gatherer.printStackTrace(error);
746 }
747 }
748
749 private void startServerEXE() {
750 if(config.exec_file != null && config.exec_address == null && Utility.isWindows() && !GS3) {
751 // First of all we create a GSDLSiteCFG object and check if a URL is already present, in which case the server is already running.
752 gsdlsite_cfg = new GSDLSiteConfig(config.exec_file);
753 String url = gsdlsite_cfg.getURL();
754 // If its already running then set exec address.
755 if(url != null) {
756 try {
757 config.exec_address = new URL(url);
758 }
759 catch(Exception error) {
760 }
761 }
762 // Otherwise its time to run the server in a spawned process.
763 if(config.exec_address == null && config.exec_file.exists()) {
764 // Configure for immediate entry. Note that this only works if the gsdlsite.cfg file exists.
765 gsdlsite_cfg.set();
766 // Spawn server
767 String command = config.exec_file.getAbsolutePath() + " " + gsdlsite_cfg.getSiteConfigFilename();
768 server = new ExternalApplication(command);
769 server.start();
770 command = null;
771 // Now we have to wait until program has started. We do this by reloading and checking
772 ///ystem.err.print("Waiting until the local library has loaded");
773 try {
774 gsdlsite_cfg.load();
775
776 int try_again = JOptionPane.YES_OPTION;
777 int attempt_count = 0;
778 while(gsdlsite_cfg.getURL() == null && try_again == JOptionPane.YES_OPTION) {
779 ///ystem.err.print(".");
780 if(attempt_count == 60) {
781 attempt_count = 0;
782 try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
783 }
784 else {
785 synchronized(this) {
786 wait(1000); // Wait one second (give or take)
787 }
788 gsdlsite_cfg.load();
789 attempt_count++;
790 }
791 }
792
793 if((url = gsdlsite_cfg.getURL()) != null) {
794 // Ta-da. Now the url should be available.
795 config.exec_address = new URL(url);
796
797 // A quick test involves opening a connection to get the home page for this collection. If this fails then we try changing the url to be localhost.
798 try {
799 Gatherer.println("Try connecting to server on config url: '" + config.exec_address + "'");
800 URLConnection connection = config.exec_address.openConnection();
801 connection.getContent();
802 }
803 catch(IOException bad_url_connection) {
804 try {
805 Gatherer.println("Try connecting to server on local host: '" + gsdlsite_cfg.getLocalHostURL() + "'");
806 config.exec_address = new URL(gsdlsite_cfg.getLocalHostURL ());
807 URLConnection connection = config.exec_address.openConnection();
808 connection.getContent();
809 }
810 catch(IOException worse_url_connection) {
811 Gatherer.println("Can't connect to server on either address.");
812 config.exec_address = null;
813 config.exec_file = null;
814 }
815 }
816 }
817 // Unable to start local library. Show appropriate message.
818 else {
819 missingEXEC();
820 }
821 }
822 catch (Exception error) {
823 error.printStackTrace();
824 }
825 }
826 // Can't do a damb thing.
827 }
828 Gatherer.println("Having started server.exe, exec_address is: " + config.exec_address);
829 }
830
831 private void stopServerEXE() {
832 if(server != null && config.exec_address != null) {
833 // See if its already exited for some reason.
834 gsdlsite_cfg.load();
835 if(gsdlsite_cfg.getURL() != null) {
836 // Send the command for it to exit.
837 configServer(GSDLSiteConfig.QUIT_COMMAND);
838 // Wait until it exits.
839 try {
840 gsdlsite_cfg.load();
841 int try_again = JOptionPane.YES_OPTION;
842 int attempt_count = 0;
843 while(gsdlsite_cfg.getURL() != null && try_again == JOptionPane.YES_OPTION) {
844 if(attempt_count == 60) {
845 attempt_count = 0;
846 try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
847 }
848 else {
849 synchronized(this) {
850 wait(1000); // Wait one second (give or take)
851 }
852 gsdlsite_cfg.load();
853 attempt_count++;
854 }
855 }
856 //if(gsdlsite_cfg.getURL() != null) {
857 //JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Server.QuitManual"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
858 //}
859 }
860 catch (Exception error) {
861 error.printStackTrace();
862 }
863 }
864 // Restore the gsdlsite_cfg.
865 if(gsdlsite_cfg != null) {
866 gsdlsite_cfg.restore();
867 }
868 // If the local server is still running then our changed values will get overwritten.
869 if(gsdlsite_cfg.getURL() != null) {
870 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Server.QuitFailed"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
871 }
872 gsdlsite_cfg = null;
873 server = null;
874 }
875 }
876
877 // TODO fill this in
878 private String testWGetVersion(String wget_path) {
879 return StaticStrings.WGET_STR;
880 }
881
882 /** 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. */
883 private class ExternalApplication
884 extends Thread {
885 private Process process = null;
886 /** The initial command string given to this sub-process. */
887 private String command = null;
888 private String[] commands = null;
889 /** Constructor.
890 * @param command The initial command <strong>String</strong>.
891 */
892 public ExternalApplication(String command) {
893 this.command = command;
894 }
895
896 public ExternalApplication(String[] commands) {
897 this.commands = commands;
898 }
899 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
900 * @see java.lang.Exception
901 * @see java.lang.Process
902 * @see java.lang.Runtime
903 * @see java.lang.System
904 * @see java.util.Vector
905 */
906 public void run() {
907 // Call an external process using the args.
908 try {
909 if(commands != null) {
910 StringBuffer whole_command = new StringBuffer();
911 for(int i = 0; i < commands.length; i++) {
912 whole_command.append(commands[i]);
913 whole_command.append(" ");
914 }
915 println("Running " + whole_command.toString());
916 Runtime rt = Runtime.getRuntime();
917 process = rt.exec(commands);
918 process.waitFor();
919 }
920 else {
921 println("Running " + command);
922 Runtime rt = Runtime.getRuntime();
923 process = rt.exec(command);
924 process.waitFor();
925 }
926 }
927 catch (Exception error) {
928 println("Error in ExternalApplication.run(): " + error);
929 printStackTrace(error);
930 }
931 // Remove ourself from Gatherer list of threads.
932 apps.remove(this);
933 // Call exit if we were the last outstanding child process thread.
934 if(apps.size() == 0 && exit == true) {
935 stopServerEXE();
936 System.exit(0);
937 }
938 }
939 public void stopExternalApplication() {
940 if(process != null) {
941 process.destroy();
942 }
943 }
944 }
945 /** 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. */
946 private class BrowserApplication
947 extends Thread {
948 private Process process = null;
949 /** The initial command string given to this sub-process. */
950 private String command = null;
951 private String url = null;
952 private String[] commands = null;
953 /** Constructor.
954 * @param command The initial command <strong>String</strong>.
955 */
956// public BrowserApplication(String command) {
957// this.command = command;
958// }
959
960 public BrowserApplication(String command, String url) {
961 StringTokenizer st = new StringTokenizer(command);
962 int num_tokens = st.countTokens();
963 this.commands = new String [num_tokens];
964 int i=0;
965 while (st.hasMoreTokens()) {
966 commands[i] = st.nextToken();
967 i++;
968 }
969 //this.commands = commands;
970 this.url = url;
971 }
972 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
973 * @see java.lang.Exception
974 * @see java.lang.Process
975 * @see java.lang.Runtime
976 * @see java.lang.System
977 * @see java.util.Vector
978 */
979 public void run() {
980 // Call an external process using the args.
981 if(commands == null) {
982 apps.remove(this);
983 return;
984 }
985 try {
986 String prog_name = commands[0];
987 String lower_name = prog_name.toLowerCase();
988 if (lower_name.indexOf("mozilla") != -1 || lower_name.indexOf("netscape") != -1) {
989 Gatherer.println("found mozilla or netscape, trying remote it");
990 // mozilla and netscape, try using a remote command to get things in the same window
991 String [] new_commands = new String[] {prog_name, "-raise", "-remote", "openURL("+url+",new-tab)"};
992 if(debug != null) {
993 printArray(new_commands);
994 }
995 Runtime rt = Runtime.getRuntime();
996 process = rt.exec(new_commands);
997 int exitCode = process.waitFor();
998 if (exitCode != 0) { // if Netscape or mozilla was not open
999 Gatherer.println("couldn't do remote, trying original command");
1000 if(debug != null) {
1001 printArray(commands);
1002 }
1003 process = rt.exec(commands); // try the original command
1004 }
1005 } else {
1006 // just run what we have been given
1007 StringBuffer whole_command = new StringBuffer();
1008 for(int i = 0; i < commands.length; i++) {
1009 whole_command.append(commands[i]);
1010 whole_command.append(" ");
1011 }
1012 println("Running " + whole_command.toString());
1013 Runtime rt = Runtime.getRuntime();
1014 process = rt.exec(commands);
1015 process.waitFor();
1016 }
1017 }
1018
1019 catch (Exception error) {
1020 println("Error in BrowserApplication.run(): " + error);
1021 printStackTrace(error);
1022 }
1023 // Remove ourself from Gatherer list of threads.
1024 apps.remove(this);
1025 // Call exit if we were the last outstanding child process thread.
1026 if(apps.size() == 0 && exit == true) {
1027 stopServerEXE();
1028 System.exit(0);
1029 }
1030 }
1031 public void printArray(String [] array) {
1032 for(int i = 0; i < array.length; i++) {
1033 debug.print(array[i]+" ");
1034 System.err.println(array[i]+" ");
1035 }
1036 }
1037 public void stopBrowserApplication() {
1038 if(process != null) {
1039 process.destroy();
1040 }
1041 }
1042 }
1043
1044 /** 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. */
1045// private class CTRLCHandler
1046// implements SignalHandler {
1047// /** <i>true</i> if we ignore any other signals we receive, most likely because we are already dealing with one, <i>false</i> otherwise. */
1048// private boolean ignore = false;
1049// /** The method called by the system to inform us a signal has occured.
1050// * @param sig The <strong>Signal</strong> itself.
1051// * @see org.greenstone.gatherer.collection.CollectionManager
1052// */
1053// public void handle(Signal sig) {
1054// if(!ignore) {
1055// ignore = true;
1056// // handle SIGINT
1057// System.out.println("Caught Ctrl-C...");
1058// if(c_man != null && c_man.ready()) {
1059// c_man.closeCollection();
1060// }
1061// exit();
1062// ignore = false;
1063// }
1064// }
1065// }
1066
1067 private class PerlTest {
1068
1069 private String[] command = new String[2];
1070
1071 public PerlTest() {
1072 if(Utility.isWindows()) {
1073 command[0] = Utility.PERL_EXECUTABLE_WINDOWS;
1074 }
1075 else {
1076 command[0] = Utility.PERL_EXECUTABLE_UNIX;
1077 }
1078 command[1] = "-version";
1079 }
1080
1081 public boolean found() {
1082 boolean found = false;
1083 try {
1084 Process prcs = Runtime.getRuntime().exec(command);
1085 prcs.waitFor();
1086 found = (prcs.exitValue() == 0);
1087 prcs = null;
1088 }
1089 catch(Exception error) {
1090 }
1091 return found;
1092 }
1093
1094 public String toString() {
1095 return command[0];
1096 }
1097 }
1098}
Note: See TracBrowser for help on using the repository browser.