PageController

Maintainability and simplicity in JSF applications

- Download - SF page - Subversion repository -

Introduction

The pagecontroller framework is a web application framework that is built on JSF. Its goal is to provide a framework that allows web applications to achieve good maintainability and extensibility through modularity and encapsulation. It should also allow greater flexibility in testing and refactoring than other contemporary web application frameworks.

Motivation

In the software development processes, the maintainability and extensibility are two service level requirements that have become very important. Meeting these requirements is important for development speed. It is also a neccessity when using an agile development process. It allows programming with confidence, not with fear.

Maintainability demands a lot from a projects architecture. The architecture should at least have the following characteristics:

These characteristics are nothing new, and they are very realistic when the right object oriented software patterns are applied in a project. This is however not that easy, when it comes to web applications. Web applications traditionally define views using HTML or JSP. They also define things like actions, pages, page transitions, controllers and more using XML. These files are often such an important part of an application, that the characteristics above should also apply to them.

With regard to the characteristics above, we identify the following problems:

Philosophy

The aim of the pagecontroller framework is to try and overcome the problems described above. Its philosophy is that XML should be avoided if it can be replaced by plain old java code. Implementing an interface or subclassing a framework class is often a viable alternative for creating an XML document which uses a DTD or schema. Benefits of a class are that it can be reused, refactored and tested easily. It does also not have to be in a predefined location.

Fragment library

JSF defines several standard components. Other components are provided by third parties. These components are accompanied by tag classes, a tld and a faces-config. This allows JSP pages to create these components. A JSP file is built up out of tags, each creating a component.

The component level is typically not the granularity with which one wants to define a page. When an application has many places where a user can edit a date, the same sequence of component tags has to be repeated: A label, an input area with a datetime converter and an error message. As we all know, repeating oneself is a 'bad thing'. Defining the components used to enter a date in a common place allows us to program more quickly, make less mistakes and change the components needed for editing a date centrally.

For these reasons, the pagecontroller framework does not use the tag classes and tld files. To maximize reuse, it defines pages in Java. A page is built up out of fragments using the composite pattern. A fragment can be a factory for a single component, a set of components or even a whole page. The fragment interface contains only a single method, createComponents(parentComponent). The fragment library is a standalone library, which can also be used without of the rest of the framework.

The example application 'guessnumber' is a single-page application demonstrating the fragment library. The part of the page for inputting a number looks like this:

protected SingleComponentFragment guessContent() {
    return new Group(
        new OutputText("Hi, can you guess the number between "),
        new OutputText(BindingBuilder.value("#{model.min} and #{model.max}?")),
        NewLine.instance,
        new InputArea(
            new Input("Guess", new InputText(BindingBuilder.value("#{model.lastGuess}"), true))
        ),
        new Button("Submit", BindingBuilder.action("#{controller.guess}"))
    );
}

Let me explain this method. This method returns a Fragment which can construct a tree of components that build op a part of the page. The Group and OutputText classes create a HtmlPanelGroup and a HtmlOutputText respectively. The NewLine creates a UIComponent which outputs a <br /> tag. The InputArea tag produces a HtmlPanelGrid with the right number of columns for displaying inputs in a tabular form. The Input class uses other fragments which will create the right components for displaying an input.

The guessnumber application shows the power of the fragment library. This application is already useful for rapid development of new components. One does not have to go through the tedious process of creating a tag class, writing a tld and registering the component in the faces-config in order to use the component.

Conversation library

For now, the conversation library is work in progress. Its aim is to define the structure of a web application using nested conversations. A conversation is a set of views sharing the same model and controller. Conversations can invoke nested conversations or give control back to a previous conversation.

The books applications demonstrates how this should work. It is also used to 'harvest' the conversation library. The books application uses a domain model with the book and author domain objects, which have a many to many relationship. To maintain data in this deceivingly simple domain requires a rather complex web application. The book conversation contains pages for adding a new book, viewing a book and editing a books properties. The author conversation does the same thing for authors. When a user clicks on an author while viewing a book, the author conversation is entered. When a user clicks the back button, he returns to the book. The stack showing the current navigation path is also shown to the user.

Conversations themselves implement the Conversation interface giving the container access to its pages. Conversations get dependencies on other conversations and on data access objects injected. Conversations can be tested outside of a web container.

The current work in progress can be viewed in subversion.