Sunday, September 18, 2011

Java 6 has a web server inside!

The what

I'm into miniaturization - anyone who knows me also knows as much. Probably because I'm not very tall for today's standards but mostly due to the sole nature of small things: they are easy to figure out. For example getting to understand every bit and piece of the whole car (whatever brand) is impossible. In many cases no one would even allow you to go that far. But having a deep understanding how manual shift gear box works shouldn't be a problem for moderately intelligent person... The exact same principle adheres to software development as far as I am concerned. I like small parts I can grasp in short amount of time and have it used right after the learning process knowing what the hell I'm doing. You might think about it in terms of components of a desktop application, a JavaScript library for dynamic web pages or (as I've found out today) in terms of a small set of classes that do exactly what they are supposed to do and you can have them do their thing in a matter of minutes. I'm obviously (as the title suggests) talking here about the embedded web server found in the com.sun.net.httpserver package.

The how

Besides being fixated on miniaturization I'm also a Groovy freak as I thing this is the best language for JVM ever created and there's nobody to convince me otherwise :D For that very reason the following example showing a miniature web application with embedded web server is a Groovy script:
import com.sun.net.httpserver.*

class ExampleHandler implements HttpHandler {
	void handle(HttpExchange exchange) throws IOException {
		def response = "Hello, world!"

		exchange.sendResponseHeaders(200, response.length());
		def outout = exchange.responseBody
		outout.write(response.bytes);
		outout.close();
	}
}

public class ExampleAuthenticator extends BasicAuthenticator {
	static users = [ "john": "john123" ]
 
	public ExampleAuthenticator(String realm) {
		super(realm);
	}

	@Override
	public boolean checkCredentials(String username, String password) {
		return users[username] == password;
	}
}

def server = HttpServer.create(new InetSocketAddress(8000), 0);
def context = server.createContext("/example", new ExampleHandler());
context.authenticator = new ExampleAuthenticator("Example application")
server.executor = null
server.start();
Let's start from the beginning...

The ExampleHandler class

This particular class is responsible for generating all the output sent later on to the server. As you can see it's a very minimalistic thing here, even to the point where the body needs to know how big it actually is. The line Exchange.sendResponseHeaders(...) shows that. The rest is pretty self explanatory so I'm not going to drill into it.

The ExampleAuthenticator class

This class provides basic authentication for our small application. It's so damn easy anyone will understand it right away but for the sake of clarity here's the bottom line:
  • Every credential is stored in the static users=[:] map

The meat

Now we have finally come to the good part! The actual use of HttpServer. Here you see how the server is created using a factory method (HttpServer.create) that takes an InetSocketAddress and some other argument I didn't drill down to just yet and gives you back an HttpServer instance ready to work. That instance does pretty much nothing so far other than a response 404 for everything you ask. To change that we create a new application context (very similar to the one found in a Servlet container) and register it under a specific path on that server. In the next line we tell the context that it is guarded by basic authentication - that's my favorite :) - and we're almost all set. The last thing is to (for whatever reason) assign an empty executor that in turn is supposed to have a side effect in the sense that a default executor will be assigned instead. That's weird...

The outcome

In 32 lines we've created a dynamic web application with authentication - ready to conquer the world! That's maybe a lot more than Sinatra or Spark but still - it's something worth knowing about. If you'd like you can utilize it directly from Java and it is still not a lot more code than what's seen here!

Have fun!

No comments: