Port Unification in GlassFish 3 – Part 3

With this third installment, we're getting to the most interesting feature:  serving multiple protocols on one port.  The uses of this are fairly obvious:  simpler administration, easier on firewalls, etc.  Many of the elements we've already seen and so should be fairly familiar.  We'll simply build on things we've seen and take them just one step further.  In this simple demo, we'll be serving up HTTP traffic and a "dummy" protocol.  We'll look at at the code needed to implement this protocol once we cover how to configure it. The first step we need to is to copy the attached protocol zip file in to GlassFish so it's ready for us to use.  Once you've downloaded the zip file, copy it to <glassfish>/domains/domain1/autodeploy/bundles/.  (You might need to create this directory first.)  If you're watching the server logs, you'll notice in a few seconds that GlassFish has detected the file and has deployed it.  With that done, we can configure the system to serve up that protocol.

This script is very similar to what we've already seen:

asadmin create-protocol pu-protocol

asadmin create-protocol-finder --protocol pu-protocol --target-protocol http-listener-1 --classname com.sun.grizzly.http.portunif.HttpProtocolFinder http-finder

asadmin create-protocol pu-dummy-protocol
asadmin create-protocol-finder --protocol pu-protocol --target-protocol pu-dummy-protocol --classname org.glassfish.devtests.web.portunif.DummyProtocolFinder dummy-finder
asadmin create-protocol-filter --protocol pu-dummy-protocol --classname org.glassfish.devtests.web.portunif.DummyProtocolFilter dummy-filter

asadmin set configs.config.server-config.network-config.network-listeners.network-listener.http-listener-1.protocol=pu-protocol

As you can see the steps here are almost identical to what we've done in the past. In this case, we're reusing the http-listener-1 <protocol> definition and pointing the HttpProtocolFinder there. This is the default protocol definition that ships with GlassFish. We're creating a new protocol definition for the dummy protocol and creating the finder and filter for the protocol. As a last step, we update the http-listener-1 <network-listener> to use the new pu-protocol we defined. And with that we're ready to test.

The HTTP test is simple enough: point your browser and http://localhost:8080. You should seen the standard GlassFish welcome (or an app if you've deployed one to that location). Testing the dummy protocol is a little more involved but not too bad. The protocol is simple enouugh. It looks for the text dummy-protocol and then responds with Dummy-Protocol-Response. If you have the nc command installed, you can simply do this:

echo dummy-protocol | nc localhost 8080

If not, you can you the telnet command. Simply telnet into localhost port 8080 and and the prompt enter dummy-protocol and hit the enter key. The server will respond with Dummy-Protocol-Response. Then you know you're done. We've seen this kind of configuration several times before. Let's look at the code that drives.

The first player in all this is the finder. This code detects the dummy protocol and responds accordingly. The finder looks like this:

public class DummyProtocolFinder implements ProtocolFinder {
    private final static String name = "dummy-protocol";
    private byte[] signature = name.getBytes();

    public String find(Context context, PUProtocolRequest protocolRequest)
            throws IOException {
        ByteBuffer buffer = protocolRequest.getByteBuffer();
        int position = buffer.position();
        int limit = buffer.limit();
        try {
            buffer.flip();
            if (buffer.remaining() >= signature.length) {
                for(int i=0; i

This code simply scans the incoming bytes looking for "dummy-protocol." if it can't find it, it returns null telling the underlying grizzly code to keep looking. If it finds it, returns that string to the caller signifying it's found the protocol. At that point, control gets handed off to the DummyProtocolFilter:

public class DummyProtocolFilter implements ProtocolFilter {
    public boolean execute(Context ctx) throws IOException {
        SelectableChannel channel = ctx.getSelectionKey().channel();
        OutputWriter.flushChannel(channel, ByteBuffer.wrap("Dummy-Protocol-Response".getBytes()));
        ctx.getSelectorHandler().closeChannel(channel);
        return false;
    }

    public boolean postExecute(Context ctx) throws IOException {
        return true;
    }
}

The filter is simple enough. It just prints back the text we've been expecting. When it's done it returns false to show that execution is finished and the response can be closed out. Obviously a more complex protocol would require a more complex filter, but this is the basis of any such filter.

That's all it takes. If you wanted to serve up more protocols, you'd simply add more filters and finders as needed.