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

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

When do not modify port is selected, it displays an error message and does nothing until you hit the restart button.

File size: 17.9 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 boolean 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 server_control_.errorMessage(dictionary.get("ServerSettings.SettingsUnchangedPortOccupied", new String[]{port}));
321 String errorMsg = "Unable to run the Greenstone server on port " + port + ". It appears to already be in use.";
322 System.err.println("\n******************");
323 logger_.error(errorMsg);
324 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.");
325 System.err.println("******************\n");
326
327 return false; // property change is unsuccessful
328
329 } else { // can modify port, try to find a new port
330
331 PortFinder portFinder = new PortFinder(portDefault, 101);
332 // Search for a free port silently from now on--don't want more
333 // messages saying that a port could not be found...
334 portNum = portFinder.findPortInRange(!verbose);
335
336 if (portNum == -1) {
337 // If we've still not found a free port, do we try the default port again?
338 System.err.println("No free port found. Going to try on " + portDefault + " anyway.");
339 port = Integer.toString(portDefault);
340 } else {
341 port = Integer.toString(portNum);
342 }
343 config_properties.setProperty("portnumber", port); // store the correct port
344
345 // write this updated port to the config file, since the configure target uses the file to run
346 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
347 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
348 scriptReadWrite.replaceOrAddLine(fileLines, "portnumber", port, false); // write the correct port
349 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
350
351 configure_required_ = true;
352 System.err.println("Running server on port " + port + ".");
353 }
354 }
355 }
356 } catch (Exception e) {
357 recordError("Exception in Server2.reload(): " + e.getMessage());
358 port = Integer.toString(portDefault);
359 }
360
361 return true;
362 }
363
364
365 // About to stop the webserver
366 // Custom GS2 action: remove the url property from the config file
367 protected void preStop() {
368 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
369 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
370
371 // Remove the url=... line, start searching from the end
372 boolean done = false;
373 for (int i = fileLines.size()-1; i >= 0 && !done; i--) {
374 String line = ((String) fileLines.get(i)).trim();
375 if(line.startsWith("url=")) {
376 fileLines.remove(i);
377 done = true;
378 }
379 }
380 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
381 }
382
383 // Called when the URL has been changed (called after a reload() and starting the server).
384 // By the time we get here, reload() would already have been called and have set
385 // both the port and worked out libraryURL
386 // This method needs to write the URL to the configfile since things should work
387 // like GS2's Local Lib Server for Windows
388 protected void postStart() {
389
390 URL libURL = null;
391 try {
392 libURL = new URL(libraryURL);
393 } catch (Exception e) {
394 recordError("Unable to convert library URL string into a valid URL, Server2.java." + e);
395 }
396
397 // 1. Test that the server is running at the libraryURL before writing it out to glisite.cfg/configfile
398 // A quick test involves opening a connection to get the home page for this collection
399 if(libURL != null && !libraryURL.equals(URL_PENDING)) {
400
401 boolean ready = false;
402 for(int i = 0; i < WAITING_TIME && !ready; i++) {
403 try {
404 libURL.openConnection();
405 //URLConnection connection = new URL(libraryURL).openConnection();
406 //connection.getContent();
407 ready = true;
408 recordSuccess("Try connecting to server on url: '" + libraryURL + "'");
409 } catch (IOException bad_url_connection) {
410 // keep looping
411 recordSuccess("NOT YET CONNECTED. Waiting to try again...");
412 try {
413 Thread.sleep(1000);
414 } catch (InterruptedException ie) {
415 ready = true;
416 recordError("Unexpected: got an InterruptedException in sleeping thread, Server2.java." + ie);
417 }
418 } catch (Exception e) {
419 ready = true;
420 recordError("Got an Exception while waiting for the connection to become live, Server2.java." + e);
421 }
422 }
423 }
424
425 // 2. Now write the URL to the config file
426 String port = config_properties.getProperty("portnumber");
427
428 ScriptReadWrite scriptReadWrite = new ScriptReadWrite();
429 ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file);
430 scriptReadWrite.replaceOrAddLine(fileLines, "url", libraryURL, true);
431 scriptReadWrite.replaceOrAddLine(fileLines, "portnumber", port, false); // write the correct port
432 scriptReadWrite.writeOutFile(config_properties_file, fileLines);
433 }
434
435
436 public static void main (String[] args)
437 {
438 if ((args.length < 1) || (args.length > 5)) {
439 System.err.println(
440 "Usage: java org.greenstone.server.Server2 <gsdl2-home-dir> [lang] [--mode=\"gli\"] [--config=configfile] [--quitport=portNum]");
441 System.exit(1);
442 }
443
444 String gsdl2_home = args[0];
445 File gsdl2_dir = new File(gsdl2_home);
446 if (!gsdl2_dir.isDirectory()) {
447 System.err.println("gsdl-home-dir directory does not exist!");
448 System.exit(1);
449 }
450
451 int index = 1; // move onto any subsequent arguments
452
453 // defaults for optional arguments
454 // if no config file is given, then it defaults to llssite.cfg (embedded in quotes to preserve spaces in the filepath)
455 File defaultConfigFile = new File(gsdl2_dir, "llssite.cfg");
456 String configfile = defaultConfigFile.getAbsolutePath();
457 int port = -1;
458 String mode = "";
459 String lang = "en";
460
461 // cycle through arguments, parsing and storing them
462 while(args.length > index) {
463
464 if(args[index].startsWith("--config=")) {
465 configfile = args[index].substring(args[index].indexOf('=')+1); // get value after '=' sign
466 gsdl2_dir = null;
467 defaultConfigFile = null;
468 }
469
470 else if(args[index].startsWith("--quitport=")) {
471 String quitport = args[index].substring(args[index].indexOf('=')+1);
472 try {
473 port = Integer.parseInt(quitport);
474 } catch(Exception e) { // parse fails
475 System.err.println("Port must be numeric. Continuing without it.");
476 }
477 }
478
479 // mode can be: "gli" if launched by GLI or unspecified. If unspecified, then
480 // the gs2-server was launched independently.
481 else if(args[index].startsWith("--mode=")) {
482 mode = args[index].substring(args[index].indexOf('=')+1);
483 }
484
485 else if(args[index].length() == 2) {
486 // there is an optional argument, but without a --FLAGNAME= prefix, so it's a language code
487 lang = args[index];
488 }
489
490 index++;
491 }
492
493 new Server2(gsdl2_home, lang, configfile, port, mode);
494 }
495}
Note: See TracBrowser for help on using the repository browser.