So Long and Thanks for All the GlassFish

I'm both excited and slightly saddened to announce that I'm leaving Oracle.  I've enjoyed my time here, the work I've done, and with whom I've done it.  Sometimes an opportunity comes up that's too enticing to pass up, though, and you just have to take it.  I hope I can continue to help the evolution of websockets in EE and plan on applying to join that EG as soon as it forms but we'll see.  I hope to with the Grizzly implementation, as well, as the standards start to evolve but again we'll have to see how things play out. It's a bittersweet thing but I'm excited about it overall.  I have my JavaOne duties next week and then one more week with Oracle and then it's on to next thing.  If you're at JavaOne next week, stop by my session and say hi.  Now to finish packing...

Websockets and Java EE

Work has begun on the Servlet Expert Group to come up with a standard set of atoms for WebSocket applications in a Java EE environment.  I'm not 100% convinced that the servlet spec is the best place to do this but I suppose it saves us the hassle of submitting another JSR and all the work that would entail.  However, that's where the work is being done for now, so whatever.  This is something I've naturally thought a lot about over the last couple of years as I've worked to implement and promote WebSockets so here is roughly how I would do it. There's a lot of "we have to have something in the servlet spec" comments floating around.  I don't necessarily agree with that sentiment but there is one thing I would: support for the upgrade request header.  This would have the servlet container automatically detect a request with this header.  The container would then query the system for all implementations of upgrade request handlers registered.  Then, based on which protocol each handler has said it deals with, hand off processing to that handler.  At this point, the request is not necessarily in the servlet stack at all but a completely separate API that might not even be back by a JSR.  This has multiple advantages in my mind.

  1. WebSockets uses this header and so this feature  is already going to be needed for WebSockets to work.
  2. It provides a general hook and customization point at which developers can choose to extend the container without resorting to modifying the source of the container itself to handle the new protocol.  More importantly, it does so in a standardized fashion allowing for portability at least among the higher levels of the API.  Certain container specific code might be needed for such things as suspending/parking requests and the like.  But these could easily be abstracted away such that the protocol logic itself could be fairly portable.
  3. This also decouples new APIs such as WebSockets from the constraints of the legacy(?) servlet API.
  4. Using this hook, someone could homebrew their own protocols using the upgrade mechanism and be able to integrate in to their container with little fuss.

Barring some tweaks here and there, that's all the servlet spec really needs to offer.  So where does that leave WebSockets?  Why, in its own JSR, of course!  I really think it needs its own separate JSR with its own EG populated by folks who know and understand the technology.  More importantly, this separate EG would feel less bound to make this new API consistent/compatible with the servlet API.  While there is certainly a need for integration with the servlet spec for access to things like the session data, binding the two APIs would really hamstring the interesting things we could do with WebSockets.  So what would all this look like?  Let's look at some mostly java mockups.

First, the servlet side upgrade handler. It would look something like this. If you've used @WebServlet, this should look familiar to you.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface HttpUpgradeHandler {    
    /**
     * The name of the target protocol
     */
    String value() default {};

    /**
     * The description of the handler
     */
    String description() default "";

    /**
     * The display name of the handler
     */
    String displayName() default "";
}

And the interface exposed for implementations:

public interface UpgradeHandler {
    public void doUpgrade(ServletRequest request, ServletResponse response) throws UpgradeException;
}

This provides a general mechanism for any application developer to register a new handler thus extending the functionality of the container without need for hacking the container itself. So what would one of these handlers look like? Maybe something like this:

@HttpUpgradeHandler(protocol ="websocket", urlPatterns={"/sample"})
public class SampleWebSocketContext extends WebSocketContext {
    @Override
    public void customizeHandshake(ServletRequest request, ServletResponse response) {
        super.customizeHandshake(request, response);
        // insert cookies here
    }

    @Override
    public WebSocketContext createContext(ServletRequest request, ServletResponse response) {
        return new SampleWebSocketContext(request, response);
    }

    private static class SampleWebSocket extends DefaultWebSocket {
        private String userName;

        public SampleWebSocketContext(ServletRequest request, ServletResponse response) {
            super(request, response);
            userName = request.getParameter("user");
        }

        public String getUserName() {
            return userName;
        }
    }
}

