Search code examples
javahttpserverclientsend

Send Command to http server


Good evening, I got this Server here

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.concurrent.atomic.AtomicInteger;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

public class Test {

public static void main(String[] args) throws Exception {
    HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
    server.createContext("/test", new MyHandler());
    server.setExecutor(null); // creates a default executor
    server.start();
}

static class MyHandler implements HttpHandler {
    AtomicInteger atomicInteger = new AtomicInteger(0); 
    int theValue = atomicInteger.get(); 
    @Override
    public void handle(HttpExchange t) throws IOException {
    String response = String.format("Besuche: %d%n", atomicInteger.addAndGet(1));
        t.sendResponseHeaders(200, response.length());
        OutputStream os = t.getResponseBody();
        os.write(response.getBytes());
        os.close();
    }
}


}

Its counting every visit i do on the website http://localhost:8000/test Now i have a client which shows me the content of the server in my console.

import java.net.*;
import java.io.*;

public class URLConnectionReader {
public static void main(String[] args) throws Exception {
    URL test = new URL("http://localhost:8000/test");
    URLConnection connect = test.openConnection();
    BufferedReader in = new BufferedReader(new InputStreamReader(connect.getInputStream()));
    String inputLine;

    while ((inputLine = in.readLine()) != null) 
        System.out.println(inputLine);
    in.close();
}
}

I want the client to send the server a command which resets the counter on the server. I could just find this here but i dont know how to implement this in my case. I hope someone can explain me what i can do now.


Solution

  • In the code you've given, MyHandler's method handle handles the requests for the /test path. So first thing you should decide upon is if you want to receive the reset command on the same path or on a different one?

    If you want to handle on the same path, then you need to modify the MyHandler to differentiate between the request to increase the number stored in atomicInteger - let's call that GET command, and the request to reset the counter - let's call that POST command. See what we have done? We have used two HTTP request methods to differentiate between the two commands. Now you want to change the MyHandler to implement that. On the handle method you receive HttpExchange object in the t parameter that has the getRequestMethod method. So the code would look something like:

    @Override
    public void handle(final HttpExchange t) throws IOException {
        final String response;
    
        final String requestMethod = t.getRequestMethod();
        if ("GET".equals(requestMethod)) {
            response = String.format("Besuche: %d%n", atomicInteger.addAndGet(1));
        }
        else if ("POST".equals(requestMethod)) {
            atomicInteger.set(0);
    
            response = "Reset to 0";
        }
        else {
            throw new IOException("Unsupported method");
        }
    
        t.sendResponseHeaders(200, response.length());
        final OutputStream os = t.getResponseBody();
        os.write(response.getBytes());
        os.close();
    }
    

    If you want to handle on a different path, let's say on /reset, you need to register another handler for that path i the main method add:

    server.createContext("/reset", new ResetHandler());
    

    Now in that handler and in the existing handler you need to share the same state of the program - the same AtomicInteger reference. This is best accomplished by creating the AtomicInteger in the main method and passing it to the two handlers using the handler's constructor. This would look something like:

    static class MyHandler implements HttpHandler {
    
        private final AtomicInteger counter;
    
        public MyHandler(final AtomicInteger counter) {
            this.counter = counter;
        }
    
        @Override
        public void handle(final HttpExchange t) throws IOException {
            // ... same code, only reference the counter
        }
    }
    
    static class ResetHandler implements HttpHandler {
        private final AtomicInteger counter;
    
        public ResetHandler(final AtomicInteger counter) {
            this.counter = counter;
        }
    
        @Override
        public void handle(final HttpExchange exchange) throws IOException {
            counter.set(0);
    
            exchange.sendResponseHeaders(200, 2);
            exchange.getResponseBody().write("OK".getBytes());
        }
    }
    

    And in the main method:

    final AtomicInteger counter = new AtomicInteger(0);
    server.createContext("/test", new MyHandler(counter));
    server.createContext("/reset", new ResetHandler(counter));
    

    There are other possibilities like using HTTP parameters or different methods, but this should get you started.

    Edited to add: In the client you can specify the request method like this:

    final URL test = new URL("http://localhost:8000/test");
    final HttpURLConnection connect = (HttpURLConnection) test.openConnection();
    connect.setRequestMethod("POST");