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

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

Server2 now takes an additional parameter -mode, which can be 'gli' and represents the property prefix to use when looking for autoenter and start_browser properties in the config file. The way the arguments to Server2 are processed has also been changed, so that it is no longer dependent on order.

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