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

Last change on this file since 37420 was 37420, checked in by kjdon, 14 months ago

have moved this block of code to after the bit where we work out site and servlet for gs3. otherwise, when we do specify a collection (eg in webswing gli), we try to make the collection path without knowing the site_name, which doesn't work properly

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