By the time control gets handed off to WebSocketContext, the appropriate headers requesting the upgrade have already been found and validated against name provided in the annotation. All that's left to do here is perform the actual upgrade. In this case, I added a method to customize the handshake for cases where, perhaps, the developer wants to add a header field or validate an existing header value. So what comes from the servlet specification is that annotation, the interface, and an exception. There might be more as details are hashed out, but that's about all I would say that the servlet specification should deliver. That paves the way for a WebSocket JSR export group to define its own atoms.

Not entirely surprisingly, I imagine a WebSocket JSR would end up with something that approximates what I built in Grizzly. That said, there are certain ... rough points that need to be smoothed over but that can most easily be smoothed over by 1) an expert group and 2) user feedback. Still, here's how I see one approach at cracking this nut.

In Grizzly, we have a WebSocketApplication which is the center of the developer's world when building WebSocket applications. I've recently come to prefer WebSocketContext instead. It's largely semantic but whatever. This is where all the application logic, if there is any, would likely want to live. Between the WebSocketContext and any potential custom implementation of WebSocket, there's a lot of room of custom logic. But none of this is tied to the servlet spec beyond the initial use of the ServletRequest and ServletResponse which I think is key.

This separation allows the WebSocket JSR evolve without needing to worry about servlet evolution. More importantly, it allows innovation to happen without needing a JSR at all. Because there's a generic upgrade hand off, developers are free to extend their container in whatever crazy directions they choose. Imagine implementing a custom JMS transport over HTTP and tunneling through your web server. Or FTP. Or SNMP. Or some completely custom, proprietary protocol. This extension point takes the EE platform one huge step down the road of enabling developers to build applications on and extending the EE platform without the need for container specific hacks. It aslo, of course, paves the way for future JSRs to provide new functionality without extraneous requirements and constraints from external JSR lifecycles.

At the risk of repeating myself, I'd like to say again that this proposal is not perfect. It almost certainly has some corner cases I haven't thought of or addressed here. But it's at least along the lines of how I've been imagining something like this would work for the last couple of years. It's a start. I have the code I showed above and more in a git hub repository if you'd like to take a look in more detail. I'd love to hear any comments you might have.

Grizzly 2.0 and Comet

