Document last updated April 4, 2001. We are very interested in feedback that would make these materials better. Feel free to write the author, Jonathan Revusky.

(Este documento en español) (Ce document en français)

Dissecting the "Hello, Niggle" servlet

In this document, we dissect the various parts of this first minimal example. We assume that you managed to go through the concrete steps outlined in the accompanying instructions that explain how to build and deploy the example.

The minimal servlet consists of the following parts:

The Java code

Conventionally, to create a new servlet using the base Java Servlet API, you define your own concrete subclass of the abstract class javax.servlet.http.HttpServlet and implement the methods doGet() and doPost(), as well as init() and destroy() if it is necessary to initialize/cleanup any resources used while the servlet is running. However, when you write a Niggle-based servlet, there will usually be no need to redefine the above methods, since the framework's base servlet class, com.revusky.niggle.servlet.NiggleServlet provides its own implementations of doGet(), doPost() and init() that you can use directly.

Of course, the question remains: where do I define my web app's functionality? The answer is that Niggle defines a separate abstract base class, com.revusky.niggle.servlet.ServletInteraction. This is really the comparable subclassing point in the Niggle framework: you write your own subclass of ServletInteraction and put your web app's functionality there.

Now, this leads us to a very basic design/architecture difference between Niggle and the base Servlet API. A servlet is basically a singleton object. One servlet instance is created and this instance services many HTTP requests over the course of its lifetime. However, in the Niggle framework, a new instance of your ServletInteraction subclass is instantiated each time the doPost() or doGet() method in com.revusky.niggle.servlet.NiggleServlet is invoked. In other words, a ServletInteraction object is a throw-away object that encapsulates the servicing of one HTTP request.

Now, if you have not done so already, take a peek at the HelloNiggleServlet.java file. You may be surprised to discover that the class is empty! You see, actually, there is no need to define any functionality here, since, as we pointed out above, the parent NiggleServlet class already defines all of the methods we typically override when writing a servlet: doGet(), doPost() and init(). Actually, the only role that this class plays is that the framework uses the name of the servlet to deduce the ServletInteraction subclass to use. Since the name of the servlet is HelloNiggleServlet, the ServletInteraction subclass is assumed to be HelloNiggleServletInteraction. (Read this technical note for a more complete technical explanation of why an application programmer must subclass both NiggleServlet and ServletInteraction.)

Below is the full code of HelloNiggleServletInteraction.java:


import com.revusky.niggle.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class HelloNiggleServletInteraction extends ServletInteraction {
    /**
     * The obligatory constructor. Your ServletInteraction subclass must have a 
     * constructor with this signature. This is the case even though we don't
     * actually have to do anything in the constructor (besides invoking
     * the superclass's constructor, that is.)
     */
     public HelloNiggleServletInteraction(HttpServletRequest request, 
                                          HttpServletResponse response, 
                                          NiggleConfig config)
     throws IOException {
         super(request, response, config);
     }
    
    /**
     * The "default" action handler. This will be invoked
     * if there is no "action" parameter defined in the request parameters.
     * Otherwise, if your request defines a parameter "action=foo"
     * the framework will take this as a signal to invoke the 
     * ServletInteraction's execFoo() method. Our simple "Hello, World"
     * servlet has only a single "default" action so we only define execDefault().
     */
    public void execDefault() throws IOException {
        this.page = getPage("hello.nhtml");
        page.expose("title", "Hello, World");
        page.expose("message", "Welcome to the brave new niggle world!");
    }
}

Take a look at the execDefault() method above. In the first of the three lines, the page variable is set and in the next 2 lines, a couple of template variables are set or exposed -- title and message.

So, what is going on here? Well, as you likely know at this point, the philosophy of the Niggle framework is based on a rigorous separation of presentation from application logic. Thus, the presentation details of any output to the client are encapsulated in a page template, which is completely separate from the application logic per se. So, the ServletInteraction class has a member variable called page and this must be set in the course of any execXXXX method. The above code is a case in point.

In short, the ServletInteraction instance has a member variable called page that encapsulates this template construct. Note that the page variable is an instance of the com.revusky.niggle.templates.Page interface.

The page template

The last section deliberately (or necessarily) left certain questions unanswered. The code in the above example assumes the existence of a page template corresponding to "hello.nhtml" and assumes a mechanism for exposing the template variables in the page was left deliberately vague.

Now it is time to get concrete about this. Below is the trivial "hello.nhtml" template that uses the 2 template variables that the java code sets.


 
<html> 
<head> <title>${title}</title> </head> 
<body> 
<P>Message: ${message}</P>
</body> 
</html> 

Note that the above page template code looks just like an HTML page. Well, it basically is an HTML page. The only thing special about it is the presence of the two strings ${title} and ${message} that are treated specially. As you likely notice, they correspond to the 2 template variables defined in the java code above via the calls to page.expose().

Essentially, the difference between a page template and a plain old static HTML page is that some of the content is determined dynamically. Note that, by default, the niggle framework leverages the open-source Freemarker template engine. A key feature of freemarker's syntax is that strings enclosed in ${...} are escaped, i.e. determined dynamically.

If you have gone through this example and are comfortable with it, I would encourage you to move on to the next example, a simple guestbook.


Addendum: A note about the Classloading issues

One interesting question is why you have to subclass NiggleServlet if it already contains all the functionality you need. I would be the first to admit that having 2 parallel subclassing points -- NiggleServlet and ServletInteraction in this case -- is normally suggestive of somewhat bad design in a class library. It certainly violates the basic KISS (keep it simple, stupid) rule of thumb.

Well, there are actually two reasons for this. The more important reason is actually kind of hypertechnical in nature. You see, a servlet runner will typically isolate different web application contexts from one another by having each one run in its own ClassLoader. If, as is likely, you put niggle.jar on the system classpath, then the class com.revusky.niggle.servlet.NiggleServlet would be loaded by the system ClassLoader. This means that it would not be able to find the various supporting classes located in <app-base>/WEB-INF/classes -- since those are only visible in the context of their own ClassLoader. By forcing the application programmer to define a subclass of NiggleServlet and place it in <app-base>/WEB-INF/classes, we make sure that the various other supporting classes, such as XXXServletInteraction can be found.

Also, a side benefit of forcing the application programmer to create a subclass of NiggleServlet is that this provides a default class name for the corresponding ServletInteraction subclass. If you name your servlet class XXX, then it is assumed that the ServletInteraction subclass (which, of course, really contains the application's functionality) is named XXXInteraction. Note, however, that, if you do not want to rely on this automatic naming scheme lookup, you can override this by specifying a INTERACTION_CLASS init parameter that specifies a different name for the ServletInteraction subclass. In fact, in prior versions of Niggle, you always had to specify this parameter. However, the default naming scheme means that the Hello, Niggle example can work without the need to specify any init parameters, which is a big win for newbie-friendliness.

Return to main text