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

Last change on this file since 31882 was 31882, checked in by ak19, 7 years ago

GLI now does storing, overriding and restoring of original proxy settings (w.r.t custom proxy settings defined through GLI Preferences' Connection tab)

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