source: gli/trunk/src/org/greenstone/gatherer/greenstone/LocalLibraryServer.java@ 19194

Last change on this file since 19194 was 19194, checked in by ak19, 15 years ago

Deals with the Linux case where the GS2 was not configured with apache-httpd (hence no physical local webserver) but where the gs2-server.sh file exists. In this case, the LocalLibraryServer.start() method first tests whether the apache-httpd directory exists before assuming the local lib server context. This minor change fixes a silent wait error on launching a local gli when the gs2-server.sh file has NOT been renamed and yet the GS2 install was not configured on install with enable-apache-httpd.

  • Property svn:keywords set to Author Date Id Revision
File size: 21.2 KB
Line 
1/**
2 *############################################################################
3 * A component of the Greenstone Librarian Interface, part of the Greenstone
4 * digital library suite from the New Zealand Digital Library Project at the
5 * University of Waikato, New Zealand.
6 *
7 * Author: Michael Dewsnip, NZDL Project, University of Waikato, NZ
8 *
9 * Copyright (C) 2004 New Zealand Digital Library Project
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *############################################################################
25 */
26
27package org.greenstone.gatherer.greenstone;
28
29
30import java.io.*;
31import java.lang.*;
32import java.net.*;
33import java.util.*;
34import javax.swing.*;
35import org.greenstone.gatherer.Configuration;
36import org.greenstone.gatherer.DebugStream;
37import org.greenstone.gatherer.Dictionary;
38import org.greenstone.gatherer.Gatherer;
39import org.greenstone.gatherer.util.PortFinder;
40import org.greenstone.gatherer.util.Utility;
41
42
43public class LocalLibraryServer
44{
45 static final private String ADD_COMMAND = "?a=config&cmd=add-collection&c=";
46 static final private String RELEASE_COMMAND = "?a=config&cmd=release-collection&c=";
47 static final private String QUIT_COMMAND = "?a=config&cmd=kill";
48
49 static private LLSSiteConfig llssite_cfg_file = null;
50 static private File local_library_server_file = null;
51
52 static private boolean running = false;
53 static private String ID = "greenstone-server"; // a sort of process ID
54
55 // Need to use sockets to tell the server program to terminate when on Linux
56 // The socket port number that we will use to communicate the termination
57 static private int port;
58
59 // The server is persistent if it does not have to reload all the values
60 // over and over again each time. Tomcat is persistent and fastcgi is too,
61 // but the Apache webserver is not persistent by default.
62 // Change the initialisation of this value depending on whether fastcgi is
63 // on. At the moment, this does not apply to the Linux' local library server.
64 static private boolean isPersistentServer = Utility.isWindows();
65
66 static public void addCollection(String collection_name)
67 {
68 if (isPersistentServer) {
69 config(ADD_COMMAND + collection_name);
70 }
71 }
72
73
74 // Used to send messages to the local library
75 static private void config(String command)
76 {
77 if (!isPersistentServer) {
78 return;
79 }
80 if (Configuration.library_url == null) {
81 System.err.println("Error: Trying to configure local library with null Configuration.library_url!");
82 return;
83 }
84
85 try {
86 URL url = new URL(Configuration.library_url.toString() + command);
87 HttpURLConnection library_connection = (HttpURLConnection) url.openConnection();
88
89 // It's very important that we read the output of the command
90 // This ensures that the command has actually finished
91 // (The response code is returned immediately)
92 InputStream library_is = library_connection.getInputStream();
93 BufferedReader library_in = new BufferedReader(new InputStreamReader(library_is, "UTF-8"));
94 String library_output_line = library_in.readLine();
95 while (library_output_line != null) {
96 DebugStream.println("Local library server output: " + library_output_line);
97 library_output_line = library_in.readLine();
98 }
99 library_in.close();
100
101 int response_code = library_connection.getResponseCode();
102 if (response_code >= HttpURLConnection.HTTP_OK && response_code < HttpURLConnection.HTTP_MULT_CHOICE) {
103 DebugStream.println("200 - Complete.");
104 }
105 else {
106 DebugStream.println("404 - Failed.");
107 }
108 }
109 catch (Exception exception) {
110 DebugStream.printStackTrace(exception);
111 }
112 }
113
114 // Used to send messages to the local server on Linux
115 static private boolean sendMessageToServer(String message) {
116 if(Utility.isWindows()) {
117 return false;
118 }
119
120 if(port == -1) {
121 return false;
122 }
123
124 try {
125 Socket clientSocket = new Socket("localhost", port);
126 Writer writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
127 writer.write(message);
128 writer.close();
129 writer = null;
130 } catch (Exception e) {
131 System.err.println("An exception occurred when trying to send the message: " + message
132 + "\nto the LocalLibraryServer.\n" + e);
133 return false;
134 }
135 return true;
136 }
137
138 static public boolean isRunning()
139 {
140 if (!running) return false;
141 llssite_cfg_file.load(true);
142 if (llssite_cfg_file.getURL() == null) return false;
143 return true;
144 }
145
146
147 static public void releaseCollection(String collection_name)
148 {
149 if (isPersistentServer) {
150 config(RELEASE_COMMAND + collection_name);
151 }
152 }
153
154 static public void start(String gsdl_path, String local_library_server_file_path)
155 {
156 // Check the local library server file (server.exe or gs2-server.sh) exists
157 local_library_server_file = new File(local_library_server_file_path);
158
159 if (!local_library_server_file.exists()) {
160 DebugStream.println("No local library at given file path.");
161
162 String defaultServerFilename = Utility.isWindows() ? "server.exe" : "gs2-server.sh";
163 local_library_server_file = new File(gsdl_path + defaultServerFilename);
164 if (!local_library_server_file.exists()) {
165 DebugStream.println("No local library at all.");
166 return;
167 }
168 }
169
170 // In the case of the Local Library Server on Linux, we need to do an extra test:
171 // If GS2 was not configured with --enable-apache-httpd, then there is no apache webserver folder,
172 // even though the gs2-server.sh file would still be there. That means if the folder is absent
173 // we still have no local library server.
174 if(!Utility.isWindows()) {
175 File localLinuxServerFolder = new File(gsdl_path, "apache-httpd");
176 if (!localLinuxServerFolder.exists() && !localLinuxServerFolder.isDirectory()) {
177 System.err.println("The web server does not exist at "
178 + localLinuxServerFolder.getAbsolutePath() + "\nNo local library at all. Trying web library");
179 DebugStream.println("The web server does not exist at "
180 + localLinuxServerFolder.getAbsolutePath() + "\nNo local library at all. Trying web library");
181 return;
182 }
183 }
184
185 llssite_cfg_file = new LLSSiteConfig(local_library_server_file);
186
187 // Spawn local library server process
188 String local_library_server_command = local_library_server_file.getAbsolutePath() + getExtraLaunchArguments(llssite_cfg_file);
189
190 // Check if the server is already running
191 String url = llssite_cfg_file.getURL();
192 if (url != null) {
193 // If it is already running then set the Greenstone web server address and we're done
194 // E.g. if previously GLI was not properly shut down, the URL property (signifying
195 // the server is still running) would still be in the glisite_cfg file.
196 try {
197 Configuration.library_url = new URL(url);
198 running = true;
199
200 // Run the server interface
201 Gatherer.spawnApplication(local_library_server_command, ID);
202 return;
203 }
204 catch (MalformedURLException exception) {
205 DebugStream.printStackTrace(exception);
206 }
207 }
208
209 // Configure the server for immediate entry
210 //llssite_cfg_file.set();
211
212 // Spawn local library server process
213 Gatherer.spawnApplication(local_library_server_command, ID);
214
215 // Wait until program has started
216 try {
217 testServerRunning(); // will set running = true when the server is up and running successfully
218 } catch (IOException bad_url_connection) {
219 try {
220 // If this fails then we try changing the url to be localhost
221 Configuration.library_url = new URL(llssite_cfg_file.getLocalHostURL());
222 DebugStream.println("Try connecting to server on local host: '" + Configuration.library_url + "'");
223 URLConnection connection = Configuration.library_url.openConnection();
224 connection.getContent();
225 running = true;
226
227 } catch (IOException worse_url_connection) {
228 DebugStream.println("Can't connect to server on either address.");
229 Configuration.library_url = null;
230 running = false;
231 }
232 }
233 }
234
235
236 static public void stop()
237 {
238 if (running == false) {
239 return;
240 }
241
242 // Send the command for it to exit.
243 if (isPersistentServer) {
244 config(QUIT_COMMAND);
245 } else {
246 if(sendMessageToServer("QUIT")) {
247 Gatherer.terminateApplication(ID);
248 } else {
249 System.err.println("Unable to stop the server, since there's no communication port to send the quit msg over."
250 + "\nPlease stop the local Greenstone server manually.");
251 }
252 }
253
254 // Wait until program has stopped, by reloading and checking the URL field
255 llssite_cfg_file.load(false);
256 int attempt_count = 0;
257 while (llssite_cfg_file.getURL() != null) {
258 new OneSecondWait(); // Wait one second (give or take)
259 llssite_cfg_file.load(false);
260 attempt_count++;
261
262 // After waiting a minute ask the user whether they want to wait another minute
263 if (attempt_count == 60) {
264 int try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
265 if (try_again == JOptionPane.NO_OPTION) {
266 return;
267 }
268 attempt_count = 0;
269 }
270 }
271
272 // Restore the llssite_cfg.
273 llssite_cfg_file.restore();
274
275 // If the local server is still running then our changed values will get overwritten.
276 if (llssite_cfg_file.getURL() != null) {
277 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Server.QuitManual"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
278 }
279
280 running = false;
281 }
282
283 static private String getExtraLaunchArguments(LLSSiteConfig site_cfg_file) {
284 String args = " " + site_cfg_file.getSiteConfigFilename();
285
286 if(Utility.isWindows()) {
287 return args;
288 }
289
290 // Else, when running the Local Library Server on Linux, need to provide a port argument
291 try {
292 PortFinder portFinder = new PortFinder(50100, 100);
293 port = portFinder.findPortInRange();
294 } catch(Exception e) {
295 System.err.println("Exception when trying to find an available port: " + e);
296 port = -1;
297 }
298
299 return args + " --quitport=" + port;
300 }
301
302
303 // This method first tests whether there is a URL in the llssite_cfg_file
304 // and after that appears, it tests whether the URL is functional.
305 static private void testServerRunning() throws IOException {
306 // Wait until program has started, by reloading and checking the URL field
307 llssite_cfg_file.load(false);
308 int attempt_count = 0;
309 while (llssite_cfg_file.getURL() == null) {
310 new OneSecondWait(); // Wait one second (give or take)
311 llssite_cfg_file.load(false);
312 attempt_count++;
313
314 // After waiting a minute ask the user whether they want to wait another minute
315 if (attempt_count == 60) {
316 int try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
317 if (try_again == JOptionPane.NO_OPTION) {
318 return;
319 }
320 attempt_count = 0;
321 }
322 }
323
324 // Ta-da. Now the url should be available
325 try {
326 Configuration.library_url = new URL(llssite_cfg_file.getURL());
327 }
328 catch (MalformedURLException exception) {
329 DebugStream.printStackTrace(exception);
330 }
331
332 // A quick test involves opening a connection to get the home page for this collection
333 try {
334 DebugStream.println("Try connecting to server on config url: '" + Configuration.library_url + "'");
335 URLConnection connection = Configuration.library_url.openConnection();
336 connection.getContent();
337 running = true;
338 }
339 catch (IOException bad_url_connection) {
340 throw bad_url_connection;
341 }
342
343
344 }
345
346 static public void checkServerRunning() {
347 if (!running) return; // don't worry about it if its not supposed to be running
348 llssite_cfg_file.load(true); // don't force reload, load only if modified
349
350 String url = llssite_cfg_file.getURL();
351 if(url != null) {
352 try {
353 Configuration.library_url = new URL(url);
354 }
355 catch (MalformedURLException exception) {
356 DebugStream.printStackTrace(exception);
357 }
358 } else {
359 // need to restart the server again
360 llssite_cfg_file.set();
361
362 // Spawn local library server process
363 String local_library_server_command = local_library_server_file.getAbsolutePath() + getExtraLaunchArguments(llssite_cfg_file);
364 running = false;
365 Gatherer.spawnApplication(local_library_server_command, ID);
366 try {
367 testServerRunning(); // don't return until the webserver is up and running
368 } catch (IOException bad_url_connection) {
369 DebugStream.println("Can't connect to server on address " + Configuration.library_url);
370 running = false;
371 }
372 }
373 }
374
375 static private class OneSecondWait
376 {
377 public OneSecondWait()
378 {
379 synchronized(this) {
380 try {
381 wait(1000);
382 }
383 catch (InterruptedException exception) {
384 }
385 }
386 }
387 }
388
389
390 static public class LLSSiteConfig
391 extends LinkedHashMap {
392 private File llssite_cfg;
393 private File glisite_cfg;
394 private String autoenter_initial;
395 private String start_browser_initial;
396
397 private long lastModified = 0;
398
399 static final private String AUTOENTER = "autoenter";
400 static final private String COLON = ":";
401 static final private String ENTERLIB = "enterlib";
402 static final private String FALSE = "0";
403 static final private String GLISITE_CFG = "glisite.cfg";
404 static final private String GSDL = "greenstone"; // httpprefix is no longer /gsdl but /greenstone
405 static final private String LLSSITE_CFG = "llssite.cfg";
406 static final private String LOCAL_HOST = "http://localhost";
407 static final private String PORTNUMBER = "portnumber";
408 static final private String SEPARATOR = "/";
409 static final private String SPECIFIC_CONFIG = "--config=";
410 static final private String STARTBROWSER = "start_browser";
411 static final private String TRUE = "1";
412 static final private String URL = "url";
413
414 public LLSSiteConfig(File server_exe) {
415 debug("New LLSSiteConfig for: " + server_exe.getAbsolutePath());
416
417 llssite_cfg = new File(server_exe.getParentFile(), LLSSITE_CFG);
418 glisite_cfg = new File(server_exe.getParentFile(), GLISITE_CFG);
419
420 File configFile = null;
421 if(!glisite_cfg.exists()) { // create it from the templates or the llssite.cfg file
422
423 File llssite_cfg_in = new File(server_exe.getParentFile(), LLSSITE_CFG+".in");
424 File glisite_cfg_in = new File(server_exe.getParentFile(), GLISITE_CFG+".in");
425
426 // need to generate glisite_cfg from glisite_cfg_in, llssite_cfg or llssite.cfg.in
427 if(glisite_cfg_in.exists()) {
428 copyConfigFile(glisite_cfg_in, glisite_cfg, false);
429 }
430 else if(llssite_cfg_in.exists()) {
431 copyConfigFile(llssite_cfg_in, glisite_cfg_in, true); // adjust for glisite.cfg
432 copyConfigFile(glisite_cfg_in, glisite_cfg, false);
433 }
434 else if(llssite_cfg.exists()) {
435 copyConfigFile(llssite_cfg, glisite_cfg, true); // adjust for glisite.cfg
436 }
437 else {
438 debug("Neither the file glisite.cfg nor llssite.cfg can be found!");
439 }
440 }
441
442 if(glisite_cfg.exists()) {
443 configFile = glisite_cfg;
444 }
445
446 autoenter_initial = null;
447 start_browser_initial = null;
448 if(configFile != null) {
449 debug("Load: " + configFile.getAbsolutePath());
450 clear();
451 try {
452 BufferedReader in = new BufferedReader(new FileReader(configFile));
453 String line = null;
454 while((line = in.readLine()) != null) {
455 String key = null;
456 String value = null;
457 int index = -1;
458 if((index = line.indexOf("=")) != -1 && line.length() >= index + 1) {
459 key = line.substring(0, index);
460 value = line.substring(index + 1);
461 }
462 else {
463 key = line;
464 }
465 put(key, value);
466 }
467 in.close();
468 }
469 catch (Exception error) {
470 error.printStackTrace();
471 }
472 }
473
474 if(glisite_cfg.exists()) {
475 lastModified = glisite_cfg.lastModified();
476 }
477 }
478
479 public boolean exists() {
480 return llssite_cfg.exists();
481 }
482
483 public String getLocalHostURL() {
484 StringBuffer url = new StringBuffer(LOCAL_HOST);
485 url.append(COLON);
486 url.append((String)get(PORTNUMBER));
487 String enterlib = (String)get(ENTERLIB);
488 if(enterlib == null || enterlib.length() == 0) {
489 // Use the default /gsdl and hope for the best.
490 url.append(SEPARATOR);
491 url.append(GSDL);
492 }
493 else {
494 if(!enterlib.startsWith(SEPARATOR)) {
495 url.append(SEPARATOR);
496 }
497 url.append(enterlib);
498 }
499 enterlib = null;
500 debug("Found Local Library Address: " + url.toString());
501 return url.toString();
502 }
503
504 public String getSiteConfigFilename() {
505 return SPECIFIC_CONFIG + glisite_cfg.getAbsolutePath();
506 }
507
508 public String getURL() {
509 // URL is made from url and portnumber
510 String url = (String) get(URL);
511
512 if(!Utility.isWindows()) {
513 return url;
514 }
515
516 if(url != null) {
517 StringBuffer temp = new StringBuffer(url);
518 temp.append(COLON);
519 temp.append((String)get(PORTNUMBER));
520 String enterlib = (String)get(ENTERLIB);
521 if(enterlib == null || enterlib.length() == 0) {
522 // Use the default /gsdl and hope for the best.
523 temp.append(SEPARATOR);
524 temp.append(GSDL);
525 }
526 else {
527 if(!enterlib.startsWith(SEPARATOR)) {
528 temp.append(SEPARATOR);
529 }
530 temp.append(enterlib);
531 }
532 enterlib = null;
533 url = temp.toString();
534 }
535 debug("Found Local Library Address: " + url);
536 return url;
537 }
538
539 public boolean isModified() {
540 return (lastModified != glisite_cfg.lastModified());
541 }
542
543 public void load(boolean reloadOnlyIfModified) {
544
545 if(isModified()) {
546 lastModified = glisite_cfg.lastModified();
547 } else if(reloadOnlyIfModified) {
548 return; // asked to reload only if modified. Don't reload since not modified
549 }
550
551 if(glisite_cfg.exists()) {
552 debug("Load: " + glisite_cfg.getAbsolutePath());
553 clear();
554 try {
555 BufferedReader in = new BufferedReader(new FileReader(glisite_cfg));
556 String line = null;
557 while((line = in.readLine()) != null) {
558 String key = null;
559 String value = null;
560 int index = -1;
561 if((index = line.indexOf("=")) != -1 && line.length() >= index + 1) {
562 key = line.substring(0, index);
563 value = line.substring(index + 1);
564 }
565 else {
566 key = line;
567 }
568 put(key, value);
569 }
570 in.close();
571 }
572 catch (Exception error) {
573 error.printStackTrace();
574 }
575 }
576 else {
577 debug("No glisite.cfg file can be found!");
578 }
579 }
580
581 /** Restore the autoenter value to its initial value, and remove url if present. */
582 public void restore() {
583 if(glisite_cfg != null) {
584 // Delete the file
585 glisite_cfg.delete();
586 }
587 else {
588 debug("Restore Initial Settings");
589 put(AUTOENTER, autoenter_initial);
590 put(STARTBROWSER, start_browser_initial);
591 remove(URL);
592 save();
593 }
594 }
595
596 public void set() {
597 debug("Set Session Settings");
598 if(autoenter_initial == null) {
599 autoenter_initial = (String) get(AUTOENTER);
600 debug("Remember autoenter was: " + autoenter_initial);
601 }
602 put(AUTOENTER, TRUE);
603 if(start_browser_initial == null) {
604 start_browser_initial = (String) get(STARTBROWSER);
605 debug("Remember start_browser was: " + start_browser_initial);
606 }
607 put(STARTBROWSER, FALSE);
608 save();
609 }
610
611 private void debug(String message) {
612 ///ystem.err.println(message);
613 }
614
615 private void save() {
616 //debug("Save: " + llssite_cfg.getAbsolutePath());
617 debug("Save: " + glisite_cfg.getAbsolutePath());
618 try {
619 //BufferedWriter out = new BufferedWriter(new FileWriter(llssite_cfg, false));
620 BufferedWriter out = new BufferedWriter(new FileWriter(glisite_cfg, false));
621 for(Iterator keys = keySet().iterator(); keys.hasNext(); ) {
622 String key = (String) keys.next();
623 String value = (String) get(key);
624 out.write(key, 0, key.length());
625 if(value != null) {
626 out.write('=');
627 out.write(value, 0, value.length());
628 }
629 out.newLine();
630 }
631 out.flush();
632 out.close();
633 }
634 catch (Exception error) {
635 error.printStackTrace();
636 }
637 }
638
639 private static void copyConfigFile(File source_cfg, File dest_cfg, boolean setToGliSiteDefaults) {
640 // source_cfg file should exist
641 // dest_cfg file should not yet exist
642 // If setToGliSiteDefaults is true, then GLIsite.cfg's default configuration
643 // is applied to concerned lines: autoenter=1, and startbrowser=0
644
645 try {
646 BufferedReader in = new BufferedReader(new FileReader(source_cfg));
647 BufferedWriter out = new BufferedWriter(new FileWriter(dest_cfg, false));
648
649 String line = null;
650 while((line = in.readLine()) != null) {
651
652 if(setToGliSiteDefaults) {
653 if(line.startsWith(AUTOENTER)) {
654 line = AUTOENTER+"=1";
655 }
656 else if(line.startsWith(STARTBROWSER)) {
657 line = STARTBROWSER+"=0";
658 }
659 }
660
661 // write out the line
662 out.write(line + "\n");
663 }
664
665 out.flush();
666 in.close();
667 out.close();
668 } catch(Exception e) {
669 System.err.println("Exception occurred when trying to copy the config file "
670 + source_cfg.getName() + " to " + dest_cfg.getName() + ": " + e);
671 e.printStackTrace();
672 }
673 }
674 }
675}
Note: See TracBrowser for help on using the repository browser.