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

Last change on this file since 25952 was 25952, checked in by ak19, 12 years ago

Because gsdl3.home (web home) is no longer a property in global.properties, the server.log file was not being found and initialised on time. It is now explicitly being initialised in Server3.java, as was already happening for Server2.java as well.

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