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

Last change on this file since 32695 was 32695, checked in by ak19, 5 years ago

Simplifying setNamesRecursively and its usage. And printComponentNames is now automatically called by new version of now-overloaded setNamesRecursively(), but only if new flag DEBUGGING_TEST_MODE set

  • Property svn:keywords set to Author Date Id Revision
File size: 69.8 KB
Line 
1/**
2*#########################################################################
3*
4* A component of the Gatherer application, part of the Greenstone digital
5* library suite from the New Zealand Digital Library Project at the
6* University of Waikato, New Zealand.
7*
8* Author: John Thompson, Greenstone Digital Library, University of Waikato
9*
10* Copyright (C) 1999 New Zealand Digital Library Project
11*
12* This program is free software; you can redistribute it and/or modify
13* it under the terms of the GNU General Public License as published by
14* the Free Software Foundation; either version 2 of the License, or
15* (at your option) any later version.
16*
17* This program is distributed in the hope that it will be useful,
18* but WITHOUT ANY WARRANTY; without even the implied warranty of
19* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20* GNU General Public License for more details.
21*
22* You should have received a copy of the GNU General Public License
23* along with this program; if not, write to the Free Software
24* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25*########################################################################
26*/
27package org.greenstone.gatherer;
28
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.gui.TestingPreparation;
59import org.greenstone.gatherer.metadata.FilenameEncoding;
60import org.greenstone.gatherer.remote.RemoteGreenstoneServer;
61import org.greenstone.gatherer.util.GS3ServerThread;
62import org.greenstone.gatherer.util.JarTools;
63import org.greenstone.gatherer.util.SafeProcess;
64import org.greenstone.gatherer.util.StaticStrings;
65import org.greenstone.gatherer.util.Utility;
66
67
68/** Containing the top-level "core" for the Gatherer, this class is the
69* common core for the GLI application and applet. It first parses the
70* command line arguments, preparing to update the configuration as
71* required. Next it loads several important support classes such as the
72* Configuration and Dictionary. Finally it creates the other important
73* managers and sends them on their way.
74* @author John Thompson, Greenstone Digital Library, University of Waikato
75* @version 2.3
76*/
77public class Gatherer
78{
79 /** The name of the GLI. */
80 static final public String PROGRAM_NAME = "Greenstone Librarian Interface";
81 /** The current version of the GLI.
82 * Note: the gs3-release-maker relies on this variable being declared
83 * in a line which matches this java regex:
84 * ^(.*)String\s*PROGRAM_VERSION\s*=\s*"trunk";
85 * If change the declaration and it no longer matches the regex, please
86 * change the regex in the gs3-release-maker code and in this message
87 */
88
89 static final public String PROGRAM_VERSION = "trunk";
90
91 static private Dimension size = new Dimension(800, 540);
92 static public RemoteGreenstoneServer remoteGreenstoneServer = null;
93
94 /** Has the exit flag been set? */
95 static final public int EXIT_THEN_RESTART= 2;
96 static public boolean exit = false;
97 static public int exit_status = 0;
98
99 static private String gli_directory_path = null;
100 static private String gli_user_directory_path = null;
101
102 static public String client_operating_system = null;
103
104 /** All of the external applications that must exit before we close the Gatherer. */
105 static private Vector apps = new Vector();
106 static private String non_standard_collect_directory_path = null;
107 static public String open_collection_file_path = null;
108 static public String gsdlsite_collecthome = "";
109 /** A public reference to the FileAssociationManager. */
110 static public FileAssociationManager assoc_man;
111 /** A public reference to the CollectionManager. */
112 static public CollectionManager c_man;
113 /** A public reference to the RecycleBin. */
114 static public RecycleBin recycle_bin;
115 /** a reference to the Servlet Configuration is GS3 */
116 static public ServletConfiguration servlet_config;
117 /** A public reference to the FileManager. */
118 static public FileManager f_man;
119 /** A public reference to the GUIManager. */
120 static public GUIManager g_man = null;
121 static private boolean g_man_built = false;
122
123 /** We are using the GLI for GS3 */
124 static public boolean GS3 = false;
125
126 static public boolean isApplet = false;
127 static public boolean isGsdlRemote = false;
128 static public boolean isLocalLibrary = false;
129
130 // for storing the original proxy settings on GLI startup
131 private static Properties startup_proxy_settings = new Properties();
132
133 /* TODO: If we're using local GLI, collections are built locally. If we're using client-GLI
134 * and it contains a gs2build folder in it, then localBuild will also be true (if this is not
135 * turned off in Preferences). If we're remote and this is turned off in Prefs, build remotely. */
136 /*static public boolean buildingLocally = true;*/
137 /** If we're using local GLI, we can always download. If we're using client-GLI, we can only
138 * download if we have a gs2build folder inside it. And if we don't turn off downloadEnabling
139 * in the preferences.
140 */
141 static public boolean isDownloadEnabled = true;
142
143 // feedback stuff
144 /** is the feedback feature enabled? */
145 static public boolean feedback_enabled = true;
146 /** the action recorder dialog */
147 static public ActionRecorderDialog feedback_dialog = null;
148
149 // Refresh reasons
150 static public final int COLLECTION_OPENED = 0;
151 static public final int COLLECTION_CLOSED = 1;
152 static public final int COLLECTION_REBUILT = 2;
153 static public final int PREFERENCES_CHANGED = 3;
154
155 //////kk added////////
156 static public String cgiBase="";
157 /////////////////
158
159 /** Magic to allow Enter to fire the default button. */
160 static {
161 KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
162 Keymap map = JTextComponent.getKeymap(JTextComponent.DEFAULT_KEYMAP);
163 map.removeKeyStrokeBinding(enter);
164 }
165
166 static private URL default_gliserver_url=null;
167
168 public Gatherer(String[] args)
169 {
170 // Display the version to make error reports a lot more useful
171 System.err.println("Version: " + PROGRAM_VERSION + "\n");
172
173 JarTools.initialise(this);
174
175 GetOpt go = new GetOpt(args);
176
177 // Remember the GSDLOS value
178 client_operating_system = go.client_operating_system;
179
180 // If feedback is enabled, set up the recorder dialog
181 if (go.feedback_enabled) {
182 // Use the default locale for now - this will be changed by the Gatherer run method
183 feedback_enabled = true;
184 feedback_dialog = new ActionRecorderDialog(Locale.getDefault());
185 }
186
187 // Are we using a remote Greenstone?
188 if (go.use_remote_greenstone) {
189 isGsdlRemote = true;
190
191 // We don't have a local Greenstone!
192 go.gsdl3_path=null;
193 go.gsdl3_src_path=null;
194
195 // Don't set go.gsdl_path to null, since gdsl_path may still be set
196 // if we have a client-gli containing gs2build folder.
197 // However, keep track of whether we can download.
198 if(go.gsdl_path == null) {
199 isDownloadEnabled = false;
200 }
201
202 // We have to use our own collect directory since we can't use the Greenstone one
203 setCollectDirectoryPath(getGLIUserDirectoryPath() + "collect" + File.separator);
204 }
205 // We have a local Greenstone. OR we have a gs2build folder inside
206 // the client-GLI folder (with which the Download panel becomes enabled)
207 if(isDownloadEnabled) {
208 LocalGreenstone.setDirectoryPath(go.gsdl_path);
209 }
210
211 // Users may specify a non-standard collect directory (eg. when running one GLI in a network environment)
212 // Processing of custom non-standard collect directory passed into gli now happens in init()
213 //if (go.collect_directory_path != null) { setCollectDirectoryPath(go.collect_directory_path); }
214
215 // More special code for running with a remote Greenstone
216 if (isGsdlRemote) {
217 if (go.fedora_info.isActive()) {
218 Configuration.TEMPLATE_CONFIG_XML = "xml/" + Configuration.FEDORA_CONFIG_PREFIX + "configRemote.xml";
219 }
220 else {
221 Configuration.TEMPLATE_CONFIG_XML = "xml/configRemote.xml";
222 }
223
224 Configuration.CONFIG_XML = "configRemote.xml";
225
226 File collect_directory = new File(Gatherer.getCollectDirectoryPath());
227 if (!collect_directory.exists() && !collect_directory.mkdir()) {
228 System.err.println("Warning: Unable to make directory: " + collect_directory);
229 }
230 }
231 else {
232 if (go.fedora_info.isActive()) {
233 Configuration.TEMPLATE_CONFIG_XML = "xml/" + Configuration.FEDORA_CONFIG_PREFIX + Configuration.CONFIG_XML;
234 }
235 // else, the CONFIG_XML uses the default config file, which is for the local GS server
236 }
237
238 if(go.testing_mode) {
239 TestingPreparation.TEST_MODE = true;
240 }
241
242 init(go.gsdl_path, go.gsdl3_path, go.gsdl3_src_path,
243 go.fedora_info,
244 go.local_library_path, go.library_url_string,
245 go.gliserver_url_string, go.debug, go.perl_path, go.no_load, go.filename, go.site_name,
246 go.servlet_path, go.collect_directory_path);
247 }
248
249
250 public void init(String gsdl_path, String gsdl3_path, String gsdl3_src_path,
251 FedoraInfo fedora_info,
252 String local_library_path,
253 String library_url_string, String gliserver_url_string, boolean debug_enabled,
254 String perl_path, boolean no_load, String open_collection,
255 String site_name, String servlet_path, String collect_directory_path)
256 {
257 if (gsdl3_path != null && !gsdl3_path.equals("")) {
258 this.GS3 = true;
259 } else {
260 gsdl3_path = null;
261 gsdl3_src_path = null;
262 }
263
264 // Create the debug stream if required
265 if (debug_enabled) {
266 DebugStream.enableDebugging();
267
268 Calendar now = Calendar.getInstance();
269 String debug_file_path = "debug" + now.get(Calendar.DATE) + "-" + now.get(Calendar.MONTH) + "-" + now.get(Calendar.YEAR) + ".txt";
270
271 // Debug file is created in the user's GLI directory
272 debug_file_path = getGLIUserDirectoryPath() + debug_file_path;
273 DebugStream.println("Debug file path: " + debug_file_path);
274 DebugStream.setDebugFile(debug_file_path);
275 DebugStream.print(System.getProperties());
276 }
277
278 // Delete plugins.dat and classifiers.dat files from previous versions of the GLI (no longer used)
279 File plugins_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "plugins.dat");
280 if (plugins_dat_file.exists()) {
281 System.err.println("Deleting plugins.dat file...");
282 Utility.delete(plugins_dat_file);
283 }
284 File classifiers_dat_file = new File(Gatherer.getGLIUserDirectoryPath() + "classifiers.dat");
285 if (classifiers_dat_file.exists()) {
286 System.err.println("Deleting classifiers.dat file...");
287 Utility.delete(classifiers_dat_file);
288 }
289
290 try {
291 // Load GLI config file
292 new Configuration(getGLIUserDirectoryPath(), gsdl_path, gsdl3_path, gsdl3_src_path, site_name,
293 fedora_info);
294
295 // Check we know where Perl is
296 Configuration.perl_path = perl_path;
297 if (isGsdlRemote && !isDownloadEnabled && Utility.isWindows() && Configuration.perl_path != null) {
298 if (Configuration.perl_path.toLowerCase().endsWith("perl.exe")) {
299 Configuration.perl_path = Configuration.perl_path.substring(0, Configuration.perl_path.length() - "perl.exe".length());
300 }
301 if (Configuration.perl_path.endsWith(File.separator)) {
302 Configuration.perl_path = Configuration.perl_path.substring(0, Configuration.perl_path.length() - File.separator.length());
303 }
304 }
305
306 // the feedback dialog has been loaded with a default locale,
307 // now set the user specified one
308 if (feedback_enabled && feedback_dialog != null) {
309 feedback_dialog.setLocale(Configuration.getLocale("general.locale", true));
310 }
311
312 // Read Dictionary
313 new Dictionary(Configuration.getLocale("general.locale", true), Configuration.getFont("general.font", true));
314
315 // check that we are using Sun Java
316 String java_vendor = System.getProperty("java.vendor");
317 if (!java_vendor.equals("Sun Microsystems Inc.")
318 && !java_vendor.equals("Oracle Corporation")) {
319 System.err.println(Dictionary.get("General.NotSunJava", java_vendor));
320 }
321
322 // Unless we're using remote building, we need to know where the local Greenstone is
323 if (!isGsdlRemote && gsdl_path == null) {
324 missingGSDL();
325 }
326
327 if (fedora_info.isActive()) {
328
329 // if we have either a remote GS 2/3 server, or if we are dealing with a
330 // local GS2, or else if it's a local GS3 but with fedora installed elsewhere,
331 // we ask for fedora login details now
332 File fedora_webapp = new File(gsdl3_src_path+File.separator+"packages"+File.separator+"tomcat"+File.separator+"webapps"+File.separator+"fedora");
333
334 if(isGsdlRemote || !GS3 || !fedora_webapp.exists()) {
335 popupFedoraInfo();
336 }
337
338 // else if we have a local GS3 with fedora installed within it, we'll be starting
339 // up fedora further below, together with the local tomcat
340 }
341
342 // the no_load flag to GLI is processed at the end of handling open_collection_file_path
343 open_collection_file_path = open_collection;
344 if (open_collection_file_path == null) {
345 open_collection_file_path = Configuration.getString(
346 "general.open_collection"+Configuration.gliPropertyNameSuffix(), true);
347 }
348
349 initCollectDirectoryPath();
350
351 if (no_load || (isGsdlRemote && open_collection_file_path.equals(""))) {
352 open_collection_file_path = null;
353 }
354
355
356 // Before calling setProxy, store anything already present
357 // Downloading happens on the machine where GLI is running from, even with clientgli
358 // For downloading with wget, we use ftp/http(s)_proxy env vars, so check if they're
359 // already set
360 if(System.getenv("http_proxy") != null) System.err.println("http_proxy already set");
361 if(System.getenv("https_proxy") != null) System.err.println("https_proxy already set");
362 if(System.getenv("ftp_proxy") != null) System.err.println("ftp_proxy already set");
363
364
365 // Finally, we're ready to find out the version of the remote Greenstone server
366 if(isGsdlRemote) {
367 // instantiate the RemoteGreenstoneServer object first
368 remoteGreenstoneServer = new RemoteGreenstoneServer();
369
370 // Set up proxy
371 setProxy();
372 // Now we set up an Authenticator
373 Authenticator.setDefault(new GAuthenticator());
374
375 int greenstoneVersion = 2;
376 requestGLIServerURL();
377 gliserver_url_string = Configuration.gliserver_url.toString();
378
379 greenstoneVersion = remoteGreenstoneServer.getGreenstoneVersion();
380 // Display the version to make error reports a lot more useful
381 System.err.println("Remote Greenstone server version: " + greenstoneVersion);
382 if(greenstoneVersion == -1) { // remote server not running
383 Gatherer.exit();
384 }
385 if(greenstoneVersion >= 3) {
386 this.GS3 = true;
387 Configuration.prepareForGS3();
388 }
389
390 if(fedora_info.isActive()) {
391 // when GS server is remote, FEDORA_HOME resides on the remote server side,
392 // but we know the library URL from user-provided information
393 library_url_string = fedora_info.getLibraryURL();
394 } else {
395 library_url_string = remoteGreenstoneServer.getLibraryURL(Configuration.gliserver_url.toString());
396 }
397 // write it into the config file
398 Configuration.setString("general.library_url", true, library_url_string);
399 }
400 else { // local greenstone: add shutdown hooks to forcibly stop the server on irregular termination
401 // And start up the local library server, if that's what we want
402
403 // The Java virtual machine shuts down in response to two kinds of events:
404 // - The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
405 // - The virtual machine is terminated in response to a user interrupt, such as typing ^C, or a system-wide event, such as user logoff or system shutdown.
406 // https://coderanch.com/t/328888/java/Killing-process-spawned-Runtime-exec
407 // So here we add a shutdown hook to take care of Ctrl-C situations where GLI is irregularly terminated
408 // Sadly, the shutdownhook never gets called on Windows, whether GS2 or GS3,
409 // when a Ctrl-C is sent to the DOS prompt that launched GLI. Because GLI on Windows
410 // currently waits to respond to a Ctrl-C until AFTER GLI is already (properly) exited
411 Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
412 public void run() {
413
414 if(Gatherer.exit != true) { // unexpected termination, such as Ctrl-C won't set Gatherer.exit
415 // so still need to at least issue the call to stop any running GS server
416
417 System.err.println("ShutDownHook called...");
418
419 if (GS3) { // issue the ant call to stop any running GS3
420 // (tomcat and networked Derby Server) by calling GS3ServerThread.stopServer()
421 if(!GS3ServerThread.wasServerLaunchedOutsideGLI()) {
422 System.err.println("Attempting to forcibly terminate the GS server...");
423 GS3ServerThread.stopServer();
424 } else {
425 System.err.println("@@@ Tomcat was launched outside GLI. Leaving it running...");
426 }
427 } else { // issue the call to stop any running GS2 local library server
428 if (LocalLibraryServer.isRunning() == true) {
429 System.err.println("Attempting to forcibly terminate the GS server...");
430 LocalLibraryServer.forceStopServer();
431 }
432 }
433 }
434 }
435 }));
436
437
438 if (!GS3) {
439 isLocalLibrary = LocalLibraryServer.start(gsdl_path, local_library_path);
440
441 }
442 else { // local GS3, start the local tomcat
443
444 if(!GS3ServerThread.wasServerLaunchedOutsideGLI()) {
445 //System.err.println("@@@@ Launching tomcat from GLI");
446 GS3ServerThread thread = new GS3ServerThread(gsdl3_src_path, "restart");
447 thread.start();
448 }
449
450 // If fedora installed inside this local GS3, then ask for fedora login details now.
451 if (fedora_info.isActive()) {
452 File fedora_webapp = new File(gsdl3_src_path+File.separator+"packages"+File.separator+"tomcat"+File.separator+"webapps"+File.separator+"fedora");
453
454 if(fedora_webapp.exists()) {
455 System.err.println("**** Waiting for the local Greenstone server to start up fedora...");
456 popupFedoraInfo();
457 }
458 }
459 }
460 // else web library: GS server is local, but doesn't use the webserver included with GS2
461 }
462
463 // The "-library_url" option overwrites anything in the config files
464 if (library_url_string != null && library_url_string.length() > 0) {
465 try {
466 System.err.println("Setting library_url to " + library_url_string + "...");
467 Configuration.library_url = new URL(library_url_string);
468 }
469 catch (MalformedURLException error) {
470 DebugStream.printStackTrace(error);
471 }
472 }
473
474
475 // Check that we now know the Greenstone library URL, since we need this for previewing collections
476 // It is not necessary if an independent GSI was launched and the user hasn't pressed Enter Library yet
477 DebugStream.println("Configuration.library_url = " + Configuration.library_url);
478 if (Configuration.library_url == null) {
479 if(isLocalLibrary) {
480 if(!LocalLibraryServer.isURLPending()) {
481 missingEXEC();
482 }
483 // else LocalLibraryServer is expecting a URL soon, so don't need to display the dialog
484 } else { // GS2 webLibrary or GS3 or remote Greenstone
485 missingEXEC();
486 }
487 }
488
489 // The "-gliserver_url" option overwrites anything in the config files
490 if (gliserver_url_string != null && gliserver_url_string.length() > 0) {
491 try {
492 System.err.println("Setting gliserver_url to " + gliserver_url_string + "...");
493 Configuration.gliserver_url = new URL(gliserver_url_string);
494 }
495 catch (MalformedURLException error) {
496 DebugStream.printStackTrace(error);
497 }
498 }
499
500 // If we're using a remote Greenstone we need to know where the gliserver script is
501 DebugStream.println("Configuration.gliserver_url = " + Configuration.gliserver_url);
502
503 if (GS3) {
504 // Load Greenstone 3 servlet configuration
505 if (isGsdlRemote){
506 servlet_config = new ServletConfiguration(Configuration.gli_user_directory_path);
507 }else{
508 servlet_config= new ServletConfiguration(gsdl3_path);
509 }
510 }
511
512 if (GS3 && Configuration.servlet_path == null) {
513 Configuration.servlet_path = servlet_config.getServletPath(Configuration.site_name);
514 }
515
516 // ensure that a directory called 'cache' exists in the GLI user directory
517 File user_cache_dir = new File(Gatherer.getGLIUserCacheDirectoryPath());
518 System.err.println("User cache dir: " + Gatherer.getGLIUserCacheDirectoryPath());
519 if (!user_cache_dir.exists() && !user_cache_dir.mkdir()) {
520 System.err.println("Warning: Unable to make directory: " + user_cache_dir);
521 }
522
523
524 if (Gatherer.isGsdlRemote) {
525 DebugStream.println("Not checking for perl path/exe");
526 }
527 else {
528 // Perl path is a little different as it is perfectly ok to
529 // start the GLI without providing a perl path
530 boolean found_perl = false;
531 if (Configuration.perl_path != null) {
532 // See if the file pointed to actually exists
533 File perl_file = new File(Configuration.perl_path);
534 found_perl = perl_file.exists();
535 perl_file = null;
536 }
537 if (Configuration.perl_path == null || !found_perl) {
538 // Run test to see if we can run perl as is.
539 PerlTest perl_test = new PerlTest();
540 if (perl_test.found()) {
541 // If so replace the perl path with the system
542 // default (or null for unix).
543 Configuration.perl_path = perl_test.toString();
544 found_perl = true;
545 }
546 }
547 if (!found_perl) {
548 // Time for an error message.
549 missingPERL();
550 }
551 }
552
553
554 // Check for ImageMagick - dependent on perl_path
555 if (Gatherer.isGsdlRemote) {
556 DebugStream.println("Not checking for ImageMagick.");
557 }
558 else if (!(new ImageMagickTest()).found()) {
559 // Time for a warning message
560 missingImageMagick();
561 }
562
563 // Check for PDFBox
564 if (Gatherer.isGsdlRemote) {
565 DebugStream.println("Not checking for PDFBox.");
566 }
567 else {
568 String gs_dir = gsdl_path; // for GS3, pdf-box is in gs2build/ext (not in GS3/ext), for GS2 it's also in GS2/ext
569 File pdfboxExtensionFolder = new File(gs_dir+File.separator+"ext"+File.separator+"pdf-box");
570 if (!(pdfboxExtensionFolder.exists() && pdfboxExtensionFolder.isDirectory())) {
571 // The user doesn't have PDFBox, inform them of it
572 String zipExtension = Utility.isWindows() ? "zip" : "tar.gz";
573 missingPDFBox(zipExtension, pdfboxExtensionFolder.getParent());
574 }
575 }
576
577 // Check that the local can support multiple filename encodings
578 //System.err.println("#### Java identifies current Locale as (file.encoding): "
579 // + System.getProperty("file.encoding"));
580 if(System.getProperty("file.encoding").equals("UTF-8")){
581 // If the locale is UTF-8, Java will interpret all filename bytes as UTF-8,
582 // which is a destructive process as it will convert characters not recognised
583 // by UTF-8 into the invalid character, rather than preserving the bytecodes.
584 // This has the effect that non-UTF8 encoded filenames on a system set to a
585 // UTF-8 locale are not 'seen' by Java (if they contain non-ASCII characters).
586 multipleFilenameEncodingsNotSupported();
587 FilenameEncoding.MULTIPLE_FILENAME_ENCODINGS_SUPPORTED = false;
588 FilenameEncoding.URL_FILE_SEPARATOR = File.separator;
589 } else {
590 FilenameEncoding.MULTIPLE_FILENAME_ENCODINGS_SUPPORTED = true;
591 FilenameEncoding.URL_FILE_SEPARATOR = "/"; // URL file separator is always "/"
592 }
593
594 // Set the default font for all Swing components.
595 FontUIResource default_font = Configuration.getFont("general.font", true);
596 Enumeration keys = UIManager.getDefaults().keys();
597 while (keys.hasMoreElements()) {
598 Object key = keys.nextElement();
599 Object value = UIManager.get(key);
600 if (value instanceof FontUIResource) {
601 UIManager.put(key, default_font);
602 }
603 }
604
605 // At this point (which is where this code originally used to be), we can set up the proxy for the
606 // non-remote case. The remote Greenstone server would already have setup its proxy when required.
607 if(!isGsdlRemote) {
608 setProxy();
609 // Now we set up an Authenticator
610 Authenticator.setDefault(new GAuthenticator());
611 }
612 assoc_man = new FileAssociationManager();
613 // Create File Manager
614 f_man = new FileManager();
615 // Create Collection Manager
616 c_man = new CollectionManager();
617 // Create Recycle Bin
618 recycle_bin = new RecycleBin();
619
620 if (GS3) {
621 if (site_name==null) {
622 site_name = Configuration.site_name;
623 servlet_path = null; // need to reset this
624 }
625 if (servlet_path == null) {
626 servlet_path = Configuration.getServletPath();
627 }
628 }
629
630
631 } catch (Exception exception) {
632 DebugStream.printStackTrace(exception);
633 }
634
635
636 // Create GUI Manager (last) or else suffer the death of a thousand NPE's
637 g_man = new GUIManager(size);
638
639 // Get a list of the core Greenstone classifiers and plugins
640 Classifiers.loadClassifiersList(null);
641 Plugins.loadPluginsList(null);
642
643 // Users may specify a non-standard collect directory (eg. when running one GLI in a network environment)
644 // Set to any custom collection directory provided to gli. This happens if gli was run as:
645 // ./gli.sh -collectdir </full/path/to/custom/collect>
646 if(collect_directory_path != null) {
647
648 // create a version of the collect_dir_path without a file-separator at end
649 String collectDir = collect_directory_path;
650 if(collectDir.endsWith(File.separator)) {
651 collectDir = collectDir.substring(0, collectDir.length()-1); // remove file separator at end
652 }
653
654 // update .gli/config.xml to contain the version of the path without file-separator at end
655 if(collect_directory_path.equals(getDefaultGSCollectDirectoryPath(false))) {
656 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
657 true, "");
658 } else {
659 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
660 true, collectDir);
661 }
662
663 // set non_standard_collect_directory_path variable. Ensures file_separator at end
664 Gatherer.setCollectDirectoryPath(collect_directory_path);
665
666 // Use version of path without file-separator at end to set collecthome in gsdlsite(3).cfg
667 if(collectDir != null) {
668 collectDir = "\""+collectDir+"\"";
669 }
670 Utility.updatePropertyConfigFile(getGsdlSiteConfigFile(), "collecthome", collectDir);
671 // if gsdlsite.cfg does not exist (if using server.exe for instance), the above method will just return
672 }
673
674 // If using a remote Greenstone we need to download the collection configurations now
675 if (Gatherer.isGsdlRemote) {
676 if (remoteGreenstoneServer.downloadCollectionConfigurations().equals("")) {
677 // !! Something went wrong downloading the collection configurations
678 System.err.println("Error: Could not download collection configurations.");
679 if(!Gatherer.isApplet) { // don't close the browser if it is an applet!
680 System.exit(0);
681 }
682 }
683 }
684 }
685
686
687 /** Returns the correct version of the (local or remote) Greenstone server if init() has already been called. */
688 public static int serverVersionNumber() {
689 return GS3 ? 3 : 2;
690 }
691
692 /** Returns "Server: version number" if init() has already been called. */
693 public static String getServerVersionAsString() {
694 return "Server: v" + serverVersionNumber();
695 }
696
697 public void openGUI()
698 {
699 // Size and place the frame on the screen
700 Rectangle bounds = Configuration.getBounds("general.bounds", true);
701 if (bounds == null) {
702 // Choose a sensible default value
703 bounds = new Rectangle(0, 0, 640, 480);
704 }
705
706 // Ensure width and height are reasonable
707 size = bounds.getSize();
708 if (size.width < 640) {
709 size.width = 640;
710 }
711 else if (size.width > Configuration.screen_size.width && Configuration.screen_size.width > 0) {
712 size.width = Configuration.screen_size.width;
713 }
714 if (size.height < 480) {
715 size.height = 480;
716 }
717 else if (size.height > Configuration.screen_size.height && Configuration.screen_size.height > 0) {
718 size.height = Configuration.screen_size.height;
719 }
720
721 if (!g_man_built) {
722
723 g_man.display();
724
725 // 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).
726 g_man.setLocation(bounds.x, bounds.y);
727 g_man.setVisible(true);
728
729 // After the window has been made visible, check that it is in the correct place
730 // sometimes java places a window not in the correct place,
731 // but with an offset. If so, we work out what the offset is
732 // and change the desired location to take that into account
733 Point location = g_man.getLocation();
734 int x_offset = bounds.x - location.x;
735 int y_offset = bounds.y - location.y;
736 // If not, offset the window to move it into the correct location
737 if (x_offset > 0 || y_offset > 0) {
738 ///ystem.err.println("changing the location to "+(bounds.x + x_offset)+" "+ (bounds.y + y_offset));
739 g_man.setLocation(bounds.x + x_offset, bounds.y + y_offset);
740 }
741
742 // 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.
743 g_man.afterDisplay();
744 g_man_built = true;
745 }
746 else {
747 g_man.setVisible(true);
748 }
749
750 // Get a list of the core Greenstone classifiers and plugins
751 /*Classifiers.loadClassifiersList(null);
752 Plugins.loadPluginsList(null);
753
754 // If using a remote Greenstone we need to download the collection configurations now
755 if (Gatherer.isGsdlRemote) {
756 if (remoteGreenstoneServer.downloadCollectionConfigurations().equals("")) {
757 // !! Something went wrong downloading the collection configurations
758 System.err.println("Error: Could not download collection configurations.");
759 System.exit(0);
760 }
761 }*/
762
763 // if we're tutorial testing GLI, want names assigned to the GUI components
764 TestingPreparation.setNamesRecursively(g_man);
765
766
767 // If there was a collection left open last time, reopen it
768 if (open_collection_file_path == null || new File(Gatherer.open_collection_file_path).isDirectory()) {
769
770 //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's disabled until the collection finishes loading. They will be enabled in collectionManager.java
771 setMenuBarEnabled(true);
772 } else {
773
774 // If there was a collection left open last time, reopen it
775 c_man.openCollectionFromLastTime();
776 }
777 }
778
779 public static void setMenuBarEnabled(boolean enabled) {
780 g_man.menu_bar.file.setEnabled(enabled);
781 g_man.menu_bar.edit.setEnabled(enabled);
782 }
783
784 /** Exits the Gatherer after ensuring that things needing saving are saved.
785 * @see java.io.FileOutputStream
786 * @see java.io.PrintStream
787 * @see java.lang.Exception
788 * @see javax.swing.JOptionPane
789 * @see org.greenstone.gatherer.Configuration
790 * @see org.greenstone.gatherer.collection.CollectionManager
791 * @see org.greenstone.gatherer.gui.GUIManager
792 */
793 static public void exit(int new_exit_status)
794 {
795 DebugStream.println("In Gatherer.exit()...");
796 exit = true;
797 if (new_exit_status != 0) {
798 // default exit_status is already 0
799 // only remember a new exit status if it is non-trivial
800 exit_status = new_exit_status;
801 }
802
803 // Save the file associations
804 if (assoc_man != null) {
805 assoc_man.save();
806 assoc_man = null;
807 }
808
809 // Get the gui to deallocate
810 if(g_man != null) {
811 g_man.destroy();
812 g_man_built = false;
813 }
814
815 // Flush debug
816 DebugStream.closeDebugStream();
817
818 // If we started a server, we should try to stop it.
819 if (LocalLibraryServer.isRunning() == true) {
820 LocalLibraryServer.stop();
821 }
822
823 // If we're using a remote Greenstone server we need to make sure that all jobs have completed first
824 if (isGsdlRemote) {
825 remoteGreenstoneServer.exit();
826 } else if (GS3) { // stop the local tomcat web server when running GS3
827 // can't call ant stop from its own thread - what if GLI has exited by then?
828 // issue call to ant stop from the main GLI thread
829 //GS3ServerThread thread = new GS3ServerThread(Configuration.gsdl_path, "stop");
830 //thread.start();
831 if(!GS3ServerThread.wasServerLaunchedOutsideGLI()) {
832 GS3ServerThread.stopServer();
833 } else {
834 System.err.println("@@@ Tomcat was launched outside GLI. Leaving it running...");
835 }
836
837 }
838
839 // Make sure we haven't started up any processes that are still running
840 if (apps.size() == 0) {
841 // If we're running as an applet we don't actually quit (just hide the main GLI window)
842 if (!Gatherer.isApplet) {
843 // This is the end...
844 System.exit(exit_status);
845 }
846 }
847 else {
848 JOptionPane.showMessageDialog(g_man, Dictionary.get("General.Outstanding_Processes"), Dictionary.get("General.Outstanding_Processes_Title"), JOptionPane.ERROR_MESSAGE);
849 g_man.setVisible(false);
850 }
851 }
852
853 static public void exit()
854 {
855 exit(0);
856 }
857
858 /** Returns the path of the current collect directory. */
859 static public String getCollectDirectoryPath()
860 {
861 if (non_standard_collect_directory_path != null) {
862 return non_standard_collect_directory_path;
863 }
864
865 return getDefaultGSCollectDirectoryPath(true); // file separator appended
866
867 }
868
869 // if we need to know whether the local server we are running is server.exe vs apache web server
870 static public boolean isPersistentServer() {
871 return (!isGsdlRemote && LocalLibraryServer.isPersistentServer());
872 }
873
874 /** Returns the path of the Greenstone "collect" directory. */
875 static public String getDefaultGSCollectDirectoryPath(boolean appendSeparator) {
876 String colDir;
877 if (GS3) {
878 colDir = getSitesDirectoryPath() + Configuration.site_name + File.separator + "collect";
879 }
880 else {
881 colDir = Configuration.gsdl_path + "collect";
882 }
883
884 if(appendSeparator) {
885 colDir += File.separator;
886 }
887 return colDir;
888 }
889
890 /** Returns the path of the GLI directory. */
891 static public String getGLIDirectoryPath()
892 {
893 return gli_directory_path;
894 }
895
896
897 /** Returns the path of the GLI "metadata" directory. */
898 static public String getGLIMetadataDirectoryPath()
899 {
900 return getGLIDirectoryPath() + "metadata" + File.separator;
901 }
902
903
904 /** Returns the path of the GLI user directory. */
905 static public String getGLIUserDirectoryPath()
906 {
907 return gli_user_directory_path;
908 }
909
910
911 /** Returns the path of the GLI user "cache" directory. */
912 static public String getGLIUserCacheDirectoryPath()
913 {
914 return getGLIUserDirectoryPath() + "cache" + File.separator;
915 }
916
917
918 /** Returns the path of the GLI user "log" directory. */
919 static public String getGLIUserLogDirectoryPath()
920 {
921 return getGLIUserDirectoryPath() + "log" + File.separator;
922 }
923
924
925 static public String getSitesDirectoryPath()
926 {
927 return Configuration.gsdl3_path + "sites" + File.separator;
928 }
929
930
931 static public void setCollectDirectoryPath(String collect_directory_path)
932 {
933 non_standard_collect_directory_path = collect_directory_path;
934 if (!non_standard_collect_directory_path.endsWith(File.separator)) {
935 non_standard_collect_directory_path = non_standard_collect_directory_path + File.separator;
936 }
937 }
938
939
940 static public void setGLIDirectoryPath(String gli_directory_path_arg)
941 {
942 gli_directory_path = gli_directory_path_arg;
943 }
944
945
946 static public void setGLIUserDirectoryPath(String gli_user_directory_path_arg)
947 {
948 gli_user_directory_path = gli_user_directory_path_arg;
949
950 // Ensure the GLI user directory exists
951 File gli_user_directory = new File(gli_user_directory_path);
952 if (!gli_user_directory.exists() && !gli_user_directory.mkdirs()) {
953 System.err.println("Error: Unable to make directory: " + gli_user_directory);
954 }
955 }
956
957
958 public static void initCollectDirectoryPath() {
959 String defaultColdir = getDefaultGSCollectDirectoryPath(false); // no file separator at end
960 String coldir = defaultColdir;
961 // If local GS and opening a collection outside the standard GS collect folder,
962 // need to open the non-standard collect folder that the collection resides in
963 if (!isGsdlRemote
964 && !open_collection_file_path.startsWith(defaultColdir))
965 {
966 File collectFolder = null;
967
968 if(!open_collection_file_path.equals("")) {
969 if(!open_collection_file_path.endsWith("gli.col")) { // then it's a collect folder
970 collectFolder = new File(open_collection_file_path);
971 } else {
972 // the filepath is a gli.col file. To get the collect folder: the 1st level up
973 // is the collection folder, 2 two levels up is the containing collect folder
974 collectFolder = new File(open_collection_file_path).getParentFile().getParentFile();
975 }
976
977 // Need to deal with colgroups as well: while there's an etc/collect.cfg
978 // in the current collectFolder, move one level up
979 String cfg_file = (Gatherer.GS3)? Utility.CONFIG_GS3_FILE : Utility.CONFIG_FILE;
980 if(new File(collectFolder.getAbsolutePath()+File.separator+cfg_file).exists()) { // colgroup
981 collectFolder = collectFolder.getParentFile();
982 }
983
984 // Inform the user that their collecthome is non-standard (not inside GS installation)
985 nonStandardCollectHomeMessage(collectFolder.getAbsolutePath(), defaultColdir); // display message
986 }
987
988 if(collectFolder == null || !collectFolder.exists()) {
989 // if GLI config file specified no collectDir (open_collection_file_path is "")
990 // OR if dealing with a local server but the collectdir no longer exists,
991 // use the default greenstone collect directory, and write that to affected files
992
993 open_collection_file_path = defaultColdir; // default GS collect dir
994 // Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(), true, "");
995 } else { // use the coldir value specified in the flags to GLI or from the last GLI session
996 coldir = collectFolder.getAbsolutePath();
997 }
998 // set it as the current folder
999 setCollectDirectoryPath(coldir); // will ensure the required file separator at end
1000 }
1001
1002 if(!isGsdlRemote) {
1003 // LocalLibraryServer would already have set glisite.cfg to the correct collecthome for server.exe
1004 // Here we set collecthome in gsdl(3)site.cfg for the GS2 apache web server and GS3 tomcat server
1005 String gsdlsitecfg = getGsdlSiteConfigFile();
1006 // update the gsdlsite config file and store the old value for use when we exit GLI
1007 if(coldir.equals(defaultColdir)) {
1008 gsdlsite_collecthome = Utility.updatePropertyConfigFile(
1009 gsdlsitecfg, "collecthome", null);
1010 } else {
1011 gsdlsite_collecthome = Utility.updatePropertyConfigFile(
1012 gsdlsitecfg, "collecthome", "\""+coldir+"\""); // no file separator
1013 // if gsdlsite.cfg does not exist (if using server.exe for instance), the above method will just return
1014 }
1015 }
1016 }
1017
1018 /** depending on the version of GS being run, return the path to the current GS' installation's gsdl(3)site.cfg */
1019 public static String getGsdlSiteConfigFile() {
1020 if(Gatherer.GS3) { // web/WEB-INF/cgi/gsdl3site.cfg
1021 return Configuration.gsdl3_path + File.separator + "WEB-INF"
1022 + File.separator + "cgi" + File.separator + "gsdl3site.cfg";
1023 } else { // cgi-bin/gsdlsite.cfg
1024 String gsdlarch = System.getenv("GSDLARCH");
1025 if(gsdlarch == null) {
1026 gsdlarch = "";
1027 }
1028 return Configuration.gsdl_path /* + File.separator */
1029 + "cgi-bin" + File.separator + client_operating_system+gsdlarch + File.separator + "gsdlsite.cfg";
1030 }
1031 }
1032
1033 public static void collectDirectoryHasChanged(
1034 String oldCollectPath, String newCollectPath, final Component container)
1035 {
1036 if(oldCollectPath.equals(newCollectPath)) {
1037 return; // nothing to be done
1038 }
1039
1040 // Will use a busy cursor if the process of changing the collect directory takes more
1041 // than half a second/500ms. See http://www.catalysoft.com/articles/busyCursor.html
1042 Cursor originalCursor = container.getCursor();
1043 java.util.TimerTask timerTask = new java.util.TimerTask() {
1044 public void run() {
1045 // set the cursor on the container:
1046 container.setCursor(new Cursor(Cursor.WAIT_CURSOR));
1047 }
1048 };
1049 java.util.Timer timer = new java.util.Timer();
1050
1051 try {
1052 timer.schedule(timerTask, 500);
1053
1054 // first save any open collection in the old location, then close it
1055 if(Gatherer.c_man.getCollection() != null) {
1056 Gatherer.g_man.saveThenCloseCurrentCollection(); // close the current collection first
1057 }
1058
1059 // change to new collect path
1060 if(newCollectPath.equals(getDefaultGSCollectDirectoryPath(true))) {
1061 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
1062 true, "");
1063 } else {
1064 Configuration.setString("general.open_collection"+Configuration.gliPropertyNameSuffix(),
1065 true, newCollectPath);
1066 }
1067 Gatherer.setCollectDirectoryPath(newCollectPath);
1068
1069
1070 // refresh the Documents in Greenstone Collections
1071 //WorkspaceTreeModel.refreshGreenstoneCollectionsNode();
1072 Gatherer.g_man.refreshWorkspaceTreeGreenstoneCollections();
1073
1074 // The web server needs to be told where a new (non-standard) collecthome home is.
1075 // The web server reads collecthome from cgi-bin/<OS>/gsdlsite.cfg, where the property
1076 // collecthome can be specified if a non-standard collecthome is to be used. If no
1077 // such property is specified in the file, then it assumes the standard GS collecthome.
1078 // This method does nothing for a remote Greenstone.
1079 if(Gatherer.isGsdlRemote) {
1080 return;
1081 }
1082
1083 // non-destructive update of gsdl(3)site.cfg (comments preserved)
1084 String collectDir = Gatherer.getCollectDirectoryPath();
1085 //collectDir = "\"" + collectDir.substring(0, collectDir.length()-1) + "\""; // remove file separator at end
1086 collectDir = collectDir.substring(0, collectDir.length()-1); // remove file separator at end
1087 if(collectDir != null) {
1088 collectDir = "\""+collectDir+"\"";
1089 }
1090 Utility.updatePropertyConfigFile(getGsdlSiteConfigFile(), "collecthome", collectDir);
1091 // if gsdlsite.cfg does not exist (if using server.exe for instance), the above method will just return
1092
1093 if(!Gatherer.GS3 && Gatherer.isLocalLibrary) {
1094 // for Images in the collection to work, the apache web server
1095 // configuration's COLLECTHOME should be updated on collectdir change.
1096 // Does nothing for server.exe at the moment
1097
1098 LocalLibraryServer.reconfigure();
1099 }
1100 } finally { // Note try-finally section without catch:
1101 // "Java's finally clause is guaranteed to be executed even when
1102 // an exception is thrown and not caught in the current scope."
1103 // See http://www.catalysoft.com/articles/busyCursor.html
1104 // the following code fragment is guaranteed to restore the original
1105 // cursor now the custom actionPerformed() processing is complete, regardless
1106 // of whether the processing method terminates normally or throws an exception
1107 // and regardless of where in the call stack the exception is caught.
1108
1109 timer.cancel();
1110 container.setCursor(originalCursor);
1111 }
1112 }
1113
1114
1115 static public void refresh(int refresh_reason)
1116 {
1117 if (g_man != null) {
1118
1119 g_man.refresh(refresh_reason, c_man.ready());
1120 }
1121
1122 // Now is a good time to force a garbage collect
1123 System.gc();
1124 }
1125
1126
1127 // used to send reload coll messages to the tomcat server
1128 static public void configGS3Server(String site, String command) {
1129
1130 // Do not do configGS3Server for a GS3 solr collection. Not at present at least, when we're stopping
1131 // and starting the GS3 server from GLI for solr cols, since this function clears the solr.xml file.
1132 /*if(Gatherer.c_man.isSolrCollection()) {
1133 return;
1134 }*/
1135
1136 if (Configuration.library_url == null){
1137 System.out.println("Error: you have not provided the Greenstone Library address.");
1138 return;
1139
1140 }
1141
1142 try {
1143 // need to add the servlet name to the exec address
1144 String raw_url = Configuration.library_url.toString() + Configuration.getServletPath() + command;
1145 URL url = new URL(raw_url);
1146 DebugStream.println("Action: " + raw_url);
1147 HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
1148 int response_code = library_connection.getResponseCode();
1149 if(HttpURLConnection.HTTP_OK <= response_code && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
1150 DebugStream.println("200 - Complete.");
1151 }
1152 else {
1153 DebugStream.println("404 - Failed.");
1154 }
1155 url = null;
1156 }
1157 catch(java.net.ConnectException connectException) {
1158 JOptionPane.showMessageDialog(g_man, Dictionary.get("Preferences.Connection.Library_Path_Connection_Failure", Configuration.library_url.toString()), Dictionary.get("General.Warning"), JOptionPane.WARNING_MESSAGE);
1159 DebugStream.println(connectException.getMessage());
1160 }
1161 catch (Exception exception) {
1162 DebugStream.printStackTrace(exception);
1163 }
1164 }
1165
1166
1167 /** Used to 'spawn' a new child application when a file is double clicked.
1168 * @param file The file to open
1169 * @see org.greenstone.gatherer.Gatherer.ExternalApplication
1170 */
1171 static public void spawnApplication(File file) {
1172 String [] commands = assoc_man.getCommand(file);
1173 if(commands != null) {
1174 ExternalApplication app = new ExternalApplication(commands);
1175 apps.add(app);
1176 app.start();
1177 }
1178 else {
1179 ///ystem.err.println("No open command available.");
1180 }
1181 }
1182
1183
1184 static public void spawnApplication(String command)
1185 {
1186 ExternalApplication app = new ExternalApplication(command);
1187 apps.add(app);
1188 app.start();
1189 }
1190
1191 static public void spawnApplication(String command, String ID)
1192 {
1193 ExternalApplication app = new ExternalApplication(command, ID);
1194 apps.add(app);
1195 app.start();
1196 }
1197
1198 static public void spawnApplication(String[] commands, String ID)
1199 {
1200 ExternalApplication app = new ExternalApplication(commands, ID);
1201 apps.add(app);
1202 app.start();
1203 }
1204
1205 static public void terminateApplication(String ID) {
1206 for(int i = 0; i < apps.size(); i++) {
1207 ExternalApplication app = (ExternalApplication)apps.get(i);
1208 if(app.getID() != null && app.getID().equals(ID)) {
1209 app.stopExternalApplication();
1210 apps.remove(app);
1211 }
1212 }
1213 }
1214
1215
1216 /** Used to 'spawn' a new browser application or reset an existing one when the preview button is clicked
1217 * @param url The url to open the browser at
1218 * @see org.greenstone.gatherer.Gatherer.BrowserApplication
1219 */
1220 static public void spawnBrowser(String url) {
1221 String command = assoc_man.getBrowserCommand(url);
1222 if (command != null) {
1223 BrowserApplication app = new BrowserApplication(command, url);
1224 apps.add(app);
1225 app.start();
1226 }
1227 else {
1228 ///ystem.err.println("No browser command available.");
1229 }
1230 }
1231
1232
1233 /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
1234 */
1235 static public void missingEXEC() {
1236 WarningDialog dialog;
1237 String configPropertyName = "general.library_url"+Configuration.gliPropertyNameSuffix();
1238
1239 if (GS3) {
1240 // Warning dialog with no cancel button and no "turn off warning" checkbox
1241 dialog = new WarningDialog("warning.MissingEXEC", Dictionary.get("MissingEXEC_GS3.Title"), Dictionary.get("MissingEXEC_GS3.Message"), configPropertyName, false, false);
1242 } else { // local case
1243 dialog = new WarningDialog("warning.MissingEXEC", Dictionary.get("MissingEXEC.Title"), Dictionary.get("MissingEXEC.Message"), configPropertyName, false);
1244 }
1245
1246 JTextField field = new URLField.Text(Configuration.getColor("coloring.editable_foreground", false), Configuration.getColor("coloring.editable_background", false));
1247
1248 // Set the default library URL to the tomcat server and port number
1249 // specified in the build.properties located in the gsdl3_src_path
1250 if (GS3) {
1251 String host = "localhost";
1252 String port = "8383";
1253
1254 File buildPropsFile = new File(Configuration.gsdl3_src_path + File.separator + "build.properties");
1255 if(buildPropsFile.exists()) {
1256 Properties props = new Properties();
1257 try{
1258 props.load(new FileInputStream(buildPropsFile));
1259 host = props.getProperty("tomcat.server", host);
1260 port = props.getProperty("tomcat.port", port);
1261 }catch(Exception e){
1262 DebugStream.println("Could not load build.properties file");
1263 System.err.println("Could not load build.properties file");
1264 }
1265 props = null;
1266 }
1267 String defaultURL = "http://"+host+":"+port+"/"+"greenstone3";
1268 field.setText(defaultURL);
1269 field.selectAll();
1270 }
1271 dialog.setValueField(field);
1272 dialog.display();
1273 dialog.dispose();
1274 dialog = null;
1275
1276 String library_url_string = Configuration.getString(configPropertyName, true);
1277 if (!library_url_string.equals("")) {
1278 try {
1279 // WarningDialog does not allow invalid URLs, so the following is ignored:
1280 // make sure the URL the user provided contains the http:// prefix
1281 // and then save the corrected URL
1282 if(!library_url_string.startsWith("http://")
1283 && !library_url_string.startsWith("https://")) {
1284 library_url_string = "http://"+library_url_string;
1285 Configuration.setString(configPropertyName, true, configPropertyName);
1286 }
1287 Configuration.library_url = new URL(library_url_string);
1288 }
1289 catch (MalformedURLException exception) {
1290 DebugStream.printStackTrace(exception);
1291 }
1292 }
1293 }
1294
1295
1296
1297 /** Prints a warning message about a missing library path, which means the final collection cannot be previewed in the Gatherer.
1298 */
1299 static private void popupFedoraInfo() {
1300
1301 FedoraLogin dialog = new FedoraLogin("Fedora Login", false);
1302
1303 if (Configuration.library_url == null) {
1304
1305 String library_url_string = dialog.getLibraryURL();
1306 if (!library_url_string.equals("")) {
1307 try {
1308 Configuration.library_url = new URL(library_url_string);
1309 }
1310 catch (MalformedURLException exception) {
1311 DebugStream.printStackTrace(exception);
1312 }
1313 }
1314 }
1315
1316 boolean showLogin = true;
1317 do {
1318 if(!dialog.loginRequested()) { // user pressed cancel to exit the FedoraLogin dialog
1319 System.exit(0);
1320 } else {
1321 showLogin = dialog.loginRequested();
1322 String hostname = dialog.getHostname();
1323 String port = dialog.getPort();
1324 String username = dialog.getUsername();
1325 String password = dialog.getPassword();
1326 String protocol = dialog.getProtocol();
1327
1328 Configuration.fedora_info.setHostname(hostname);
1329 Configuration.fedora_info.setPort(port);
1330 Configuration.fedora_info.setUsername(username);
1331 Configuration.fedora_info.setPassword(password);
1332 Configuration.fedora_info.setProtocol(protocol);
1333
1334 String ping_url_str = protocol + "://" + hostname + ":" + port + "/fedora";
1335 String login_str = username + ":" + password;
1336
1337 String login_encoding = Base64.encodeBytes(login_str.getBytes());
1338
1339 try {
1340 URL ping_url = new URL(ping_url_str);
1341 URLConnection uc = ping_url.openConnection();
1342 uc.setRequestProperty ("Authorization", "Basic " + login_encoding);
1343 // Attempt to access some content ...
1344 InputStream content = (InputStream)uc.getInputStream();
1345
1346 // if no exception occurred in the above, we would have come here:
1347 showLogin = false;
1348 dialog.dispose();
1349 }
1350 catch (Exception exception) {
1351 // TODO: move into dictionary
1352 String[] errorMessage = {"Failed to connect to the Fedora server.", "It might not be running, or",
1353 "incorrect username and/or password."};
1354 dialog.setErrorMessage(errorMessage);
1355 //DebugStream.printStackTrace(exception);
1356 // exception occurred, show the dialog again (do this after printing to
1357 // debugStream, else the above does not get done for some reason).
1358 dialog.setVisible(true);
1359 }
1360 }
1361 } while(showLogin);
1362
1363 dialog = null; // no more need of the dialog
1364
1365 // Now we are connected.
1366 }
1367
1368
1369
1370 static private void requestGLIServerURL()
1371 {
1372 WarningDialog dialog;
1373 String[] defaultURLs = {
1374 "http://localhost:8080/greenstone3/cgi-bin/gliserver.pl",
1375 "http://localhost:8080/gsdl/cgi-bin/gliserver.pl"
1376 };
1377
1378 // Warning dialog with no cancel button and no "turn off warning" checkbox
1379 // (since user-input of the gliserver script is mandatory)
1380 dialog = new WarningDialog("warning.MissingGLIServer", Dictionary.get("MissingGLIServer.Title"), Dictionary.get("MissingGLIServer.Message"), "general.gliserver_url", false, false);
1381
1382 dialog.setValueField(new URLField.DropDown(Configuration.getColor("coloring.editable_foreground", false),
1383 Configuration.getColor("coloring.editable_background", false),
1384 defaultURLs, "general.gliserver_url",
1385 "general.open_collection"+Configuration.gliPropertyNameSuffix(),
1386 "gliserver.pl"));
1387
1388 if (Gatherer.default_gliserver_url!=null){
1389 dialog.setValueField(Gatherer.default_gliserver_url.toString());
1390 }
1391
1392 // A WarningDialog cannot always be made to respond (let alone to exit the program) on close. We
1393 // handle the response of this particular WarningDialog here: a URL for gliserver.pl is a crucial
1394 // piece of user-provided data. Therefore, if no URL was entered for gliserver.pl, it'll exit safely.
1395 dialog.addWindowListener(new WindowAdapter() {
1396 public void windowClosing(WindowEvent e) {
1397 Gatherer.exit();
1398 }
1399 });
1400
1401 dialog.display();
1402 dialog.dispose();
1403 dialog = null;
1404
1405
1406 String gliserver_url_string = Configuration.getString("general.gliserver_url", true);
1407 if (!gliserver_url_string.equals("")) {
1408 try {
1409 Configuration.gliserver_url = new URL(gliserver_url_string);
1410 Configuration.setString("general.gliserver_url", true, gliserver_url_string);
1411 }
1412 catch (MalformedURLException exception) {
1413 DebugStream.printStackTrace(exception);
1414 }
1415 }
1416 }
1417
1418
1419 /** Prints a warning message about a missing GSDL path, which although not fatal pretty much ensures nothing will work properly in the GLI.
1420 */
1421 static private void missingGSDL() {
1422 WarningDialog dialog = new WarningDialog("warning.MissingGSDL", Dictionary.get("MissingGSDL.Title"), Dictionary.get("MissingGSDL.Message"), null, false);
1423 dialog.display();
1424 dialog.dispose();
1425 dialog = null;
1426 }
1427
1428 /** Prints a warning message about missing a valid ImageMagick path, which although not fatal means building image collections won't work */
1429 static private void missingImageMagick() {
1430 WarningDialog dialog = new WarningDialog("warning.MissingImageMagick", Dictionary.get("MissingImageMagick.Title"), Dictionary.get("MissingImageMagick.Message"), null, false);
1431 dialog.display();
1432 dialog.dispose();
1433 dialog = null;
1434 }
1435
1436 /** Prints a message informing the user where they can get PDFBox from to process PDF files of v1.5 and greater */
1437 static private void missingPDFBox(String zipExtension, String extFolder) {
1438 // point to the correct version of the PDFBox extension for this Greenstone release
1439 String releaseTag = "";
1440 if(!PROGRAM_VERSION.equals("trunk")) { // assume it's a release version
1441 releaseTag = "main/tags/"+PROGRAM_VERSION+"/";
1442 }
1443
1444 WarningDialog dialog = new WarningDialog("warning.MissingPDFBox", Dictionary.get("MissingPDFBox.Title"), Dictionary.get("MissingPDFBox.Message", new String[]{releaseTag, zipExtension, extFolder}), null, false);
1445 dialog.display();
1446 dialog.dispose();
1447 dialog = null;
1448 }
1449
1450 /** 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. */
1451 static private void missingPERL() {
1452 WarningDialog dialog = new WarningDialog("warning.MissingPERL", Dictionary.get("MissingPERL.Title"), Dictionary.get("MissingPERL.Message"), null, false);
1453 dialog.display();
1454 dialog.dispose();
1455 dialog = null;
1456 }
1457
1458 /** Prints a message informing the user that their collecthome is non-standard (not inside GS installation) */
1459 static private void nonStandardCollectHomeMessage(String open_collection_file_path, String defaultColDir) {
1460 WarningDialog dialog = new WarningDialog("warning.NonStandardCollectHome", Dictionary.get("NonStandardCollectHome.Title"), Dictionary.get("NonStandardCollectHome.Message", new String[]{open_collection_file_path, defaultColDir}), null, false);
1461 dialog.display();
1462 dialog.dispose();
1463 dialog = null;
1464 }
1465
1466 /** Prints a warning message about the OS not supporting multiple filename encodings. */
1467 static private void multipleFilenameEncodingsNotSupported() {
1468 WarningDialog dialog = new WarningDialog("warning.NoEncodingSupport",
1469 Dictionary.get("NoEncodingSupport.Title"),
1470 Dictionary.get("NoEncodingSupport.Message"), null, false);
1471 dialog.display();
1472 dialog.dispose();
1473 dialog = null;
1474 }
1475
1476 /** Sets up the proxy connection by setting JVM Environment flags and creating a new Authenticator.
1477 * @see java.lang.Exception
1478 * @see java.lang.System
1479 * @see java.net.Authenticator
1480 * @see org.greenstone.gatherer.Configuration
1481 * @see org.greenstone.gatherer.GAuthenticator
1482 */
1483 static public void setProxy() {
1484 try {// Can throw several exceptions
1485 boolean use_proxy = Configuration.get("general.use_proxy", true);
1486
1487 setProxyForProtocol("http", use_proxy);
1488 setProxyForProtocol("https", use_proxy);
1489 setProxyForProtocol("ftp", use_proxy);
1490
1491 } catch (Exception error) {
1492 DebugStream.println("Error in Gatherer.initProxy(): " + error);
1493 DebugStream.printStackTrace(error);
1494 }
1495 }
1496
1497 private static void setProxyForProtocol(String protocol, boolean use_proxy) throws Exception {
1498 // These are Java properties, therefore see
1499 // https://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html
1500 // https://docs.oracle.com/javase/8/docs/technotes/guides/net/proxies.html
1501 // https://stackoverflow.com/questions/14243590/proxy-settings-in-java
1502
1503 // Just need to warn the user that we're overriding proxy settings using custom defined proxy settings
1504 // and returning to using the original proxy settings when custom defined proxy settings are turned off
1505 // We don't actually need to store/restore the original settings, as Java system vars like http.proxyHost
1506 // http.proxyPort don't seem to be set even if on GLI startup the env vars like http(s)_proxy were already set.
1507
1508
1509 if(use_proxy) {
1510 if(System.getenv(protocol+"_proxy") != null) {
1511 System.err.println("Overriding original "+protocol+" proxy settings");
1512 }
1513
1514 // set the custom proxy defined through GLI for this protocol
1515 System.setProperty(protocol+".proxyHost", Configuration.getString("general."+protocol.toUpperCase()+"_proxy_host", true));
1516 System.setProperty(protocol+".proxyPort", Configuration.getString("general."+protocol.toUpperCase()+"_proxy_port", true));
1517
1518 // Not sure what proxyType is. And proxySet ceased to exist since JDK 6 or before. See links above.
1519 // But we used to set them both for HTTP before, so still doing so for proxyType, since it may or may not exist
1520 // But proxySet doesn't exist anymore, so not continuing with that.
1521 if(protocol.equals("http")) {
1522 System.setProperty(protocol+".proxyType", "4");
1523 //System.setProperty(protocol+".proxySet", "true");
1524 }
1525
1526 }
1527
1528 else { // use_proxy=false, not using proxy defined through GLI, so
1529 // either unset proxy vars for this protocol, or restore any original settings for them
1530
1531 if(System.getenv(protocol+"_proxy") != null) {
1532 System.err.println("Restoring original "+protocol+" proxy settings");
1533 }
1534
1535 System.setProperty(protocol+".proxyHost", "");
1536 System.setProperty(protocol+".proxyPort", "");
1537 //if(protocol.equals("http")) {
1538 //System.setProperty(protocol+".proxySet", "false");
1539 //}
1540 }
1541 }
1542
1543
1544 /** 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 voluntarily 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. */
1545 static private class ExternalApplication
1546 extends Thread {
1547 private SafeProcess process = null;
1548 /** The initial command string given to this sub-process. */
1549 private String command = null;
1550 private String[] commands = null;
1551
1552 private String ID = null;
1553
1554 /** Constructor.
1555 * @param command The initial command <strong>String</strong>.
1556 */
1557 public ExternalApplication(String command) {
1558 this.command = command;
1559 }
1560
1561 public ExternalApplication(String[] commands) {
1562 this.commands = commands;
1563 }
1564
1565 public ExternalApplication(String command, String ID) {
1566 this.command = command;
1567 this.ID = ID;
1568 }
1569
1570 public ExternalApplication(String[] commands, String ID) {
1571 this.commands = commands;
1572 this.ID = ID;
1573 }
1574
1575 public String getID() {
1576 return ID;
1577 }
1578
1579 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
1580 * @see java.lang.Exception
1581 * @see java.lang.Process
1582 * @see java.lang.Runtime
1583 * @see java.lang.System
1584 * @see java.util.Vector
1585 */
1586 public void run() {
1587 // Call an external process using the args.
1588 try {
1589 if(commands != null) {
1590 StringBuffer whole_command = new StringBuffer();
1591 for(int i = 0; i < commands.length; i++) {
1592 // get rid of any quotes around parameters in file associations
1593 if(commands[i].startsWith("\"") || commands[i].startsWith("\'")) {
1594 commands[i] = commands[i].substring(1);
1595 }
1596 if(commands[i].endsWith("\"") || commands[i].endsWith("\'")) {
1597 commands[i] = commands[i].substring(0, commands[i].length()-1);
1598 }
1599
1600 if (i>0) {
1601 whole_command.append(" ");
1602 }
1603 whole_command.append(commands[i]);
1604 }
1605 DebugStream.println("Running " + whole_command.toString());
1606 process = new SafeProcess(commands);
1607 }
1608 else {
1609 DebugStream.println("Running " + command);
1610 process = new SafeProcess(command);
1611 }
1612 process.runProcess();
1613 }
1614 catch (Exception exception) {
1615 DebugStream.printStackTrace(exception);
1616 }
1617 // Remove ourself from Gatherer list of threads.
1618 apps.remove(this);
1619 // Call exit if we were the last outstanding child process thread.
1620 if (apps.size() == 0 && exit == true) {
1621 // In my opinion (DB) there is no need to exit here,
1622 // the 'run' method ending naturally brings this
1623 // thread to an end. In fact it is potentially
1624 // dangerous to exit here, as the main thread in the
1625 // Gatherer class may be stopped prematurely. As it so
1626 // happens the point at which the ExternalApplication thread
1627 // is asked to stop (Back in the main Gatherer thread) is after
1628 // various configuration files have been saved.
1629 //
1630 // A similar argument holds for BrowserApplication thread below.
1631 System.exit(exit_status);
1632 }
1633 }
1634 public void stopExternalApplication() {
1635 if(process != null) {
1636 SafeProcess.log("*** stopExternalApplication called.");
1637 process.cancelRunningProcess();
1638 }
1639 }
1640 }
1641 /** 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. */
1642 static private class BrowserApplication
1643 extends Thread {
1644 private SafeProcess process = null;
1645 /** The initial command string given to this sub-process. */
1646 private String command = null;
1647 private String url = null;
1648 private String[] commands = null;
1649
1650 public BrowserApplication(String command, String url) {
1651 StringTokenizer st = new StringTokenizer(command);
1652 int num_tokens = st.countTokens();
1653 this.commands = new String [num_tokens];
1654 int i=0;
1655 while (st.hasMoreTokens()) {
1656 commands[i] = st.nextToken();
1657 i++;
1658 }
1659 //this.commands = commands;
1660 this.url = url;
1661 }
1662 /** We start the child process inside a new thread so it doesn't block the rest of Gatherer.
1663 * @see java.lang.Exception
1664 * @see java.lang.Process
1665 * @see java.lang.Runtime
1666 * @see java.lang.System
1667 * @see java.util.Vector
1668 */
1669 public void run() {
1670 // Call an external process using the args.
1671 if(commands == null) {
1672 apps.remove(this);
1673 return;
1674 }
1675 try {
1676 String prog_name = commands[0];
1677 String lower_name = prog_name.toLowerCase();
1678 if (lower_name.indexOf("mozilla") != -1 || lower_name.indexOf("netscape") != -1) {
1679 DebugStream.println("found mozilla or netscape, trying remote it");
1680 // mozilla and netscape, try using a remote command to get things in the same window
1681 String [] new_commands = new String[] {prog_name, "-raise", "-remote", "openURL("+url+",new-tab)"};
1682 printArray(new_commands);
1683
1684 process = new SafeProcess(new_commands);
1685 int exitCode = process.runProcess();
1686 if (exitCode != 0) { // if Netscape or mozilla was not open
1687 DebugStream.println("couldn't do remote, trying original command");
1688 printArray(commands);
1689 process = null;
1690 process = new SafeProcess(commands); // try the original command
1691 process.runProcess();
1692 }
1693 } else {
1694 // just run what we have been given
1695 StringBuffer whole_command = new StringBuffer();
1696 for(int i = 0; i < commands.length; i++) {
1697 whole_command.append(commands[i]);
1698 whole_command.append(" ");
1699 }
1700 DebugStream.println("Running " + whole_command.toString());
1701 process = new SafeProcess(commands);
1702 process.runProcess();
1703 }
1704 }
1705
1706 catch (Exception exception) {
1707 DebugStream.printStackTrace(exception);
1708 }
1709 // Remove ourself from Gatherer list of threads.
1710 apps.remove(this);
1711 // Call exit if we were the last outstanding child process thread.
1712 if (apps.size() == 0 && exit == true) {
1713 System.exit(exit_status);
1714 }
1715 }
1716 public void printArray(String [] array) {
1717 for(int i = 0; i < array.length; i++) {
1718 DebugStream.print(array[i]+" ");
1719 System.err.println(array[i]+" ");
1720 }
1721 }
1722 public void stopBrowserApplication() {
1723 if(process != null) {
1724 SafeProcess.log("*** stopBrowserApplication called.");
1725 process.cancelRunningProcess();
1726 }
1727 }
1728 }
1729
1730
1731 private class ImageMagickTest
1732 {
1733 public boolean found()
1734 {
1735 // at this stage, GLI has already sourced setup.bash, and the necessary
1736 // env variables will be available to the perl process we're about to launch
1737 boolean found = false;
1738
1739
1740 // run the command `/path/to/perl -S gs-magick.pl identify -version`
1741 ArrayList cmd_list = new ArrayList();
1742 if (!Gatherer.isGsdlRemote) {
1743 if(Configuration.perl_path != null) {
1744 cmd_list.add(Configuration.perl_path);
1745 } else {
1746 System.err.println("***** ImageMagickTest Warning: Perl_path not set, calling 'perl' instead.");
1747 cmd_list.add("perl");
1748 }
1749 cmd_list.add("-S");
1750 }
1751 cmd_list.add("gs-magick.pl");
1752 if(Utility.isWindows()) {
1753 cmd_list.add("identify.exe");
1754 } else {
1755 cmd_list.add("identify");
1756 }
1757 cmd_list.add("-version");
1758
1759 String[] command_parts = (String[]) cmd_list.toArray(new String[0]);
1760
1761 String cmd_str = "";
1762 for(int i = 0; i < command_parts.length; i++) {
1763 cmd_str += command_parts[i] + " ";
1764 }
1765 DebugStream.println("***** Running ImageMagickTest command: " + cmd_str);
1766
1767 SafeProcess image_magick_process = new SafeProcess(command_parts);
1768 int exitValue = image_magick_process.runProcess(); // default process iostream handling
1769 //new way of detection of ImageMagick
1770 // Inspect the standard output of the process and seach for two particular occurrences: Version and ImageMagick.
1771 String output = image_magick_process.getStdOutput().toLowerCase();
1772 if (output.indexOf("version") != -1 || output.indexOf("imagemagick") != -1) {
1773 found = true;
1774 } // else found var remains false
1775
1776 return found;
1777 //return (image_magick_process.exitValue() == 0);
1778
1779 }
1780 }
1781
1782
1783 private class PerlTest
1784 {
1785 private String[] command = new String[2];
1786
1787 public PerlTest()
1788 {
1789 command[0] = (Utility.isWindows() ? Utility.PERL_EXECUTABLE_WINDOWS : Utility.PERL_EXECUTABLE_UNIX);
1790 command[1] = "-version";
1791 }
1792
1793 public boolean found()
1794 {
1795 try {
1796 SafeProcess perl_process = new SafeProcess(command);
1797 int exitValue = perl_process.runBasicProcess();
1798 return (exitValue == 0);
1799 }
1800 catch (Exception exception) {
1801 return false;
1802 }
1803 }
1804
1805 public String toString() {
1806 return command[0];
1807 }
1808 }
1809
1810}
Note: See TracBrowser for help on using the repository browser.