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

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

Works with the template glisite.cfg.in and llssite.cfg.in files to generate the glisite.cfg file if this is missing.

  • Property svn:keywords set to Author Date Id Revision
File size: 20.3 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()) { // create it from the templates or the llssite.cfg file
406
407 File llssite_cfg_in = new File(server_exe.getParentFile(), LLSSITE_CFG+".in");
408 File glisite_cfg_in = new File(server_exe.getParentFile(), GLISITE_CFG+".in");
409
410 // need to generate glisite_cfg from glisite_cfg_in, llssite_cfg or llssite.cfg.in
411 if(glisite_cfg_in.exists()) {
412 copyConfigFile(glisite_cfg_in, glisite_cfg, false);
413 }
414 else if(llssite_cfg_in.exists()) {
415 copyConfigFile(llssite_cfg_in, glisite_cfg_in, true); // adjust for glisite.cfg
416 copyConfigFile(glisite_cfg_in, glisite_cfg, false);
417 }
418 else if(llssite_cfg.exists()) {
419 copyConfigFile(llssite_cfg, glisite_cfg, true); // adjust for glisite.cfg
420 }
421 else {
422 debug("Neither the file glisite.cfg nor llssite.cfg can be found!");
423 }
424 }
425
426 if(glisite_cfg.exists()) {
427 configFile = glisite_cfg;
428 }
429
430 autoenter_initial = null;
431 start_browser_initial = null;
432 if(configFile != null) {
433 debug("Load: " + configFile.getAbsolutePath());
434 clear();
435 try {
436 BufferedReader in = new BufferedReader(new FileReader(configFile));
437 String line = null;
438 while((line = in.readLine()) != null) {
439 String key = null;
440 String value = null;
441 int index = -1;
442 if((index = line.indexOf("=")) != -1 && line.length() >= index + 1) {
443 key = line.substring(0, index);
444 value = line.substring(index + 1);
445 }
446 else {
447 key = line;
448 }
449 put(key, value);
450 }
451 in.close();
452 }
453 catch (Exception error) {
454 error.printStackTrace();
455 }
456 }
457
458 if(glisite_cfg.exists()) {
459 lastModified = glisite_cfg.lastModified();
460 }
461 }
462
463 public boolean exists() {
464 return llssite_cfg.exists();
465 }
466
467 public String getLocalHostURL() {
468 StringBuffer url = new StringBuffer(LOCAL_HOST);
469 url.append(COLON);
470 url.append((String)get(PORTNUMBER));
471 String enterlib = (String)get(ENTERLIB);
472 if(enterlib == null || enterlib.length() == 0) {
473 // Use the default /gsdl and hope for the best.
474 url.append(SEPARATOR);
475 url.append(GSDL);
476 }
477 else {
478 if(!enterlib.startsWith(SEPARATOR)) {
479 url.append(SEPARATOR);
480 }
481 url.append(enterlib);
482 }
483 enterlib = null;
484 debug("Found Local Library Address: " + url.toString());
485 return url.toString();
486 }
487
488 public String getSiteConfigFilename() {
489 return SPECIFIC_CONFIG + glisite_cfg.getAbsolutePath();
490 }
491
492 public String getURL() {
493 // URL is made from url and portnumber
494 String url = (String) get(URL);
495
496 if(!Utility.isWindows()) {
497 return url;
498 }
499
500 if(url != null) {
501 StringBuffer temp = new StringBuffer(url);
502 temp.append(COLON);
503 temp.append((String)get(PORTNUMBER));
504 String enterlib = (String)get(ENTERLIB);
505 if(enterlib == null || enterlib.length() == 0) {
506 // Use the default /gsdl and hope for the best.
507 temp.append(SEPARATOR);
508 temp.append(GSDL);
509 }
510 else {
511 if(!enterlib.startsWith(SEPARATOR)) {
512 temp.append(SEPARATOR);
513 }
514 temp.append(enterlib);
515 }
516 enterlib = null;
517 url = temp.toString();
518 }
519 debug("Found Local Library Address: " + url);
520 return url;
521 }
522
523 public boolean isModified() {
524 return (lastModified != glisite_cfg.lastModified());
525 }
526
527 public void load(boolean reloadOnlyIfModified) {
528
529 if(isModified()) {
530 lastModified = glisite_cfg.lastModified();
531 } else if(reloadOnlyIfModified) {
532 return; // asked to reload only if modified. Don't reload since not modified
533 }
534
535 if(glisite_cfg.exists()) {
536 debug("Load: " + glisite_cfg.getAbsolutePath());
537 clear();
538 try {
539 BufferedReader in = new BufferedReader(new FileReader(glisite_cfg));
540 String line = null;
541 while((line = in.readLine()) != null) {
542 String key = null;
543 String value = null;
544 int index = -1;
545 if((index = line.indexOf("=")) != -1 && line.length() >= index + 1) {
546 key = line.substring(0, index);
547 value = line.substring(index + 1);
548 }
549 else {
550 key = line;
551 }
552 put(key, value);
553 }
554 in.close();
555 }
556 catch (Exception error) {
557 error.printStackTrace();
558 }
559 }
560 else {
561 debug("No glisite.cfg file can be found!");
562 }
563 }
564
565 /** Restore the autoenter value to its initial value, and remove url if present. */
566 public void restore() {
567 if(glisite_cfg != null) {
568 // Delete the file
569 glisite_cfg.delete();
570 }
571 else {
572 debug("Restore Initial Settings");
573 put(AUTOENTER, autoenter_initial);
574 put(STARTBROWSER, start_browser_initial);
575 remove(URL);
576 save();
577 }
578 }
579
580 public void set() {
581 debug("Set Session Settings");
582 if(autoenter_initial == null) {
583 autoenter_initial = (String) get(AUTOENTER);
584 debug("Remember autoenter was: " + autoenter_initial);
585 }
586 put(AUTOENTER, TRUE);
587 if(start_browser_initial == null) {
588 start_browser_initial = (String) get(STARTBROWSER);
589 debug("Remember start_browser was: " + start_browser_initial);
590 }
591 put(STARTBROWSER, FALSE);
592 save();
593 }
594
595 private void debug(String message) {
596 ///ystem.err.println(message);
597 }
598
599 private void save() {
600 //debug("Save: " + llssite_cfg.getAbsolutePath());
601 debug("Save: " + glisite_cfg.getAbsolutePath());
602 try {
603 //BufferedWriter out = new BufferedWriter(new FileWriter(llssite_cfg, false));
604 BufferedWriter out = new BufferedWriter(new FileWriter(glisite_cfg, false));
605 for(Iterator keys = keySet().iterator(); keys.hasNext(); ) {
606 String key = (String) keys.next();
607 String value = (String) get(key);
608 out.write(key, 0, key.length());
609 if(value != null) {
610 out.write('=');
611 out.write(value, 0, value.length());
612 }
613 out.newLine();
614 }
615 out.flush();
616 out.close();
617 }
618 catch (Exception error) {
619 error.printStackTrace();
620 }
621 }
622
623 private static void copyConfigFile(File source_cfg, File dest_cfg, boolean setToGliSiteDefaults) {
624 // source_cfg file should exist
625 // dest_cfg file should not yet exist
626 // If setToGliSiteDefaults is true, then GLIsite.cfg's default configuration
627 // is applied to concerned lines: autoenter=1, and startbrowser=0
628
629 try {
630 BufferedReader in = new BufferedReader(new FileReader(source_cfg));
631 BufferedWriter out = new BufferedWriter(new FileWriter(dest_cfg, false));
632
633 String line = null;
634 while((line = in.readLine()) != null) {
635
636 if(setToGliSiteDefaults) {
637 if(line.startsWith(AUTOENTER)) {
638 line = AUTOENTER+"=1";
639 }
640 else if(line.startsWith(STARTBROWSER)) {
641 line = STARTBROWSER+"=0";
642 }
643 }
644
645 // write out the line
646 out.write(line + "\n");
647 }
648
649 out.flush();
650 in.close();
651 out.close();
652 } catch(Exception e) {
653 System.err.println("Exception occurred when trying to copy the config file "
654 + source_cfg.getName() + " to " + dest_cfg.getName() + ": " + e);
655 e.printStackTrace();
656 }
657 }
658 }
659}
Note: See TracBrowser for help on using the repository browser.