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

Last change on this file since 37355 was 37355, checked in by davidb, 14 months ago

Addition to code: if the '-load' file specified is relative, then it prepends the collect_dir. A complication here is that collect_dir as a member field isn't set yet, and so we have to check ourselves if we are in the situation of a custom collect dir provided on the command-line, or else going to be usesing the default one

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