Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9AA7B9B88 for ; Thu, 5 Jan 2012 10:08:42 +0000 (UTC) Received: (qmail 85595 invoked by uid 500); 5 Jan 2012 10:08:41 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 85493 invoked by uid 500); 5 Jan 2012 10:08:28 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 85474 invoked by uid 99); 5 Jan 2012 10:08:24 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 Jan 2012 10:08:24 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 05 Jan 2012 10:08:22 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 12138238897D; Thu, 5 Jan 2012 10:08:02 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1227536 - in /sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app: ControlListener.java Main.java Date: Thu, 05 Jan 2012 10:08:01 -0000 To: commits@sling.apache.org From: cziegeler@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20120105100802.12138238897D@eris.apache.org> Author: cziegeler Date: Thu Jan 5 10:08:01 2012 New Revision: 1227536 URL: http://svn.apache.org/viewvc?rev=1227536&view=rev Log: SLING-2345 : Improve control port handling Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/ControlListener.java sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/ControlListener.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/ControlListener.java?rev=1227536&r1=1227535&r2=1227536&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/ControlListener.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/ControlListener.java Thu Jan 5 10:08:01 2012 @@ -20,8 +20,12 @@ package org.apache.sling.launchpad.app; import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; +import java.io.LineNumberReader; import java.io.OutputStreamWriter; import java.net.ConnectException; import java.net.InetAddress; @@ -68,8 +72,8 @@ class ControlListener implements Runnabl // the response sent by the server if the command executed successfully private static final String RESPONSE_OK = "OK"; - // The default port to listen on and to connect to - private static final int DEFAULT_LISTEN_PORT = 63000; + // The default port to listen on and to connect to - we select it randomly + private static final int DEFAULT_LISTEN_PORT = 0; // The reference to the Main class to shutdown on request private final Main slingMain; @@ -77,13 +81,15 @@ class ControlListener implements Runnabl // The socket address used for control communication private final SocketAddress socketAddress; + private final boolean writePortConfig; + /** * Creates an instance of this control support class. *

