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

Last change on this file was 38302, checked in by anupama, 7 months ago

Webswing authentication bypass when logged in, using JSessionID this time. But what should be in FROM attribute of response message from SystemAction? No response is coming from a service.

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