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

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

Replaced all Gatherer.print* with DebugStream.print*.

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