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

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

Newer version of setSize() introduced to support the new init sequence for webSwing GLI that requires login first before GLI window displayed; Fine-tuning of colours used.

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