Harald Kirsch

genug Unfug.

2014-12-21

The Java-Only Web Application (Part II)

Contents

In my previous post I described that I wanted to try a pure Java web application. In particular I wanted to avoid angle-bracket programming (aka XML-programming). And I did not want to replace the angle brackets by '@'-programming. So no JSPs or similar and no Spring.

I described already the servelet engine and how to create the HTML without JSP. Further ingredients follow now:

URL Parameters

URL parameters get into the servlet like

request.getParameter("some-param-name");

but there are several pitfalls to avoid when dealing with them:

  • The parameter may not exist, if only because a user has manually trimmed the URL. In this case getParameter() returns null.
  • A parameter of the given name may exist several times in the URL. This may or may not be required by the application. If it is, we would have to use getParameterValues() instead.
  • The parameter may be available but not parseable. For example an integer value is expected but the parameter does not parse as an integer.
  • Finally the parameter may be parseable but does not fit logically to other parameters or the state of the application, like a negative value when a non-negative is needed.

But this is not all there is to parameter handling. Getting them in from the URL is only one side of the coin. The other is to write them out to URLs and form parameters. To handle all this, I use a rather simple but effective class called UrlParam<T>. It is immutable and captures three pieces of information as can be seen from the constructor:

UrlParam(String name, TYPE value, ParamCodec<TYPE> pCodec)

We have the name of the parameter in the URL, a default value and a codec which translates back and forth between the value type and a string representation. Further, the class has methods to convert from the request and into a URL or a form parameter.

UrlParam<TYPE> fromFirst(ServletRequest req);
String getForUrlParam();
String getForInputParam();

The latter two take care of the necessary URL or HTML encoding on top of the conversion provided by the codec. A few example codecs which wwere written easily are for String values (a no-op), Integer values, not forgetting to catch the unchecked NumberFormatException, boolean, enums and dates.

A tricky part I am not yet completely decided on is whether I use null or a special value as the default value of a UrlParam to signal the complete absence of a value, when even a real default does not make sense. I tend more and more to never use null.

Since UrlParam is immutable, it turned out that statically initializing a template for each parameter was just right. It is then used at the start of a doGet() or doPost() to parse from a request parameter and later to fill either URLs or form parameters.

Validation of parameters can sometimes be done only piecemeal: is the parameter an integer, is it an existing user id, is the next parameter the name of a list, does the user with the id have access to this list, is the value he wants to enter valid for the list, etc. The validation needs to take into account complex dependencies of between the parameters only relevant for this particular servlet. And the way to handle errors changes depending on how far we get through the validation, which is why a simple yes/no decision is not sufficient. This is typically handled at the start of a servlet request method. Only when the control flow gets past the last validation step, either the view is created (doGet) or the model is changed (doPost).

Database Access

Currently I am using H2 as the database in embedded mode. It comes with an easy to use connection pool.

For SQL generation I use JOOQ rather than anything JPA. The reason is that the application's focus is on manipulating the contents of the underlying database, not on using it as an object store. I don't want to abstract away from the fact the my data is in a database. On the contrary, I want to use the database as a database.

In a further blog post I want to describe the security model and access rights and what I learned from implementing it.