The Source for Java Technology Collaboration
User: Password:



   

Building Web Components Without a Component Framework Building Web Components Without a Component Framework

by Michael Jouravlev
08/04/2005

Contents
What Is a Web Component?
Two-Phase Request Processing
The Lifecycle of a Standalone Component
Single-State Component
Multiple-State Component
JSP Control
JSP Controls Vs. Portlets
JSP/Servlets Compatibility
Creating JSP Components Using Struts
Struts Dialogs
DialogAction Navigation Rules
Handling Error Messages
Keeping State
What About AJAX?
Conclusion
Live Demos
References and Source Code

JSF is touted to be the ultimate component framework for Java web application programming. Tapestry claims to be based on the idea of component development. And across enemy lines, ASP.NET generated a whole new market for web components. What are web components and can they be developed with something more traditional like JSP and Struts?

What Is a Web Component?

A web component can be defined as a stateful server-side object that handles client events and input data, renders itself according to its state, and has a certain lifecycle. A web component can be embedded into another component, can contain other components, or can be standalone. Embedded components are often called controls, especially by the ASP.NET crowd.

Depending on the particular component architecture, the parent/child association can relate either to server objects or to visual representation. For example, JSF differentiates between a server-side component and a corresponding page widget, while Tapestry combines both component template and a Java class in one definition.

This article treats a web component in the old-fashioned way, as a resource that is identified with a unique location, accepts user input from request parameters, and is able to render itself.

What is new in that, you may wonder? Nothing but good old HTTP with a twist. If you use JSP as the presentation layer for your web applications, this article may open some new possibilities.

Two-Phase Request Processing

The central concept of the discussed approach is the splitting of one submit request into two phases: input and output. This two-phase request processing solves several issues related to the submission of HTML forms, like implicit double submits, annoying POSTDATA messages, and unfriendly user experience for reload, back, and forward buttons. The two-phase request/response sequence looks like this:

  • The browser submits input data to a component.
  • The component processes the input, updates its state, and redirects the browser to the result location.
  • The browser loads a result page using another request.

Because this pattern includes redirection, it can also be called "Redirect-After-Post" or "Post/Redirect/Get." It must be understood that redirection is an inherent part of this pattern. Redirection allows splitting one solid "submit input data, respond with result page" process into two phases, which are completely independent from the server standpoint. This technique is implemented in several frameworks either as the main vehicle for component lifecycle handling (Wicket, Ruby on Rails), or as an option (JSF).

Two-phase request processing has three modes of operation:

  • With an initialization event, a component is prepared for use with new set of data.
  • In the input phase, a component accepts input data, updates the domain model, and generates error messages.
  • In the view rendering phase, a component generates a result page.

The Lifecycle of a Standalone Component

A standalone component has a whole page for itself, so the address of the web page is the same as the location of a component. When a HTML form is submitted, the component handles the event, validates input data, and updates its state.

If there's an error, the component saves error data in the session and redirects to itself. This is called component reloading. Redirection to the same location does not cause an infinite loop, because the new request is of the GET type and is "clean;" that is, it does not contain query parameters. When the component receives a "clean" GET request, it renders itself.

If no errors were detected, the component can either relinquish control to another component, or can reload itself and render a page corresponding to its new state. Redirection is a preferred way of passing control to prevent implicit resubmits.

Stateful web components must be explicitly initialized using a special request parameter. Otherwise, it would be impossible to distinguish between the following situations:

  • Using the component with a fresh set of data.
  • Navigating to component using a link.
  • Manually reloading a component using the browser's refresh button.
  • Automatically reloading a component as the second phase of request processing.

The initialization event offers a chance to reset and clean the component, and to fill it with new data. Three other events--linking, manual refreshing, and automatic reloading--are treated in the uniform fashion: the component receives a "clean" GET request and renders a view corresponding to current state. This means that navigating to the standalone component via a link displays the current state of the component, but does not initialize it.

Single-State Component

Figure 1 shows the a simplest case of a standalone component, which has only one state and one view. Such a component can be called a dialog. This particular dialog is used for user login. It collects the user name and password and validates them. If the login information is valid, it redirects to the user's home page. If invalid, the dialog generates an error message, temporarily stores it in the session, and reloads itself. After reloading, the dialog redisplays the invalid user name and password along with an error message. The cycle repeats until a user enters valid login information.

Figure 1. Standalone login dialog
Figure 1. Standalone login dialog

The login dialog is a stateful object; it saves the user name and password between login attempts. On the other hand, the login dialog does not define an explicit state name, because there are no other states in which the login dialog can exist.

The login dialog is represented on a web page as an HTML form. When the form is rendered, its input fields are populated with dialog properties. When the form is submitted, the request sends form data directly to the login dialog.

It may appear that the dialog does not have to be initialized explicitly: each time it is navigated to, it can be recreated. This is not true. A dialog handles a request in two phases, so it is impossible to distinguish the reload phase from navigating to it using a web link. In both cases, the dialog is accessed with a GET request, so there should be something different between the requests that sets apart initialization and reload operations.

Therefore, all two-phase components, even simple ones, must be explicitly initialized. If the login page is the first page of a website, it will be initialized at creation time. Otherwise, a link to the login dialog should contain an initialization parameter.

Multiple-State Component

Figure 2 shows a version of the standalone login component, which not only allows the user to log in, but also tracks the user's login status. This component has two different states: "not logged in" and "logged in," and two corresponding views.

Figure 2. Standalone multi-state login component
Figure 2. Standalone multi-state login component

Whenever a logged-in user navigates to the login component location, the component displays user information and allows the user to log out.

Pages: 1, 2, 3, 4

Next Page » 

View all java.net Articles.

 Feed java.net RSS Feeds