* The host (name or address) and port number of the socket is defined by * the listenSpec parameter. This parameter is defined as * [ host ":" ] port. If the parameter is empty or - * null it defaults to localhost:63000. If the host name + * null it defaults to localhost:0. If the host name * is missing it defaults to localhost. * * @param slingMain The Main class reference. This is only required if this @@ -91,10 +97,16 @@ class ControlListener implements Runnabl * commands. Otherwise this argument may be null. * @param listenSpec The specification for the host and port for the socket * connection. See above for the format of this parameter. + * @param selectNewPort Parameter specifying if a new port should be selected + * or if no port is specified a stored port should be + * used. */ - ControlListener(Main slingMain, String listenSpec) { + ControlListener(final Main slingMain, + final String listenSpec, + final boolean selectNewPort) { this.slingMain = slingMain; - this.socketAddress = getSocketAddress(listenSpec); + this.socketAddress = this.getSocketAddress(listenSpec, selectNewPort); + this.writePortConfig = selectNewPort; } /** @@ -103,7 +115,7 @@ class ControlListener implements Runnabl */ void listen() { if (socketAddress != null) { - Thread listener = new Thread(this); + final Thread listener = new Thread(this); listener.setDaemon(true); listener.setName("Apache Sling Control Listener@" + socketAddress); listener.start(); @@ -139,8 +151,11 @@ class ControlListener implements Runnabl try { server = new ServerSocket(); server.bind(socketAddress); - Main.info("Apache Sling Control Server started", null); - } catch (IOException ioe) { + if ( this.writePortConfig ) { + this.writePortToConfigFile(server); + } + Main.info("Apache Sling Control Server started at " + server.getInetAddress() + ":" + server.getLocalPort(), null); + } catch (final IOException ioe) { Main.error("Failed to start Sling Control Server", ioe); return; } @@ -148,9 +163,9 @@ class ControlListener implements Runnabl try { while (true) { - Socket s = server.accept(); + final Socket s = server.accept(); try { - String command = readLine(s); + final String command = readLine(s); Main.info(s.getRemoteSocketAddress() + ">" + command, null); if (COMMAND_STOP.equals(command)) { @@ -174,36 +189,37 @@ class ControlListener implements Runnabl } } } - } catch (IOException ioe) { + } catch (final IOException ioe) { Main.error("Failure reading from client", ioe); } finally { try { server.close(); - } catch (IOException ignore) { + } catch (final IOException ignore) { } } } // ---------- socket support - private SocketAddress getSocketAddress(String listenSpec) { + private SocketAddress getSocketAddress(String listenSpec, final boolean selectNewPort) { try { - if (listenSpec != null) { - int colon = listenSpec.indexOf(':'); - if (colon < 0) { - return new InetSocketAddress(InetAddress.getLocalHost(), - Integer.parseInt(listenSpec)); - } - return new InetSocketAddress(listenSpec.substring(0, colon), - Integer.parseInt(listenSpec.substring(colon + 1))); + if ( listenSpec == null && !selectNewPort ) { + listenSpec = this.readPortFromConfigFile(); } - - return new InetSocketAddress(InetAddress.getLocalHost(), - DEFAULT_LISTEN_PORT); - } catch (NumberFormatException nfe) { + if ( listenSpec == null ) { + listenSpec = InetAddress.getLocalHost().getHostName() + ':' + String.valueOf(DEFAULT_LISTEN_PORT); + } + final int colon = listenSpec.indexOf(':'); + if (colon < 0) { + return new InetSocketAddress(InetAddress.getLocalHost(), + Integer.parseInt(listenSpec)); + } + return new InetSocketAddress(listenSpec.substring(0, colon), + Integer.parseInt(listenSpec.substring(colon + 1))); + } catch (final NumberFormatException nfe) { Main.error("Cannot parse port number from '" + listenSpec + "'", null); - } catch (UnknownHostException uhe) { + } catch (final UnknownHostException uhe) { Main.error("Unknown host in '" + listenSpec + "': " + uhe.getMessage(), null); } @@ -219,21 +235,21 @@ class ControlListener implements Runnabl * * @return A code indicating success of sending the command. */ - private int sendCommand(String command) { + private int sendCommand(final String command) { if (socketAddress != null) { Socket socket = null; try { socket = new Socket(); socket.connect(socketAddress); writeLine(socket, command); - String result = readLine(socket); + final String result = readLine(socket); Main.info("Sent '" + command + "' to " + socketAddress + ": " + result, null); return 0; // LSB code for everything's fine - } catch (ConnectException ce) { + } catch (final ConnectException ce) { Main.info("No Apache Sling running at " + socketAddress, null); return 3; // LSB code for programm not running - } catch (IOException ioe) { + } catch (final IOException ioe) { Main.error("Failed sending '" + command + "' to " + socketAddress, ioe); return 1; // LSB code for programm dead @@ -245,23 +261,74 @@ class ControlListener implements Runnabl } } } - } else { - Main.info("No socket address to send '" + command + "' to", null); - return 4; // LSB code for unknown status } + Main.info("No socket address to send '" + command + "' to", null); + return 4; // LSB code for unknown status } - private String readLine(Socket socket) throws IOException { - BufferedReader br = new BufferedReader(new InputStreamReader( + private String readLine(final Socket socket) throws IOException { + final BufferedReader br = new BufferedReader(new InputStreamReader( socket.getInputStream(), "UTF-8")); return br.readLine(); } - private void writeLine(Socket socket, String line) throws IOException { - BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( + private void writeLine(final Socket socket, final String line) throws IOException { + final BufferedWriter bw = new BufferedWriter(new OutputStreamWriter( socket.getOutputStream(), "UTF-8")); bw.write(line); bw.write("\r\n"); bw.flush(); } + + /** + * Return the control port file + */ + private File getConfigFile() { + final File configDir = new File(this.slingMain.getSlingHome(), "conf"); + return new File(configDir, "controlport"); + } + + /** + * Read the port from the config file + * @return The port or null + */ + private String readPortFromConfigFile() { + final File configFile = this.getConfigFile(); + if ( configFile.canRead() ) { + FileReader fr = null; + try { + fr = new FileReader(configFile); + final LineNumberReader lnr = new LineNumberReader(fr); + return lnr.readLine(); + } catch (final IOException ignore) { + // ignore + } finally { + if ( fr != null ) { + try { fr.close(); } catch ( final IOException ignore ) {} + } + } + + } + return null; + } + + private void writePortToConfigFile(final ServerSocket socket) { + final File configFile = this.getConfigFile(); + configFile.getParentFile().mkdirs(); + FileWriter fw = null; + try { + fw = new FileWriter(configFile); + fw.write(socket.getInetAddress().getHostName()); + fw.write(':'); + fw.write(String.valueOf(socket.getLocalPort())); + fw.write('\n'); + } catch (final IOException ignore) { + // ignore + } finally { + if ( fw != null ) { + try { fw.close(); } catch ( final IOException ignore ) {} + } + } + + } } Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java?rev=1227536&r1=1227535&r2=1227536&view=diff ============================================================================== --- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java (original) +++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/app/Main.java Thu Jan 5 10:08:01 2012 @@ -87,7 +87,7 @@ public class Main { * @param args The command line arguments supplied when starting the Sling * Launcher through the Java VM. */ - public static void main(String[] args) { + public static void main(final String[] args) { final Map rawArgs = parseCommandLine(args); // support usage first @@ -100,7 +100,7 @@ public class Main { System.exit(1); } - Main main = new Main(props); + final Main main = new Main(props); // check for control commands int rc = main.doControlAction(); @@ -136,7 +136,7 @@ public class Main { * * @see #getSlingHome(Map) */ - private String slingHome; + private final String slingHome; /** * The {@link Loader} class used to create the Framework class loader and @@ -151,6 +151,11 @@ public class Main { private Launcher sling; /** + * Flag to indicate if Sling has already been started. + */ + private boolean started = false; + + /** * Creates an instance of this main loader class. The provided arguments are * used to configure the OSGi framework being launched with the * {@link #startSling(URL)} method. @@ -165,6 +170,13 @@ public class Main { this.commandLineArgs = (args == null) ? new HashMap() : args; + // sling.home from the command line or system properties, else default + String home = getSlingHome(commandLineArgs); + final File slingHomeFile = new File(home); + if (!slingHomeFile.isAbsolute()) { + home = slingHomeFile.getAbsolutePath(); + } + this.slingHome = home; } /** @@ -225,10 +237,10 @@ public class Main { * (Programm Not Running), 4 (Unknown Problem). */ protected int doControlAction() { - ControlAction action = getControlAction(); + final ControlAction action = getControlAction(); if (action != null) { - ControlListener sl = new ControlListener(this, - commandLineArgs.remove(PROP_CONTROL_SOCKET)); + final ControlListener sl = new ControlListener(this, + commandLineArgs.remove(PROP_CONTROL_SOCKET), action == ControlAction.START); switch (action) { case START: sl.listen(); @@ -238,8 +250,6 @@ public class Main { case STOP: sl.shutdownServer(); return 0; - default: - error("Unsupported control action: " + action, null); } } @@ -276,19 +286,13 @@ public class Main { protected boolean doStart() { // prevent duplicate start - if (this.slingHome != null) { + if ( this.started) { info("Apache Sling has already been started", null); return true; } - // sling.home from the command line or system properties, else default - String slingHome = getSlingHome(commandLineArgs); - File slingHomeFile = new File(slingHome); - if (!slingHomeFile.isAbsolute()) { - slingHome = slingHomeFile.getAbsolutePath(); - } info("Starting Apache Sling in " + slingHome, null); - this.slingHome = slingHome; + this.started = true; // The Loader helper Loader loaderTmp = null; @@ -412,7 +416,7 @@ public class Main { } // further cleanup - this.slingHome = null; + this.started = false; } /** @@ -464,6 +468,13 @@ public class Main { } /** + * Return the absolute path to sling home + */ + public String getSlingHome() { + return this.slingHome; + } + + /** * Define the sling.launchpad parameter implementing the algorithme defined * on the wiki page to find the setting according to this algorithm: *

    @@ -480,7 +491,7 @@ public class Main { */ private static File getLaunchpadHome(final String slingHome, final Map commandLineArgs) { - String launchpadHomeParam = commandLineArgs.get(SharedConstants.SLING_LAUNCHPAD); + final String launchpadHomeParam = commandLineArgs.get(SharedConstants.SLING_LAUNCHPAD); if (launchpadHomeParam == null || launchpadHomeParam.length() == 0) { commandLineArgs.put(SharedConstants.SLING_LAUNCHPAD, slingHome); return new File(slingHome);