Re: How to stop Java HTTP server
On Wed, 13 Oct 2010, Shiladitya wrote:
I need a way to call httpServerExe.stop() from this thread.
So the main thread can be like this:
httpServerExe.start();
while(!terminated) {
Thread.sleep(4000);
}
httpServerExe.stop();
That's the wrong way to do it. Rather than sleeping in a loop, this thread
should wait on a monitor, and threads which want to stop the server should
notify that monitor.
The main code would look like:
server.start();
synchronized (terminationLock) {
while (!terminated) terminationLock.wait();
}
server.stop();
Code which wants to stop it can go:
terminated = true;
synchronized (terminationLock) {
terminationLock.notify();
}
I have set up a handler for a URL (/terminateCommand). So if anyone send
a request to this URL, the terminated flag should be set and main thread
should stop the http server.
But I can't figure out how to set the flag from one of the handlers so
that main thread gets interrupted.
The handler has to have a reference to the place the flag lives. If the
flag is a static variable on a class, then it can go directly to the class
by name:
MainClass.terminated = true;
synchronized (terminationLock) {
MainClass.terminationLock.notify();
}
Although of course it would be better to wrap that in a method:
MainClass.terminate();
class MainClass {
private static boolean terminated;
private static Object terminationLock;
public static void terminate() {
terminated = true;
synchronized (terminationLock) {
terminationLock.notify();
}
}
}
If it's on an object, then you will need to pass a reference to that
object to the handler somehow, perhaps when you construct it.
void main(String... args) {
HttpServer server = HttpServer.create();
ServerController controller = new ServerController(server);
HttpHandler terminationHandler = new TerminationHandler(controller);
server.createContext("/terminate", terminationHandler);
new Thread(controller).start;
}
class ServerController implements Runnable {
private HttpServer server;
private boolean terminated;
private Object terminationLock = new Object();
public ServerController(HttpServer server) {
this.server = server;
}
public void run() {
server.start();
synchronized (terminationLock) {
try {
while (!terminated) terminationLock.wait();
}
catch (InterruptedException e) {}
}
server.stop();
}
public void terminate() {
terminated = true;
synchronized (terminationLock) {
terminationLock.notify();
}
}
}
You could dispense with the terminationLock by using the ServerController
itself to wait and notify on, but i tend to steer way from that, and use
private objects as locks, so that the wait/notify activity of the methods
can't 'leak' across the interface.
An even better way to do this, actually, would be with a
java.util.concurrent.CountDownLatch with a count of one:
class ServerController implements Runnable {
private HttpServer server;
private CountDownLatch latch = new CountDownLatch(1);
public ServerController(HttpServer server) {
this.server = server;
}
public void run() {
server.start();
try {
latch.await();
}
catch (InterruptedException e) {}
server.stop();
}
public void terminate() {
latch.countDown();
}
}
tom
--
you can't feel your stomack with glory -- Czako