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 | */
|
---|
27 | package org.greenstone.gatherer;
|
---|
28 | /**************************************************************************************
|
---|
29 | * Written: ??/??/02
|
---|
30 | * Revised: ??/??/02 - Commented
|
---|
31 | * ??/??/03 - Added support for local library server
|
---|
32 | * 20/07/03 - Rewrote argument parsing so that spaces no longer cause GLI to die. Also added time out when starting local library.
|
---|
33 | **************************************************************************************/
|
---|
34 |
|
---|
35 | import com.l2fprod.gui.*;
|
---|
36 | import com.l2fprod.gui.plaf.skin.*;
|
---|
37 | import com.l2fprod.util.*;
|
---|
38 | import java.awt.*;
|
---|
39 | import java.awt.event.*;
|
---|
40 | import java.io.*;
|
---|
41 | import java.lang.*;
|
---|
42 | import java.net.*;
|
---|
43 | import java.util.*;
|
---|
44 | import javax.swing.*;
|
---|
45 | import javax.swing.plaf.*;
|
---|
46 | import javax.swing.text.*;
|
---|
47 | import org.greenstone.gatherer.Configuration;
|
---|
48 | import org.greenstone.gatherer.GAuthenticator;
|
---|
49 | import org.greenstone.gatherer.cdm.CommandTokenizer;
|
---|
50 | import org.greenstone.gatherer.collection.CollectionManager;
|
---|
51 | import org.greenstone.gatherer.file.FileManager;
|
---|
52 | import org.greenstone.gatherer.file.FileAssociationManager;
|
---|
53 | import org.greenstone.gatherer.gui.Coloring;
|
---|
54 | import org.greenstone.gatherer.gui.GUIManager;
|
---|
55 | import org.greenstone.gatherer.gui.Splash;
|
---|
56 | import org.greenstone.gatherer.gui.WarningDialog;
|
---|
57 | import org.greenstone.gatherer.msm.MetadataSetManager;
|
---|
58 | import org.greenstone.gatherer.util.ArrayTools;
|
---|
59 | import org.greenstone.gatherer.util.GSDLSiteConfig;
|
---|
60 | import org.greenstone.gatherer.util.StaticStrings;
|
---|
61 | import org.greenstone.gatherer.util.Utility;
|
---|
62 | import sun.misc.*;
|
---|
63 | /** Containing the main() method for the Gatherer, this class is the starting point for the rest of the application. It first parses the command line arguments, preparing to update the configuration as required. Next it loads several important support classes such as the Configuration and Dictionary. Finally it creates the other important managers and sends them on their way.
|
---|
64 | * @author John Thompson, Greenstone Digital Library, University of Waikato
|
---|
65 | * @version 2.3
|
---|
66 | */
|
---|
67 | public class Gatherer {
|
---|
68 |
|
---|
69 | static final private String SKIN_DEFINITION_FILE = "lib/greenaqua/greenaqua.xml";
|
---|
70 |
|
---|
71 | /** Has the exit flag been set? <i>true</i> if so, <i>false</i> otherwise. */
|
---|
72 | public boolean exit = false;
|
---|
73 | /** The size of the Gatherer window. */
|
---|
74 | public Dimension frame_size = null;
|
---|
75 | /** A temporary shared memory area to store HIndexes to speed up metadata.xml writing. */
|
---|
76 | public Hashtable known_indexes = null;
|
---|
77 | /** Legacy copy of the debug_ps. */
|
---|
78 | public PrintStream debug_ps;
|
---|
79 | /** All of the external applications that must exit before we close the Gatherer. */
|
---|
80 | public Vector apps = new Vector();
|
---|
81 | /** Messages that have been issued before we have anyway to show them, ie prior to Log initialization. */
|
---|
82 | public Vector waiting_messages = new Vector();
|
---|
83 | /** The manager in charge of remembering what file extension gets opened with what program. */
|
---|
84 | static public FileAssociationManager assoc_man;
|
---|
85 | /** A public reference to the CollectionManager. */
|
---|
86 | static public CollectionManager c_man;
|
---|
87 | /** A public reference to the Gatherer's configuration. */
|
---|
88 | static public Configuration config;
|
---|
89 | /** A public reference to the Dictionary. */
|
---|
90 | static public Dictionary dictionary;
|
---|
91 | /** A public reference to the FileManager. */
|
---|
92 | static public FileManager f_man;
|
---|
93 | /** A public reference to the GUIManager. */
|
---|
94 | static public GUIManager g_man;
|
---|
95 | /** A static reference to ourselves. */
|
---|
96 | static public Gatherer self;
|
---|
97 | /** A public reference to the message log. */
|
---|
98 | static public Log log;
|
---|
99 | /** The debug print stream. */
|
---|
100 | static public PrintStream debug;
|
---|
101 | /** The name of the necessary environment variable to check for in the programs environment. */
|
---|
102 | static public String KEY = "GSDLPATH";
|
---|
103 | /** 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. */
|
---|
104 | static public String extra_env[] = null;
|
---|
105 | private GSDLSiteConfig gsdlsite_cfg = null;
|
---|
106 | private ExternalApplication server = null;
|
---|
107 | /** The name of the Gatherers configuration file. */
|
---|
108 | static private String CONFIG_FILE_NAME = "gatherer.cfg";
|
---|
109 |
|
---|
110 | /** Magic to allow Enter to fire the default button. */
|
---|
111 | static {
|
---|
112 | KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
|
---|
113 | Keymap map = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
|
---|
114 | map.removeKeyStrokeBinding(enter);
|
---|
115 | }
|
---|
116 |
|
---|
117 |
|
---|
118 |
|
---|
119 | /** Constructor. Make the three main modules, c_man, f_man and g_man, and any other necessary classes such as Dictionary.
|
---|
120 | * @param size The desired size of the Gatherer window as a <strong>Dimension</strong>.
|
---|
121 | * @param gsdl_path The path to the gsdl directory, gathered from the startup arguments, and presented as a <strong>String</strong>.
|
---|
122 | * @param exec_path The path to the library executable, gathered from the startup arguments, and presented as a <strong>String</strong>.
|
---|
123 | * @param debug_enabled <i>true</i> to print verbose debug messages to "debug.txt", <i>false</i> otherwise.
|
---|
124 | * @param perl_path The path to the PERL compiler as a <strong>String</strong>. Necessary for windows platform versions.
|
---|
125 | * @param splash A reference to the splash screen.
|
---|
126 | * @param no_load <i>true</i> to prevent the previously opened collection from reopening.
|
---|
127 | * @see java.io.FileOutputStream
|
---|
128 | * @see java.io.PrintStream
|
---|
129 | * @see java.lang.Exception
|
---|
130 | * @see java.lang.StringBuffer
|
---|
131 | * @see java.util.Calendar
|
---|
132 | * @see org.greenstone.gatherer.Configuration
|
---|
133 | * @see org.greenstone.gatherer.Dictionary
|
---|
134 | * @see org.greenstone.gatherer.Gatherer.CTRLCHandler
|
---|
135 | * @see org.greenstone.gatherer.GAuthenticator
|
---|
136 | * @see org.greenstone.gatherer.collection.CollectionManager
|
---|
137 | * @see org.greenstone.gatherer.file.FileManager
|
---|
138 | * @see org.greenstone.gatherer.gui.GUIManager
|
---|
139 | * @see org.greenstone.gatherer.gui.Splash
|
---|
140 | */
|
---|
141 | public Gatherer() {
|
---|
142 | this.self = this;
|
---|
143 | }
|
---|
144 |
|
---|
145 | public void run(Dimension size, String gsdl_path, String exec_path, boolean debug_enabled, String perl_path, boolean no_load, Splash splash, String open_collection) {
|
---|
146 |
|
---|
147 | // This will hopefully catch ctrl-c and terminate, and exit gracefully. However it is platform specific, and may not be supported by some JVMs.
|
---|
148 | /** It does, but I get bloody sick of it working when the Gatherer hangs.
|
---|
149 | CTRLCHandler handler = new CTRLCHandler();
|
---|
150 | Signal.handle(new Signal("INT"), handler);
|
---|
151 | Signal.handle(new Signal("TERM"), handler);
|
---|
152 | handler = null;
|
---|
153 | */
|
---|
154 | // Create the debug stream only if required.
|
---|
155 | if(debug_enabled) {
|
---|
156 | try {
|
---|
157 | Calendar now = Calendar.getInstance();
|
---|
158 | StringBuffer name = new StringBuffer("debug");
|
---|
159 | name.append(now.get(Calendar.DATE));
|
---|
160 | name.append("-");
|
---|
161 | name.append(now.get(Calendar.MONTH));
|
---|
162 | name.append("-");
|
---|
163 | name.append(now.get(Calendar.YEAR));
|
---|
164 | name.append(".txt");
|
---|
165 | this.debug = new PrintStream(new FileOutputStream(name.toString()));
|
---|
166 | Properties props = System.getProperties();
|
---|
167 | props.list(debug);
|
---|
168 | // Legacy
|
---|
169 | debug_ps = debug;
|
---|
170 | }
|
---|
171 | catch(Exception error) {
|
---|
172 | ///ystem.err.println("Error in Gatherer.init(): " + error);
|
---|
173 | error.printStackTrace();
|
---|
174 | System.exit(1);
|
---|
175 | }
|
---|
176 | }
|
---|
177 | try {
|
---|
178 | // Create log
|
---|
179 | log = new Log();
|
---|
180 | // Load Config
|
---|
181 | loadConfig(gsdl_path, exec_path, perl_path);
|
---|
182 |
|
---|
183 | // Read Dictionary
|
---|
184 | dictionary = new Dictionary(config.getLocale("general.locale", true), config.getFont("general.font", true));
|
---|
185 |
|
---|
186 | if(gsdl_path == null) {
|
---|
187 | missingGSDL(dictionary);
|
---|
188 | }
|
---|
189 |
|
---|
190 | // If we were given a server run it if neccessary.
|
---|
191 | if(config.exec_file != null) {
|
---|
192 | startServerEXE();
|
---|
193 | }
|
---|
194 |
|
---|
195 | // 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.
|
---|
196 |
|
---|
197 | if(config.exec_file == null && config.exec_address == null) {
|
---|
198 | missingEXEC(dictionary);
|
---|
199 | }
|
---|
200 | // Perl path is a little different as it is perfectly ok to start the Gatherer without providing a perl path
|
---|
201 | boolean found_perl = false;
|
---|
202 | if(config.perl_path != null) {
|
---|
203 | // See if the file pointed to actually exists
|
---|
204 | File perl_file = new File(config.perl_path);
|
---|
205 | found_perl = perl_file.exists();
|
---|
206 | perl_file = null;
|
---|
207 | }
|
---|
208 | if(config.perl_path == null || !found_perl) {
|
---|
209 | // Run test to see if we can run perl as is.
|
---|
210 | PerlTest perl_test = new PerlTest();
|
---|
211 | if(perl_test.found()) {
|
---|
212 | // If so replace the perl path with the system default (or null for unix).
|
---|
213 | config.perl_path = perl_test.toString();
|
---|
214 | found_perl = true;
|
---|
215 | }
|
---|
216 | }
|
---|
217 | if(!found_perl) {
|
---|
218 | // Time for an error message.
|
---|
219 | missingPERL(dictionary);
|
---|
220 | }
|
---|
221 |
|
---|
222 | // Size and place the frame on the screen
|
---|
223 | Rectangle bounds = config.getBounds("general.bounds", true);
|
---|
224 | if (bounds == null) {
|
---|
225 | // Choose a sensible default value
|
---|
226 | bounds = new Rectangle(0, 0, 640, 480);
|
---|
227 | }
|
---|
228 |
|
---|
229 | // Ensure width and height are reasonable
|
---|
230 | size = bounds.getSize();
|
---|
231 | if (size.width < 640) {
|
---|
232 | size.width = 640;
|
---|
233 | }
|
---|
234 | else if (size.width > config.screen_size.width) {
|
---|
235 | size.width = config.screen_size.width;
|
---|
236 | }
|
---|
237 | if (size.height < 480) {
|
---|
238 | size.height = 480;
|
---|
239 | }
|
---|
240 | else if (size.height > config.screen_size.height) {
|
---|
241 | size.height = config.screen_size.height;
|
---|
242 | }
|
---|
243 | // Set default font
|
---|
244 | setUIFont(config.getFont("general.font", true), config.getFont("general.tooltip_font", true));
|
---|
245 | // Set up proxy
|
---|
246 | setProxy();
|
---|
247 | // Now we set up an Authenticator
|
---|
248 | Authenticator.setDefault(new GAuthenticator());
|
---|
249 |
|
---|
250 | assoc_man = new FileAssociationManager();
|
---|
251 | // Create File Manager
|
---|
252 | f_man = new FileManager();
|
---|
253 | // Create Collection Manager
|
---|
254 | c_man = new CollectionManager();
|
---|
255 | // If there was an open collection last session, reopen it.
|
---|
256 | if(open_collection == null) {
|
---|
257 | open_collection = config.getString("general.open_collection", true);
|
---|
258 | }
|
---|
259 | if(!no_load && open_collection.length() > 0) {
|
---|
260 | c_man.loadCollection(open_collection);
|
---|
261 | }
|
---|
262 | // Create GUI Manager (last) or else suffer the death of a thousand NPE's
|
---|
263 | splash.toFront();
|
---|
264 | g_man = new GUIManager(size);
|
---|
265 | g_man.display();
|
---|
266 |
|
---|
267 | // 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).
|
---|
268 | g_man.setLocation(bounds.x, bounds.y);
|
---|
269 | g_man.setVisible(true);
|
---|
270 |
|
---|
271 | // After the window has been made visible, check that it is in the correct place
|
---|
272 | Point location = g_man.getLocation();
|
---|
273 | int x_offset = bounds.x - location.x;
|
---|
274 | int y_offset = bounds.y - location.y;
|
---|
275 | // If not, offset the window to move it into the correct location
|
---|
276 | if (x_offset > 0 || y_offset > 0) {
|
---|
277 | g_man.setLocation(bounds.x + x_offset, bounds.y + y_offset);
|
---|
278 | }
|
---|
279 |
|
---|
280 | // 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.
|
---|
281 | g_man.afterDisplay();
|
---|
282 | // Hide the splash.
|
---|
283 | splash.hide();
|
---|
284 | splash.destroy();
|
---|
285 | splash = null;
|
---|
286 | }
|
---|
287 | catch (Exception error) {
|
---|
288 | error.printStackTrace();
|
---|
289 | }
|
---|
290 | }
|
---|
291 |
|
---|
292 | /** Exits the Gatherer after ensuring that things needing saving are saved.
|
---|
293 | * @see java.io.FileOutputStream
|
---|
294 | * @see java.io.PrintStream
|
---|
295 | * @see java.lang.Exception
|
---|
296 | * @see javax.swing.JOptionPane
|
---|
297 | * @see org.greenstone.gatherer.Configuration
|
---|
298 | * @see org.greenstone.gatherer.collection.CollectionManager
|
---|
299 | * @see org.greenstone.gatherer.gui.GUIManager
|
---|
300 | */
|
---|
301 | public void exit() {
|
---|
302 | exit = true;
|
---|
303 | // If we have an open collection make note of it.
|
---|
304 | config.setString("general.open_collection", true, null);
|
---|
305 | if(c_man.ready()) {
|
---|
306 | ///ystem.err.println("Collection open.");
|
---|
307 | if(c_man.saved()) {
|
---|
308 | ///ystem.err.println("Collection has been recently saved, so I'll remember it for next time.");
|
---|
309 | config.setString("general.open_collection", true, c_man.getCollectionFilename());
|
---|
310 | }
|
---|
311 | c_man.closeCollection();
|
---|
312 | }
|
---|
313 | if(assoc_man != null) {
|
---|
314 | assoc_man.save();
|
---|
315 | assoc_man = null;
|
---|
316 | }
|
---|
317 |
|
---|
318 | // Store the current position and size (if reasonable) of the Gatherer for next time
|
---|
319 | Rectangle bounds = g_man.getBounds();
|
---|
320 | config.setBounds("general.bounds", true, bounds);
|
---|
321 |
|
---|
322 | // Save configuration.
|
---|
323 | saveConfig();
|
---|
324 | // Flush debug
|
---|
325 | if(debug != null) {
|
---|
326 | try {
|
---|
327 | debug.flush();
|
---|
328 | debug.close();
|
---|
329 | }
|
---|
330 | catch (Exception error) {
|
---|
331 | error.printStackTrace();
|
---|
332 | }
|
---|
333 | }
|
---|
334 |
|
---|
335 | // If we started a server, we should try to stop it.
|
---|
336 | if(gsdlsite_cfg != null) {
|
---|
337 | stopServerEXE();
|
---|
338 | }
|
---|
339 |
|
---|
340 | if(apps.size() == 0) {
|
---|
341 | System.exit(0);
|
---|
342 | }
|
---|
343 | else {
|
---|
344 | JOptionPane.showMessageDialog(g_man, get("General.Outstanding_Processes"), get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
|
---|
345 | g_man.hide();
|
---|
346 | }
|
---|
347 | }
|
---|
348 | /** Overloaded to call get with both a key and an empty argument array.
|
---|
349 | * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
|
---|
350 | * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
|
---|
351 | */
|
---|
352 | public String get(String key) {
|
---|
353 | return dictionary.get(key, (String[])null);
|
---|
354 | }
|
---|
355 | /** Overloaded to call get with both a key and an argument array with one element.
|
---|
356 | * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
|
---|
357 | * @param arg A single argument as a <strong>String</strong>.
|
---|
358 | * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call.
|
---|
359 | */
|
---|
360 | public String get(String key, String arg) {
|
---|
361 | String args[] = new String[1];
|
---|
362 | args[0] = arg;
|
---|
363 | return dictionary.get(key, args);
|
---|
364 | }
|
---|
365 | /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned. <BR>
|
---|
366 | * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
|
---|
367 | * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
|
---|
368 | * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
|
---|
369 | * @return A <strong>String</strong> which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatically populated with formatting Strings of with argument String provided in the get call.
|
---|
370 | * @see org.greenstone.gatherer.Gatherer
|
---|
371 | * @see org.greenstone.gatherer.Dictionary
|
---|
372 | */
|
---|
373 | public String get(String key, String args[]) {
|
---|
374 | return dictionary.get(key, args);
|
---|
375 | }
|
---|
376 | /** Retrieve the metadata directory, as required by any MSMCaller implementation.
|
---|
377 | * @return The currently active collection metadata directory as a <strong>String</strong>.
|
---|
378 | * @see org.greenstone.gatherer.collection.CollectionManager
|
---|
379 | */
|
---|
380 | public String getCollectionMetadata() {
|
---|
381 | if(c_man != null && c_man.ready()) {
|
---|
382 | return c_man.getCollectionMetadata();
|
---|
383 | }
|
---|
384 | return "";
|
---|
385 | }
|
---|
386 | /** Retrieve a reference to the frame that any dialog boxes will appear relative to, as required by any MSMCaller or CDMCaller implementation.
|
---|
387 | * @return A <strong>JFrame</strong>.
|
---|
388 | * @see org.greenstone.gatherer.gui.GUIManager
|
---|
389 | */
|
---|
390 | public JFrame getFrame() {
|
---|
391 | return g_man;
|
---|
392 | }
|
---|
393 | /** Method to retrieve a reference to the metadata set manager class. This is then used to create the 'metadataset' commands in the collection configuration file.
|
---|
394 | * @return A reference to the <Strong>MetadataSetManager</strong>.
|
---|
395 | * @see org.greenstone.gatherer.collection.CollectionManager
|
---|
396 | */
|
---|
397 | public MetadataSetManager getMSM() {
|
---|
398 | if(c_man != null && c_man.getCollection() != null && c_man.getCollection().msm != null) {
|
---|
399 | return c_man.getCollection().msm;
|
---|
400 | }
|
---|
401 | return null;
|
---|
402 | }
|
---|
403 | /** Used to 'spawn' a new child application when a file is double clicked.
|
---|
404 | * @param command The command to run in the child process to start the application, garnered from the registry of a default associations file, and presented as a <strong>String</strong>.
|
---|
405 | * @see java.util.Vector
|
---|
406 | * @see org.greenstone.gatherer.Gatherer.ExternalApplication
|
---|
407 | */
|
---|
408 | public void spawnApplication(File file) {
|
---|
409 | String command = assoc_man.getCommand(file);
|
---|
410 | if(command != null) {
|
---|
411 | ExternalApplication app = new ExternalApplication(command);
|
---|
412 | apps.add(app);
|
---|
413 | app.start();
|
---|
414 | }
|
---|
415 | else {
|
---|
416 | ///ystem.err.println("No open command available.");
|
---|
417 | }
|
---|
418 | }
|
---|
419 |
|
---|
420 | /** The entry point into the Gatherer. Parses arguments.
|
---|
421 | * @param args A collection of arguments that may include: initial screen size, dictionary, path to the GSDL etc.
|
---|
422 | * @see java.io.File
|
---|
423 | * @see java.io.FileInputStream
|
---|
424 | * @see java.lang.Exception
|
---|
425 | * @see java.util.Properties
|
---|
426 | * @see org.greenstone.gatherer.Dictionary
|
---|
427 | * @see org.greenstone.gatherer.Gatherer
|
---|
428 | * @see org.greenstone.gatherer.gui.Splash
|
---|
429 | * @see org.greenstone.gatherer.util.StaticStrings
|
---|
430 | */
|
---|
431 | static public void main(String[] args) {
|
---|
432 | // A serious hack, but its good enough to stop crappy 'Could not lock user prefs' error messages.
|
---|
433 | // Thanks to Walter Schatz from the java forums.
|
---|
434 | System.setProperty("java.util.prefs.syncInterval","2000000"); // One message every 600 hours!
|
---|
435 |
|
---|
436 | Gatherer gatherer = new Gatherer();
|
---|
437 |
|
---|
438 | boolean debug = false;
|
---|
439 | boolean no_load = false;
|
---|
440 | Dictionary dictionary = new Dictionary(null, null); // Default dictionary. Only used for starting error messages.
|
---|
441 | Dimension size = new Dimension(800, 540);
|
---|
442 | String exec_path = null;
|
---|
443 | String extra = null;
|
---|
444 | String filename = null;
|
---|
445 | String gsdl_path = null;
|
---|
446 | String perl_path = null;
|
---|
447 | // Parse arguments
|
---|
448 | int argument_index = 0;
|
---|
449 | String next_token = null;
|
---|
450 | while(argument_index < args.length || next_token != null) {
|
---|
451 | // 1. We start by attempting to parse an argument name. An argument must start with a '-', and should not contain spaces. If anything else is encountered it is ignored.
|
---|
452 | String argument_name = null;
|
---|
453 | if(next_token == null) {
|
---|
454 | next_token = args[argument_index];
|
---|
455 | argument_index++;
|
---|
456 | }
|
---|
457 | if(next_token.startsWith(StaticStrings.MINUS_CHARACTER)) {
|
---|
458 | // Trim second '-' just to be kind to Unixy-type people
|
---|
459 | if(next_token.startsWith(StaticStrings.MINUS_CHARACTER + StaticStrings.MINUS_CHARACTER)) {
|
---|
460 | argument_name = next_token.substring(1);
|
---|
461 | }
|
---|
462 | else {
|
---|
463 | argument_name = next_token;
|
---|
464 | }
|
---|
465 | }
|
---|
466 | next_token = null;
|
---|
467 | // 2. If we now have an argument name we continue by attempting to parse a value. A value is taken to be the sequence of space seperated Strings between the last argument name and up to but not including the next argument name. Of course an argument needn't have any value (ie -debug, -help), in which case value will be null.
|
---|
468 | if(argument_name != null) {
|
---|
469 | String argument_value = null;
|
---|
470 | StringBuffer argument_value_buffer = new StringBuffer("");
|
---|
471 | while(argument_index < args.length && next_token == null) {
|
---|
472 | next_token = args[argument_index];
|
---|
473 | argument_index++;
|
---|
474 | // If we just parsed an arbitary String then append it to value, followed by a single space
|
---|
475 | if(!next_token.startsWith(StaticStrings.MINUS_CHARACTER)) {
|
---|
476 | argument_value_buffer.append(next_token);
|
---|
477 | argument_value_buffer.append(StaticStrings.SPACE_CHARACTER);
|
---|
478 | next_token = null;
|
---|
479 | }
|
---|
480 | // If the argument token retrieved is an argument name, then leave it in next_token, which will cause the argument parsing process to move onto the next step.
|
---|
481 | }
|
---|
482 | // If a value now exists in argument buffer, retrieve it. Remove the last character as it will be an erroneous space.
|
---|
483 | if(argument_value_buffer.length() > 0) {
|
---|
484 | argument_value = argument_value_buffer.substring(0, argument_value_buffer.length() - 1);
|
---|
485 | }
|
---|
486 |
|
---|
487 | // 3. We now have the argument name, and any associated value. We are ready to store the data in the appropriate variables.
|
---|
488 | Gatherer.println("Parsed Argument: name=" + argument_name + (argument_value != null ? (", value=" + argument_value) : ", no value"));
|
---|
489 | // 3a. First those arguments that have no associated value
|
---|
490 | if(argument_value == null) {
|
---|
491 | if(argument_name.equals(StaticStrings.HELP_ARGUMENT)) {
|
---|
492 | printUsage(dictionary);
|
---|
493 | System.exit(0);
|
---|
494 | }
|
---|
495 | // Run GLI in debug mode. Produces debug log plus extra messages.
|
---|
496 | else if(argument_name.equals(StaticStrings.DEBUG_ARGUMENT)) {
|
---|
497 | debug = true;
|
---|
498 | }
|
---|
499 | // Forces no loading on previous collection.
|
---|
500 | else if(argument_name.equals(StaticStrings.NO_LOAD_ARGUMENT)) {
|
---|
501 | no_load = true;
|
---|
502 | filename = null;
|
---|
503 | }
|
---|
504 | // Specify the use of Greenstone LAF.
|
---|
505 | else if(argument_name.equals(StaticStrings.SKIN_ARGUMENT)) {
|
---|
506 | // SkinLF
|
---|
507 | try {
|
---|
508 | SkinLookAndFeel.setSkin(SkinLookAndFeel.loadThemePackDefinition(SkinUtils.toURL(new File(SKIN_DEFINITION_FILE))));
|
---|
509 | SkinLookAndFeel.enable();
|
---|
510 | }
|
---|
511 | catch (Exception error) {
|
---|
512 | ///ystem.err.println("Error: " + error);
|
---|
513 | error.printStackTrace();
|
---|
514 | }
|
---|
515 | }
|
---|
516 | }
|
---|
517 | // 3b. Now for those that do
|
---|
518 | else {
|
---|
519 | // Parse the path to the GSDL. Required argument.
|
---|
520 | if(argument_name.equals(StaticStrings.GSDL_ARGUMENT)) {
|
---|
521 | if(argument_value.endsWith(File.separator)) {
|
---|
522 | gsdl_path = argument_value;
|
---|
523 | }
|
---|
524 | else {
|
---|
525 | gsdl_path = argument_value + File.separator;
|
---|
526 | }
|
---|
527 | }
|
---|
528 | // Specify a collection to load initially. Could be used for file associations.
|
---|
529 | else if(argument_name.equals(StaticStrings.LOAD_ARGUMENT)) {
|
---|
530 | filename = argument_value;
|
---|
531 | no_load = false;
|
---|
532 | }
|
---|
533 | // Parse the url to a running web server, or a file path to the local library server.
|
---|
534 | else if(argument_name.equals(StaticStrings.LIBRARY_ARGUMENT)) {
|
---|
535 | exec_path = argument_value;
|
---|
536 | // If there is no colon in first five characters of the exec_path (which would either be an existing protocol, or a windows file path to say a local library), we can append the protocol http://.
|
---|
537 | if(argument_value.lastIndexOf(StaticStrings.COLON_CHARACTER, 5) == -1) {
|
---|
538 | exec_path = StaticStrings.HTTP_PROTOCOL_STR + argument_value;
|
---|
539 | }
|
---|
540 | else {
|
---|
541 | exec_path = argument_value;
|
---|
542 | }
|
---|
543 | // If the user has given us an address, but it ends with a '/' we assume we're using the greenstone library.cgi
|
---|
544 | if(exec_path.startsWith(StaticStrings.HTTP_PROTOCOL_STR) && exec_path.endsWith(StaticStrings.URL_SEPARATOR_CHARACTER)) {
|
---|
545 | exec_path = exec_path + StaticStrings.LIBRARY_STR;
|
---|
546 | }
|
---|
547 | }
|
---|
548 | // Parse the path to PERL. If not provided its assumes perl should be availble on the PATH.
|
---|
549 | else if(argument_name.equals(StaticStrings.PERL_ARGUMENT)) {
|
---|
550 | perl_path = argument_value;
|
---|
551 | // Test whether this points to the Perl bin directory or the Perl executable itself.
|
---|
552 | File perl_file = new File(perl_path);
|
---|
553 | if(perl_file.isDirectory()) {
|
---|
554 | // If this is windows we create a child file perl.exe, otherwise we create perl
|
---|
555 | if(Utility.isWindows()) {
|
---|
556 | perl_file = new File(perl_file, Utility.PERL_EXECUTABLE_WINDOWS);
|
---|
557 | }
|
---|
558 | else {
|
---|
559 | perl_file = new File(perl_file, Utility.PERL_EXECUTABLE_UNIX);
|
---|
560 | }
|
---|
561 | // And store this new path.
|
---|
562 | perl_path = perl_file.getAbsolutePath();
|
---|
563 | perl_file = null;
|
---|
564 | }
|
---|
565 | // Otherwise its fine as it is
|
---|
566 | }
|
---|
567 | }
|
---|
568 | }
|
---|
569 | // Argument name was null, nothing to be done.
|
---|
570 | }
|
---|
571 | next_token = null;
|
---|
572 | // Arguments all parsed.
|
---|
573 |
|
---|
574 | // Splash screen.
|
---|
575 | Splash splash = new Splash();
|
---|
576 |
|
---|
577 | gatherer.run(size, gsdl_path, exec_path, debug, perl_path, no_load, splash, filename);
|
---|
578 | }
|
---|
579 |
|
---|
580 | /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
|
---|
581 | */
|
---|
582 | static public void missingEXEC(Dictionary dictionary) {
|
---|
583 | WarningDialog dialog = new WarningDialog("warning.MissingEXEC", "general.exec_address", dictionary);
|
---|
584 | //NoSettingDialog dialog = new NoSettingDialog("warning.MissingEXEC", "NoSettingEXEC.Message", false, dictionary);
|
---|
585 | dialog.display();
|
---|
586 | dialog.dispose();
|
---|
587 | dialog = null;
|
---|
588 | ///ystem.out.println(dictionary.get("General.Missing_EXEC"));
|
---|
589 | }
|
---|
590 |
|
---|
591 | /** Prints a warning message about a missing GSDL path, which although not fatal pretty much ensures nothing will work properly in the Gatherer.
|
---|
592 | */
|
---|
593 | static public void missingGSDL(Dictionary dictionary) {
|
---|
594 | WarningDialog dialog = new WarningDialog("warning.MissingGSDL", false, dictionary);
|
---|
595 | dialog.display();
|
---|
596 | dialog.dispose();
|
---|
597 | dialog = null;
|
---|
598 | ///ystem.out.println(dictionary.get("General.Missing_GSDL"));
|
---|
599 | }
|
---|
600 |
|
---|
601 | /** 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. */
|
---|
602 | static public void missingPERL(Dictionary dictionary) {
|
---|
603 | WarningDialog dialog = new WarningDialog("warning.MissingPERL", false, dictionary);
|
---|
604 | dialog.display();
|
---|
605 | dialog.dispose();
|
---|
606 | dialog = null;
|
---|
607 | ///ystem.out.println(dictionary.get("General.Missing_PERL"));
|
---|
608 | }
|
---|
609 |
|
---|
610 | /** Print a message to the debug stream. */
|
---|
611 | static synchronized public void println(String message) {
|
---|
612 | if(debug != null) {
|
---|
613 | debug.println(message);
|
---|
614 | System.err.println(message);
|
---|
615 | }
|
---|
616 | }
|
---|
617 |
|
---|
618 | /** Print a stack trace to the debug stream. */
|
---|
619 | static synchronized public void printStackTrace(Exception exception) {
|
---|
620 | if(debug != null) {
|
---|
621 | exception.printStackTrace(debug);
|
---|
622 | exception.printStackTrace();
|
---|
623 | }
|
---|
624 | }
|
---|
625 | /** Prints a usage message to screen.
|
---|
626 | */
|
---|
627 | static public void printUsage(Dictionary dictionary) {
|
---|
628 | System.out.println(dictionary.get("General.Usage"));
|
---|
629 | }
|
---|
630 |
|
---|
631 | /** Sets up the proxy connection by setting JVM Environment flags and creating a new Authenticator.
|
---|
632 | * @see java.lang.Exception
|
---|
633 | * @see java.lang.System
|
---|
634 | * @see java.net.Authenticator
|
---|
635 | * @see org.greenstone.gatherer.Configuration
|
---|
636 | * @see org.greenstone.gatherer.GAuthenticator
|
---|
637 | */
|
---|
638 | static public void setProxy() {
|
---|
639 | try {// Can throw several exceptions
|
---|
640 | if(Gatherer.config.get("general.use_proxy", true)) {
|
---|
641 | System.setProperty("http.proxyType", "4");
|
---|
642 | System.setProperty("http.proxyHost", Gatherer.config.getString("general.proxy_host", true));
|
---|
643 | System.setProperty("http.proxyPort", Gatherer.config.getString("general.proxy_port", true));
|
---|
644 | System.setProperty("http.proxySet", "true");
|
---|
645 | } else {
|
---|
646 | System.setProperty("http.proxySet", "false");
|
---|
647 | }
|
---|
648 | } catch (Exception error) {
|
---|
649 | Gatherer.println("Error in Gatherer.initProxy(): " + error);
|
---|
650 | Gatherer.printStackTrace(error);
|
---|
651 | }
|
---|
652 | }
|
---|
653 |
|
---|
654 | /** Set all the default fonts of the program to a choosen font, except the tooltip font which should be some fixed width font.
|
---|
655 | * @param f The default font to use in the Gatherer as a <strong>FontUIResource</strong>.
|
---|
656 | * @param ttf The tooltip font to use also as a <strong>FontUIResource</strong>.
|
---|
657 | * @see java.util.Enumeration
|
---|
658 | * @see javax.swing.UIManager
|
---|
659 | */
|
---|
660 | static public void setUIFont (FontUIResource f, FontUIResource ttf){
|
---|
661 | // sets the default font for all Swing components.
|
---|
662 | // ex.
|
---|
663 | // setUIFont (new FontUIResource("Serif",Font.ITALIC,12));
|
---|
664 | //
|
---|
665 | Enumeration keys = UIManager.getDefaults().keys();
|
---|
666 | while (keys.hasMoreElements()) {
|
---|
667 | Object key = keys.nextElement();
|
---|
668 | Object value = UIManager.get (key);
|
---|
669 | if (value instanceof FontUIResource)
|
---|
670 | UIManager.put (key, f);
|
---|
671 | }
|
---|
672 | // Now set the tooltip font to some fixed width font
|
---|
673 | UIManager.put("ToolTip.font", ttf);
|
---|
674 | }
|
---|
675 |
|
---|
676 | /** Loads the configuration file if one exists. Otherwise it creates a new one. Currently uses serialization.
|
---|
677 | * @param size The desired size of the Gatherer window as a <strong>Dimension</strong>.
|
---|
678 | * @param gsdl_path The path to the gsdl directory, gathered from the startup arguments, and presented as a <strong>String</strong>.
|
---|
679 | * @param exec_path The path to the library executable, gathered from the startup arguments, and presented as a <strong>String</strong>.
|
---|
680 | * @param perl_path The path to the PERL compiler as a <strong>String</strong>. Necessary for windows platform versions.
|
---|
681 | * @see java.io.FileInputStream
|
---|
682 | * @see java.io.ObjectInputStream
|
---|
683 | * @see java.lang.Exception
|
---|
684 | * @see org.greenstone.gatherer.Configuration
|
---|
685 | */
|
---|
686 | private void loadConfig(String gsdl_path, String exec_path, String perl_path) {
|
---|
687 | try {
|
---|
688 | config = new Configuration(gsdl_path, exec_path, perl_path);
|
---|
689 | }
|
---|
690 | catch (Exception error) {
|
---|
691 | Gatherer.println("config.xml is not a well formed XML document.");
|
---|
692 | Gatherer.printStackTrace(error);
|
---|
693 | }
|
---|
694 | }
|
---|
695 |
|
---|
696 | /** Creates and dispatches a message given the initial details.
|
---|
697 | * @param level An <i>int</i> indicating the message level for this message.
|
---|
698 | * @param message A <strong>String</strong> which contains the payload of this message.
|
---|
699 | * @see org.greenstone.gatherer.Message
|
---|
700 | * @see org.greenstone.gatherer.Log
|
---|
701 | */
|
---|
702 | private void message(int level, String message) {
|
---|
703 | Message msg = new Message(Message.GENERAL, level, message);
|
---|
704 | log.add(msg);
|
---|
705 | }
|
---|
706 |
|
---|
707 | /** 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). */
|
---|
708 | private void saveConfig() {
|
---|
709 | try {
|
---|
710 | config.save();
|
---|
711 | } catch (Exception error) {
|
---|
712 | Gatherer.printStackTrace(error);
|
---|
713 | }
|
---|
714 | }
|
---|
715 |
|
---|
716 | private void startServerEXE() {
|
---|
717 | if(config.exec_file != null && config.exec_address == null && Utility.isWindows()) {
|
---|
718 | // First of all we create a GSDLSiteCFG object and check if a URL is already present, in which case the server is already running.
|
---|
719 | gsdlsite_cfg = new GSDLSiteConfig(config.exec_file);
|
---|
720 | String url = gsdlsite_cfg.getURL();
|
---|
721 | // If its already running then set exec address.
|
---|
722 | if(url != null) {
|
---|
723 | try {
|
---|
724 | config.exec_address = new URL(url);
|
---|
725 | }
|
---|
726 | catch(Exception error) {
|
---|
727 | }
|
---|
728 | }
|
---|
729 | // Otherwise its time to run the server in a spawned process.
|
---|
730 | if(config.exec_address == null && config.exec_file.exists()) {
|
---|
731 | // Configure for immediate entry. Note that this only works if the gsdlsite.cfg file exists.
|
---|
732 | gsdlsite_cfg.set();
|
---|
733 | // Spawn server
|
---|
734 | String command = config.exec_file.getAbsolutePath() + " " + gsdlsite_cfg.getSiteConfigFilename();
|
---|
735 | server = new ExternalApplication(command);
|
---|
736 | server.start();
|
---|
737 | command = null;
|
---|
738 | // Now we have to wait until program has started. We do this by reloading and checking
|
---|
739 | ///ystem.err.print("Waiting until the local library has loaded");
|
---|
740 | try {
|
---|
741 | gsdlsite_cfg.load();
|
---|
742 |
|
---|
743 | int try_again = JOptionPane.YES_OPTION;
|
---|
744 | int attempt_count = 0;
|
---|
745 | while(gsdlsite_cfg.getURL() == null && try_again == JOptionPane.YES_OPTION) {
|
---|
746 | ///ystem.err.print(".");
|
---|
747 | if(attempt_count == 60) {
|
---|
748 | try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, dictionary.get("Server.QuitTimeOut"), dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
|
---|
749 | }
|
---|
750 | else {
|
---|
751 | synchronized(this) {
|
---|
752 | wait(1000); // Wait one second (give or take)
|
---|
753 | }
|
---|
754 | gsdlsite_cfg.load();
|
---|
755 | attempt_count++;
|
---|
756 | }
|
---|
757 | }
|
---|
758 |
|
---|
759 | if((url = gsdlsite_cfg.getURL()) != null) {
|
---|
760 | // Ta-da. Now the url should be available.
|
---|
761 | config.exec_address = new URL(url);
|
---|
762 |
|
---|
763 | // 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.
|
---|
764 | try {
|
---|
765 | Gatherer.println("Try connecting to server on config url.");
|
---|
766 | URLConnection connection = config.exec_address.openConnection();
|
---|
767 | connection.getContent();
|
---|
768 | }
|
---|
769 | catch(IOException bad_url_connection) {
|
---|
770 | try {
|
---|
771 | Gatherer.println("Try connecting to server on local host.");
|
---|
772 | config.exec_address = new URL(gsdlsite_cfg.getLocalHostURL ());
|
---|
773 | URLConnection connection = config.exec_address.openConnection();
|
---|
774 | connection.getContent();
|
---|
775 | }
|
---|
776 | catch(IOException worse_url_connection) {
|
---|
777 | Gatherer.println("Can't connect to server on either address.");
|
---|
778 | config.exec_address = null;
|
---|
779 | config.exec_file = null;
|
---|
780 | }
|
---|
781 | }
|
---|
782 | }
|
---|
783 | // Unable to start local library. Show appropriate message.
|
---|
784 | else {
|
---|
785 | missingEXEC(dictionary);
|
---|
786 | }
|
---|
787 | }
|
---|
788 | catch (Exception error) {
|
---|
789 | error.printStackTrace();
|
---|
790 | }
|
---|
791 | }
|
---|
792 | // Can't do a damb thing.
|
---|
793 | }
|
---|
794 | Gatherer.println("Having started server.exe, exec_address is: " + config.exec_address);
|
---|
795 | }
|
---|
796 |
|
---|
797 | private void stopServerEXE() {
|
---|
798 | if(server != null && config.exec_address != null) {
|
---|
799 | // See if its already exited for some reason.
|
---|
800 | gsdlsite_cfg.load();
|
---|
801 | if(gsdlsite_cfg.getURL() != null) {
|
---|
802 | // Send the command for it to exit.
|
---|
803 | Gatherer.g_man.preview_pane.configServer(GSDLSiteConfig.QUIT_COMMAND);
|
---|
804 | // Wait until it exits.
|
---|
805 | try {
|
---|
806 | gsdlsite_cfg.load();
|
---|
807 | int try_again = JOptionPane.YES_OPTION;
|
---|
808 | int attempt_count = 0;
|
---|
809 | while(gsdlsite_cfg.getURL() != null && try_again == JOptionPane.YES_OPTION) {
|
---|
810 | if(attempt_count == 60) {
|
---|
811 | try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, dictionary.get("Server.QuitTimeOut"), dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
|
---|
812 | }
|
---|
813 | else {
|
---|
814 | synchronized(this) {
|
---|
815 | wait(1000); // Wait one second (give or take)
|
---|
816 | }
|
---|
817 | gsdlsite_cfg.load();
|
---|
818 | attempt_count++;
|
---|
819 | }
|
---|
820 | }
|
---|
821 | //if(gsdlsite_cfg.getURL() != null) {
|
---|
822 | //JOptionPane.showMessageDialog(Gatherer.g_man, dictionary.get("Server.QuitManual"), dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
|
---|
823 | //}
|
---|
824 | }
|
---|
825 | catch (Exception error) {
|
---|
826 | error.printStackTrace();
|
---|
827 | }
|
---|
828 | }
|
---|
829 | // Restore the gsdlsite_cfg.
|
---|
830 | if(gsdlsite_cfg != null) {
|
---|
831 | gsdlsite_cfg.restore();
|
---|
832 | }
|
---|
833 | // If the local server is still running then our changed values will get overwritten.
|
---|
834 | if(gsdlsite_cfg.getURL() != null) {
|
---|
835 | JOptionPane.showMessageDialog(Gatherer.g_man, dictionary.get("Server.QuitFailed"), dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
|
---|
836 | }
|
---|
837 | gsdlsite_cfg = null;
|
---|
838 | server = null;
|
---|
839 | }
|
---|
840 | }
|
---|
841 |
|
---|
842 | /** 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. */
|
---|
843 | private class ExternalApplication
|
---|
844 | extends Thread {
|
---|
845 | private Process process = null;
|
---|
846 | /** The initial command string given to this sub-process. */
|
---|
847 | private String command = null;
|
---|
848 | private String[] commands = null;
|
---|
849 | /** Constructor.
|
---|
850 | * @param command The initial command <strong>String</strong>.
|
---|
851 | */
|
---|
852 | public ExternalApplication(String command) {
|
---|
853 | this.command = command;
|
---|
854 | }
|
---|
855 |
|
---|
856 | public ExternalApplication(String[] commands) {
|
---|
857 | this.commands = commands;
|
---|
858 | }
|
---|
859 | /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
|
---|
860 | * @see java.lang.Exception
|
---|
861 | * @see java.lang.Process
|
---|
862 | * @see java.lang.Runtime
|
---|
863 | * @see java.lang.System
|
---|
864 | * @see java.util.Vector
|
---|
865 | */
|
---|
866 | public void run() {
|
---|
867 | // Call an external process using the args.
|
---|
868 | try {
|
---|
869 | if(commands != null) {
|
---|
870 | StringBuffer whole_command = new StringBuffer();
|
---|
871 | for(int i = 0; i < commands.length; i++) {
|
---|
872 | whole_command.append(commands[i]);
|
---|
873 | whole_command.append(" ");
|
---|
874 | }
|
---|
875 | println("Running " + whole_command.toString());
|
---|
876 | Runtime rt = Runtime.getRuntime();
|
---|
877 | process = rt.exec(commands);
|
---|
878 | process.waitFor();
|
---|
879 | }
|
---|
880 | else {
|
---|
881 | println("Running " + command);
|
---|
882 | Runtime rt = Runtime.getRuntime();
|
---|
883 | process = rt.exec(command);
|
---|
884 | process.waitFor();
|
---|
885 | }
|
---|
886 | }
|
---|
887 | catch (Exception error) {
|
---|
888 | println("Error in ExternalApplication.run(): " + error);
|
---|
889 | printStackTrace(error);
|
---|
890 | }
|
---|
891 | // Remove ourself from Gatherer list of threads.
|
---|
892 | apps.remove(this);
|
---|
893 | // Call exit if we were the last outstanding child process thread.
|
---|
894 | if(apps.size() == 0 && exit == true) {
|
---|
895 | stopServerEXE();
|
---|
896 | System.exit(0);
|
---|
897 | }
|
---|
898 | }
|
---|
899 | public void stopExternalApplication() {
|
---|
900 | if(process != null) {
|
---|
901 | process.destroy();
|
---|
902 | }
|
---|
903 | }
|
---|
904 | }
|
---|
905 |
|
---|
906 | /** 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. */
|
---|
907 | private class CTRLCHandler
|
---|
908 | implements SignalHandler {
|
---|
909 | /** <i>true</i> if we ignore any other signals we receive, most likely because we are already dealing with one, <i>false</i> otherwise. */
|
---|
910 | private boolean ignore = false;
|
---|
911 | /** The method called by the system to inform us a signal has occured.
|
---|
912 | * @param sig The <strong>Signal</strong> itself.
|
---|
913 | * @see org.greenstone.gatherer.collection.CollectionManager
|
---|
914 | */
|
---|
915 | public void handle(Signal sig) {
|
---|
916 | if(!ignore) {
|
---|
917 | ignore = true;
|
---|
918 | // handle SIGINT
|
---|
919 | System.out.println("Caught Ctrl-C...");
|
---|
920 | if(c_man != null && c_man.ready()) {
|
---|
921 | c_man.closeCollection();
|
---|
922 | }
|
---|
923 | exit();
|
---|
924 | ignore = false;
|
---|
925 | }
|
---|
926 | }
|
---|
927 | }
|
---|
928 |
|
---|
929 | private class PerlTest {
|
---|
930 |
|
---|
931 | private String[] command = new String[2];
|
---|
932 |
|
---|
933 | public PerlTest() {
|
---|
934 | if(Utility.isWindows()) {
|
---|
935 | command[0] = Utility.PERL_EXECUTABLE_WINDOWS;
|
---|
936 | }
|
---|
937 | else {
|
---|
938 | command[0] = Utility.PERL_EXECUTABLE_UNIX;
|
---|
939 | }
|
---|
940 | command[1] = "-version";
|
---|
941 | }
|
---|
942 |
|
---|
943 | public boolean found() {
|
---|
944 | boolean found = false;
|
---|
945 | try {
|
---|
946 | Process prcs = Runtime.getRuntime().exec(command);
|
---|
947 | prcs.waitFor();
|
---|
948 | found = (prcs.exitValue() == 0);
|
---|
949 | prcs = null;
|
---|
950 | }
|
---|
951 | catch(Exception error) {
|
---|
952 | }
|
---|
953 | return found;
|
---|
954 | }
|
---|
955 |
|
---|
956 | public String toString() {
|
---|
957 | return command[0];
|
---|
958 | }
|
---|
959 | }
|
---|
960 | }
|
---|
961 |
|
---|
962 |
|
---|
963 |
|
---|
964 |
|
---|
965 |
|
---|