Port Unification in GlassFish 3 - Part 1

There are two main cases I want to cover here:  port redirection and serving multiple protocols on one port.  I'm pretty sure that covering both in one post would egregiously long so I'm going to break things up into two posts.  In this first post, we'll cover what will likely the be more common use case:  port redirection.  In this example scenario, you only want to serve requests via https rather than http.  In this case, you can configure GlassFish to return a 302 and push clients off to https transparently.  This type of configuration has been available in GlassFish since at least v2 and is still available in v3.  However, in v3 it wasn't "officially" supported so you had to manually massage your domain.xml. While documented in various blogs around net, it's not officially supported in v3.  As of, well now I guess, that's all changed.  I've added some asadmin commands to the 3.1 nightly builds that expose a more user friendly way to configure port unification.  In this blog, I'll introduce these commands and show you how to set up a simple redirect to enforce https requests on a given listener.  As always, when experimenting with this sort of thing, you should back up your domain.xml so if you hose your configuration, you can easily roll back to a working configuration.

There are two main concepts involved:  <protocol-filter> and <protocol-finder>.  There are a handful of other elements involved but we've hidden them from you by default since very few people will need to manage those elements.  The first step is to create the <protocol-filter>:

asadmin create-protocol --securityenabled=false http-redirect
asadmin create-protocol-filter --protocol http-redirect --classname com.sun.grizzly.config.HttpRedirectFilter redirect-filter

We need to create a new <protocol> element to hold our new filter first.  You can't simply reuse, say, http-listener-1 because port unification elements and <http>/<ssl> can't coexist on the same protocol elements.  You could of course issue a number of commands to preserve the name of http-listener-1 but the work involved is likely not worth it.  It's certainly overkill for this example so I'll leave that as an exercise for you if you're that interested in it.  The next asadmin command creates the actual protocol filter.  With these two commands we have now have a new entry in our domain.xml that looks like this:





      
   

Notice that there are new elements: <protocol-chain-instance-handler> and <protocol-chain>. These are some implementation details that should be mostly irrelevant to all but a handful of users. I only mention them so that you'll be expecting to see them and that you know you can safely skip over them. With those pieces in place, we can now create our finders.

To create our finders, we need to create another <protocol> element to hold them and then create the finders themselves:

asadmin create-protocol --securityenabled=false pu-protocol
asadmin create-protocol-finder --protocol pu-protocol --target-protocol http-listener-2 --classname com.sun.grizzly.config.HttpProtocolFinder http-finder
asadmin create-protocol-finder --protocol pu-protocol --target-protocol http-redirect --classname com.sun.grizzly.config.HttpProtocolFinder http-redirect

Note that the first <protocol-finder> refers to the http-listener-2 <protocol>. We'll be using that protocol definition to configure the https processing. The second finder refers to the <http-finder protocol> definition we just created and it is this piece that will be doing the redirect from http->https for us. The first finder will trap all https requests and hand them off, while the second will handle all cleartext http requests and redirect for us. The resulting domain.xml elements looks like this:





   

Again, we silently create the <port-unification> element for you so you needn't worry about it. These elements that we silently create for you, we will also silently delete them for you when you delete the last elements contained in them. So those are our port unification elements. With those created, we just need to reconfigure listener to use these new elements:

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

With that, we can try hitting port 8080 and see things in action. The easiest way to see this, probably, is to use wget:

wget -q -S http://localhost:8080/

With this command, you should see the following output:

  HTTP/1.1 302 Moved Temporarily
  Location: https://localhost:8080/
  Connection:close
  Cache-control: private

As you can see there, the server returns a 302 back to the client with the new location of https://localhost:8080. That's all it takes. Now every request will use https regardless of the original request. You could, of course, use a similar set up to push everyone from https back to http. This is especially useful for those without any need for https and are concerned about server load since https can be expensive to process.

In the next entry, I'll tackle the use case of serving up multiple protocols from one listener. This will be especially useful for those behind firewalls wanting to open only a single port to the outside world. Hopefully this will get you started. If you have any questions, feel free to leave a comment or ask on the glassfish users mailing list.

For convenience, here are all the commands necessary to try this out at home in one downloadable file:

wget -q -S http://localhost:8080/

asadmin create-protocol --securityenabled=false http-redirect
asadmin create-protocol-filter --protocol http-redirect --classname com.sun.grizzly.config.HttpRedirectFilter redirect-filter

asadmin create-protocol --securityenabled=false pu-protocol
asadmin create-protocol-finder --protocol pu-protocol --target-protocol http-listener-2 --classname com.sun.grizzly.config.HttpProtocolFinder http-finder
asadmin create-protocol-finder --protocol pu-protocol --target-protocol http-redirect --classname com.sun.grizzly.config.HttpProtocolFinder http-redirect

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

wget -q -S http://localhost:8080/

Documenting the GlassFish v3 Schema

Once work had started on GlassFish v3 the decision was made to drop schema validation for the domain.xml configuration file.  In previous versions, you could be assured that your xml was valid because we shipped a DTD to enforce that.  In v3, however, that is no longer the case.  The decision was made because v3 is very different in some fundamental ways.  In v3, you can add an arbitrary container to GlassFish and configure it via domain.xml.  This dynamic nature of the document structure makes validation difficult at best so the decision was made to drop validation altogether.  However, the problem still remains of how to determine what the document should look like. First things first, you should avoid editing that xml file by hand.  You should be able to do everything you need via either the admin GUI console or the asadmin CLI tool.  That said, that still doesn't necessarily help you know what values can go where.  The question has come up dozens of times even among the development team.  Various teams have updated and migrated their respective sections of the document leaving some confusion about the new schema.  (My own work on the grizzly-config updates is probably the biggest offender here).  There are, to my knowledge, two different attempts to fix this.

Tim Quinn developed the first publicly available tool.  You can find that here.  I had my own going on locally as well.  I borrowed some ideas from Tim's approach and came up with this.  My version differs from Tim's in that it runs in container as an asadmin command.  This has a few advantages but most importantly is that I think it's easier to use.  The output I generate is also a bit more accessible than Tim's but then Tim's was really a rough first cut.  I'm not sure he's done much with it since.  I, on the other hand, still get questions about the grizzly-config schema changes so this is near and dear to my heart.

At the moment, it only generates a javadoc-like HTML output.  I plan on adding a DTD and XSD option but there are some disconnects between the internal Java API used to configure GlassFish and what a user sees in domain.xml that make this not so trivial.  You can find those details here.  The HTML generated reflects the currently valid structure of the document and not the content.  This structure changes as you add/remove modules such as JRuby support and the like.  The files are generated in the config directory (<glassfish>/domains/domain1/index.html for most people).

The color scheme is a work in progress.  The main blue is a bit jarring, I think, but I just haven't had much time to play with such things lately.  You can find sample output here.  In the detail frame you'll see that some elements have properties defined.  This lists all the documented properties on that attribute.  In a perfect world, that list would be exhaustive but that's not always possible.  e.g., Some configuration elements such as JDBC connection pools configure third party libraries and capturing all possible properties there is impossible.  Nevertheless, for all internal GlassFish items this list should give you much of what you need.  If you find a missing property, don't hesitate to file an issue with the GlassFish tracker and we'll try to update our documentation.

If you find an issue with the doc tool itself, please file an issue and I'll do my best to correct it.  This is an unofficial contribution to GlassFish, though, so bugging the GlassFish lists isn't likely to help much.  I hope this tool helps you as you evaluate v3.  We really are very excited about this one.