package org.greenstone.server; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.URL; //import java.net.URLConnection; import java.util.Properties; import java.util.ArrayList; import org.apache.log4j.*; import org.greenstone.server.BaseServer; import org.greenstone.server.BaseProperty; public class Server2 extends BaseServer { private static final int WAITING_TIME = 60; // time to wait and check for whether the server is running protected String libraryURL; private class QuitListener extends Thread { int quitPort = -1; ServerSocket serverSocket = null; public QuitListener(int quitport) throws Exception { ///Server2.this.recordSuccess("In QuitListener constructor"); this.quitPort = quitport; serverSocket = new ServerSocket(quitPort); } public void run() { Socket connection = null; try { // wait for a connection connection = serverSocket.accept(); // read input try { BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line = null; if((line = reader.readLine()) != null) { if(line.equals("QUIT")) { // Server2.this.recordSuccess("In QuitListener - line is QUIT"); reader.close(); reader = null; serverSocket.close(); serverSocket = null; } } } catch(Exception e) { Server2.this.recordError("Exception in QuitListener thread."); } finally { Server2.this.stop(); System.exit(0); } } catch(IOException ioe) { Server2.this.recordError("Server2.QuitListener: Unable to make the connection with the client socket." + ioe); } } } public Server2(String gsdl2_home, String lang, String configfile, int quitPort) { super(gsdl2_home, lang, configfile, "etc"+File.separator+"logs-gsi"); // configfile can be either glisite.cfg or llssite.cfg Property = new Server2Property(); String frame_title = dictionary.get("ServerControl.Frame_Title"); server_control_ = new Server2Control(this,frame_title); /* Make command tagets for managing Web server */ START_CMD = "web-start"; RESTART_CMD = "web-restart"; CONFIGURE_CMD = "configure-web " + configfile; STOP_CMD = "web-stop"; // now we can monitor for the quit command if applicable if(quitPort != -1) { // First check if given port is within the range of allowed ports if(PortFinder.isAssignablePortNumber(quitPort)) { try { new QuitListener(quitPort).start(); } catch(Exception e) { Server2.this.recordError("Exception constructing the QuitListener thread."); } } else { recordError("QuitPort provided is not within acceptable range: (" + PortFinder.PORTS_RESERVED + " - " + PortFinder.MAX_PORT + "]" ); quitPort = -1; } } autoStart(); } // Prepare the log4j.properties for GS2 protected void initLogger() { String libjavaFolder = gsdl_home+File.separator+"lib"+File.separator+"java"+File.separator; File propsFile = new File(libjavaFolder+"log4j.properties"); // create it from the template file log4j.properties.in if(!propsFile.exists()) { try { // need to set gsdl2.home property's value to be gsdl_home, // so that the location of the log files gets resolved correctly // load the template log4j.properties.in file into logProps FileInputStream infile = new FileInputStream(new File(libjavaFolder+"log4j.properties.in")); if(infile != null) { Properties logProps = new Properties(); logProps.load(infile); infile.close(); // set gsdl3.home to gsdl_home logProps.setProperty("gsdl2.home", gsdl_home); // write the customised properties out to a custom log4j.properties file FileOutputStream outfile = new FileOutputStream(propsFile); if(outfile != null) { logProps.store(outfile, "Customised log4j.properties file"); outfile.close(); } else { System.err.println("Could not store properties file " + propsFile + " for Server2."); } } } catch(Exception e) { System.err.println("Exception occurred when custom-configuring the logger for Server2.\n" + e); } } // now configure the logger with the custom log4j.properties file if(propsFile.exists()) { PropertyConfigurator.configure(propsFile.getAbsolutePath()); } else { System.err.println("Could not create properties file " + propsFile + " for Server2."); } } protected int runTarget(String cmd) { RunMake runMake = new RunMake(); runMake.setTargetCmd(cmd); runMake.run(); return runMake.getTargetState(); } public String getBrowserURL() { return libraryURL; } // works out the library URL again public void reload() { // default values, to be replaced with what's in gsdlsite.cfg String host = "localhost"; String port = "80"; String gwcgi; String httpprefix = "greenstone"; String suffix = "/cgi-bin/library.cgi"; // get the prefix from the gsdlsite.cfg and build.properties files // (port number and servername) try{ File gsdlsite_cfg = new File(gsdl_home + File.separator + "cgi-bin" + File.separator + "gsdlsite.cfg"); FileInputStream fin = new FileInputStream(gsdlsite_cfg); Properties gsdlProperties = new Properties(); if(fin != null) { gsdlProperties.load(fin); gwcgi = gsdlProperties.getProperty("gwcgi"); if(gwcgi != null) { suffix = gwcgi; } else { httpprefix = gsdlProperties.getProperty("httpprefix", httpprefix); suffix = httpprefix + suffix; } fin.close(); } else { recordError("Could not open gsdlsite_cfg for reading, using default library prefix."); } //reloadConfigProperties(); port = config_properties.getProperty("portnumber", port); } catch(Exception e) { recordError("Exception trying to load properties from gsdlsite_cfg. Using default library prefix.", e); suffix = httpprefix + suffix; } libraryURL = "http://" + host + ":" + port + suffix; } public void reloadConfigProperties() { super.reloadConfigProperties(); // make sure the port is okay, otherwise find another port // first choice is port 80, second choice starts at 8282 String port = config_properties.getProperty("portnumber", "80"); int portDefault = 8282; try { int portNum = Integer.parseInt(port); if(!PortFinder.isPortAvailable(portNum)) { PortFinder portFinder = new PortFinder(portDefault, 101); portNum = portFinder.findPortInRange(); port = (portNum == -1) ? Integer.toString(portDefault) : Integer.toString(portNum); config_properties.setProperty("portnumber", port); // store the correct port // write this updated port to the config file, since the configure target uses the file to run ScriptReadWrite scriptReadWrite = new ScriptReadWrite(); ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file); scriptReadWrite.replaceOrAddLine(fileLines, "portnumber", port, false); // write the correct port scriptReadWrite.writeOutFile(config_properties_file, fileLines); configure_required_ = true; } } catch (Exception e) { recordError("Exception in Server2.reload(): " + e.getMessage()); port = Integer.toString(portDefault); } } // About to stop the webserver // Custom GS2 action: remove the url property from the config file protected void preStop() { ScriptReadWrite scriptReadWrite = new ScriptReadWrite(); ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file); if (fileLines.contains("url="+getBrowserURL())) { // would be last element, remove it: fileLines.remove(fileLines.size()-1); } scriptReadWrite.writeOutFile(config_properties_file, fileLines); } // Called when the URL has been changed (called after a reload() and starting the server). // By the time we get here, reload() would already have been called and have set // both the port and worked out libraryURL // This method needs to write the URL to the configfile since things should work // like GS2's Local Lib Server for Windows protected void postStart() { URL libURL = null; try { libURL = new URL(libraryURL); } catch (Exception e) { recordError("Unable to convert library URL string into a valid URL, Server2.java." + e); } // 1. Test that the server is running at the libraryURL before writing it out to glisite.cfg/configfile // A quick test involves opening a connection to get the home page for this collection if(libURL != null) { boolean ready = false; for(int i = 0; i < WAITING_TIME && !ready; i++) { try { libURL.openConnection(); //URLConnection connection = new URL(libraryURL).openConnection(); //connection.getContent(); ready = true; recordSuccess("Try connecting to server on url: '" + libraryURL + "'"); } catch (IOException bad_url_connection) { // keep looping recordSuccess("NOT YET CONNECTED. Waiting to try again..."); try { Thread.sleep(1000); } catch (InterruptedException ie) { ready = true; recordError("Unexpected: got an InterruptedException in sleeping thread, Server2.java." + ie); } } catch (Exception e) { ready = true; recordError("Got an Exception while waiting for the connection to become live, Server2.java." + e); } } } // 2. Now write the URL to the config file String port = config_properties.getProperty("portnumber"); ScriptReadWrite scriptReadWrite = new ScriptReadWrite(); ArrayList fileLines = scriptReadWrite.readInFile(BaseServer.config_properties_file); scriptReadWrite.replaceOrAddLine(fileLines, "url", libraryURL, true); scriptReadWrite.replaceOrAddLine(fileLines, "portnumber", port, false); // write the correct port scriptReadWrite.writeOutFile(config_properties_file, fileLines); } public static void main (String[] args) { if ((args.length < 1) || (args.length > 4)) { System.err.println( "Usage: java org.greenstone.server.Server2 [lang] [--config=configfile] [--quitport=portNum]"); System.exit(1); } String gsdl2_home = args[0]; File gsdl2_dir = new File(gsdl2_home); if (!gsdl2_dir.isDirectory()) { System.err.println("gsdl-home-dir directory does not exist!"); System.exit(1); } String lang = (args.length>=2) ? args[1] : "en"; // if no config file is given, then the following defaults to llssite.cfg String configfile = (args.length>=3 && args[2].startsWith("--config=")) ? args[2] : gsdl2_home+File.separator+"llssite.cfg"; int equalSign = configfile.indexOf('='); if(equalSign != -1) { configfile = configfile.substring(equalSign+1); } String quitport = (args.length == 4 && args[3].startsWith("--quitport=")) ? args[3] : ""; equalSign = quitport.indexOf('='); int port = -1; if(equalSign != -1) { try { quitport = quitport.substring(equalSign+1); port = Integer.parseInt(quitport); } catch(Exception e) { // parse fails System.err.println("Port must be numeric. Continuing without it."); } } //System.err.println("Running server with config file: " + configfile); new Server2(gsdl2_home, lang, configfile, port); } }