incubator-sling-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From fmesc...@apache.org
Subject svn commit: r1332702 - in /sling/trunk/launchpad/base/src: main/java/org/apache/sling/launchpad/app/ControlListener.java main/java/org/apache/sling/launchpad/app/Main.java test/java/org/apache/sling/launchpad/app/ControlListenerTest.java
Date Tue, 01 May 2012 15:34:50 GMT
Author: fmeschbe
Date: Tue May  1 15:34:50 2012
New Revision: 1332702

URL: http://svn.apache.org/viewvc?rev=1332702&view=rev
Log:
Add unit tests for ControlListener

Added:
    sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/ControlListenerTest.java
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=1332702&r1=1332701&r2=1332702&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
Tue May  1 15:34:50 2012
@@ -31,7 +31,7 @@ import java.net.ConnectException;
 import java.net.InetSocketAddress;
 import java.net.ServerSocket;
 import java.net.Socket;
-import java.net.SocketAddress;
+import java.util.Random;
 
 /**
  * The <code>ControlListener</code> class is a helper class for the {@link Main}
@@ -79,10 +79,10 @@ class ControlListener implements Runnabl
     // The reference to the Main class to shutdown on request
     private final Main slingMain;
 
-    // The socket address used for control communication
-    private final SocketAddress socketAddress;
+    private final String listenSpec;
 
-    private final boolean writePortConfig;
+    private String secretKey;
+    private InetSocketAddress socketAddress;
 
     /**
      * Creates an instance of this control support class.
@@ -98,39 +98,38 @@ class ControlListener implements Runnabl
      *            commands. Otherwise this argument may be <code>null</code>.
      * @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(final Main slingMain,
-                    final String listenSpec,
-                    final boolean selectNewPort) {
+    ControlListener(final Main slingMain, final String listenSpec) {
         this.slingMain = slingMain;
-        this.socketAddress = this.getSocketAddress(listenSpec, selectNewPort);
-        this.writePortConfig = selectNewPort;
+        this.listenSpec = listenSpec; // socketAddress = this.getSocketAddress(listenSpec,
selectNewPort);
     }
 
     /**
      * Implements the server side of the control connection starting a thread
      * listening on the host and port configured on setup of this instance.
      */
