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

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

Moved the current_modal static variable out of the Gatherer class into the ModalDialog class. This removes more dependencies on the Gatherer class.

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