With the release of Grizzly 2.0, I'd like to highlight one of its newest features: comet support. When implementing support for comet in grizzly 2.0, I tried as best I could to make it API compatible with your 1.9 applications. That said, there are a handful of changes that were made to clean things up a little and simplify some of the implementation details.  I'll outline the changes you'll need to make to existing apps before building a new one from scratch. Most of the changes are largely cosmetic. The first change you'll notice is that the package names have changed. With the advent of 2.0, grizzly now lives under the org.glassfish.grizzly rather than com.sun.grizzly. CometHandler is the core of any comet application code and it, too, has received a minor makeover:

  • attach() has been removed from the interface. This won't actually affect your code unless you happen to have used @Override. This method has been typically used to attach things like the HttpRequest object to your CometHandler instance. In reality, this kind of information can be passed via the constructor or a method on your subclass. Grizzly doesn't actually reference this method or the attachment in any way so it has been removed from the interface. You are, of course, welcome to continue using attach() if you'd like. But since Grizzly never uses it internally, there's no sense in forcing all implementations to implement it.
  • Four new methods have been added added to the interface:
    1. Response getResponse();
    2. void setResponse(Response response);
    3. CometContext<E> getCometContext();
    4. void setCometContext(CometContext<E> context);

    Your CometHandler implementation needs only provide these getters/setters and the fields they imply. Grizzly will handle the setting of those values itself. It didn't make it into 2.0 (because I got sidetracked) but 2.0.1 will have a DefaultCometHandler that takes care of that for you if you choose. The type of <E> should be consistent with the data type you want to pass to your handlers when an event occurs. Typically, this will simply be a String but, of course, could be almost anything.

  • The type of comet events have been modernized. In 1.9 you had a set of int constants to manage. In 2.0, I've changed them to an enum. This probably won't affect your code overly much but you do need to change any thing like CometEvent.READ to CometEvent.Type.READ. Enum comparisons being what they are, everything else should just compile as long as you used the named constants.
  • A great number of items have been deprecated as well. The compiler will highlight these for you. All the deprecated methods should continue to work as you would expect, but I would recommend changing over when you get the chance. (You're already having to tweak code anyway.) We've striven to keep things API compatible as much as possible to ease the transition, but these methods might go away in the future so it's best to be prepared.

    The riskiest change, to my mind, is that the execution type has been removed. The execution model of grizzly 2.0 makes supporting that feature complicated. However, when examining every comet app and unit test I could find, I didn't find that this feature was really ever used that much anyway. Indeed, when asked about it some of the original authors weren't really entirely sure about the feature anyway. If you find that you really need that feature the decision can be readdressed. But I have to warn you, prepare yourself for some disappointment because it seems unlikely to happen. But you never know.

That should cover the changes you'll see. There are a number of other changes behind the scenes, of course, but hopefully we've done a good job of shielding you from those. Now that we've seen what changes you need to make to an existing application, let's see what it takes to write a new one. With 2.0, creating a grizzly instance to run your apps becomes much, much simpler. From here on out, we'll take a look at the comet click counter example you can find in the samples folder of the source repository.

To start grizzly, you just need a few lines of code:

        HttpServer httpServer = HttpServer.createSimpleServer("./", PORT);
        httpServer.getServerConfiguration().addHttpHandler(new ServletHandler(new LongPollingServlet()),
            QUERY_PATH);
        final Collection listeners = httpServer.getListeners();
        for (NetworkListener listener : listeners) {
            listener.registerAddOn(new CometAddOn());
        }
        httpServer.start();

This snippet sets up all the HTTP bits you'll need to serve up your comet application. With that set up, the next piece is the servlet manage your requests and the handler that provides your application logic.

public class LongPollingServlet extends HttpServlet {
    final AtomicInteger counter = new AtomicInteger();
    private static final long serialVersionUID = 1L;
    private String contextPath = null;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        ServletContext context = config.getServletContext();
        contextPath = context.getContextPath() + "/long_polling";
        CometEngine engine = CometEngine.getEngine();
        CometContext cometContext = engine.register(contextPath);
        cometContext.setExpirationDelay(5 * 30 * 1000);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        CometEngine engine = CometEngine.getEngine();
        CometContext context = engine.getCometContext(contextPath);
        final int hash = context.addCometHandler(new CounterHandler(res, counter));
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException {
        counter.incrementAndGet();
        CometContext context = CometEngine.getEngine().getCometContext(contextPath);
        context.notify(null);

        PrintWriter writer = res.getWriter();
        writer.write("success");
        writer.flush();
    }
}
public class CounterHandler extends DefaultCometHandler {
    private HttpServletResponse httpResponse;
    private AtomicInteger counter;

    CounterHandler(HttpServletResponse httpResponse, final AtomicInteger counter) {
        this.httpResponse = httpResponse;
        this.counter = counter;
    }

    public void onEvent(CometEvent event) throws IOException {
        if (CometEvent.Type.NOTIFY == event.getType()) {
            httpResponse.addHeader("X-JSON", "{\"counter\":" + counter.get() + " }");
            PrintWriter writer = httpResponse.getWriter();
            writer.write("success");
            writer.flush();
            event.getCometContext().resumeCometHandler(this);
        }
    }

    public void onInterrupt(CometEvent event) throws IOException {
        httpResponse.addHeader("X-JSON", "{\"counter\":" + counter.get() + " }");
       PrintWriter writer = httpResponse.getWriter();
        writer.write("success");
        writer.flush();
    }
}

The init() in the servlet registers the comet context we'll use to track all the handlers that various requests will park. That's the java code you need. Without overdoing it, a quick look at the javascript side should cover it.

var counter = {
      'poll' : function() {
         new Ajax.Request('long_polling', {
            method : 'GET',
            onSuccess : counter.update
         });
      },
      'increment' : function() {
         new Ajax.Request('long_polling', {
            method : 'POST'
         });
      },
      'update' : function(req, json) {
         $('count').innerHTML = json.counter;
         counter.poll();
      }
}

When the page loads, it makes the initial GET request to the server. That request gets parked in doGet() above. That request will stay open until the user clicks on a link in the html from the sample application. That click triggers a POST post. In doPost(), we call notify() on the context which triggers the parked CometHandler to finally respond to that initial GET request. Once that request finally responds, the javascript code will make another GET which gets parked and the process repeats itself. In this way multiple clients can track and update the counter on the server.

This is just a basic example, of course, ut it covers all the basic building blocks you'll need for more complex applications. For more examples, you can look through the sample applications. There are more examples in 1.9 than 2.0 right but, changes listed above aside, should help you find the answers. We're putting more and more documentation up at the website and, of course, we have mailing lists where you can post your questions. I think you'll find that 2.0 is much more pleasant to work with. So please take a look and give us some feedback on the lists. We'd love to hear about your experiences.