-    void listen() {
-        if (socketAddress != null) {
-            final Thread listener = new Thread(this);
-            listener.setDaemon(true);
-            listener.setName("Apache Sling Control Listener@" + socketAddress);
-            listener.start();
-        } else {
-            Main.info("No socket address to listen to", null);
+    boolean listen() {
+        final File configFile = getConfigFile();
+        if (configFile.canRead() && statusServer() == 0) {
+            // server already running, fail
+            Main.error("Sling already active in " + this.slingMain.getSlingHome(), null);
+            return false;
         }
+        configFile.delete();
+
+        final Thread listener = new Thread(this);
+        listener.setDaemon(true);
+        listener.setName("Apache Sling Control Listener (inactive)");
+        listener.start();
+        return true;
     }
 
     /**
      * Implements the client side of the control connection sending the command
      * to shutdown Sling.
      */
-    void shutdownServer() {
-        sendCommand(COMMAND_STOP);
+    int shutdownServer() {
+        return sendCommand(COMMAND_STOP);
     }
 
     /**
@@ -148,34 +147,71 @@ class ControlListener implements Runnabl
      * upon them.
      */
     public void run() {
+        this.configure(false);
+
         ServerSocket server = null;
         try {
             server = new ServerSocket();
-            server.bind(socketAddress);
-            if ( this.writePortConfig ) {
-                this.writePortToConfigFile(server);
-            }
-            Main.info("Apache Sling Control Server started at " + server.getInetAddress()
+ ":" + server.getLocalPort(), null);
+            server.bind(this.socketAddress);
+            writePortToConfigFile(getConfigFile(),
+                new InetSocketAddress(server.getInetAddress(), server.getLocalPort()), this.secretKey);
+            Thread.currentThread().setName(
+                "Apache Sling Control Listener@" + server.getInetAddress() + ":" + server.getLocalPort());
+            Main.info("Apache Sling Control Listener started", null);
         } catch (final IOException ioe) {
-            Main.error("Failed to start Sling Control Server", ioe);
+            Main.error("Failed to start Apache Sling Control Listener", ioe);
             return;
         }
 
+        long delay = 0;
+
         try {
             while (true) {
 
                 final Socket s = server.accept();
+
+                // delay processing after unsuccessfull attempts
+                if (delay > 0) {
+                    Main.info(s.getRemoteSocketAddress() + ": Delay: " + (delay / 1000),
null);
+                    try {
+                        Thread.sleep(delay);
+                    } catch (InterruptedException e) {
+                    }
+                }
+
                 try {
-                    final String command = readLine(s);
+                    final String commandLine = readLine(s);
+                    if (commandLine == null) {
+                        final String msg = "ERR: missing command";
+                        Main.info(s.getRemoteSocketAddress() + "<" + msg, null);
+                        writeLine(s, msg);
+                        continue;
+                    }
+
+                    final int blank = commandLine.indexOf(' ');
+                    if (blank < 0) {
+                        final String msg = "ERR: missing key";
+                        Main.info(s.getRemoteSocketAddress() + "<" + msg, null);
+                        writeLine(s, msg);
+                        continue;
+                    }
+
+                    if (!secretKey.equals(commandLine.substring(0, blank))) {
+                        final String msg = "ERR: wrong key";
+                        Main.info(s.getRemoteSocketAddress() + "<" + msg, null);
+                        writeLine(s, msg);
+                        delay = (delay > 0) ? delay * 2 : 1000L;
+                        continue;
+                    }
+
+                    final String command = commandLine.substring(blank + 1);
                     Main.info(s.getRemoteSocketAddress() + ">" + command, null);
 
                     if (COMMAND_STOP.equals(command)) {
                         slingMain.doStop();
                         Main.info(s.getRemoteSocketAddress() + "<" + RESPONSE_OK, null);
                         writeLine(s, RESPONSE_OK);
-
-                        Main.info("Apache Sling shut down, exiting Java VM", null);
-                        System.exit(0);
+                        break;
 
                     } else if (COMMAND_STATUS.equals(command)) {
                         Main.info(s.getRemoteSocketAddress() + "<" + RESPONSE_OK, null);
@@ -202,37 +238,18 @@ class ControlListener implements Runnabl
             } catch (final IOException ignore) {
             }
         }
+
+        getConfigFile().delete();
+
+        // everything has stopped and when this thread terminates,
+        // the VM should stop. If there are still some non-daemon threads
+        // active, this will not happen, so we force this here ...
+        Main.info("Apache Sling terminated, exiting Java VM", null);
+        slingMain.terminateVM(0);
     }
 
     // ---------- socket support
 
-    private SocketAddress getSocketAddress(String listenSpec, final boolean selectNewPort)
{
-        try {
-            if ( listenSpec == null && !selectNewPort ) {
-                listenSpec = this.readPortFromConfigFile();
-            }
-            if ( listenSpec == null ) {
-                listenSpec = DEFAULT_LISTEN_INTERFACE + ":" + DEFAULT_LISTEN_PORT;
-            }
-            final int colon = listenSpec.indexOf(':');
-            final InetSocketAddress addr;
-            if (colon < 0) {
-                addr = new InetSocketAddress(DEFAULT_LISTEN_INTERFACE, Integer.parseInt(listenSpec));
-            } else {
-                addr = new InetSocketAddress(listenSpec.substring(0, colon),
-                    Integer.parseInt(listenSpec.substring(colon + 1)));
-            }
-            if (!addr.isUnresolved()) {
-                return addr;
-            }
-            Main.error("Unknown host in '" + listenSpec, null);
-        } catch (final NumberFormatException nfe) {
-            Main.error("Cannot parse port number from '" + listenSpec + "'",
-                null);
-        }
-
-        return null;
-    }
 
 
     /**
@@ -244,22 +261,25 @@ class ControlListener implements Runnabl
      * @return A code indicating success of sending the command.
      */
     private int sendCommand(final String command) {
-        if (socketAddress != null) {
+        if (configure(true)) {
+            if (this.secretKey == null) {
+                Main.info("Missing secret key to protect sending '" + command + "' to " +
this.socketAddress, null);
+                return 4; // LSB code for unknown status
+            }
+
             Socket socket = null;
             try {
                 socket = new Socket();
-                socket.connect(socketAddress);
-                writeLine(socket, command);
+                socket.connect(this.socketAddress);
+                writeLine(socket, this.secretKey + " " + command);
                 final String result = readLine(socket);
-                Main.info("Sent '" + command + "' to " + socketAddress + ": "
-                    + result, null);
+                Main.info("Sent '" + command + "' to " + this.socketAddress + ": " + result,
null);
                 return 0; // LSB code for everything's fine
             } catch (final ConnectException ce) {
-                Main.info("No Apache Sling running at " + socketAddress, null);
+                Main.info("No Apache Sling running at " + this.socketAddress, null);
                 return 3; // LSB code for programm not running
             } catch (final IOException ioe) {
-                Main.error("Failed sending '" + command + "' to "
-                    + socketAddress, ioe);
+                Main.error("Failed sending '" + command + "' to " + this.socketAddress, ioe);
                 return 1; // LSB code for programm dead
             } finally {
                 if (socket != null) {
@@ -289,6 +309,53 @@ class ControlListener implements Runnabl
     }
 
     /**
+     * Read the port from the config file
+     * @return The port or null
+     */
+    private boolean configure(final boolean fromConfigFile) {
+        boolean result = false;
+        if (fromConfigFile) {
+            final File configFile = this.getConfigFile();
+            if (configFile.canRead()) {
+                FileReader fr = null;
+                try {
+                    fr = new FileReader(configFile);
+                    final LineNumberReader lnr = new LineNumberReader(fr);
+                    this.socketAddress = getSocketAddress(lnr.readLine());
+                    this.secretKey = lnr.readLine();
+                    result = true;
+                } catch (final IOException ignore) {
+                    // ignore
+                } finally {
+                    if (fr != null) {
+                        try {
+                            fr.close();
+                        } catch (final IOException ignore) {
+                        }
+                    }
+                }
+            }
+        } else {
+            this.socketAddress = getSocketAddress(this.listenSpec);
+            this.secretKey = generateKey();
+            result = true;
+        }
+
+        return result;
+    }
+
+    private static String generateKey() {
+        String keys = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789";
+        int len = keys.length();
+        Random r = new Random(System.currentTimeMillis() + 33 * System.nanoTime());
+        char[] c = new char[32];
+        for (int i = 0; i < c.length; i++) {
+            c[i] = keys.charAt(r.nextInt(len));
+        }
+        return new String(c);
+    }
+
+    /**
      * Return the control port file
      */
     private File getConfigFile() {
@@ -296,47 +363,60 @@ class ControlListener implements Runnabl
         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 ) {}
+    private static InetSocketAddress getSocketAddress(String listenSpec) {
+        try {
+
+            final String address;
+            final int port;
+            if (listenSpec == null) {
+                address = DEFAULT_LISTEN_INTERFACE;
+                port = DEFAULT_LISTEN_PORT;
+            } else {
+                final int colon = listenSpec.indexOf(':');
+                if (colon < 0) {
+                    address = DEFAULT_LISTEN_INTERFACE;
+                    port = Integer.parseInt(listenSpec);
+                } else {
+                    address = listenSpec.substring(0, colon);
+                    port = Integer.parseInt(listenSpec.substring(colon + 1));
                 }
             }
 
+            final InetSocketAddress addr = new InetSocketAddress(address, port);
+            if (!addr.isUnresolved()) {
+                return addr;
+            }
+
+            Main.error("Unknown host in '" + listenSpec, null);
+        } catch (final NumberFormatException nfe) {
+            Main.error("Cannot parse port number from '" + listenSpec + "'",
+                null);
         }
+
         return null;
     }
 
-    private void writePortToConfigFile(final ServerSocket socket) {
-        final File configFile = this.getConfigFile();
+    private static void writePortToConfigFile(final File configFile, final InetSocketAddress
socketAddress,
+            final String secretKey) {
         configFile.getParentFile().mkdirs();
         FileWriter fw = null;
         try {
             fw = new FileWriter(configFile);
-            fw.write(socket.getInetAddress().getHostName());
+            fw.write(socketAddress.getAddress().getHostAddress());
             fw.write(':');
-            fw.write(String.valueOf(socket.getLocalPort()));
+            fw.write(String.valueOf(socketAddress.getPort()));
+            fw.write('\n');
+            fw.write(secretKey);
             fw.write('\n');
         } catch (final IOException ignore) {
             // ignore
         } finally {
-            if ( fw != null ) {
-                try { fw.close(); } catch ( final IOException ignore ) {}
+            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=1332702&r1=1332701&r2=1332702&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 Tue
May  1 15:34:50 2012
@@ -116,7 +116,7 @@ public class Main {
         // check for control commands
         int rc = main.doControlAction();
         if (rc >= 0) {
-            System.exit(rc);
+            main.terminateVM(rc);
         }
 
         // finally start Sling
@@ -242,31 +242,49 @@ public class Main {
      *         continue as intended, maybe starting the Sling Application. This
      *         code is returned if the start action (or no action at all) is
      *         supplied. Otherwise the VM should terminate with the returned
-     *         code as its exit code. For the stop action, this will be zero. For
-     *         the status action, this will be a LSB compliant code for daemon
-     *         status check: 0 (application running), 1 (Programm Dead), 3
-     *         (Programm Not Running), 4 (Unknown Problem).
+     *         code as its exit code. For the stop action, this will be zero.
+     *         For the status action, this will be a LSB compliant code for
+     *         daemon status check: 0 (application running), 1 (Programm Dead),
+     *         3 (Programm Not Running), 4 (Unknown Problem).
+     * @see <a
+     *      href="http://refspecs.linuxbase.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html">Init
Script Actions</a>
+     *      for a definition of the LSB status codes
      */
     protected int doControlAction() {
         final ControlAction action = getControlAction();
         if (action != null) {
             final ControlListener sl = new ControlListener(this,
-                commandLineArgs.remove(PROP_CONTROL_SOCKET), action == ControlAction.START);
+                commandLineArgs.remove(PROP_CONTROL_SOCKET));
             switch (action) {
                 case START:
-                    sl.listen();
+                    if (!sl.listen()) {
+                        // assume service already running
+                        return 0;
+                    }
                     break;
                 case STATUS:
                     return sl.statusServer();
                 case STOP:
-                    sl.shutdownServer();
-                    return 0;
+                    return sl.shutdownServer();
             }
         }
 
         return -1;
     }
 
+    /**
+     * Terminates the VM which was started by calling the
+     * {@link #main(String[])} method of this class using the
+     * <code>status</code> value as the application exit status code.
+     * <p>
+     * This method does not return.
+     *
+     * @param status The application status exit code.
+     */
+    void terminateVM(final int status) {
+        System.exit(status);
+    }
+
     private ControlAction getControlAction() {
         Object action = this.commandLineArgs.remove(PROP_CONTROL_ACTION);
         if (action != null) {
@@ -434,7 +452,7 @@ public class Main {
      * Define the sling.home parameter implementing the algorithme defined on
      * the wiki page to find the setting according to this algorithm:
      * <ol>
-     * <li>Command line option <code>-c</code></li>
+     * <li>Configuration property <code>sling.home</code></li>
      * <li>System property <code>sling.home</code></li>
      * <li>Environment variable <code>SLING_HOME</code></li>
      * <li>Default value <code>sling</code></li>
@@ -629,7 +647,7 @@ public class Main {
             System.out.println("    start         listen for control connection (uses -j)");
             System.out.println("    stop          terminate running Apache Sling (uses -j)");
             System.out.println("    status        check whether Apache Sling is running (uses
-j)");
-            System.out.println("    -j adr        host and port to use for control connection
in the format '[host:]port' (default localhost:63000)");
+            System.out.println("    -j adr        host and port to use for control connection
in the format '[host:]port' (default 127.0.0.1:0)");
             System.out.println("    -l loglevel   the initial loglevel (0..4, FATAL, ERROR,
WARN, INFO, DEBUG)");
             System.out.println("    -f logfile    the log file, \"-\" for stdout (default
logs/error.log)");
             System.out.println("    -c slinghome  the sling context directory (default sling)");

Added: sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/ControlListenerTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/ControlListenerTest.java?rev=1332702&view=auto
==============================================================================
--- sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/ControlListenerTest.java
(added)
+++ sling/trunk/launchpad/base/src/test/java/org/apache/sling/launchpad/app/ControlListenerTest.java
Tue May  1 15:34:50 2012
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.launchpad.app;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.util.HashMap;
+
+import junit.framework.TestCase;
+
+import org.apache.sling.launchpad.base.shared.SharedConstants;
+
+public class ControlListenerTest extends TestCase {
+
+    private static String SLING1 = "target/sling.test/1";
+
+    private static String SLING2 = "target/sling.test/2";
+
+    private static String CTL = "conf/controlport";
+
+    private final File ctlFile1 = new File(SLING1, CTL);
+
+    private final File ctlFile2 = new File(SLING2, CTL);
+
+    @Override
+    protected void tearDown() throws Exception {
+        ctlFile1.delete();
+        ctlFile2.delete();
+
+        super.tearDown();
+    }
+
+    public void test_start_status_stop() {
+        int port = getPort();
+        MyMain main = new MyMain(SLING1);
+
+        ControlListener cl = new ControlListener(main, String.valueOf(port));
+        TestCase.assertTrue(cl.listen());
+        delay(); // wait for sever to start
+
+        TestCase.assertTrue(ctlFile1.canRead());
+
+        TestCase.assertEquals(0, new ControlListener(main, null).statusServer());
+
+        TestCase.assertEquals(0, new ControlListener(main, null).shutdownServer());
+
+        TestCase.assertTrue(main.stopCalled);
+
+        delay();
+        TestCase.assertFalse(ctlFile1.exists());
+    }
+
+    public void test_parallel_start_status_stop() {
+        int port1 = getPort();
+        MyMain main1 = new MyMain(SLING1);
+        ControlListener server1 = new ControlListener(main1, String.valueOf(port1));
+        TestCase.assertTrue(server1.listen());
+        delay(); // wait for sever to start
+
+        int port2 = getPort();
+        MyMain main2 = new MyMain(SLING2);
+        ControlListener server2 = new ControlListener(main2, String.valueOf(port2));
+        TestCase.assertTrue(server2.listen());
+        delay(); // wait for sever to start
+
+        TestCase.assertTrue(ctlFile1.canRead());
+        TestCase.assertTrue(ctlFile2.canRead());
+
+        TestCase.assertEquals(0, new ControlListener(main1, null).statusServer());
+        TestCase.assertEquals(0, new ControlListener(main1, null).shutdownServer());
+
+        TestCase.assertEquals(0, new ControlListener(main2, null).statusServer());
+        TestCase.assertEquals(0, new ControlListener(main2, null).shutdownServer());
+
+        TestCase.assertTrue(main1.stopCalled);
+        TestCase.assertTrue(main2.stopCalled);
+
+        delay();
+        TestCase.assertFalse(ctlFile1.exists());
+        TestCase.assertFalse(ctlFile2.exists());
+    }
+
+    public void test_no_start_in_same_sling_home() {
+        int port1 = getPort();
+        MyMain main1 = new MyMain(SLING1);
+        ControlListener server1 = new ControlListener(main1, String.valueOf(port1));
+        TestCase.assertTrue(server1.listen());
+        delay(); // wait for sever to start
+
+        int port2 = getPort();
+        MyMain main2 = new MyMain(SLING1);
+        ControlListener server2 = new ControlListener(main2, String.valueOf(port2));
+        TestCase.assertFalse(server2.listen());
+        delay(); // wait for sever to start
+
+        TestCase.assertTrue(ctlFile1.canRead());
+        TestCase.assertFalse(ctlFile2.canRead());
+
+        TestCase.assertEquals(0, new ControlListener(main1, null).statusServer());
+        TestCase.assertEquals(0, new ControlListener(main1, null).shutdownServer());
+
+        TestCase.assertTrue(main1.stopCalled);
+
+        delay();
+        TestCase.assertFalse(ctlFile1.exists());
+
+        // retry cl2
+        TestCase.assertTrue(server2.listen());
+        delay(); // wait for sever to start
+
+        TestCase.assertEquals(0, new ControlListener(main2, null).statusServer());
+        TestCase.assertEquals(0, new ControlListener(main2, null).shutdownServer());
+
+        TestCase.assertTrue(main2.stopCalled);
+
+        delay();
+        TestCase.assertFalse(ctlFile2.exists());
+    }
+
+    public void test_no_status() throws IOException {
+        int port = getPort();
+        MyMain main = new MyMain(SLING1);
+
+        TestCase.assertFalse(ctlFile1.exists());
+        ctlFile1.getParentFile().mkdirs();
+        FileOutputStream out = new FileOutputStream(ctlFile1);
+        PrintWriter pw = new PrintWriter(out);
+        pw.println("127.0.0.1:" + port);
+        pw.println("password");
+        pw.close();
+
+        TestCase.assertTrue(new File(SLING1, CTL).canRead());
+
+        TestCase.assertEquals(3, new ControlListener(main, null).statusServer());
+
+        TestCase.assertEquals(3, new ControlListener(main, null).shutdownServer());
+
+        TestCase.assertFalse(main.stopCalled);
+
+        TestCase.assertTrue(ctlFile1.exists());
+    }
+
+    public void test_no_configuration_for_status() {
+        int port = getPort();
+        MyMain main = new MyMain(SLING1);
+
+        TestCase.assertFalse(ctlFile1.exists());
+
+        TestCase.assertEquals(4, new ControlListener(main, String.valueOf(port)).statusServer());
+
+        TestCase.assertEquals(4, new ControlListener(main, String.valueOf(port)).shutdownServer());
+
+        TestCase.assertFalse(main.stopCalled);
+
+        TestCase.assertFalse(ctlFile1.exists());
+    }
+
+    public void test_no_key_for_status() throws IOException {
+        int port = getPort();
+        MyMain main = new MyMain(SLING1);
+
+        TestCase.assertFalse(ctlFile1.exists());
+        ctlFile1.getParentFile().mkdirs();
+        FileOutputStream out = new FileOutputStream(ctlFile1);
+        PrintWriter pw = new PrintWriter(out);
+        pw.println("127.0.0.1:" + port);
+        pw.close();
+
+        TestCase.assertTrue(new File(SLING1, CTL).canRead());
+
+        TestCase.assertEquals(4, new ControlListener(main, null).statusServer());
+
+        TestCase.assertEquals(4, new ControlListener(main, null).shutdownServer());
+
+        TestCase.assertFalse(main.stopCalled);
+
+        TestCase.assertTrue(ctlFile1.exists());
+    }
+
+    private int getPort() {
+        ServerSocket s = null;
+        try {
+            s = new ServerSocket(0);
+            return s.getLocalPort();
+        } catch (IOException ignore) {
+        } finally {
+            if (s != null) {
+                try {
+                    s.close();
+                } catch (IOException i2) {
+                }
+            }
+        }
+
+        TestCase.fail("Cannot acquire port");
+        return 0; // compiler satisfaction
+    }
+
+    private void delay() {
+        try {
+            Thread.sleep(200);
+        } catch (InterruptedException ie) {
+        }
+    }
+
+    private static class MyMain extends Main {
+
+        boolean stopCalled;
+
+        MyMain(final String slingHome) {
+            super(new HashMap<String, String>() {
+                {
+                    put(SharedConstants.SLING_HOME, slingHome);
+                }
+            });
+        }
+
+        protected void doStop() {
+            this.stopCalled = true;
+        }
+
+        @Override
+        void terminateVM(int status) {
+            // not really
+        }
+    }
+}



Mime
View raw message