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

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

Moved the init_images function from Gatherer into Utility (it is used by the GEMS).

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