2006-01-23

My vote for Dolphin

In case I haven't said this publicly enough yet: I consider Isolates the most urgently needed innovation for Java. By far. I'm surprised this doesn't get more attention. I'll celebrate the day when we can start and tear down subsystems without worrying about thread and memory leaks. The day where I can clearly distinguish between a problem in my software or a customer customization. Until then, I have completely given up on webapp redeployment, for example. A quote from Bill's post: "Isolates are slated for Java 1.6". Sun, please get this out of the door for Dolphin!
Posted by Matthias at 24:17.16. Comment: blog@mernst.org

2006-01-22

Mustang's HTTP Server

Update: Alan Bateman has kindly provided me with a link to the HTTP server API documentation. This will soon be hooked up in the Mustang docs.

Several times, I've seen Mustang's inclusion of an HTTP server mentioned. A technical article points to bug 6270015, which asks for support of a lightweight HTTP server API. This bug is marked "closed, fixed". Yet, you won't find anything in the Mustang JavaDoc on it. What's the deal? Well, if we read carefully, Mustang will include an HTTP server API, not JSE 6. If we follow David Herrons recommendation, we should therefore forget about this quickly.

However, that API looks like it had some thinking put into it, is documented and itself distinguishes thoroughly between com.sun.* (sort-of presentable?) and sun.* (don't go there?) packages. Here's how you run a simple server:

  HttpServer httpServer = HttpServer.create(new InetSocketAddress(8000), 5);
  httpServer.createContext("/", new HttpHandler() {
    public void handle(final HttpExchange exchange) throws IOException {
      Headers requestHeaders = exchange.getRequestHeaders();
      exchange.getResponseHeaders().set("Content-Type", "text/plain;charset=utf-8");
      exchange.sendResponseHeaders(200, 0);
      OutputStream responseBody = exchange.getResponseBody();
      PrintWriter printWriter = new PrintWriter(new OutputStreamWriter(responseBody, "UTF-8"));
      for (Map.Entry<String, List<String>> entry : requestHeaders.entrySet())
        printWriter.println(entry.getKey() + ": " + entry.getValue());

      printWriter.close();
    }
  });

  // the server will be single-threaded unless you uncomment this line
  // httpServer.setExecutor(Executors.newCachedThreadPool());
  httpServer.start();

Simple enough. If this thing survives further scrutiny it has the potential to put Jetty out of business for me for embedded HTTP endpoints. If it just weren't for the license...

Posted by Matthias at 23:01.22. Comment: blog@mernst.org
Edited on: 2006-01-23 21:45.16

2006-01-13

Mastering NIO

For the umpteenth time, I'm trying to move from an intellectual to a practical understanding of non-blocking network IO and I've come to something working this time. I know about MINA, I've read about emberIO, yet I want to learn it the hard way by building a framework myself that is simple, purely non-blocking and extensible. I'm not actually expecting to reach the fastest or most scalable solution, actually I'm more interested in the programming model. Non-blocking IO flips the roles: you no longer have an inputstream/outputstream pair that you can operate with in a single method call. Instead your code needs to become a state machine; input is pushed into it; output is pulled from it. That's why it's so hard to get the servlet api together with NIO.

So what do I have?

An IODispatcher represents a selector with an associated thread pool. You add channels and associated protocols to a dispatcher:

class IODispatcher {
  public <C extends SelectableChannel> void addChannel(C channel, Protocol<? super C> protocol)
}
Each registered channel runs a protocol, an implementation of the following interface:
public interface Protocol<C> {
  void setConnection(ChannelConnection<? extends C> connection);
  int interest();
  void run() throws IOException;
  void destroy();
}

The IODispatcher selects on the channel with the protocol's current interest. When selected it will run the protocol in the thread pool. While running, the channel's interest is set to 0 and the IODispatcher ensures that this protocol instance will not run again concurrently. When #run finishes, the protocol will be entered for selection again with a possibly new interest set. If the protocol closes its channel or throws an IOException, the IODispatcher will remove the protocol and invoke its #destroy method.

A Protocol is a state machine. In order to make writing protocols easier, there's a MultiStageProtocol with individual stages that can indicate successor stages after running. These are the building blocks I hope to build abstractions on; so far I have acceptor, connector and writer stages. Input and conversions are typical next candidates. For reference, the connector stage looks as follows:

public class Connector<C extends SocketChannel> implements ProtocolStage<C> {
  private ProtocolStage<C> next;

  public Connector(ProtocolStage<C> next) {
this.next = next;
  }

  public int interest() {
return SelectionKey.OP_CONNECT;
  }

  public ProtocolStage<C> run(ChannelConnection<? extends C> connection) throws IOException {
return connection.getChannel().finishConnect() ? next : this;
  }

  public void destroy(ChannelConnection<? extends C> connection) {
  }
}

The code is running very nicely now; I stumbled over two NIO bugs (4729342,5076772) that I'm preparing fixes for. In the longer run, I'd like to build a renderer for my Axt template engine that implements a pull model and run it on this NIO framework.

That was the morning news, time for a shower now.

Posted by Matthias at 8:33.19. Comment: blog@mernst.org