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

Last change on this file since 19513 was 19513, checked in by ak19, 15 years ago

Reverting to before recent commits for working with independently launched GSI (which wrote out URL_pending to llssite.cfg file)

  • Property svn:keywords set to Author Date Id Revision
File size: 47.7 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.io.*;
32import java.lang.*;
33import java.net.*;
34import java.util.*;
35import javax.swing.*;
36import javax.swing.plaf.*;
37import javax.swing.text.*;
38
39
40import org.greenstone.gatherer.Configuration;
41import org.greenstone.gatherer.GAuthenticator;
42import org.greenstone.gatherer.FedoraInfo;
43import org.greenstone.gatherer.collection.CollectionManager;
44import org.greenstone.gatherer.feedback.ActionRecorderDialog;
45import org.greenstone.gatherer.feedback.Base64;
46import org.greenstone.gatherer.file.FileManager;
47import org.greenstone.gatherer.file.FileAssociationManager;
48import org.greenstone.gatherer.file.RecycleBin;
49import org.greenstone.gatherer.greenstone.Classifiers;
50import org.greenstone.gatherer.greenstone.LocalGreenstone;
51import org.greenstone.gatherer.greenstone.LocalLibraryServer;
52import org.greenstone.gatherer.greenstone.Plugins;
53import org.greenstone.gatherer.greenstone3.ServletConfiguration;
54import org.greenstone.gatherer.gui.GUIManager;
55import org.greenstone.gatherer.gui.URLField;
56import org.greenstone.gatherer.gui.WarningDialog;
57import org.greenstone.gatherer.gui.FedoraLogin;
58import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
59import org.greenstone.gatherer.util.JarTools;
60import org.greenstone.gatherer.util.StaticStrings;
61import org.greenstone.gatherer.util.Utility;
62
63
64/** Containing the top-level "core" for the Gatherer, this class is the
65 * common core for the GLI application and applet. It first parses the
66 * command line arguments, preparing to update the configuration as
67 * required. Next it loads several important support classes such as the
68 * Configuration and Dictionary. Finally it creates the other important
69 * managers and sends them on their way.
70 * @author John Thompson, Greenstone Digital Library, University of Waikato
71 * @version 2.3
72 */
73public class Gatherer
74{
75 /** The name of the GLI. */
76 static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
77 /** The current version of the GLI.
78 * Note: the gs3-release-maker relies on this variable being declared
79 * in a line which maches this java regex:
80 * ^(.*)String\s*PROGRAM_VERSION\s*=\s*"trunk";
81 * If change the declaration and it no longer matches the regex, please
82 * change the regex in the gs3-release-maker code and in this message
83 */
84
85 static final public String PROGRAM_VERSION = "trunk";
86
87 static private Dimension size = new Dimension(800, 540);
88 static public RemoteGreenstoneServer remoteGreenstoneServer = null;
89
90 /** Has the exit flag been set? */
91 static final public int EXIT_THEN_RESTART= 2;
92 static public boolean exit = false;
93 static public int exit_status = 0;
94
95 static private String gli_directory_path = null;
96 static private String gli_user_directory_path = null;
97
98 static public String client_operating_system = null;
99
100 /** All of the external applications that must exit before we close the Gatherer. */
101 static private Vector apps = new Vector();
102 static private String non_standard_collect_directory_path = null;
103 static public String open_collection_file_path = null;
104 /** A public reference to the FileAssociationManager. */
105 static public FileAssociationManager assoc_man;
106 /** A public reference to the CollectionManager. */
107 static public CollectionManager c_man;
108 /** A public reference to the RecycleBin. */
109 static public RecycleBin recycle_bin;
110 /** a reference to the Servlet Configuration is GS3 */
111 static public ServletConfiguration servlet_config;
112 /** A public reference to the FileManager. */
113 static public FileManager f_man;
114 /** A public reference to the GUIManager. */
115 static public GUIManager g_man = null;
116 static private boolean g_man_built = false;
117
118 /** We are using the GLI for GS3 */
119 static public boolean GS3 = false;
120
121 static public boolean isApplet = false;
122 static public boolean isGsdlRemote = false;
123
124 /* TODO: If we're using local GLI, collections are built locally. If we're using client-GLI
125 * and it contains a gs2build folder in it, then localBuild will also be true (if this is not
126 * turned off in Preferences). If we're remote and this is turned off in Prefs, build remotely. */
127 /*static public boolean buildingLocally = true;*/
128 /** If we're using local GLI, we can always download. If we're using client-GLI, we can only
129 * download if we have a gs2build folder inside it. And if we don't turn off downloadEnabling
130 * in the preferences.
131 */
132 static public boolean isDownloadEnabled = true;
133
134 // feedback stuff
135 /** is the feedback feature enabled? */
136 static public boolean feedback_enabled = true;
137 /** the action recorder dialog */
138 static public ActionRecorderDialog feedback_dialog = null;
139
140 // Refresh reasons
141 static public final int COLLECTION_OPENED = 0;
142 static public final int COLLECTION_CLOSED = 1;
143 static public final int COLLECTION_REBUILT = 2;
144 static public final int PREFERENCES_CHANGED = 3;
145
146 //////kk added////////
147 static public String cgiBase="";
148 /////////////////
149
150 /** Magic to allow Enter to fire the default button. */
151 static {
152 KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
153 Keymap map = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
154 map.removeKeyStrokeBinding(enter);
155 }
156
157 static private URL default_gliserver_url=null;
158
159 public Gatherer(String[] args)
160 {
161 // Display the version to make error reports a lot more useful
162 System.err.println("Version: " + PROGRAM_VERSION + "\n");
163
164 JarTools.initialise(this);
165
166 GetOpt go = new GetOpt(args);
167
168 // Remember the GSDLOS value
169 client_operating_system = go.client_operating_system;
170
171 // If feedback is enabled, set up the recorder dialog
172 if (go.feedback_enabled) {
173 // Use the default locale for now - this will be changed by the Gatherer run method
174 feedback_enabled = true;
175 feedback_dialog = new ActionRecorderDialog(Locale.getDefault());
176 }
177
178 // Are we using a remote Greenstone?
179 if (go.use_remote_greenstone) {
180 isGsdlRemote = true;
181
182 // We don't have a local Greenstone!
183 go.gsdl3_path=null;
184 go.gsdl3_src_path=null;
185
186 // Don't set go.gsdl_path to null, since gdsl_path may still be set
187 // if we have a client-gli containing gs2build folder.
188 // However, keep track of whether we can download.
189 if(go.gsdl_path == null) {
190 isDownloadEnabled = false;
191 }
192
193 // We have to use our own collect directory since we can't use the Greenstone one
194 setCollectDirectoryPath(getGLIUserDirectoryPath() + "collect" + File.separator);
195 }
196 // We have a local Greenstone. OR we have a gs2build folder inside
197 // the client-GLI folder (with which the Download panel becomes enabled)
198 if(isDownloadEnabled) {
199 LocalGreenstone.setDirectoryPath(go.gsdl_path);
200 }
201
202 // Users may specify a non-standard collect directory (eg. when running one GLI in a network environment)
203 if (go.collect_directory_path != null) {
204 setCollectDirectoryPath(go.collect_directory_path);
205 }
206
207 // More special code for running with a remote Greenstone
208 if (isGsdlRemote) {
209 if (go.fedora_info.isActive()) {
210 Configuration.TEMPLATE_CONFIG_XML = "xml/" + Configuration.FEDORA_CONFIG_PREFIX + "configRemote.xml";
211 }
212 else {
213 Configuration.TEMPLATE_CONFIG_XML = "xml/configRemote.xml";
214 }
215
216 Configuration.CONFIG_XML = "configRemote.xml";
217
218 File collect_directory = new File(Gatherer.getCollectDirectoryPath());
219 if (!collect_directory.exists() && !collect_directory.mkdir()) {
220 System.err.println("Warning: Unable to make directory: " + collect_directory);
221 }
222 }
223 else {
224 if (go.fedora_info.isActive()) {
225 Configuration.TEMPLATE_CONFIG_XML = "xml/" + Configuration.FEDORA_CONFIG_PREFIX + Configuration.CONFIG_XML;
226 }
227 // else, the CONFIG_XML uses the default config file, which is for the local GS server
228 }
229
230 init(go.gsdl_path, go.gsdl3_path, go.gsdl3_src_path,
231 go.fedora_info,
232 go.local_library_path, go.library_url_string,
233 go.gliserver_url_string, go.debug, go.perl_path, go.no_load, go.filename, go.site_name,
234 go.servlet_path);
235 }
236
237
238 public void init(String gsdl_path, String gsdl3_path, String gsdl3_src_path,
239 FedoraInfo fedora_info,
240 String local_library_path,
241 String library_url_string, String gliserver_url_string, boolean debug_enabled,
242 String perl_path, boolean no_load, String open_collection,
243 String site_name, String servlet_path)
244 {
245 if (gsdl3_path != null && !gsdl3_path.equals("")) {
246 this.GS3 = true;
247 } else {
248 gsdl3_path = null;
249 gsdl3_src_path = null;
250 }
251
252 // Create the debug stream if required
253 if (debug_enabled) {
254 DebugStream.enableDebugging();
255
256 Calendar now = Calendar.getInstance();
257 String debug_file_path = "debug" + now.get(Calendar.DATE) + "-" + now.get(Calendar.MONTH) + "-" + now.get(Calendar.YEAR) + ".txt";
258
259 // Debug file is created in the user's GLI directory
260 debug_file_path = getGLIUserDirectoryPath() + debug_file_path;
261 DebugStream.println("Debug file path: " + debug_file_path);
262 DebugStream.setDebugFile(debug_file_path);
263 DebugStream.print(System.getProperties());
264 }
265
266 // Delete plugins.dat and classifiers.dat files from previous versions of the GLI (no longer used)
267 File plugins_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "plugins.dat");
268 if (plugins_dat_file.exists()) {
269 System.err.println("Deleting plugins.dat file...");
270 Utility.delete(plugins_dat_file);
271 }
272 File classifiers_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "classifiers.dat");
273 if (classifiers_dat_file.exists()) {
274 System.err.println("Deleting classifiers.dat file...");
275 Utility.delete(classifiers_dat_file);
276 }
277
278 try {
279 // Load GLI config file
280 new Configuration(getGLIUserDirectoryPath(), gsdl_path, gsdl3_path, gsdl3_src_path, site_name,
281 fedora_info);
282
283 // Check we know where Perl is
284 Configuration.perl_path = perl_path;
285 if (isGsdlRemote && !isDownloadEnabled && Utility.isWindows() && Configuration.perl_path != null) {
286 if (Configuration.perl_path.toLowerCase().endsWith("perl.exe")) {
287 Configuration.perl_path = Configuration.perl_path.substring(0, Configuration.perl_path.length() - "perl.exe".length());
288 }
289 if (Configuration.perl_path.endsWith(File.separator)) {
290 Configuration.perl_path = Configuration.perl_path.substring(0, Configuration.perl_path.length() - File.separator.length());
291 }
292 }
293
294 // the feedback dialog has been loaded with a default locale,
295 // now set the user specified one
296 if (feedback_enabled && feedback_dialog != null) {
297 feedback_dialog.setLocale(Configuration.getLocale("general.locale", true));
298 }
299
300 // Read Dictionary
301 new Dictionary(Configuration.getLocale("general.locale", true), Configuration.getFont("general.font", true));
302
303 // check that we are using Sun Java
304 String java_vendor = System.getProperty("java.vendor");
305 if (!java_vendor.equals("Sun Microsystems Inc.")) {
306 System.err.println(Dictionary.get("General.NotSunJava", java_vendor));
307 }
308
309 // Unless we're using remote building, we need to know where the local Greenstone is
310 if (!isGsdlRemote && gsdl_path == null) {
311 missingGSDL();
312 }
313
314 if (fedora_info.isActive()) {
315 popupFedoraInfo();
316 }
317
318 // Finally, we're ready to find out the version of the remote Greenstone server
319 if(isGsdlRemote) {
320 // instantiate the RemoteGreenstoneServer object first
321 remoteGreenstoneServer = new RemoteGreenstoneServer();
322
323 // Set up proxy
324 setProxy();
325 // Now we set up an Authenticator
326 Authenticator.setDefault(new GAuthenticator());
327
328 int greenstoneVersion = 2;
329 requestGLIServerURL();
330 gliserver_url_string = Configuration.gliserver_url.toString();
331
332 greenstoneVersion = remoteGreenstoneServer.getGreenstoneVersion();
333 // Display the version to make error reports a lot more useful
334 System.err.println("Remote Greenstone server version: " + greenstoneVersion);
335 if(greenstoneVersion >= 3) {
336 this.GS3 = true;
337 Configuration.prepareForGS3();
338 }
339
340 if(fedora_info.isActive()) {
341 // when GS server is remote, FEDORA_HOME resides on the remote server side,
342 // but we know the library URL from user-provided information
343 library_url_string = fedora_info.getLibraryURL();
344 } else {
345 library_url_string = remoteGreenstoneServer.getLibraryURL(Configuration.gliserver_url.toString());
346 }
347 // write it into the config file
348 Configuration.setString("general.library_url", true, library_url_string);
349 }
350 else { // local greenstone: Start up the local library server, if that's what we want
351 if (local_library_path != null && !GS3) {
352 LocalLibraryServer.start(gsdl_path, local_library_path);
353 }
354 }
355
356 // The "-library_url" option overwrites anything in the config files
357 if (library_url_string != null && library_url_string.length() > 0) {
358 try {
359 System.err.println("Setting library_url to " + library_url_string + "...");
360 Configuration.library_url = new URL(library_url_string);
361 }
362 catch (MalformedURLException error) {
363 DebugStream.printStackTrace(error);
364 }
365 }
366
367
368 // Check that we now know the Greenstone library URL, since we need this for previewing collections
369 DebugStream.println("Configuration.library_url = " + Configuration.library_url);
370 if (Configuration.library_url == null) {
371 missingEXEC();
372 }
373
374 // The "-gliserver_url" option overwrites anything in the config files
375 if (gliserver_url_string != null && gliserver_url_string.length() > 0) {
376 try {
377 System.err.println("Setting gliserver_url to " + gliserver_url_string + "...");
378 Configuration.gliserver_url = new URL(gliserver_url_string);
379 }
380 catch (MalformedURLException error) {
381 DebugStream.printStackTrace(error);
382 }
383 }
384
385 // If we're using a remote Greenstone we need to know where the gliserver script is
386 DebugStream.println("Configuration.gliserver_url = " + Configuration.gliserver_url);
387
388 if (GS3) {
389 // Load Greenstone 3 servlet configuration
390 if (isGsdlRemote){
391 servlet_config = new ServletConfiguration(Configuration.gli_user_directory_path);
392 }else{
393 servlet_config= new ServletConfiguration(gsdl3_path);
394 }
395 }
396
397 if (GS3 && Configuration.servlet_path == null) {
398 Configuration.servlet_path = servlet_config.getServletPath(Configuration.site_name);
399 }
400
401 // ensure that a directory called 'cache' exists in the GLI user directory
402 File user_cache_dir = new File(Gatherer.getGLIUserCacheDirectoryPath());
403 System.err.println("User cache dir: " + Gatherer.getGLIUserCacheDirectoryPath());
404 if (!user_cache_dir.exists() && !user_cache_dir.mkdir()) {
405 System.err.println("Warning: Unable to make directory: " + user_cache_dir);
406 }
407
408 // Check for ImageMagick
409 if (Gatherer.isGsdlRemote) {
410 DebugStream.println("Not checking for ImageMagick.");
411 }
412 else if (!(new ImageMagickTest()).found()) {
413 // Time for a warning message
414 missingImageMagick();
415 }
416
417 if (Gatherer.isGsdlRemote) {
418 DebugStream.println("Not checking for perl path/exe");
419 }
420 else {
421 // Perl path is a little different as it is perfectly ok to
422 // start the GLI without providing a perl path
423 boolean found_perl = false;
424 if (Configuration.perl_path != null) {
425 // See if the file pointed to actually exists
426 File perl_file = new File(Configuration.perl_path);
427 found_perl = perl_file.exists();
428 perl_file = null;
429 }
430 if (Configuration.perl_path == null || !found_perl) {
431 // Run test to see if we can run perl as is.
432 PerlTest perl_test = new PerlTest();
433 if (perl_test.found()) {
434 // If so replace the perl path with the system
435 // default (or null for unix).
436 Configuration.perl_path = perl_test.toString();
437 found_perl = true;
438 }
439 }
440 if (!found_perl) {
441 // Time for an error message.
442 missingPERL();
443 }
444 }
445
446 // Set the default font for all Swing components.
447 FontUIResource default_font = Configuration.getFont("general.font", true);
448 Enumeration keys = UIManager.getDefaults().keys();
449 while (keys.hasMoreElements()) {
450 Object key = keys.nextElement();
451 Object value = UIManager.get(key);
452 if (value instanceof FontUIResource) {
453 UIManager.put(key, default_font);
454 }
455 }
456
457 assoc_man = new FileAssociationManager();
458 // Create File Manager
459 f_man = new FileManager();
460 // Create Collection Manager
461 c_man = new CollectionManager();
462 // Create Recycle Bin
463 recycle_bin = new RecycleBin();
464
465 if (GS3) {
466 if (site_name==null) {
467 site_name = Configuration.site_name;
468 servlet_path = null; // need to reset this
469 }
470 if (servlet_path == null) {
471 servlet_path = Configuration.getServletPath();
472 }
473 }
474
475 open_collection_file_path = open_collection;
476 if (open_collection_file_path == null) {
477 open_collection_file_path = Configuration.getString(
478 "general.open_collection"+Configuration.gliPropertyNameSuffix(), true);
479 }
480 if (no_load || open_collection_file_path.equals("")) {
481 open_collection_file_path = null;
482 }
483 }
484 catch (Exception exception) {
485 DebugStream.printStackTrace(exception);
486 }
487
488
489 // Create GUI Manager (last) or else suffer the death of a thousand NPE's
490 g_man = new GUIManager(size);
491
492 // Get a list of the core Greenstone classifiers and plugins
493 Classifiers.loadClassifiersList(null);
494 Plugins.loadPluginsList(null);
495
496 // If using a remote Greenstone we need to download the collection configurations now
497 if (Gatherer.isGsdlRemote) {
498 if (remoteGreenstoneServer.downloadCollectionConfigurations().equals("")) {
499 // !! Something went wrong downloading the collection configurations
500 System.err.println("Error: Could not download collection configurations.");
501 if(!Gatherer.isApplet) { // don't close the browser if it is an applet!
502 System.exit(0);
503 }
504 }
505 }
506 }
507
508
509 /** Returns the correct version of the (local or remote) Greenstone server if init() has already been called. */
510 public static int serverVersionNumber() {
511 return GS3 ? 3 : 2;
512 }
513
514 /** Returns "Server: version number" if init() has already been called. */
515 public static String getServerVersionAsString() {
516 return "Server: v" + serverVersionNumber();
517 }
518
519 public void openGUI()
520 {
521 // Size and place the frame on the screen
522 Rectangle bounds = Configuration.getBounds("general.bounds", true);
523 if (bounds == null) {
524 // Choose a sensible default value
525 bounds = new Rectangle(0, 0, 640, 480);
526 }
527
528 // Ensure width and height are reasonable
529 size = bounds.getSize();
530 if (size.width < 640) {
531 size.width = 640;
532 }
533 else if (size.width > Configuration.screen_size.width && Configuration.screen_size.width > 0) {
534 size.width = Configuration.screen_size.width;
535 }
536 if (size.height < 480) {
537 size.height = 480;
538 }
539 else if (size.height > Configuration.screen_size.height && Configuration.screen_size.height > 0) {
540 size.height = Configuration.screen_size.height;
541 }
542
543 if (!g_man_built) {
544
545 g_man.display();
546
547 // 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).
548 g_man.setLocation(bounds.x, bounds.y);
549 g_man.setVisible(true);
550
551 // After the window has been made visible, check that it is in the correct place
552 // sometimes java places a window not in the correct place,
553 // but with an offset. If so, we work out what the offset is
554 // and change the desired location to take that into account
555 Point location = g_man.getLocation();
556 int x_offset = bounds.x - location.x;
557 int y_offset = bounds.y - location.y;
558 // If not, offset the window to move it into the correct location
559 if (x_offset > 0 || y_offset > 0) {
560 ///ystem.err.println("changing the location to "+(bounds.x + x_offset)+" "+ (bounds.y + y_offset));
561 g_man.setLocation(bounds.x + x_offset, bounds.y + y_offset);
562 }
563
564 // 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.
565 g_man.afterDisplay();
566 g_man_built = true;
567 }
568 else {
569 g_man.setVisible(true);
570 }
571
572 // Get a list of the core Greenstone classifiers and plugins
573 /*Classifiers.loadClassifiersList(null);
574 Plugins.loadPluginsList(null);
575
576 // If using a remote Greenstone we need to download the collection configurations now
577 if (Gatherer.isGsdlRemote) {
578 if (remoteGreenstoneServer.downloadCollectionConfigurations().equals("")) {
579 // !! Something went wrong downloading the collection configurations
580 System.err.println("Error: Could not download collection configurations.");
581 System.exit(0);
582 }
583 }*/
584
585 // If there was a collection left open last time, reopen it
586 if (open_collection_file_path == null) {
587
588 //the menu bar items, file and edit, are disabled from the moment of their creation. if there is no left-over collection from the last session, enable them; otherwise it is untill the collection finishes loading, will they be enabled in collectionManager.java
589 setMenuBarEnabled(true);
590 } else {
591
592 // If there was a collection left open last time, reopen it
593 c_man.openCollectionFromLastTime();
594 }
595 }
596
597 public static void setMenuBarEnabled(boolean enabled) {
598 g_man.menu_bar.file.setEnabled(enabled);
599 g_man.menu_bar.edit.setEnabled(enabled);
600 }
601
602 /** Exits the Gatherer after ensuring that things needing saving are saved.
603 * @see java.io.FileOutputStream
604 * @see java.io.PrintStream
605 * @see java.lang.Exception
606 * @see javax.swing.JOptionPane
607 * @see org.greenstone.gatherer.Configuration
608 * @see org.greenstone.gatherer.collection.CollectionManager
609 * @see org.greenstone.gatherer.gui.GUIManager
610 */
611 static public void exit(int new_exit_status)
612 {
613 DebugStream.println("In Gatherer.exit()...");
614 exit = true;
615 if (new_exit_status != 0) {
616 // default exit_status is already 0
617 // only remember a new exit status if it is non-trivial
618 exit_status = new_exit_status;
619 }
620
621 // Save the file associations
622 if (assoc_man != null) {
623 assoc_man.save();
624 assoc_man = null;
625 }
626
627 // Get the gui to deallocate
628 if(g_man != null) {
629 g_man.destroy();
630 g_man_built = false;
631 }
632
633 // Flush debug
634 DebugStream.closeDebugStream();
635
636 // If we started a server, we should try to stop it.
637 if (LocalLibraryServer.isRunning() == true) {
638 LocalLibraryServer.stop();
639 }
640
641 // If we're using a remote Greenstone server we need to make sure that all jobs have completed first
642 if (isGsdlRemote) {
643 remoteGreenstoneServer.exit();
644 }
645
646 // Make sure we haven't started up any processes that are still running
647 if (apps.size() == 0) {
648 // If we're running as an applet we don't actually quit (just hide the main GLI window)
649 if (!Gatherer.isApplet) {
650 // This is the end...
651 System.exit(exit_status);
652 }
653 }
654 else {
655 JOptionPane.showMessageDialog(g_man, Dictionary.get("General.Outstanding_Processes"), Dictionary.get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
656 g_man.setVisible(false);
657 }
658 }
659
660 static public void exit()
661 {
662 exit(0);
663 }
664
665 /** Returns the path of the Greenstone "collect" directory. */
666 static public String getCollectDirectoryPath()
667 {
668 if (non_standard_collect_directory_path != null) {
669 return non_standard_collect_directory_path;
670 }
671
672 if (!GS3) {
673 return Configuration.gsdl_path + "collect" + File.separator;
674 }
675 else {
676 return getSitesDirectoryPath() + Configuration.site_name + File.separator + "collect" + File.separator;
677 }
678 }
679
680
681 /** Returns the path of the GLI directory. */
682 static public String getGLIDirectoryPath()
683 {
684 return gli_directory_path;
685 }
686
687
688 /** Returns the path of the GLI "metadata" directory. */
689 static public String getGLIMetadataDirectoryPath()
690 {
691 return getGLIDirectoryPath() + "metadata" + File.separator;
692 }
693
694
695 /** Returns the path of the GLI user directory. */
696 static public String getGLIUserDirectoryPath()
697 {
698 return gli_user_directory_path;
699 }
700
701
702 /** Returns the path of the GLI user "cache" directory. */
703 static public String getGLIUserCacheDirectoryPath()
704 {
705 return getGLIUserDirectoryPath() + "cache" + File.separator;
706 }
707
708
709 /** Returns the path of the GLI user "log" directory. */
710 static public String getGLIUserLogDirectoryPath()
711 {
712 return getGLIUserDirectoryPath() + "log" + File.separator;
713 }
714
715
716 static public String getSitesDirectoryPath()
717 {
718 return Configuration.gsdl3_path + "sites" + File.separator;
719 }
720
721
722 static public void setCollectDirectoryPath(String collect_directory_path)
723 {
724 non_standard_collect_directory_path = collect_directory_path;
725 if (!non_standard_collect_directory_path.endsWith(File.separator)) {
726 non_standard_collect_directory_path = non_standard_collect_directory_path + File.separator;
727 }
728 }
729
730
731 static public void setGLIDirectoryPath(String gli_directory_path_arg)
732 {
733 gli_directory_path = gli_directory_path_arg;
734 }
735
736
737 static public void setGLIUserDirectoryPath(String gli_user_directory_path_arg)
738 {
739 gli_user_directory_path = gli_user_directory_path_arg;
740
741 // Ensure the GLI user directory exists
742 File gli_user_directory = new File(gli_user_directory_path);
743 if (!gli_user_directory.exists() && !gli_user_directory.mkdirs()) {
744 System.err.println("Error: Unable to make directory: " + gli_user_directory);
745 }
746 }
747
748
749 static public void refresh(int refresh_reason)
750 {
751 if (g_man != null) {
752
753 g_man.refresh(refresh_reason, c_man.ready());
754 }
755
756 // Now is a good time to force a garbage collect
757 System.gc();
758 }
759
760
761 // used to send reload coll messages to the tomcat server
762 static public void configGS3Server(String site, String command) {
763 if (Configuration.library_url == null){
764 System.out.println("Error: you have not provide the Greenstone Library address.");
765 return;
766
767 }
768
769 try {
770 // need to add the servlet name to the exec address
771 String raw_url = Configuration.library_url.toString() + Configuration.getServletPath() + command;
772 URL url = new URL(raw_url);
773 DebugStream.println("Action: " + raw_url);
774 HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
775 int response_code = library_connection.getResponseCode();
776 if(HttpURLConnection.HTTP_OK <= response_code && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
777 DebugStream.println("200 - Complete.");
778 }
779 else {
780 DebugStream.println("404 - Failed.");
781 }
782 url = null;
783 }
784 catch(java.net.ConnectException connectException) {
785 JOptionPane.showMessageDialog(g_man, Dictionary.get("Preferences.Connection.Library_Path_Connection_Failure", Configuration.library_url.toString()), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE);
786 DebugStream.println(connectException.getMessage());
787 }
788 catch (Exception exception) {
789 DebugStream.printStackTrace(exception);
790 }
791 }
792
793
794 /** Used to 'spawn' a new child application when a file is double clicked.
795 * @param file The file to open
796 * @see org.greenstone.gatherer.Gatherer.ExternalApplication
797 */
798 static public void spawnApplication(File file) {
799 String [] commands = assoc_man.getCommand(file);
800 if(commands != null) {
801 ExternalApplication app = new ExternalApplication(commands);
802 apps.add(app);
803 app.start();
804 }
805 else {
806 ///ystem.err.println("No open command available.");
807 }
808 }
809
810
811 static public void spawnApplication(String command)
812 {
813 ExternalApplication app = new ExternalApplication(command);
814 apps.add(app);
815 app.start();
816 }
817
818 static public void spawnApplication(String command, String ID)
819 {
820 ExternalApplication app = new ExternalApplication(command, ID);
821 apps.add(app);
822 app.start();
823 }
824
825 static public void terminateApplication(String ID) {
826 for(int i = 0; i < apps.size(); i++) {
827 ExternalApplication app = (ExternalApplication)apps.get(i);
828 if(app.getID() != null && app.getID().equals(ID)) {
829 app.stopExternalApplication();
830 apps.remove(app);
831 }
832 }
833 }
834
835
836 /** Used to 'spawn' a new browser application or reset an existing one when the preview button is clicked
837 * @param url The url to open the browser at
838 * @see org.greenstone.gatherer.Gatherer.BrowserApplication
839 */
840 static public void spawnBrowser(String url) {
841 String command = assoc_man.getBrowserCommand(url);
842 if (command != null) {
843 BrowserApplication app = new BrowserApplication(command, url);
844 apps.add(app);
845 app.start();
846 }
847 else {
848 ///ystem.err.println("No browser command available.");
849 }
850 }
851
852
853 /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
854 */
855 static private void missingEXEC() {
856 WarningDialog dialog;
857 String configPropertyName = "general.library_url"+Configuration.gliPropertyNameSuffix();
858
859 if (GS3) {
860 // Warning dialog with no cancel button and no "turn off warning" checkbox
861 dialog = new WarningDialog("warning.MissingEXEC", Dictionary.get("MissingEXEC_GS3.Title"), Dictionary.get("MissingEXEC_GS3.Message"), configPropertyName, false, false);
862 } else { // local case
863 dialog = new WarningDialog("warning.MissingEXEC", Dictionary.get("MissingEXEC.Title"), Dictionary.get("MissingEXEC.Message"), configPropertyName, false);
864 }
865
866 JTextField field = new URLField.Text(Configuration.getColor("coloring.editable_foreground", false), Configuration.getColor("coloring.editable_background", false));
867
868 // Set the default library URL to the tomcat server and port number
869 // specified in the build.properties located in the gsdl3_src_path
870 if (GS3) {
871 String host = "localhost";
872 String port = "8080";
873
874 File buildPropsFile = new File(Configuration.gsdl3_src_path + File.separator + "build.properties");
875 if(buildPropsFile.exists()) {
876 Properties props = new Properties();
877 try{
878 props.load(new FileInputStream(buildPropsFile));
879 host = props.getProperty("tomcat.server", host);
880 port = props.getProperty("tomcat.port", port);
881 }catch(Exception e){
882 DebugStream.println("Could not load build.properties file");
883 System.err.println("Could not load build.properties file");
884 }
885 props = null;
886 }
887 String defaultURL = "http://"+host+":"+port+"/"+"greenstone3/library";
888 field.setText(defaultURL);
889 field.selectAll();
890 }
891 dialog.setValueField(field);
892 dialog.display();
893 dialog.dispose();
894 dialog = null;
895
896 String library_url_string = Configuration.getString(configPropertyName, true);
897 if (!library_url_string.equals("")) {
898 try {
899 // WarningDialog does not allow invalid URLs, so the following is ignored:
900 // make sure the URL the user provided contains the http:// prefix
901 // and then save the corrected URL
902 if(!library_url_string.startsWith("http://")
903 && !library_url_string.startsWith("https://")) {
904 library_url_string = "http://"+library_url_string;
905 Configuration.setString(configPropertyName, true, configPropertyName);
906 }
907 Configuration.library_url = new URL(library_url_string);
908 }
909 catch (MalformedURLException exception) {
910 DebugStream.printStackTrace(exception);
911 }
912 }
913 }
914
915
916
917 /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
918 */
919 static private void popupFedoraInfo() {
920
921 FedoraLogin dialog = new FedoraLogin("Fedora Login", false);
922
923 if (Configuration.library_url == null) {
924
925 String library_url_string = dialog.getLibraryURL();
926 if (!library_url_string.equals("")) {
927 try {
928 Configuration.library_url = new URL(library_url_string);
929 }
930 catch (MalformedURLException exception) {
931 DebugStream.printStackTrace(exception);
932 }
933 }
934 }
935
936 boolean showLogin = true;
937 do {
938 if(!dialog.loginRequested()) { // user pressed cancel to exit the FedoraLogin dialog
939 System.exit(0);
940 } else {
941 showLogin = dialog.loginRequested();
942 String hostname = dialog.getHostname();
943 String port = dialog.getPort();
944 String username = dialog.getUsername();
945 String password = dialog.getPassword();
946 String protocol = dialog.getProtocol();
947
948 Configuration.fedora_info.setHostname(hostname);
949 Configuration.fedora_info.setPort(port);
950 Configuration.fedora_info.setUsername(username);
951 Configuration.fedora_info.setPassword(password);
952 Configuration.fedora_info.setProtocol(protocol);
953
954 String ping_url_str = protocol + "://" + hostname + ":" + port + "/fedora";
955 String login_str = username + ":" + password;
956
957 String login_encoding = Base64.encodeBytes(login_str.getBytes());
958
959 try {
960 URL ping_url = new URL(ping_url_str);
961 URLConnection uc = ping_url.openConnection();
962 uc.setRequestProperty ("Authorization", "Basic " + login_encoding);
963 // Attempt to access some content ...
964 InputStream content = (InputStream)uc.getInputStream();
965
966 // if no exception occurred in the above, we would have come here:
967 showLogin = false;
968 dialog.dispose();
969 }
970 catch (Exception exception) {
971 // TODO: move into dictionary
972 String[] errorMessage = {"Failed to connect to the Fedora server.", "It might not be running, or",
973 "incorrect username and/or password."};
974 dialog.setErrorMessage(errorMessage);
975 //DebugStream.printStackTrace(exception);
976 // exception occurred, show the dialog again (do this after printing to
977 // debugStream, else the above does not get done for some reason).
978 dialog.setVisible(true);
979 }
980 }
981 } while(showLogin);
982
983 dialog = null; // no more need of the dialog
984
985 // Now we are connected.
986 }
987
988
989
990 static private void requestGLIServerURL()
991 {
992 WarningDialog dialog;
993 String[] defaultURLs = {
994 "http://localhost:8080/greenstone3/cgi-bin/gliserver.pl",
995 "http://localhost:8080/gsdl/cgi-bin/gliserver.pl"
996 };
997
998 // Warning dialog with no cancel button and no "turn off warning" checkbox
999 // (since user-input of the gliserver script is mandatory)
1000 dialog = new WarningDialog("warning.MissingGLIServer", Dictionary.get("MissingGLIServer.Title"), Dictionary.get("MissingGLIServer.Message"), "general.gliserver_url", false, false);
1001
1002 dialog.setValueField(new URLField.DropDown(Configuration.getColor("coloring.editable_foreground", false),
1003 Configuration.getColor("coloring.editable_background", false),
1004 defaultURLs, "general.gliserver_url",
1005 "general.open_collection"+Configuration.gliPropertyNameSuffix(),
1006 "gliserver.pl"));
1007
1008 if (Gatherer.default_gliserver_url!=null){
1009 dialog.setValueField(Gatherer.default_gliserver_url.toString());
1010 }
1011
1012 // A WarningDialog cannot always be made to respond (let alone to exit the program) on close. We
1013 // handle the response of this particular WarningDialog here: a URL for gliserver.pl is a crucial
1014 // piece of user-provided data. Therefore, if no URL was entered for gliserver.pl, it'll exit safely.
1015 dialog.addWindowListener(new WindowAdapter() {
1016 public void windowClosing(WindowEvent e) {
1017 Gatherer.exit();
1018 }
1019 });
1020
1021 dialog.display();
1022 dialog.dispose();
1023 dialog = null;
1024
1025
1026 String gliserver_url_string = Configuration.getString("general.gliserver_url", true);
1027 if (!gliserver_url_string.equals("")) {
1028 try {
1029 Configuration.gliserver_url = new URL(gliserver_url_string);
1030 Configuration.setString("general.gliserver_url", true, gliserver_url_string);
1031 }
1032 catch (MalformedURLException exception) {
1033 DebugStream.printStackTrace(exception);
1034 }
1035 }
1036 }
1037
1038
1039 /** Prints a warning message about a missing GSDL path, which although not fatal pretty much ensures nothing will work properly in the GLI.
1040 */
1041 static private void missingGSDL() {
1042 WarningDialog dialog = new WarningDialog("warning.MissingGSDL", Dictionary.get("MissingGSDL.Title"), Dictionary.get("MissingGSDL.Message"), null, false);
1043 dialog.display();
1044 dialog.dispose();
1045 dialog = null;
1046 }
1047
1048 /** Prints a warning message about missing a valid ImageMagick path, which although not fatal means building image collections won't work */
1049 static private void missingImageMagick() {
1050 WarningDialog dialog = new WarningDialog("warning.MissingImageMagick", Dictionary.get("MissingImageMagick.Title"), Dictionary.get("MissingImageMagick.Message"), null, false);
1051 dialog.display();
1052 dialog.dispose();
1053 dialog = null;
1054 }
1055
1056 /** Prints a warning message about missing a valid PERL path, which although not fatal pretty much ensures no collection creation/building will work properly in the GLI. */
1057 static private void missingPERL() {
1058 WarningDialog dialog = new WarningDialog("warning.MissingPERL", Dictionary.get("MissingPERL.Title"), Dictionary.get("MissingPERL.Message"), null, false);
1059 dialog.display();
1060 dialog.dispose();
1061 dialog = null;
1062 }
1063
1064
1065 /** Sets up the proxy connection by setting JVM Environment flags and creating a new Authenticator.
1066 * @see java.lang.Exception
1067 * @see java.lang.System
1068 * @see java.net.Authenticator
1069 * @see org.greenstone.gatherer.Configuration
1070 * @see org.greenstone.gatherer.GAuthenticator
1071 */
1072 static public void setProxy() {
1073 try {// Can throw several exceptions
1074 if(Configuration.get("general.use_proxy", true)) {
1075 System.setProperty("http.proxyType", "4");
1076 System.setProperty("http.proxyHost", Configuration.getString("general.proxy_host", true));
1077 System.setProperty("http.proxyPort", Configuration.getString("general.proxy_port", true));
1078 System.setProperty("http.proxySet", "true");
1079 } else {
1080 System.setProperty("http.proxyHost", "");
1081 System.setProperty("http.proxyPort", "");
1082 System.setProperty("http.proxySet", "false");
1083 }
1084 } catch (Exception error) {
1085 DebugStream.println("Error in Gatherer.initProxy(): " + error);
1086 DebugStream.printStackTrace(error);
1087 }
1088 }
1089
1090
1091 /** 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. */
1092 static private class ExternalApplication
1093 extends Thread {
1094 private Process process = null;
1095 /** The initial command string given to this sub-process. */
1096 private String command = null;
1097 private String[] commands = null;
1098
1099 private String ID = null;
1100
1101 /** Constructor.
1102 * @param command The initial command <strong>String</strong>.
1103 */
1104 public ExternalApplication(String command) {
1105 this.command = command;
1106 }
1107
1108 public ExternalApplication(String[] commands) {
1109 this.commands = commands;
1110 }
1111
1112 public ExternalApplication(String command, String ID) {
1113 this.command = command;
1114 this.ID = ID;
1115 }
1116
1117 public String getID() {
1118 return ID;
1119 }
1120
1121 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
1122 * @see java.lang.Exception
1123 * @see java.lang.Process
1124 * @see java.lang.Runtime
1125 * @see java.lang.System
1126 * @see java.util.Vector
1127 */
1128 public void run() {
1129 // Call an external process using the args.
1130 try {
1131 if(commands != null) {
1132 StringBuffer whole_command = new StringBuffer();
1133 for(int i = 0; i < commands.length; i++) {
1134 whole_command.append(commands[i]);
1135 whole_command.append(" ");
1136 }
1137 DebugStream.println("Running " + whole_command.toString());
1138 Runtime rt = Runtime.getRuntime();
1139 process = rt.exec(commands);
1140 process.waitFor();
1141 }
1142 else {
1143 DebugStream.println("Running " + command);
1144 Runtime rt = Runtime.getRuntime();
1145 process = rt.exec(command);
1146 process.waitFor();
1147 }
1148 }
1149 catch (Exception exception) {
1150 DebugStream.printStackTrace(exception);
1151 }
1152 // Remove ourself from Gatherer list of threads.
1153 apps.remove(this);
1154 // Call exit if we were the last outstanding child process thread.
1155 if (apps.size() == 0 && exit == true) {
1156 // In my opinion (DB) there is no need to exit here,
1157 // the 'run' method ending naturally brings this
1158 // thread to an end. In fact it is potentially
1159 // dangerous to exit here, as the main thread in the
1160 // Gatherer class may be stopped prematurely. As it so
1161 // happens the point at which the ExternalApplication thread
1162 // is asked to stop (Back in the main Gatherer thread) is after
1163 // various configuration files have been saved.
1164 //
1165 // A similar argument holds for BrowserApplication thread below.
1166 System.exit(exit_status);
1167 }
1168 }
1169 public void stopExternalApplication() {
1170 if(process != null) {
1171 process.destroy();
1172 }
1173 }
1174 }
1175 /** 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. */
1176 static private class BrowserApplication
1177 extends Thread {
1178 private Process process = null;
1179 /** The initial command string given to this sub-process. */
1180 private String command = null;
1181 private String url = null;
1182 private String[] commands = null;
1183
1184 public BrowserApplication(String command, String url) {
1185 StringTokenizer st = new StringTokenizer(command);
1186 int num_tokens = st.countTokens();
1187 this.commands = new String [num_tokens];
1188 int i=0;
1189 while (st.hasMoreTokens()) {
1190 commands[i] = st.nextToken();
1191 i++;
1192 }
1193 //this.commands = commands;
1194 this.url = url;
1195 }
1196 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
1197 * @see java.lang.Exception
1198 * @see java.lang.Process
1199 * @see java.lang.Runtime
1200 * @see java.lang.System
1201 * @see java.util.Vector
1202 */
1203 public void run() {
1204 // Call an external process using the args.
1205 if(commands == null) {
1206 apps.remove(this);
1207 return;
1208 }
1209 try {
1210 String prog_name = commands[0];
1211 String lower_name = prog_name.toLowerCase();
1212 if (lower_name.indexOf("mozilla") != -1 || lower_name.indexOf("netscape") != -1) {
1213 DebugStream.println("found mozilla or netscape, trying remote it");
1214 // mozilla and netscape, try using a remote command to get things in the same window
1215 String [] new_commands = new String[] {prog_name, "-raise", "-remote", "openURL("+url+",new-tab)"};
1216 printArray(new_commands);
1217
1218 Runtime rt = Runtime.getRuntime();
1219 process = rt.exec(new_commands);
1220 int exitCode = process.waitFor();
1221 if (exitCode != 0) { // if Netscape or mozilla was not open
1222 DebugStream.println("couldn't do remote, trying original command");
1223 printArray(commands);
1224 process = rt.exec(commands); // try the original command
1225 }
1226 } else {
1227 // just run what we have been given
1228 StringBuffer whole_command = new StringBuffer();
1229 for(int i = 0; i < commands.length; i++) {
1230 whole_command.append(commands[i]);
1231 whole_command.append(" ");
1232 }
1233 DebugStream.println("Running " + whole_command.toString());
1234 Runtime rt = Runtime.getRuntime();
1235 process = rt.exec(commands);
1236 process.waitFor();
1237 }
1238 }
1239
1240 catch (Exception exception) {
1241 DebugStream.printStackTrace(exception);
1242 }
1243 // Remove ourself from Gatherer list of threads.
1244 apps.remove(this);
1245 // Call exit if we were the last outstanding child process thread.
1246 if (apps.size() == 0 && exit == true) {
1247 System.exit(exit_status);
1248 }
1249 }
1250 public void printArray(String [] array) {
1251 for(int i = 0; i < array.length; i++) {
1252 DebugStream.print(array[i]+" ");
1253 System.err.println(array[i]+" ");
1254 }
1255 }
1256 public void stopBrowserApplication() {
1257 if(process != null) {
1258 process.destroy();
1259 }
1260 }
1261 }
1262
1263
1264 private class ImageMagickTest
1265 {
1266 public boolean found()
1267 {
1268 try {
1269 String[] command = new String[2];
1270 command[0] = (Utility.isWindows() ? "identify.exe" : "identify");
1271 command[1] = "-version";
1272 Process image_magick_process = Runtime.getRuntime().exec(command);
1273 image_magick_process.waitFor();
1274
1275 //new way of detection of ImageMagick
1276 InputStreamReader isr = new InputStreamReader(image_magick_process.getInputStream());
1277
1278 BufferedReader br = new BufferedReader(isr);
1279 // Capture the standard output stream and seach for two particular occurances: Version and ImageMagick.
1280
1281 String line = br.readLine();
1282 if (line == null) {
1283 return false;
1284 }
1285 String lc_line = line.toLowerCase();
1286 if (lc_line.indexOf("version") != -1 || lc_line.indexOf("imagemagick") != -1) {
1287 return true;
1288 } else {
1289 return false;
1290 }
1291
1292 //return (image_magick_process.exitValue() == 0);
1293 }
1294 catch (IOException exception) {
1295 return false;
1296 }
1297 catch (InterruptedException exception) {
1298 return false;
1299 }
1300 }
1301 }
1302
1303
1304 private class PerlTest
1305 {
1306 private String[] command = new String[2];
1307
1308 public PerlTest()
1309 {
1310 command[0] = (Utility.isWindows() ? Utility.PERL_EXECUTABLE_WINDOWS : Utility.PERL_EXECUTABLE_UNIX);
1311 command[1] = "-version";
1312 }
1313
1314 public boolean found()
1315 {
1316 try {
1317 Process perl_process = Runtime.getRuntime().exec(command);
1318 perl_process.waitFor();
1319 return (perl_process.exitValue() == 0);
1320 }
1321 catch (Exception exception) {
1322 return false;
1323 }
1324 }
1325
1326 public String toString() {
1327 return command[0];
1328 }
1329 }
1330}
Note: See TracBrowser for help on using the repository browser.