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

Last change on this file since 38258 was 38258, checked in by anupama, 9 months ago

I think I have webswing gli authentication working out without an authentication popup when the user is also logged in through greenstone, without breaking existing functionality. I still can't work out why the WebswingAuthenticator has static members and yet a proper constructor is called. This commit contains debug statements. Added a webswing javascript function that Java can call for debugging statements going into the browser's console using console.log, called jsConsoleLog.

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