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

Last change on this file since 32050 was 32050, checked in by ak19, 6 years ago

Related to previous commit, revision 32049. Now tested successfully on Windows. Suppressing some debug statements.

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