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

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

Part 1 of 2 commits for ticket 766 (the other commits will be in GS2): the GSI settings dialog now provides the ability to freeze the port number.

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