source: main/trunk/greenstone3/src/java/org/greenstone/server/Server2.java@ 24503

Last change on this file since 24503 was 24503, checked in by ak19, 13 years ago

Still part of the changes for introducing the --mode=gli flag that's passed to the GS2 server so that we can merge the two cfg files glisite and llssite. Now the url property in the config file is also to be prefixed with the mode, so that GLI's LocalLibraryServer can work out whether GLI launched the GSI or whether it was launched independently (outside GLI).

File size: 19.7 KB
Line 
1
2package org.greenstone.server;
3
4import java.io.BufferedReader;
5import java.io.File;
6import java.io.FileInputStream;
7import java.io.FileOutputStream;
8import java.io.InputStreamReader;
9import java.io.IOException;
10import java.net.InetAddress;
11import java.net.ServerSocket;
12import java.net.Socket;
13import java.net.UnknownHostException;
14import java.net.URL;
15//import java.net.URLConnection;
16import java.util.ArrayList;
17import java.util.Properties;
18import java.util.StringTokenizer;
19
20import org.apache.log4j.*;
21
22import org.greenstone.util.PortFinder;
23import org.greenstone.util.ScriptReadWrite;
24import org.greenstone.util.RunMake;
25import org.greenstone.util.RunAnt;
26
27import org.greenstone.server.BaseServer;
28import org.greenstone.server.BaseProperty;
29
30
31public class Server2 extends BaseServer
32{
33 private static final int WAITING_TIME = 10; // time to wait and check for whether the server is running
34 private static final String URL_PENDING="URL_pending";
35
36 protected String libraryURL;
37 protected String property_prefix;
38
39 private class QuitListener extends Thread
40 {
41 int quitPort = -1;
42 ServerSocket serverSocket = null;
43
44 public QuitListener(int quitport) throws Exception {
45 ///Server2.this.recordSuccess("In QuitListener constructor");
46 this.quitPort = quitport;
47 serverSocket = new ServerSocket(quitPort);
48 }
49
50 public void run() {
51 Socket connection = null;
52
53 try {
54 // wait for a connection
55 connection = serverSocket.accept();
56 boolean stop = false;
57
58 // read input
59 try {
60 BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
61 String line = null;
62 while((line = reader.readLine()) != null) {
63 if(line.equals("QUIT")) {
64 stop = true;
65 // Server2.this.recordSuccess("In QuitListener - line is QUIT");
66 reader.close();
67 reader = null;
68 serverSocket.close();
69 serverSocket = null;
70 break;
71 } else if(line.equals("RECONFIGURE")) {
72 server_control_.displayMessage(dictionary.get("ServerControl.Configuring"));
73 reconfigRequired();
74 } else if(line.equals("RESTART")) {
75
76 // If the GSI is set to NOT autoenter/autostart the server, then write url=URL_PENDING out to the file.
77 // When the user finally presses the Enter Library button and so has started up the server, the correct
78 // url will be written out to the configfile.
79 String url = property_prefix+"url";
80 if(config_properties.getProperty(BaseServer.Property.AUTOSTART, "").equals("0")) {
81 if(config_properties.getProperty(url) == null) {
82 config_properties.setProperty(url, URL_PENDING);
83 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
84 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
85 scriptReadWrite.replaceOrAddLine(fileLines, url, URL_PENDING, true);
86 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
87 }
88 }
89
90 autoStart();
91 }
92 }
93 } catch(Exception e) {
94 Server2.this.recordError("Exception in QuitListener thread.");
95 } finally {
96 if(stop) {
97 Server2.this.stop();
98 System.exit(0);
99 }
100 }
101 } catch(IOException ioe) {
102 Server2.this.recordError("Server2.QuitListener: Unable to make the connection with the client socket." + ioe);
103 }
104 }
105 }
106
107
108 public Server2(String gsdl2_home, String lang, String configfile, int quitPort, String mode)
109 {
110 super(gsdl2_home, lang, configfile, "etc"+File.separator+"logs-gsi");
111 // configfile can be either glisite.cfg or llssite.cfg
112
113 //logger_.error("gsdlhome: " + gsdl2_home + " | lang: " + lang + " | configfile: "
114 //+ configfile + " | mode: " + property_prefix + " | quitport: " + quitPort);
115
116 // property_prefix is the mode we're running in (gli or empty) and contains the prefix
117 // string to look for in config file for auto_enter, start_browser and url properties
118 property_prefix = mode;
119 if(!property_prefix.equals("") && !property_prefix.endsWith(".")) { // ensure a '.' is suffixed if non-empty
120 property_prefix += ".";
121 }
122 Property = new Server2Property(property_prefix);
123
124
125 String frame_title = dictionary.get("ServerControl.Frame_Title");
126 server_control_ = new Server2Control(this,frame_title);
127
128 /* Make command targets for managing Web server */
129 START_CMD = "web-start";
130 RESTART_CMD = "web-restart";
131 CONFIGURE_CMD = "configure-web \"" + configfile + "\"";
132 STOP_CMD = "web-stop";
133
134 // now we can monitor for the quit command if applicable
135 if(quitPort != -1) {
136 // First check if given port is within the range of allowed ports
137 if(PortFinder.isAssignablePortNumber(quitPort)) {
138 try {
139 new QuitListener(quitPort).start();
140 } catch(Exception e) {
141 Server2.this.recordError("Exception constructing the QuitListener thread.");
142 }
143 }
144 else {
145 recordError("QuitPort provided is not within acceptable range: ("
146 + PortFinder.PORTS_RESERVED + " - " + PortFinder.MAX_PORT + "]" );
147 quitPort = -1;
148 }
149 }
150
151 // For some machines, localhost is not sufficient,
152 // need hostname defined as well (e.g. Ubuntu 10.10)
153 InetAddress inetAddress = null;
154 try {
155 inetAddress = InetAddress.getLocalHost();
156 String hosts = inetAddress.getHostName();
157 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
158 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
159 scriptReadWrite.replaceOrAddLine(fileLines, "hosts", hosts, true);
160 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
161 } catch(UnknownHostException e) {
162 // Unable to get hostname, need to try for the default localhost without it
163 }
164
165 // If the GSI is set to NOT autoenter/autostart the server, then write url=URL_PENDING out to the file.
166 // When the user finally presses the Enter Library button and so has started up the server, the correct
167 // url will be written out to the configfile.
168 if(config_properties.getProperty(BaseServer.Property.AUTOSTART, "").equals("0")) {//if(configfile.endsWith("llssite.cfg")) {
169 String url = property_prefix+"url";
170 if(config_properties.getProperty(url) == null) {
171 config_properties.setProperty(url, URL_PENDING);
172 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
173 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
174 scriptReadWrite.replaceOrAddLine(fileLines, url, URL_PENDING, true);
175 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
176 }
177 }
178
179 autoStart();
180 }
181
182 // Prepare the log4j.properties for GS2
183 protected void initLogger() {
184
185 String libjavaFolder = gsdl_home+File.separator+"lib"+File.separator+"java"+File.separator;
186 File propsFile = new File(libjavaFolder+"log4j.properties");
187
188 // create it from the template file log4j.properties.in
189 if(!propsFile.exists()) {
190 try {
191 // need to set gsdl2.home property's value to be gsdl_home,
192 // so that the location of the log files gets resolved correctly
193
194 // load the template log4j.properties.in file into logProps
195 FileInputStream infile = new FileInputStream(new File(libjavaFolder+"log4j.properties.in"));
196 if(infile != null) {
197 Properties logProps = new Properties();
198 logProps.load(infile);
199 infile.close();
200
201 // set gsdl3.home to gsdl_home
202 logProps.setProperty("gsdl2.home", gsdl_home);
203
204 // write the customised properties out to a custom log4j.properties file
205 FileOutputStream outfile = new FileOutputStream(propsFile);
206 if(outfile != null) {
207 logProps.store(outfile, "Customised log4j.properties file");
208 outfile.close();
209 } else {
210 System.err.println("Could not store properties file " + propsFile + " for Server2.");
211 }
212 }
213 } catch(Exception e) {
214 System.err.println("Exception occurred when custom-configuring the logger for Server2.\n" + e);
215 }
216 }
217
218 // now configure the logger with the custom log4j.properties file
219 if(propsFile.exists()) {
220 PropertyConfigurator.configure(propsFile.getAbsolutePath());
221 } else {
222 System.err.println("Could not create properties file " + propsFile + " for Server2.");
223 }
224 }
225
226
227 protected int runTarget(String cmd)
228 {
229 RunMake runMake = new RunMake();
230 runMake.setTargetCmd(cmd);
231 runMake.run();
232 return runMake.getTargetState();
233 }
234
235 public String getBrowserURL() {
236 return libraryURL;
237 }
238
239 // works out the library URL again
240 public void reload() {
241 // default values, to be replaced with what's in gsdlsite.cfg
242 String host = "localhost";
243 String port = "80";
244 String gwcgi;
245 String httpprefix = "/greenstone";
246 String suffix = "/cgi-bin/library.cgi";
247
248 // get the prefix from the gsdlsite.cfg and build.properties files (port number and servername)
249 try{
250 File gsdlsite_cfg = new File(gsdl_home + File.separator + "cgi-bin" + File.separator + "gsdlsite.cfg");
251 FileInputStream fin = new FileInputStream(gsdlsite_cfg);
252 Properties gsdlProperties = new Properties();
253 if(fin != null) {
254 gsdlProperties.load(fin);
255
256 gwcgi = gsdlProperties.getProperty("gwcgi");
257 if(gwcgi != null) {
258 suffix = gwcgi;
259 } else {
260 httpprefix = gsdlProperties.getProperty("httpprefix", httpprefix);
261 suffix = httpprefix + suffix;
262 }
263 fin.close();
264 } else {
265 recordError("Could not open gsdlsite_cfg for reading, using default library prefix.");
266 }
267 //reloadConfigProperties();
268 port = config_properties.getProperty("portnumber", port);
269
270 // The "hosts" property in the config file contains more than one allowed host
271 // Need to work out the particular host chosen from the address_resolution_method
272 // Default is address_resolution_method 2: localhost
273 String addressResolutionMethod = config_properties.getProperty("address_resolution_method");
274 int address_resolution_method = (addressResolutionMethod == null) ? 2 : Integer.parseInt(addressResolutionMethod);
275 InetAddress inetAddress = null;
276 try {
277 inetAddress = InetAddress.getLocalHost();
278 } catch(UnknownHostException e) {
279 logger_.error(e);
280 logger_.info("Defaulting host IP to "+ host); // use the default
281 address_resolution_method = 2;
282 inetAddress = null;
283 }
284 switch(address_resolution_method) {
285 case 0:
286 host = inetAddress.getHostName();
287 break;
288 case 1:
289 host = inetAddress.getHostAddress();
290 break;
291 case 2:
292 host = "localhost";
293 break;
294 case 3:
295 host = "127.0.0.1";
296 break;
297 default:
298 host = "localhost";
299 }
300 } catch(Exception e) {
301 recordError("Exception trying to load properties from gsdlsite_cfg. Using default library prefix.", e);
302 suffix = httpprefix + suffix;
303 }
304
305 libraryURL = "http://" + host + ":" + port + suffix;
306 }
307
308 public boolean reloadConfigProperties(boolean port_has_changed) {
309 super.reloadConfigProperties(port_has_changed);
310
311 // make sure the port is okay, otherwise find another port
312 // first choice is port 80, second choice starts at 8282
313 String port = config_properties.getProperty("portnumber", "80");
314 String keepport = config_properties.getProperty("keepport", "0"); // default is to not try to force the same port if in use by other servers
315
316 int portDefault = 8282;
317 try {
318 int portNum = Integer.parseInt(port);
319 boolean verbose = true;
320 if(port_has_changed) { // this is the test that prevents the server from arbitrarily shifting the port.
321 // only check at configured port if it's not the current port (the port we
322 // are still running on), because that will always be in use and unavailable.
323 if(!PortFinder.isPortAvailable(portNum, verbose)) { // first time, print any Port Unavailable messages
324 if(keepport.equals("1")) {
325 server_control_.errorMessage(dictionary.get("ServerSettings.SettingsUnchangedPortOccupied", new String[]{port}));
326 String errorMsg = "Unable to run the Greenstone server on port " + port + ". It appears to already be in use.";
327 System.err.println("\n******************");
328 logger_.error(errorMsg);
329 System.err.println("If you wish to try another port, go to File > Settings of the Greenstone Server interface and either change the port number or untick the \"Do Not Modify Port\" option there. Then press the \"Enter Library\" button.");
330 System.err.println("******************\n");
331
332 return false; // property change is unsuccessful
333
334 } else { // can modify port, try to find a new port
335
336 PortFinder portFinder = new PortFinder(portDefault, 101);
337 // Search for a free port silently from now on--don't want more
338 // messages saying that a port could not be found...
339 portNum = portFinder.findPortInRange(!verbose);
340
341 if (portNum == -1) {
342 // If we've still not found a free port, do we try the default port again?
343 System.err.println("No free port found. Going to try on " + portDefault + " anyway.");
344 port = Integer.toString(portDefault);
345 } else {
346 port = Integer.toString(portNum);
347 }
348 config_properties.setProperty("portnumber", port); // store the correct port
349
350 // write this updated port to the config file, since the configure target uses the file to run
351 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
352 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
353 scriptReadWrite.replaceOrAddLine(fileLines, "portnumber", port, false); // write the correct port
354 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
355
356 configure_required_ = true;
357 System.err.println("Running server on port " + port + ".");
358 }
359 }
360 }
361 } catch (Exception e) {
362 recordError("Exception in Server2.reload(): " + e.getMessage());
363 port = Integer.toString(portDefault);
364 }
365
366 return true;
367 }
368
369
370 // About to stop the webserver
371 // Custom GS2 action: remove the url property from the config file
372 protected void preStop() {
373 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
374 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
375
376 // Remove the url=... line, start searching from the end
377 boolean done = false;
378 for (int i = fileLines.size()-1; i >= 0 && !done; i--) {
379 String line = ((String) fileLines.get(i)).trim();
380 if(line.startsWith(property_prefix+"url=")) {
381 fileLines.remove(i);
382 done = true;
383 }
384 }
385 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
386 }
387
388 // Called when the URL has been changed (called after a reload() and starting the server).
389 // By the time we get here, reload() would already have been called and have set
390 // both the port and worked out libraryURL
391 // This method needs to write the URL to the configfile since things should work
392 // like GS2's Local Lib Server for Windows
393 protected void postStart() {
394
395 URL libURL = null;
396 try {
397 libURL = new URL(libraryURL);
398 } catch (Exception e) {
399 recordError("Unable to convert library URL string into a valid URL, Server2.java." + e);
400 }
401
402 // 1. Test that the server is running at the libraryURL before writing it out to glisite.cfg/configfile
403 // A quick test involves opening a connection to get the home page for this collection
404 if(libURL != null && !libraryURL.equals(URL_PENDING)) {
405
406 boolean ready = false;
407 for(int i = 0; i < WAITING_TIME && !ready; i++) {
408 try {
409 libURL.openConnection();
410 //URLConnection connection = new URL(libraryURL).openConnection();
411 //connection.getContent();
412 ready = true;
413 recordSuccess("Try connecting to server on url: '" + libraryURL + "'");
414 } catch (IOException bad_url_connection) {
415 // keep looping
416 recordSuccess("NOT YET CONNECTED. Waiting to try again...");
417 try {
418 Thread.sleep(1000);
419 } catch (InterruptedException ie) {
420 ready = true;
421 recordError("Unexpected: got an InterruptedException in sleeping thread, Server2.java." + ie);
422 }
423 } catch (Exception e) {
424 ready = true;
425 recordError("Got an Exception while waiting for the connection to become live, Server2.java." + e);
426 }
427 }
428 }
429
430 // 2. Now write the URL to the config file
431 String port = config_properties.getProperty("portnumber");
432
433 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
434 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
435 scriptReadWrite.replaceOrAddLine(fileLines, property_prefix+"url", libraryURL, true);
436 scriptReadWrite.replaceOrAddLine(fileLines, "portnumber", port, false); // write the correct port
437 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
438 }
439
440
441 public static void main (String[] args)
442 {
443 if ((args.length < 1) || (args.length > 5)) {
444 System.err.println(
445 "Usage: java org.greenstone.server.Server2 <gsdl2-home-dir> [lang] [--mode=\"gli\"] [--config=configfile] [--quitport=portNum]");
446 System.exit(1);
447 }
448
449 String gsdl2_home = args[0];
450 File gsdl2_dir = new File(gsdl2_home);
451 if (!gsdl2_dir.isDirectory()) {
452 System.err.println("gsdl-home-dir directory does not exist!");
453 System.exit(1);
454 }
455
456 //for(int i = 0; i < args.length; i++) { System.err.println("Arg[" + i + "]: |" + args[i] + "|"); }
457
458 // for every subsequent argument, check whether we're dealing with amalgamated
459 // parameters in that argument. If so, split on whitespace and reconstruct arguments
460 for(int i = 1; i < args.length; i++) {
461
462 // if the *last* occurrence of a flag parameter is not at the start of
463 // this argument then we're dealing with amalgamated parameters in this
464 // argument. Need to split on whitespace and reconstitute the args list
465 int lastIndex = args[i].lastIndexOf("--");
466 if(lastIndex > 0) {
467
468 StringTokenizer tokenizer = new StringTokenizer(args[i]); // splits on whitespace
469 String[] tokens = new String[tokenizer.countTokens()+i];
470 int j = 0;
471 for(; j < i; j++) { // copy over previous arguments
472 tokens[j] = args[j];
473 }
474
475 // the remainder comes from the tokens
476 for(; tokenizer.hasMoreTokens(); j++) {
477 tokens[j] = tokenizer.nextToken();
478 }
479 args = null;
480 args = tokens;
481 }
482
483 }
484
485 // Defaults for optional arguments
486
487 // if no config file is given, then it defaults to llssite.cfg
488 // (embedded in quotes to preserve spaces in the filepath)
489 File defaultConfigFile = new File(gsdl2_dir, "llssite.cfg");
490 String configfile = defaultConfigFile.getAbsolutePath();
491 int port = -1;
492 String mode = "";
493 String lang = "en";
494
495 int index = 1; // move onto any subsequent arguments (past 1st GSDLHOME arg)
496 if (args.length > index && !args[index].startsWith("--")) {
497 lang = args[index]; // 2nd arg is not a flag option, so must be language
498 index++;
499 }
500
501 // Cycle through arguments, parsing and storing them
502 // note that the batch file could have split arguments in the config-
503 // filepath over several parameters. Here we join them back up again.
504 while(args.length > index) {
505
506 if(args[index].startsWith("--config=")) {
507 configfile = args[index].substring(args[index].indexOf('=')+1); // get value after '=' sign
508 gsdl2_dir = null;
509 defaultConfigFile = null;
510 }
511
512 else if(args[index].startsWith("--quitport=")) {
513 String quitport = args[index].substring(args[index].indexOf('=')+1);
514 try {
515 port = Integer.parseInt(quitport);
516 } catch(Exception e) { // parse fails
517 System.err.println("Port must be numeric. Continuing without it.");
518 }
519 }
520
521 // mode can be: "gli" if launched by GLI or unspecified. If unspecified, then
522 // the gs2-server was launched independently.
523 else if(args[index].startsWith("--mode=")) {
524 mode = args[index].substring(args[index].indexOf('=')+1);
525 }
526
527 else if(!args[index].startsWith("--")) { // assume it's part of the config file name (that this path had spaces in it)
528 configfile = configfile + " " + args[index]; // reinstate space in path
529 }
530
531 index++;
532 }
533
534 //System.err.println("\n\n*******\n\ngsdlhome: " + gsdl2_home + " | lang: " + lang + " |configfile:"
535 // + configfile + "| mode: " + mode + " | quitport: " + port + "\n\n*************\n");
536 new Server2(gsdl2_home, lang, configfile, port, mode);
537 }
538}
Note: See TracBrowser for help on using the repository browser.