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

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

When the local server application doesn't terminate properly and a URL is still left in the glisite.cfg/llssite.cfg file, LocalLibraryServer.java now on STARTUP launches the server app. Previously gli would not launch the server app in such a case because it assumed the server was still running. This caused the missing server phenomenon: because the url would never be removed from glisite.cfg since the server app would never be run, the server would never be launched from GLI.

  • Property svn:keywords set to Author Date Id Revision
File size: 18.6 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 llssite_cfg_file = new LLSSiteConfig(local_library_server_file);
170
171 // Spawn local library server process
172 String local_library_server_command = local_library_server_file.getAbsolutePath() + getExtraLaunchArguments(llssite_cfg_file);
173
174 // Check if the server is already running
175 String url = llssite_cfg_file.getURL();
176 if (url != null) {
177 // If it is already running then set the Greenstone web server address and we're done
178 // E.g. if previously GLI was not properly shut down, the URL property (signifying
179 // the server is still running) would still be in the glisite_cfg file.
180 try {
181 Configuration.library_url = new URL(url);
182 running = true;
183
184 // Run the server interface
185 Gatherer.spawnApplication(local_library_server_command, ID);
186 return;
187 }
188 catch (MalformedURLException exception) {
189 DebugStream.printStackTrace(exception);
190 }
191 }
192
193 // Configure the server for immediate entry
194 //llssite_cfg_file.set();
195
196 // Spawn local library server process
197 Gatherer.spawnApplication(local_library_server_command, ID);
198
199 // Wait until program has started
200 try {
201 testServerRunning(); // will set running = true when the server is up and running successfully
202 } catch (IOException bad_url_connection) {
203 try {
204 // If this fails then we try changing the url to be localhost
205 Configuration.library_url = new URL(llssite_cfg_file.getLocalHostURL());
206 DebugStream.println("Try connecting to server on local host: '" + Configuration.library_url + "'");
207 URLConnection connection = Configuration.library_url.openConnection();
208 connection.getContent();
209 running = true;
210
211 } catch (IOException worse_url_connection) {
212 DebugStream.println("Can't connect to server on either address.");
213 Configuration.library_url = null;
214 running = false;
215 }
216 }
217 }
218
219
220 static public void stop()
221 {
222 if (running == false) {
223 return;
224 }
225
226 // Send the command for it to exit.
227 if (isPersistentServer) {
228 config(QUIT_COMMAND);
229 } else {
230 if(sendMessageToServer("QUIT")) {
231 Gatherer.terminateApplication(ID);
232 } else {
233 System.err.println("Unable to stop the server, since there's no communication port to send the quit msg over."
234 + "\nPlease stop the local Greenstone server manually.");
235 }
236 }
237
238 // Wait until program has stopped, by reloading and checking the URL field
239 llssite_cfg_file.load(false);
240 int attempt_count = 0;
241 while (llssite_cfg_file.getURL() != null) {
242 new OneSecondWait(); // Wait one second (give or take)
243 llssite_cfg_file.load(false);
244 attempt_count++;
245
246 // After waiting a minute ask the user whether they want to wait another minute
247 if (attempt_count == 60) {
248 int try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
249 if (try_again == JOptionPane.NO_OPTION) {
250 return;
251 }
252 attempt_count = 0;
253 }
254 }
255
256 // Restore the llssite_cfg.
257 llssite_cfg_file.restore();
258
259 // If the local server is still running then our changed values will get overwritten.
260 if (llssite_cfg_file.getURL() != null) {
261 JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("Server.QuitManual"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
262 }
263
264 running = false;
265 }
266
267 static private String getExtraLaunchArguments(LLSSiteConfig site_cfg_file) {
268 String args = " " + site_cfg_file.getSiteConfigFilename();
269
270 if(Utility.isWindows()) {
271 return args;
272 }
273
274 // Else, when running the Local Library Server on Linux, need to provide a port argument
275 try {
276 PortFinder portFinder = new PortFinder(50100, 100);
277 port = portFinder.findPortInRange();
278 } catch(Exception e) {
279 System.err.println("Exception when trying to find an available port: " + e);
280 port = -1;
281 }
282
283 return args + " --quitport=" + port;
284 }
285
286
287 // This method first tests whether there is a URL in the llssite_cfg_file
288 // and after that appears, it tests whether the URL is functional.
289 static private void testServerRunning() throws IOException {
290 // Wait until program has started, by reloading and checking the URL field
291 llssite_cfg_file.load(false);
292 int attempt_count = 0;
293 while (llssite_cfg_file.getURL() == null) {
294 new OneSecondWait(); // Wait one second (give or take)
295 llssite_cfg_file.load(false);
296 attempt_count++;
297
298 // After waiting a minute ask the user whether they want to wait another minute
299 if (attempt_count == 60) {
300 int try_again = JOptionPane.showConfirmDialog(Gatherer.g_man, Dictionary.get("Server.QuitTimeOut"), Dictionary.get("General.Warning"), JOptionPane.YES_NO_OPTION);
301 if (try_again == JOptionPane.NO_OPTION) {
302 return;
303 }
304 attempt_count = 0;
305 }
306 }
307
308 // Ta-da. Now the url should be available
309 try {
310 Configuration.library_url = new URL(llssite_cfg_file.getURL());
311 }
312 catch (MalformedURLException exception) {
313 DebugStream.printStackTrace(exception);
314 }
315
316 // A quick test involves opening a connection to get the home page for this collection
317 try {
318 DebugStream.println("Try connecting to server on config url: '" + Configuration.library_url + "'");
319 URLConnection connection = Configuration.library_url.openConnection();
320 connection.getContent();
321 running = true;
322 }
323 catch (IOException bad_url_connection) {
324 throw bad_url_connection;
325 }
326
327
328 }
329
330 static public void checkServerRunning() {
331 if (!running) return; // don't worry about it if its not supposed to be running
332 llssite_cfg_file.load(true); // don't force reload, load only if modified
333
334 String url = llssite_cfg_file.getURL();
335 if(url != null) {
336 try {
337 Configuration.library_url = new URL(url);
338 }
339 catch (MalformedURLException exception) {
340 DebugStream.printStackTrace(exception);
341 }
342 } else {
343 // need to restart the server again
344 llssite_cfg_file.set();
345
346 // Spawn local library server process
347 String local_library_server_command = local_library_server_file.getAbsolutePath() + getExtraLaunchArguments(llssite_cfg_file);
348 running = false;
349 Gatherer.spawnApplication(local_library_server_command, ID);
350 try {
351 testServerRunning(); // don't return until the webserver is up and running
352 } catch (IOException bad_url_connection) {
353 DebugStream.println("Can't connect to server on address " + Configuration.library_url);
354 running = false;
355 }
356 }
357 }
358
359 static private class OneSecondWait
360 {
361 public OneSecondWait()
362 {
363 synchronized(this) {
364 try {
365 wait(1000);
366 }
367 catch (InterruptedException exception) {
368 }
369 }
370 }
371 }
372
373
374 static public class LLSSiteConfig
375 extends LinkedHashMap {
376 private File llssite_cfg;
377 private File glisite_cfg;
378 private String autoenter_initial;
379 private String start_browser_initial;
380
381 private long lastModified = 0;
382
383 static final private String AUTOENTER = "autoenter";
384 static final private String COLON = ":";
385 static final private String ENTERLIB = "enterlib";
386 static final private String FALSE = "0";
387 static final private String GLISITE_CFG = "glisite.cfg";
388 static final private String GSDL = "greenstone"; // httpprefix is no longer /gsdl but /greenstone
389 static final private String LLSSITE_CFG = "llssite.cfg";
390 static final private String LOCAL_HOST = "http://localhost";
391 static final private String PORTNUMBER = "portnumber";
392 static final private String SEPARATOR = "/";
393 static final private String SPECIFIC_CONFIG = "--config=";
394 static final private String STARTBROWSER = "start_browser";
395 static final private String TRUE = "1";
396 static final private String URL = "url";
397
398 public LLSSiteConfig(File server_exe) {
399 debug("New LLSSiteConfig for: " + server_exe.getAbsolutePath());
400
401 llssite_cfg = new File(server_exe.getParentFile(), LLSSITE_CFG);
402 glisite_cfg = new File(server_exe.getParentFile(), GLISITE_CFG);
403
404 File configFile = null;
405 if(glisite_cfg.exists()) {
406 configFile = glisite_cfg;
407 } else if(llssite_cfg.exists()) {
408 configFile = llssite_cfg;
409 } else {
410 debug("Neither the file glisite.cfg nor llssite.cfg can be found!");
411 }
412
413 autoenter_initial = null;
414 start_browser_initial = null;
415 if(configFile != null) {
416 debug("Load: " + configFile.getAbsolutePath());
417 clear();
418 try {
419 BufferedReader in = new BufferedReader(new FileReader(configFile));
420 String line = null;
421 while((line = in.readLine()) != null) {
422 String key = null;
423 String value = null;
424 int index = -1;
425 if((index = line.indexOf("=")) != -1 && line.length() >= index + 1) {
426 key = line.substring(0, index);
427 value = line.substring(index + 1);
428 }
429 else {
430 key = line;
431 }
432 put(key, value);
433 }
434 in.close();
435 }
436 catch (Exception error) {
437 error.printStackTrace();
438 }
439 }
440
441 if(glisite_cfg.exists()) {
442 lastModified = glisite_cfg.lastModified();
443 }
444 }
445
446 public boolean exists() {
447 return llssite_cfg.exists();
448 }
449
450 public String getLocalHostURL() {
451 StringBuffer url = new StringBuffer(LOCAL_HOST);
452 url.append(COLON);
453 url.append((String)get(PORTNUMBER));
454 String enterlib = (String)get(ENTERLIB);
455 if(enterlib == null || enterlib.length() == 0) {
456 // Use the default /gsdl and hope for the best.
457 url.append(SEPARATOR);
458 url.append(GSDL);
459 }
460 else {
461 if(!enterlib.startsWith(SEPARATOR)) {
462 url.append(SEPARATOR);
463 }
464 url.append(enterlib);
465 }
466 enterlib = null;
467 debug("Found Local Library Address: " + url.toString());
468 return url.toString();
469 }
470
471 public String getSiteConfigFilename() {
472 return SPECIFIC_CONFIG + glisite_cfg.getAbsolutePath();
473 }
474
475 public String getURL() {
476 // URL is made from url and portnumber
477 String url = (String) get(URL);
478
479 if(!Utility.isWindows()) {
480 return url;
481 }
482
483 if(url != null) {
484 StringBuffer temp = new StringBuffer(url);
485 temp.append(COLON);
486 temp.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 temp.append(SEPARATOR);
491 temp.append(GSDL);
492 }
493 else {
494 if(!enterlib.startsWith(SEPARATOR)) {
495 temp.append(SEPARATOR);
496 }
497 temp.append(enterlib);
498 }
499 enterlib = null;
500 url = temp.toString();
501 }
502 debug("Found Local Library Address: " + url);
503 return url;
504 }
505
506 public boolean isModified() {
507 return (lastModified != glisite_cfg.lastModified());
508 }
509
510 public void load(boolean reloadOnlyIfModified) {
511
512 if(isModified()) {
513 lastModified = glisite_cfg.lastModified();
514 } else if(reloadOnlyIfModified) {
515 return; // asked to reload only if modified. Don't reload since not modified
516 }
517
518 if(glisite_cfg.exists()) {
519 debug("Load: " + glisite_cfg.getAbsolutePath());
520 clear();
521 try {
522 BufferedReader in = new BufferedReader(new FileReader(glisite_cfg));
523 String line = null;
524 while((line = in.readLine()) != null) {
525 String key = null;
526 String value = null;
527 int index = -1;
528 if((index = line.indexOf("=")) != -1 && line.length() >= index + 1) {
529 key = line.substring(0, index);
530 value = line.substring(index + 1);
531 }
532 else {
533 key = line;
534 }
535 put(key, value);
536 }
537 in.close();
538 }
539 catch (Exception error) {
540 error.printStackTrace();
541 }
542 }
543 else {
544 debug("No glisite.cfg file can be found!");
545 }
546 }
547
548 /** Restore the autoenter value to its initial value, and remove url if present. */
549 public void restore() {
550 if(glisite_cfg != null) {
551 // Delete the file
552 glisite_cfg.delete();
553 }
554 else {
555 debug("Restore Initial Settings");
556 put(AUTOENTER, autoenter_initial);
557 put(STARTBROWSER, start_browser_initial);
558 remove(URL);
559 save();
560 }
561 }
562
563 public void set() {
564 debug("Set Session Settings");
565 if(autoenter_initial == null) {
566 autoenter_initial = (String) get(AUTOENTER);
567 debug("Remember autoenter was: " + autoenter_initial);
568 }
569 put(AUTOENTER, TRUE);
570 if(start_browser_initial == null) {
571 start_browser_initial = (String) get(STARTBROWSER);
572 debug("Remember start_browser was: " + start_browser_initial);
573 }
574 put(STARTBROWSER, FALSE);
575 save();
576 }
577
578 private void debug(String message) {
579 ///ystem.err.println(message);
580 }
581
582 private void save() {
583 //debug("Save: " + llssite_cfg.getAbsolutePath());
584 debug("Save: " + glisite_cfg.getAbsolutePath());
585 try {
586 //BufferedWriter out = new BufferedWriter(new FileWriter(llssite_cfg, false));
587 BufferedWriter out = new BufferedWriter(new FileWriter(glisite_cfg, false));
588 for(Iterator keys = keySet().iterator(); keys.hasNext(); ) {
589 String key = (String) keys.next();
590 String value = (String) get(key);
591 out.write(key, 0, key.length());
592 if(value != null) {
593 out.write('=');
594 out.write(value, 0, value.length());
595 }
596 out.newLine();
597 }
598 out.flush();
599 out.close();
600 }
601 catch (Exception error) {
602 error.printStackTrace();
603 }
604 }
605 }
606}
Note: See TracBrowser for help on using the repository browser.