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

Last change on this file since 30765 was 30765, checked in by davidb, 8 years ago

More forgiving test for java vendor

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