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

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

If not testing, don't need GLI's GUI components to be assigned names. Leaves GLI more efficient when run as GLI proper, while GLI will do a bit more work when running GLI for testing.

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