Merge remote-tracking branch 'origin/jetty-7' into jetty-8
This commit is contained in:
commit
b69b52d984
|
@ -40,7 +40,7 @@ import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||||
* <p>
|
* <p>
|
||||||
* Commands "stop" and "status" are currently supported.
|
* Commands "stop" and "status" are currently supported.
|
||||||
*/
|
*/
|
||||||
public class ShutdownMonitor extends Thread
|
public class ShutdownMonitor
|
||||||
{
|
{
|
||||||
// Implementation of safe lazy init, using Initialization on Demand Holder technique.
|
// Implementation of safe lazy init, using Initialization on Demand Holder technique.
|
||||||
static class Holder
|
static class Holder
|
||||||
|
@ -53,11 +53,164 @@ public class ShutdownMonitor extends Thread
|
||||||
return Holder.instance;
|
return Holder.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShutdownMonitorThread
|
||||||
|
*
|
||||||
|
* Thread for listening to STOP.PORT for command to stop Jetty.
|
||||||
|
* If ShowndownMonitor.exitVm is true, then Sytem.exit will also be
|
||||||
|
* called after the stop.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ShutdownMonitorThread extends Thread
|
||||||
|
{
|
||||||
|
|
||||||
|
public ShutdownMonitorThread ()
|
||||||
|
{
|
||||||
|
setDaemon(true);
|
||||||
|
setName("ShutdownMonitor");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if (serverSocket == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (serverSocket != null)
|
||||||
|
{
|
||||||
|
Socket socket = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket = serverSocket.accept();
|
||||||
|
|
||||||
|
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String receivedKey = lin.readLine();
|
||||||
|
if (!key.equals(receivedKey))
|
||||||
|
{
|
||||||
|
System.err.println("Ignoring command with incorrect key");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream out = socket.getOutputStream();
|
||||||
|
|
||||||
|
String cmd = lin.readLine();
|
||||||
|
debug("command=%s",cmd);
|
||||||
|
if ("stop".equals(cmd))
|
||||||
|
{
|
||||||
|
// Graceful Shutdown
|
||||||
|
debug("Issuing graceful shutdown..");
|
||||||
|
ShutdownThread.getInstance().run();
|
||||||
|
|
||||||
|
// Reply to client
|
||||||
|
debug("Informing client that we are stopped.");
|
||||||
|
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
// Shutdown Monitor
|
||||||
|
debug("Shutting down monitor");
|
||||||
|
close(socket);
|
||||||
|
socket = null;
|
||||||
|
close(serverSocket);
|
||||||
|
serverSocket = null;
|
||||||
|
|
||||||
|
if (exitVm)
|
||||||
|
{
|
||||||
|
// Kill JVM
|
||||||
|
debug("Killing JVM");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ("status".equals(cmd))
|
||||||
|
{
|
||||||
|
// Reply to client
|
||||||
|
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
debug(e);
|
||||||
|
System.err.println(e.toString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
close(socket);
|
||||||
|
socket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
System.err.printf("ShutdownMonitorThread already started");
|
||||||
|
return; // cannot start it again
|
||||||
|
}
|
||||||
|
|
||||||
|
startListenSocket();
|
||||||
|
|
||||||
|
if (serverSocket == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
System.err.println("Starting ShutdownMonitorThread");
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startListenSocket()
|
||||||
|
{
|
||||||
|
if (port < 0)
|
||||||
|
{
|
||||||
|
if (DEBUG)
|
||||||
|
System.err.println("ShutdownMonitor not in use (port < 0): " + port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
|
||||||
|
if (port == 0)
|
||||||
|
{
|
||||||
|
// server assigned port in use
|
||||||
|
port = serverSocket.getLocalPort();
|
||||||
|
System.out.printf("STOP.PORT=%d%n",port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
// create random key
|
||||||
|
key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
|
||||||
|
System.out.printf("STOP.KEY=%s%n",key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
debug(e);
|
||||||
|
System.err.println("Error binding monitor port " + port + ": " + e.toString());
|
||||||
|
serverSocket = null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// establish the port and key that are in use
|
||||||
|
debug("STOP.PORT=%d",port);
|
||||||
|
debug("STOP.KEY=%s",key);
|
||||||
|
debug("%s",serverSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private boolean DEBUG;
|
private boolean DEBUG;
|
||||||
private int port;
|
private int port;
|
||||||
private String key;
|
private String key;
|
||||||
private boolean exitVm;
|
private boolean exitVm;
|
||||||
private ServerSocket serverSocket;
|
private ServerSocket serverSocket;
|
||||||
|
private ShutdownMonitorThread thread;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ShutdownMonitor using configuration from the System properties.
|
* Create a ShutdownMonitor using configuration from the System properties.
|
||||||
|
@ -149,77 +302,6 @@ public class ShutdownMonitor extends Thread
|
||||||
return exitVm;
|
return exitVm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (serverSocket == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (serverSocket != null)
|
|
||||||
{
|
|
||||||
Socket socket = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket = serverSocket.accept();
|
|
||||||
|
|
||||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
|
||||||
String key = lin.readLine();
|
|
||||||
if (!this.key.equals(key))
|
|
||||||
{
|
|
||||||
System.err.println("Ignoring command with incorrect key");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputStream out = socket.getOutputStream();
|
|
||||||
|
|
||||||
String cmd = lin.readLine();
|
|
||||||
debug("command=%s",cmd);
|
|
||||||
if ("stop".equals(cmd))
|
|
||||||
{
|
|
||||||
// Graceful Shutdown
|
|
||||||
debug("Issuing graceful shutdown..");
|
|
||||||
ShutdownThread.getInstance().run();
|
|
||||||
|
|
||||||
// Reply to client
|
|
||||||
debug("Informing client that we are stopped.");
|
|
||||||
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
|
|
||||||
out.flush();
|
|
||||||
|
|
||||||
// Shutdown Monitor
|
|
||||||
debug("Shutting down monitor");
|
|
||||||
close(socket);
|
|
||||||
socket = null;
|
|
||||||
close(serverSocket);
|
|
||||||
serverSocket = null;
|
|
||||||
|
|
||||||
if (exitVm)
|
|
||||||
{
|
|
||||||
// Kill JVM
|
|
||||||
debug("Killing JVM");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ("status".equals(cmd))
|
|
||||||
{
|
|
||||||
// Reply to client
|
|
||||||
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
|
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
debug(e);
|
|
||||||
System.err.println(e.toString());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
close(socket);
|
|
||||||
socket = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDebug(boolean flag)
|
public void setDebug(boolean flag)
|
||||||
{
|
{
|
||||||
|
@ -228,89 +310,70 @@ public class ShutdownMonitor extends Thread
|
||||||
|
|
||||||
public void setExitVm(boolean exitVm)
|
public void setExitVm(boolean exitVm)
|
||||||
{
|
{
|
||||||
if (isAlive())
|
synchronized (this)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("ShutdownMonitor already started");
|
if (thread != null && thread.isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitorThread already started");
|
||||||
}
|
}
|
||||||
this.exitVm = exitVm;
|
this.exitVm = exitVm;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setKey(String key)
|
public void setKey(String key)
|
||||||
{
|
{
|
||||||
if (isAlive())
|
synchronized (this)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("ShutdownMonitor already started");
|
if (thread != null && thread.isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitorThread already started");
|
||||||
}
|
}
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setPort(int port)
|
public void setPort(int port)
|
||||||
{
|
{
|
||||||
if (isAlive())
|
synchronized (this)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("ShutdownMonitor already started");
|
if (thread != null && thread.isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitorThread already started");
|
||||||
}
|
}
|
||||||
this.port = port;
|
this.port = port;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void start()
|
protected void start() throws Exception
|
||||||
{
|
{
|
||||||
if (isAlive())
|
ShutdownMonitorThread t = null;
|
||||||
|
synchronized (this)
|
||||||
{
|
{
|
||||||
System.err.printf("ShutdownMonitor already started");
|
if (thread != null && thread.isAlive())
|
||||||
|
{
|
||||||
|
System.err.printf("ShutdownMonitorThread already started");
|
||||||
return; // cannot start it again
|
return; // cannot start it again
|
||||||
}
|
}
|
||||||
startListenSocket();
|
|
||||||
if (serverSocket == null)
|
thread = new ShutdownMonitorThread();
|
||||||
{
|
t = thread;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super.start();
|
if (t != null)
|
||||||
|
t.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startListenSocket()
|
|
||||||
|
protected boolean isAlive ()
|
||||||
{
|
{
|
||||||
if (this.port < 0)
|
boolean result = false;
|
||||||
|
synchronized (this)
|
||||||
{
|
{
|
||||||
if (DEBUG)
|
result = (thread != null && thread.isAlive());
|
||||||
System.err.println("ShutdownMonitor not in use (port < 0): " + port);
|
}
|
||||||
return;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
setDaemon(true);
|
|
||||||
setName("ShutdownMonitor");
|
|
||||||
|
|
||||||
this.serverSocket = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
|
|
||||||
if (this.port == 0)
|
|
||||||
{
|
|
||||||
// server assigned port in use
|
|
||||||
this.port = serverSocket.getLocalPort();
|
|
||||||
System.out.printf("STOP.PORT=%d%n",this.port);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.key == null)
|
|
||||||
{
|
|
||||||
// create random key
|
|
||||||
this.key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
|
|
||||||
System.out.printf("STOP.KEY=%s%n",this.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
debug(e);
|
|
||||||
System.err.println("Error binding monitor port " + this.port + ": " + e.toString());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// establish the port and key that are in use
|
|
||||||
debug("STOP.PORT=%d",this.port);
|
|
||||||
debug("STOP.KEY=%s",this.key);
|
|
||||||
debug("%s",serverSocket);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// All rights reserved. This program and the accompanying materials
|
||||||
|
// are made available under the terms of the Eclipse Public License v1.0
|
||||||
|
// and Apache License v2.0 which accompanies this distribution.
|
||||||
|
//
|
||||||
|
// The Eclipse Public License is available at
|
||||||
|
// http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
//
|
||||||
|
// The Apache License v2.0 is available at
|
||||||
|
// http://www.opensource.org/licenses/apache2.0.php
|
||||||
|
//
|
||||||
|
// You may elect to redistribute this code under either of these licenses.
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.LineNumberReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShutdownMonitorTest
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ShutdownMonitorTest
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShutdown ()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
//test port and key assignment
|
||||||
|
ShutdownMonitor.getInstance().setPort(0);
|
||||||
|
ShutdownMonitor.getInstance().setExitVm(false);
|
||||||
|
ShutdownMonitor.getInstance().start();
|
||||||
|
String key = ShutdownMonitor.getInstance().getKey();
|
||||||
|
int port = ShutdownMonitor.getInstance().getPort();
|
||||||
|
|
||||||
|
//try starting a 2nd time (should be ignored)
|
||||||
|
ShutdownMonitor.getInstance().start();
|
||||||
|
|
||||||
|
|
||||||
|
stop(port,key,true);
|
||||||
|
assertTrue(!ShutdownMonitor.getInstance().isAlive());
|
||||||
|
|
||||||
|
//should be able to change port and key because it is stopped
|
||||||
|
ShutdownMonitor.getInstance().setPort(0);
|
||||||
|
ShutdownMonitor.getInstance().setKey("foo");
|
||||||
|
ShutdownMonitor.getInstance().start();
|
||||||
|
|
||||||
|
key = ShutdownMonitor.getInstance().getKey();
|
||||||
|
port = ShutdownMonitor.getInstance().getPort();
|
||||||
|
assertTrue(ShutdownMonitor.getInstance().isAlive());
|
||||||
|
|
||||||
|
stop(port,key,true);
|
||||||
|
assertTrue(!ShutdownMonitor.getInstance().isAlive());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void stop (int port, String key, boolean check)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
Socket s = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//send stop command
|
||||||
|
s = new Socket(InetAddress.getByName("127.0.0.1"),port);
|
||||||
|
|
||||||
|
OutputStream out = s.getOutputStream();
|
||||||
|
out.write((key + "\r\nstop\r\n").getBytes());
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
if (check)
|
||||||
|
{
|
||||||
|
//wait a little
|
||||||
|
Thread.currentThread().sleep(600);
|
||||||
|
|
||||||
|
//check for stop confirmation
|
||||||
|
LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream()));
|
||||||
|
String response;
|
||||||
|
if ((response = lin.readLine()) != null)
|
||||||
|
{
|
||||||
|
assertEquals("Stopped", response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new IllegalStateException("No stop confirmation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (s != null) s.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -13,7 +13,8 @@
|
||||||
<name>Jetty :: SPDY :: Parent</name>
|
<name>Jetty :: SPDY :: Parent</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<npn.version>1.1.0.v20120525</npn.version>
|
<npn.version>1.1.5.v20130313</npn.version>
|
||||||
|
<npn.api.version>1.1.0.v20120525</npn.api.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.npn</groupId>
|
<groupId>org.eclipse.jetty.npn</groupId>
|
||||||
<artifactId>npn-api</artifactId>
|
<artifactId>npn-api</artifactId>
|
||||||
<version>1.0.0.v20120402</version>
|
<version>${npn.api.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.npn</groupId>
|
<groupId>org.eclipse.jetty.npn</groupId>
|
||||||
<artifactId>npn-api</artifactId>
|
<artifactId>npn-api</artifactId>
|
||||||
<version>${npn.version}</version>
|
<version>${npn.api.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
Loading…
Reference in New Issue