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

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

Fixed the ModalDialog so it works with Java 1.5.0.

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