How to stop Java HTTP server

S

Shiladitya

Hi,
I am using the embedded Sun Java Http server : com.sun.net.httpserver.

I wrote code for setting the executor, adding context and starting it.
This is written in the main thread.
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();

}

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.

TIA
Shiladitya
 
T

Tom Anderson

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
 
S

Shiladitya

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();

}


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

That was very helpful Tom. I have tested it out and it works nicely !
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top