C H A P T E R  2

Develop an Application

This Suntrademark ONE Application Framework Develop an Application chapter explains in detail the creation and usage of application components that can then be assembled into a complete functional application.


Create an Application

What is a Sun ONE Application Framework Application?

The Sun ONE Application Framework notion of application is essentially the same as the J2EE notion of a Web-tier application. In short, a Sun ONE Application Framework application is a J2EE Web-tier application with some Sun-ONE-Application-Framework-specific features. As such, Sun ONE Application Framework applications use the standard Web Application aRchive (WAR) structure as their basis. Therefore, when you create a Sun ONE Application Framework application, you are creating a Sun-ONE-Application -Framework-specific WAR file, and implicitly defining a single ServletContext for that application. Each Sun ONE Application Framework application has a single standard web.xml file, containing some Sun-ONE-Application-Framework-specific data.

Because a Sun ONE Application Framework application is in the end a J2EE application in a WAR file structure, you can use other J2EE features within the same application. For example, it is perfectly feasible and acceptable to use non-Sun-ONE-Application-Framework JSPs or servlets in the same WAR file. To a limited extent and as permitted by the J2EE specification, these non-Sun-ONE-Application- Framework application components can interoperate with Sun ONE Application Framework application components. For more information, see the section Interoperating With Sun ONE Application Framework Applications in Chapter 3, Programming Guide.

A Sun ONE Application Framework application is also a logical entity which describes a related set of components that interact to serve a specific function. In more concrete terms, an application is a set of pages, Views, Models, and application specific code that are deployed as a single unit as a single WAR file. Any changes to any of the parts of the application generally require the re-deployment of the entire application (as a WAR file, per the J2EE specification). The application WAR file will contain all relevant libraries, classes, and resources required for that application to function, with the notable exception of those libraries provided by the J2EE container.

Application-Level Entities

In addition to the Sun ONE Application Framework runtime library, web.xml file, and other assorted WAR file artifacts, each Sun ONE Application Framework application generally has an application servlet. This servlet serves as a base class for the various module servlets in the application (see below), and therefore provides an opportunity to perform application-level event handling, initialization, or other tasks related to each request.

Modules

Because real-world applications can become extremely large, and have different parts with slightly different functional requirements, the Sun ONE Application Framework adds an application sub-unit called a module. A Sun ONE Application Framework application consists of one or more Sun ONE Application Framework modules deployed as a single unit. All Sun ONE Application Framework applications must have at least one module.

Do not confuse the Sun ONE Application Framework usage of the term module with J2EE use of the term, which can be used as a synonym for a J2EE Web application as a whole. For example, you might see a J2EE Web application or WAR file described as a Web module. In this document, all references to application will refer specifically to a J2EE Web application or WAR file as a whole, and all uses of the module will refer to Sun-ONE-Application-Framework-specific modules, which have no analogue in J2EE.

In physical terms, a module is a single Java package under the application WAR file's WEB-INF/classes directory (the remainder of this section will refer to paths relative to this directory). A module package is an arbitrary package chosen by the developer, and can consist of any number of subdirectories. For example, both main and com.mycompany.main might be module packages.

Perhaps the most important distinction between a module package and any other arbitrary package is that only ViewBeans inside a module package will be accessible to clients of the application (see more below). This is accomplished primarily via a servlet mapping in the application's web.xml file. This mapping maps the module's module servlet (explained below) to a URL path. Generally, this URL path is a simple name and not fully qualified. For example, although a module package might actually be com.mycompany.main, to an external client, it might be identified only by the URL path /main. This reduces complexity for the users of the application, and reduces the length of URLs. The URL mapping need not share any similarity to the module package. In the example above, a URL path of /foo would also have been possible.

Clients can only request logical page names (not class names), which are automatically mapped to ViewBean class names by the module servlet. Therefore, it follows that only ViewBeans are directly accessible to external clients. For security and other reasons, all ViewBeans within a module package must exist directly within that package. ViewBeans within subpackages are not accessible (the subpackage must be declared as a module for those ViewBeans to become accessible), though they can be used in other ways by the application (for example, as subclasses).

Module Servlet

Each module has a single module servlet that handles all client requests for objects within that module. The module servlet acts as a front controller, intercepting all client requests and firing events as needed before dispatching the request to an application component. For example, the module servlet has events related to the beginning and end of a request, session initiation and timeout, and various error conditions. These events are described in the section on Handle Requests.

A module servlet generally derives from the application's application servlet. Because the application servlet is the superclass, the module can override or add behavior specified for the entire application as needed. For example, this becomes useful if a particular module has different requirements for handling certain events, such as session timeout. The module author can specialize the module's behavior as needed, yet still leverage common application-wide front controller behavior.

There is no strict requirement that a module servlet derive from the application's application servlet base class. It can instead just directly derive from the Sun ONE Application Framework's com.iplanet.jato.ApplicationServletBase class. However, there is seldom need to avoid the derivation, and the Sun ONE Application Framework IDE toolset will automatically create module servlets that derive from the application servlet base class.

Package Structure

In general, a Sun ONE Application Framework application's WEB-INF/classes directory looks like the following:

/Base application package (may be multiple directories deep)
<Application servlet>
     <Other application classes/objects/files>
     /<module 1>
        <Module servlet>
        <Other module classes/objects/files>
     /<module 2>
        <Module servlet>
        <Other module classes/objects/files>
     ...
     /<module n>
        <Module servlet>
        <Other module classes/objects/files>

Each module is a self-contained sub-package of the overall application. Pages and objects in one module can interact with objects in other modules via cross-module navigation and/or simple class references. Cross-module navigation is covered later in this document.


Create a WAR File

Sun ONE Application Framework applications are packaged like any other J2EE Web-tier application in a standard Web Application Archive (WAR) file. Sun ONE Application Framework applications have certain assumptions as to where certain files will be located within the WAR file. The following is the recommended layout for Sun ONE Application Framework WAR files:

/[base application package]
    /[module 1] 
        [Module JSP files]
    /[module 2]
        [Module JSP files]
    ...
    /[module n];
        [Module JSP files]
/[other static resources]
/WEB-INF
    web.xml (the application deployment descriptor)
    /classes
        /[base application package]
            [Application servlet class]
            [Other application classes/objects/files]
            /[module package 1]
                [Module servlet]
                [Other module classes/objects/files]
            /[module package 2]
                [Module servlet]
                [Other module classes/objects/files]
            ...
            /[module package n]
                [Module servlet]
                [Other module classes/objects/files]
    /lib
        [Sun ONE Application Framework runtime jar file]
        [other Sun ONE Application Framework component libraries]
        [other application jar/zip files]
    /tld
        /com_iplanet_jato
            jato.tld (the Sun ONE Application Framework tag library descriptor)

There are two parallel directory hierarchies--one for JSP files, and one for module classes. These two directory hierarchies should remain in parallel, although strictly, they need not. Specifically, each ViewBean is configured with the URL of its JSP peer during development, and this URL is arbitrary. However, to avoid naming collisions between modules which might be developed by different groups, the parallel directory structure illustrated above should be maintained.

Use Component Libraries

Although earlier versions of the Sun ONE Application Framework had rich support for certain types of application components, version 2.0 formalizes this support and extends it to most types of framework objects. Beginning with version 2.0, Views, Models, and Commands--as well as supporting classes--can all be designated components. With this designation, these objects become introspectable and manipulatable by the IDE toolset to allow for highly-productive visual development of a Sun ONE Application Framework application.

The Sun ONE Application Framework defines a basic set of components, and Sun Microsystems and other developers are expected to provide additional component libraries that significantly extend the features and power of the core framework. For information on creating your own reusable components and component libraries, see the Sun ONE Application Framework Component Author's Guide.

What is a Sun ONE Application Framework Component?

Since its inception, the Sun ONE Application Framework has supported a component model for certain types of objects. However, this component model relied on developers to learn each component's API and write code to use that component in his or her application. Although this level of functionality was sufficient and provided a significant productivity advantage over contemporary competitors (which had, and still have, no component models), Sun ONE Application Framework version 2.0 has significantly extended its component model to encompass all types of primary application objects (Views, Models, and Commands) and to allow rich IDE-based development of Sun ONE Application Framework applications.

In version 2.0 terms, a component is one of the various types of supported component classes in conjunction with metadata information. This metadata is encapsulated in a Sun-ONE-Application-Framework-specific class called a ComponentInfo class. At design-time, the development environment can inspect the ComponentInfo and present the component in an easy-to-use visual fashion.

The metadata stored in ComponentInfo classes is intended to enable automated use of the component in a development environment, such as the Sun ONE Studio. Developers can still manually create and use various types of components in their applications without defining a ComponentInfo class.

There are two types of Sun ONE Application Framework components. The first type is referred to as a distributable component. Distributable components are packaged in a component library and are generally deployed as part of a set of components. Distributable components have explicit ComponentInfo classes associated with them, and are specifically developed to be deployed for use by other developers.

By contrast, the second type of Sun ONE Application Framework component is referred to as an application-specific component, or a non-distributable component (do not confuse the term distributable in this context with the J2EE use of distributable to describe applications that run on multiple VMs; the reference is to distribution to other developers in this context). These components are only reusable within the application in which they are defined. They generally do not have explicit ComponentInfos associated with them, and exist as first-class objects in the current application. As an example, whenever you build a ContainerView or Model in your application, you are building an non-distributable component for use within that application. Because the IDE toolset knows how to manipulate these components directly, they are usable within the same application without any additional work by the developer. However, it generally takes some additional work to turn non-distributable components into distributable components (such as adding an explicit ComponentInfo class).

There is also another special classification of component, which is the extensible component. Extensible components are components that can be subclassed to create new types of components. Non-extensible components can have instances created of them, but cannot be extended to add new behavior. As of the current version of the Sun ONE Application Framework, all non-distributable components are derived from extensible components (though they are not themselves extensible components). Only certain distributable components are extensible components.

If all of this sounds confusing at first, don't worry. The IDE toolset will automatically manage these subtleties for you so you can just concentrate on building your application. As an application developer, you will generally never need to worry about whether a component is extensible or not, or whether it has a ComponentInfo class.

Sun ONE Application Framework Component Library

The Sun ONE Application Framework Component Library contains the core interfaces, runtime classes, and many basic components that you will use to create a Sun ONE Application Framework application. The component library is packaged as a single JAR file, and should appear in your application's WEB-INF/lib directory.

When creating a Sun ONE Application Framework application using the IDE toolset, the current version of the component library is automatically added to the application's WEB-INF/lib directory. If you open an application created in a previous version of the IDE toolset, you might be prompted to upgrade the application, including the Sun ONE Application Framework runtime library.

Other Component Libraries

In addition to the Sun ONE Application Framework Component Library, you might add additional component libraries to your application simply by placing them in your application's WEB-INF/lib directory. The IDE toolset will automatically recognize and mount the component library (it might take a minute or two), after which you will have the library's new components available for use within your application.

Unpacking of Tag Libraries

As part of a Sun ONE Application Framework component library, a library developer might provide one or more tag libraries to support rendering of the library's View components. Tag libraries are declared in the component library's component manifest file, and when the IDE toolset recognizes the component library, its tag library descriptors (.tld files) are automatically unpacked from the library JAR file for use by the application. In addition, the IDE toolset automatically adds tag library entries to the web.xml file.

Tag library descriptor files are unpacked to a special location under the application's WEB-INF/tld directory based on the name of the library to ensure that same-named files from different libraries do not conflict. In this scheme, library names are converted to directory names by replacing dots (".") with underscores ("_"). For example, the component library's internal library name is com.iplanet.jato, which is translated to com_iplanet_jato when unpacking the tag library descriptor. The Sun ONE Application Framework component library's tag descriptor file ultimately appears under the WEB-INF/tld/com_iplanet_jato directory in your application.

The tag descriptor's derived physical directory name is automatically registered to a logical resource name in the web.xml file for use by the application. This logical name is chosen by the component library author. In the Sun ONE Application Framework component library's case, the descriptor is registered as the resource /WEB-INF/jato.tld.

The tag descriptor unpacking mechanism makes use of timestamps to determine if an existing file should be overwritten when a new version of the library is added to an application. This feature ensures that upgrading of an application's component libraries is just a single step for a developer.

Unpacking of Additional Files

In addition to unpacking tag descriptor files automatically, the IDE toolset can also unpack any other additional files the library author wants when a component library is added to an application. These additional files can include JAR files, static HTML files, image files, JSPs, or any other type of file. This is completely automatic when a new component library is added to an application in the IDE, but be sure to read each component library's documentation and keep an eye out for additional files that might appear suddenly in your application directory structure after adding a new library.


Create a Page (ViewBean)

As outlined above, a single logical page in your application generally consists of two parts: the ViewBean, and an associated JSP. The emphasis in the IDE toolset is on the ViewBean half, since it is a Java class and is a natural fit for the types of authoring tasks (such as configuration of components) required by the developer. Therefore, the JSP can be considered the subordinate half of a logical page object, and the following sections emphasize the tasks required to create a ViewBean first, and how to create and manage its set of JSPs second.

Create a ViewBean Class

Creating a ViewBean is straightforward. If you are using the IDE toolset, it is as simple as selecting New -> Sun ONE Application Framework (JATO) -> Page (ViewBean) in the IDE, and selecting a choice from the ViewBean list of the New View Wizard.

You must create ViewBeans in a Sun ONE Application Framework module package for them to be accessible to clients of your application. ViewBeans outside a module package can be used as superclasses for other ViewBeans inside module packages, but cannot themselves be accessed by clients.

When you create the ViewBean using the wizard, you will generally create a companion, or peer, JSP file to render that ViewBean. This JSP file will appear under your application's document root, and be automatically associated with your ViewBean by a <jato:useViewBean> tag declaration. By convention, the path to the JSP mirrors the package name of the ViewBean, so that a ViewBean placed in a com.mycompany.main package will have a JSP created in a com/mycompany/main subdirectory of the application document root. See more about a ViewBean's JSP associations in the sections below.

If you are creating a ViewBean manually, you can simply create a subclass of com.iplanet.jato.view.BasicViewBean or another ViewBean class in one of your application's module packages. However, a ViewBean created manually is not manipulatable in the IDE as anything but a plain Java file--you have to manually add all components and event handlers to the ViewBean yourself. You also need to add and associate JSP files with the ViewBean manually.

Naming

Previous versions of the Sun ONE Application Framework used a strict naming convention to map request page names to ViewBean class names. This restriction has been removed beginning with version 2.1 and ViewBeans can be name just like any other class. For existing applications that need to maintain backward compatibility, there is a web.xml setting that can toggle the use of the strict convention. For more information, see Chapter 4, Deploy an Application.

By default, the IDE toolset creates applications that allow ViewBeans without the strict naming convention, meaning ViewBean classes can assume any name you want.

Code

If you double-click the ViewBean class in the IDE, or open it with a text editor, you see that the ViewBean generally has some preexisting code from its initial creation, plus some code in protected blocks that cannot be edited (in the IDE at least).

Do not use another editor to edit the protected code blocks in your ViewBean or other Sun ONE Application Framework object. Your changes will just be overwritten the next time you make a change to the class in the IDE. If you need to add code to a particular spot within the protected areas, either rethink what you are trying to do (chances are you don't really need to add code there), or use the Code Generation tab for the ViewBean or one of its child components to add code in a standard way.

You can generally add any other code or methods to the ViewBean that you want, or override some of its methods that do not have a visual IDE representation. Some of the more interesting methods you might want to override for advanced techniques are getDisplayURL(), mapRequestParameters(), setRequestContext(), securityCheck(), beginChildDisplay(), and handleRequest().

Code within your ViewBean classes generally does not need to be thread-safe, as each request thread gets a private copy of a ViewBean. Also note that ViewBeans are request-scoped objects, so do not try to save data in a ViewBean instance between requests.

Manage JSPs

The most common technique for rendering a ViewBean as a response to a client request is to use what is called a peer JSP. This JSP contains custom Sun ONE Application Framework tags that associate it with its peer ViewBean. At runtime, the JSP and the ViewBean work together to render a dynamic response to the current request. This combination of JSP + ViewBean allows for powerful layout and content capabilities (the strengths of JSP technology) while keeping JSPs easy to maintain and code-free.

Each JSP can only be associated with a single ViewBean, but a ViewBean can be associated with many JSPs at the same time. These other JSPs can contain variations on the content and layout used to render the ViewBean; this is the parallel content feature discussed in the section Display URLs and Parallel Content. However, despite the presence of this feature, ViewBeans predominantly use only a single JSP in most applications.

JSPs have what is frequently referred to as a uses relationship with their peer ViewBeans. In other words, JSPs use their peer ViewBeans while rendering a response. ViewBeans, however, do not use their associated JSPs in the same fashion; that is, their relationship is not symmetrical. During rendering, the JSP pulls data from the ViewBean. The ViewBean is called by the JSP to provide this data, but it never calls the JSP for anything. The JSP is in the driver's seat when it comes to the rendering or display process.

For a JSP to be associated with a ViewBean, it must minimally have a valid <jato:useViewBean> tag declaration that calls out the ViewBean's class. At runtime, when the ViewBean is forwarded to display itself, it must select a JSP with a matching <jato:useViewBean> tag and return the JSP's URL relative to the application's document root as its display URL (via the getDisplayURL() and/or getDefaultDisplayURL() methods).

In the Sun ONE Application Framework IDE toolset, each ViewBean node has a sub-category node called JSPs. One or more JSP nodes can appear underneath this node, and each of these JSPs are associated with the current ViewBean via a <jato:useViewBean> tag declaration that calls out the ViewBean's class name.

Each of these associated JSPs is assumed to be managed by the ViewBean. Managed means that these JSPs should be automatically synchronized with the ViewBean as child View components are added. (This idea of managing a JSP is purely a design-time notion and has no runtime meaning.) More on this feature in the sections below.

The primary use to the developer for these JSP nodes is to allow him or her to easily open a ViewBean's JSP file, and assuming there is more than one managed JSP, to select a default for the ViewBean's display. The developer can right-click on any JSP node in the JSPs category and select the Set as Default JSP menu item to select that JSP as the ViewBean's current default. There can be only one default at a time.

Setting a particular JSP as the ViewBean's default results in the URL for that JSP being set as the ViewBean's default display URL, via the setDefaultDisplayURL() method. You might notice the generated code that calls this method in your ViewBean in one of the protected code blocks.

When a ViewBean is executed during runtime, the default JSP is used to render the ViewBean unless the developer has overridden the ViewBean's getDisplayURL() method to return a different value. Therefore, during development, you can usually switch between JSPs for alternate test runs by setting a different default JSP and recompiling the ViewBean.

Add Child View Components

A ViewBean is generally useless without adding some child View components to it to represent display fields on the page. Therefore, a major part of authoring a page is adding child View components to the ViewBean and configuring them to access Model data.

You can easily add a child View component to your ViewBean by right-clicking on its Visual Components node and selecting Add Visual Component... You will be presented with a component chooser dialog that shows you the currently available View Components in the application and each of its mounted application libraries. Alternatively, you can choose a component to add from the Component Palette.

Child View components basically come in two different types. The first type is Views that implement the com.iplanet.jato.view.DisplayField interface and effectively act as leaves on the tree of View components. DisplayFields usually represent a single primitive piece of data, such as a String or Integer, and frequently can be changed by the user and submitted back to the server. A good example of a DisplayField View component is the Basic Text Field component that comes with the Standard Component Library.

Occasionally, some DisplayField components are complex, meaning they also implement the ContainerView interface and have child View components themselves. Generally developers interact with these components as DisplayFields and have no idea that they are themselves compound components.

The various DisplayField components provided in the Standard Component Library all have the ability to be associated with a Model via a ModelReference and a Model field binding. For more information, see Chapter 3, Programming Guide, Working with Values.

The second type of View component is the ContainerView (or, alternatively, pagelet), which really encompasses a couple of subtypes including the TiledView and TreeView, and other types provided by third parties. ContainerViews are special types of Views that can contain other Views (including other ContainerViews), and they function as compound components. Through ContainerViews, View components can be nested to any arbitrary level in what is commonly called a View component hierarchy. In client-side application terms, a ContainerView is the equivalent of a panel component, like JPanel in Swing. A TiledView component is roughly described as a table component (though it is not limited to that use), and a TreeView component is equivalent to a tree component like JTree in Swing.

Various types of ContainerViews might have custom properties and methods to allow developers to more easily interact with them, rather than needing to work with or understand the complex set of components they contain. ContainerViews are most frequently application-specific non-distributable components, meaning they are generally types within the current application that can be partially implemented or extended by the developer.

In terms of adding a ContainerView component to a ViewBean (or another ContainerView), there is no real difference from adding any other type of View component. ContainerViews expose properties that can be configured just like other View components. The one difference is that ContainerViews generally expose their inner complexity for purposes of interacting with the ViewBean's JSP. Specifically, developers can generally see children of ContainerViews and individually synchronize and lay out those components.

After a child View component has been added to the ViewBean or other ContainerView, the developer simply needs to configure it via its property sheet. As each property is filled out, the generated code in the ViewBean will be updated to configure the component at runtime. Also, as each child View component is added to the ViewBean, a matching JSP tag is added to the ViewBean's managed JSP(s). This tag will be minimally configured, and added with only basic regard to the static content layout in the JSP. The developer must add any additional desired attributes to this tag and arrange it to suit the page's layout. See the following section for more details.

Synchronize to the JSP

Just because a child View component is added to a ViewBean, it might not or should not necessarily be rendered when the ViewBean is displayed. For example, some View components should only appear on certain JSPs associated with a ViewBean, or might be used only by application code for their association with a Model field.

Each child View component must have a representation in a JSP associated with a ViewBean to be rendered with that ViewBean. This representation is normally a custom JSP tag provided by the component author. For example, when you add a Basic Text Field component to a ViewBean in the IDE, the toolset automatically adds a <jato:textField> tag to the JSP so that component will be rendered when the ViewBean is displayed.

Therefore, inherent in the notion of adding View components to a ViewBean is the idea of synchronizing one or more of the ViewBean's managed JSPs to the set of child View components. Each JSP basically has the ability to use only the fields that are relevant to it, so the developer needs a way to easily manage the JSP representation of each child View component.

The Synchronize to ViewBean... feature aims to make this JSP management easier. By right-clicking on a JSP node in a ViewBean and selecting this menu item, you open a dialog that you can use to select each of the child View components you want to appear in that particular JSP. When you press OK, the changes are made in the JSP--deleted component tags are removed, and inserted component tags are added. You can then open the JSP file itself and arrange these tags to work within your JSP's overall layout (inserted tags are added near the end of the file).

This feature is simply a convenience. You can manually synchronize a ViewBean to a JSP by adding, editing, or removing tags in the JSP file. In fact, some View components might not support automated synchronization, and will require manual synchronization to appear in the rendered output.

JSP tags are added to a JSP based on the content type of the JSP. Developers have the ability to select a tag template for each content type their component supports, so depending on the dialect of your JSP, you might see different JSP tags for the same View component when using different content types. Pay attention to the features each set of tags supports, as they might also differ by content type

Execute a Page from the IDE

Generally, when writing a Sun ONE Application Framework application, you want to be able to run the current page to see how it is working and to test its JSP's layout. Instead of manually packaging the application, deploying it in your container, then opening a browser to the correct URL, you can do this all in one step by simply executing the ViewBean.

First, make sure your application has been fully compiled at least once by selecting Build All... from the application node. (All the files in your current module will be compiled for you when you execute the ViewBean.) Right-click on the desired ViewBean and select the Execute Page (Redeploy) menu item or toolbar button. Depending on which J2EE server you have selected as your default for Web applications (see Sun ONE Studio help), this will automatically deploy your application and load a browser with the correct URL for that ViewBean. If you have made any changes to application code, you must execute the page with the Redeploy option, or your changes will not be reflected in the application. The only exception to this is changes to the JSP, which are automatically detected.

You can only execute ViewBeans in a Sun ONE Application Framework module. Remember, ViewBeans outside a module cannot be accessed by application clients.


Create Pagelet (ContainerView) Components

This section describes creating View components from extensible components contained within a component library. Extensible components are components that are meant to be extended (subclassed) to create new types of components. After a new component type has been defined (using the extensible component as the basis), many instances of it might be used within a given application.

Create a ContainerView Class

There is really nothing different about creating a ContainerViews class; the process is analogous to creating a ViewBean class. The only difference is that ContainerViews, like all pagelets, cannot be executed on their own. They must be designated as children of another component and placed inside a page to be run.

One other difference is that ContainerViews and the other types of pagelets might opt not to create a JSP fragment, and instead delegate all rendering to its parent component. This means that custom tags that represent the pagelet and its children are placed in the parent's JSP (or its parent if it does not have one of its own, and so on) instead of in a standalone JSP fragment.

Primary Models

Many types of ContainerViews use the notion of a primary model, or a model that drives their rendering. For example, TiledView implementations generally require a primary model of type DatasetModel to proceed from tile to tile, and to know when to stop iterating. In the same way, TreeView implementations also require a primary model of type TreeModel to display a hierarchical view of that data.


Handle Requests

Handling and responding to client requests is inarguably the reason Sun ONE Application Framework applications exist. This section outlines the various features Sun ONE Application Framework provides for handling and responding to client requests.

Request Lifecycle

In general, each request consists of two parts: the submit phase and the display phase.

When a user accesses a page in a Sun ONE Application Framework, he or she generates an HTTP request to the server where the application is running. This client request is initially handled by the application's module servlet, which acts as the front controller for a particular application module. The module servlet fires various request lifecycle events (for example, session timeout detection) and then determines a ViewBean class to invoke based on the information submitted from the client. The ViewBean class the servlet invokes is normally the same class that was responsible for generating the user's previous response. In this way, transitions between pages (ViewBeans) occur in a Sun ONE Application Framework on the server only, as directed by the application developer.

When a page is asked to respond to a request, its ViewBean's invokeRequestHandler() method is called by the module servlet. That is the first point of entry to the application proper. This begins the submit phase. During the submit phase, submitted values are mapped to View components and Models, then an event handler is invoked to process the request and prepare a result. The submit phase generally ends when the application (or the framework) calls the forwardTo() method on the same or another ViewBean from inside an event handler, thus beginning the display phase.

During the display phase, a number of things happen, the most important of which is that the JSP associated with the ViewBean is rendered. This causes a callback to the associated ViewBean's beginDisplay() method. The ViewBean and all its children then render as the JSP is processed, finally completing with the endDisplay() method being called on the ViewBean. The request is not yet complete, however, as the forwardTo() method returns to whatever code called it. When that code completes, the call stack unwinds and the response is sent to the client.

Just before the call stack unwinds, the module servlet fires more request lifecycle events, and any registered RequestCompletionListeners are called so that they can do things like add last-minute information to the session (but not affect the response in any way). This completes the request.

Front Controller Events

Before each request is dispatched to an individual RequestHandler (the ViewBean or one of its children), it is processed by the front controller. In concrete terms, the front controller is the module servlet. The module servlet normally derives from the application's application servlet, which normally derives from com.iplanet.jato.ApplicationServletBase (it is possible that there could be some variation from this scheme, but ultimately, all Sun ONE Application Framework servlets must derive from ApplicationServletBase). ApplicationServletBase fires a number of events during request processing. Developers can respond to these events by overriding the event callback methods in the application or module servlet. These events offer the opportunity to consolidate general request processing logic in a single location.

The following table lists events fired by the module servlet (more information is available in the JavaDoc for com.iplanet.jato.ApplicationServletBase):

Event Method

Description

onAfterRequest

Fired after the current request is complete. Can be used to clean up request-specific resources or finalize data in the session.

onBeforeRequest

Fired when a new request is received. Can be used to verify some portion of the request (such as a user principal parameter), or redirect the request upon some condition.

onInitializeHandler

Fired to allow application-specific initialization of a RequestHandler instance (normally a ViewBean). Can be used to handle common initialization of ViewBeans, perhaps based on some request attribute.

onNewSession

Fired when a request without a session is received and a new session is created for the client. Can be used to prepopulate the user session with data.

onRequestHandlerNotFound

Fired when the requested RequestHandler (i.e. ViewBean) was not found. Typically used to respond to.

onRequestHandlerNotSpecified

Fired when a RequestHandler (i.e. ViewBean) was not specified in the request

onSessionTimeout

Fired when a request with an expired session ID is received. Typically used to reinitialize the client's session or redirect to a login page.

onUncaughtException

Fired when an unexpected exception occurs during request processing. Typically used to present an error page to the client.


To use these events, application developers simply override these event methods and perform whatever logic is required. The most common behavior is to redirect the request to a different page than that which was originally requested by the client. This is common for error or session timeout conditions. However, these events are fired as request processing occurs, and they provide no specific mechanism to communicate to the main request processing logic that normal processing should stop.

Therefore, there is a technique commonly used in these circumstances. The Sun ONE Application Framework provides a special exception class, com.iplanet.jato.CompleteRequestException, that can be thrown anywhere during request processing, without actually causing an error condition to be raised to the client. The common use of this exception is to redirect processing of a request to another ViewBean, or perhaps by sending a result directly back to the client using the Servlet API, and then throw a CompleteRequestException so that the original request stops in its tracks. This exception essentially tells the request processing infrastructure of the Sun ONE Application Framework that the developer has handled the response already and further processing is not necessary. The following is an example of using this technique to redirect a request to a different ViewBean in the case of a session timeout:

public void onSessionTimeout(RequestContext requestContext)
{
    // Obtain a ViewBean in the application
    ViewBean viewBean=requestContext.getViewBeanManager().getViewBean(SessionTimeoutViewBean.class);
    // Forward the request to a ViewBean
    viewBean.forwardTo(requestContext);
		
    // Abort normal request processing
    throw new CompleteRequestException();
}

If you neglect to throw the CompleteRequestException in a scenario in which the response has already been handled, you will generally either get a J2EE or application error, or cause the first response to be completely ignored by the container, thereby defeating the purpose of handling the event.

Unlike other places you place code in your application, code in the module or application servlet must be threadsafe. Therefore, you must avoid using member variables (static or otherwise) to store request-scoped data in the servlet.

Application Events

After the front controller has fired various events for a request and determined which RequestHandler (for example, ViewBean) should dispatch the request, the ViewBean is invoked to complete the handling of the request. Specifically, the ViewBean's responsibility is to determine which of its subcomponents is responsible for handling the request, and to invoke that component to actually handle the event. This process is called request dispositioning.

An argument can be made at this point that the logical Controller role is at least partially filled by the ViewBean, which might seem confusing to some because it has been stated that the ViewBean is (also) a View component. This is part of what makes a ViewBean special, its dual nature as both a View and partial Controller of the request. This situation is actually quite intuitive--much like a window or dialog object in a client-side application determines which GUI widgest contained within it should receive a mouse click event, the ViewBean is responsible for determining which View component within it should respond to a request event.

This approach follows naturally from the fact that the Sun ONE Application Framework uses a component model to provide aggregation of an application from components. Just like Swing visual components have logic to help them determine which of their child components was clicked, so the Sun ONE Application Framework has similar logic. Without this ability, it would be impossible to create View components that can be assembled and wired together to create a View hierarchy.

During request dispositioning, the ViewBean and each of its contained ContainerViews in turn examine the javax.servlet.http.HttpServletRequest object to determine if it is the component responsible for handling this request. Once a responsible component is found, the request is dispatched to it, which generally causes a business logic event to be fired.

This abstract description might leave you wondering what is meant by the term responsible component. The responsible component is the first View component that implements com.iplanet.jato.RequestHandler to return a non-null result from the acceptRequest() method when it is called during request processing. A component normally decides whether to return an object from this method by examining the request parameters and determining if they contain a name-value pair that corresponds to an event that should be handled by this component. The details of this process are beyond the scope of this document, but the most important part to understand is that CommandFields are the key decision makers in this process. CommandFields is explained in the next section.

CommandFields

CommandFields are special types of Views that correspond to a component on a page that can be activated by the client to initiate a request to the server. Although any type of View could theoretically implement the CommandField interface, this wouldn't make much sense. Instead, only certain types of Views, such as button display fields, should implement this interface. For example, in HTML terms, both buttons (<input type="submit">) and links (<a href="...">) are represented in the application by CommandFields in the Sun ONE Application Framework, because these are components that users click (activate) and cause another request to be sent to the server.

CommandFields can be added to a ViewBean or other container just like any other View component, and the Sun ONE Application Framework component library contains both button and HREF/link CommandField components. The difference is that the framework understands that these types of components are special and therefore they are treated in a specific way. Specifically, they are examined during request dispositioning to determine if they were the source of the current request.

The end result of this process is that, for example, when a user clicks a button on a form in an HTML application, the result is that the button component in the application is called upon to determine how to handle that request. The button component has special properties that tell the parent component what to do to invoke business logic for that request. Specifically, an activated button or other CommandField specifies a developer-defined Command object that should be invoked for the current request. Alternatively, a CommandField can specify that a default Command object be invoked to handle the current request (by not specifying an alternative).

Command Descriptor Property

The developer specifies which Command object will be invoked when the field is activated via the field's Request Handler property. A CommandDescriptor is a Sun ONE Application Framework object that encodes the information needed at runtime to construct a particular instance of a Command class and invoke it. Minimally, the CommandDescriptor specifies which Command class should be instantiated at runtime. (the Command class is only constructed if the corresponding CommandField is activated.)

By omitting a value for a field's Request Handler property, the developer implicitly indicates to the framework that it should use a default Command object to handle the request.

This choice of Command objects leads to two alternate ways of handling a Sun ONE Application Framework business logic event: via a request event handler method on the parent of the CommandField (if the default Command is used), or via a developer-defined Command object. Both alternatives are explained in the following sections.

Request Event Method Handlers

The most common approach for handling request events is to use a request event method handler. The developer implements a method with a certain naming convention and signature that will automatically be called when the corresponding CommandField is activated. This is much analogous to implementing an event handler method for a client-side application.

The advantages of this approach are that it is easy to understand and maintain, keeps code localized to a relevant object, and allows the developer to write simple procedural logic. The disadvantage of this approach is that this event logic is not reusable between different fields or pages, though of course these methods can call common methods that are reusable in this fashion.

In the Sun ONE Application Framework, this event handler method is implemented in the parent of the responsible CommandField. This is more intuitive than it might sound. For example, if you create a new ViewBean and add a button component to it as a child, you would implement the request event handler method in the parent of the button component, the ViewBean.

You could not implement this method anywhere else, because you are creating an instance of the button component within the container--you cannot add a new method to an instance! This fact underscores the fact that there is a close relationship between a ContainerView type and its child component instances, and that both the container and its children work together to form a functional component.

The signature of the request event handling method is the following, where <childName> is the local (unqualified) name of the child component:

public void handle<childName>Request(RequestInvocationEvent event)

For example, in the example above, if you added a button component named submit to your ViewBean, you would need to implement the following method in your ViewBean in to handle events from the button:

public void handleSubmitRequest(RequestInvocationEvent event)

(The name of the child component is automatically uppercased as needed to create a conventional method name.)

Although you can add this method to a ContainerView class manually, the advantage of using the Sun ONE Application Framework module for Sun ONE Studio is that you can simply right-click and choose the handleRequest event from the popup-menu. This adds the appropriate method stub to your class for you.

Important: This style of event handling is only used if the developer does not specify a value for the CommandField's Request Handler property. If the developer specifies a descriptor for a CommandField, the framework assumes that the Command object specified in the descriptor will handle the request completely. The IDE might still allow you to add an event handler stub to your View, but it will not be invoked if a descriptor is specified!

See the sections below for information on how to actually implement business logic in your event handler methods.

Command Event Handlers

The alternative to a request event handler method is to implement a Command object directly, and associate it with a CommandField directly by supplying a value for the field's Request Handler property.

The advantages of this technique are that it allows reuse of application-specific or library-provided behavior, provides point-and-click application assembly, and to some, keeps View components cleaner by eliminating event handler methods. The disadvantages of this approach are that it causes a proliferation of Command classes (potentially one for every CommandField instance), it decouples event handling logic from objects that generate those events (less encapsulation of component behavior), requires more up-front design, and might require more code to accomplish the same task as a request event method handler.

To use this approach, developers simply create a Java class that implements the com.iplanet.jato.command.Command interface (by hand or by using the wizard in the Sun ONE Application Framework toolset). Once this work is done, the Command is available to be specified in the Command Class property of a CommandField's Request Handler property.

See the sections below for information on how to actually implement business logic in your Command objects.

Which Event Handling Approach Should I Use?

A general recommendation on deciding which request event handling approach to use is to be practical about which techniques solves the application requirements. It has been found that most applications will actually use both styles.

In general, when you want to encapsulate event handling logic within a component, are creating a component for reuse, or simply want to create a functional object quickly without worrying about abstracting every detail of the event handling, request event handler methods might be the more appropriate choice.

If, by contrast, you want to abstract away the details of event handling into common classes, need reusability of complex logic, or want to provide pre-built request event handling logic that can easily be assembled into an application, use Command objects.

Another thing to consider is that, in general, Command objects take more work up front to create, but might pay off later in terms of reusability. Request event handler methods are quick, easy, and familiar to many application developers that have used Swing or other client-side application development technologies, but might require more care to make important logic reusable.

In the end, there are no absolute rules, and no need to decide one way or another, even within the same object. The Sun ONE Application Framework gives you the flexibility to decide on a per-field basis which approach works best, and developers are encouraged to be open to the best approach for the job at hand.

Write Event Handling Logic

Regardless of how you elect to handle a request event, using either an event handler method or a Command object, you must write some logic to have your application do something meaningful. In general, your event handling logic will follow a routine pattern:

1. Execute business logic

a. Obtain values submitted by the user

b. Process these values

c. Prepare objects with results and for display

2. Render a response to the client

Event handling logic is typically procedural in nature--each request is primarily handled by a single method body, though this logic might make references to any objects or methods it wants (just like any other Java code).

Forward References

Sun ONE Application Framework objects such as ViewBeans can be forward-referenced within event handling logic, to allow configuration of these objects for the forthcoming display cycle. For example, it is possible for a developer to obtain a value from a field on the current page and then set this value on a different field on a different page within his event handling logic. This technique should seem familiar to developers who have used client-side application development technologies, where GUI widgets are stateful and can be referenced from more or less anywhere in the application at any time.

Business Logic

With exception of the use of the Sun ONE Application Framework API, it is assumed that most developers are already familiar with the general concept of writing application business logic. Because the use of the Sun ONE Application Framework API is covered in Chapter 3, Programming Guide, this skips to the discussion of how the developers reply to a client request after their business logic executes.

In addition to using the Sun ONE Application Framework API, developers have full freedom to use the J2EE APIs provided by their container from within their event handling logic. For example, it is perfectly feasible and acceptable to use Servlet, JDBC, JNDI, EJB, JavaMail, or other J2EE technologies or APIs within the scope of a Sun ONE Application Framework event handler. However, in some cases, the Sun ONE Application Framework provides features that make using these APIs considerably easier. Some of these capabilities are described in Chapter 3, Programming Guide.

Render a Response

After executing business logic in response to a request, the developer must determine the response that should be sent to the client, and depending on the desired technique, actually render this response. You will always be sending some kind of response to a client request, be it another page or an error message. In most cases, the response will be another page that follows logically from the executed request. For example, if the user clicks a button to add an item to his shopping cart, the response would probably be to show a page with the details of the user's shopping cart.

Every request comes to a crucial point in which it transitions from focusing on the request, and begins to focus on sending a response to the request. In Sun ONE Application Framework terms, this turning point in the request lifecycle is commonly referred to as the switch from the submit cycle to the display cycle. During the submit cycle, submitted values are mapped to View components and Models, and an event handler is invoked to process the results and prepare a result. During the display cycle, the result is rendered, or displayed, to the client.

Pageflow

The ubiquitous thin-client style of chaining pages together is frequently called pageflow. The user flows from one page to another by invoking an action on the first page, which sends a request to the server and results in a response page being sent back to the client.

There are many approaches to addressing pageflow. Some frameworks take the position that pageflow is a first-class requirement that should be directly addressed by a prospective framework. For example, these frameworks might specify that business logic return a JSP URL that should be used to render the response. A common problem with these approaches is that the response rendering mechanism then becomes very brittle--it is hard to send a response using anything except this mechanism. If this mechanism assumes a JSP or URL will be invoked to render a response, it becomes hard to satisfy certain application requirements that are at odds with this approach. For example, some application requests might result in sending back a binary response (such as a PDF file). These scenarios are difficult to solve if the framework assumes that the application cannot directly respond to the client.

By contrast, the Sun ONE Application Framework enables an easy pageflow mechanism, but leaves the decision of how to render a response in the hands of the developer. Specifically, Sun ONE Application Framework developers have the ability to easily forward to or include any ViewBean in the response, forward to or include any arbitrary URL, or send a result back directly to a client using the standard Servlet API.

Display a ViewBean

The most common approach to rendering a result is to forward the request to another ViewBean (this terminology derives from the underlying J2EE Servlet feature which allows forwarding of a request to response URL). In Sun ONE Application Framework terms, this is frequently referred to as displaying the ViewBean. Because ViewBeans generally have a URL for a peer resource such as a JSP associated with them, the framework can handle the details of actually invoking the appropriate JSP for a ViewBean if it simply knows which ViewBean should be used to display a response.

Therefore, after executing business logic for a given request, the developer might simply obtain a reference to the desired target ViewBean using the ViewBeanManager, and call the ViewBean's forwardTo() method to cause that ViewBean to be rendered as a response to the client:

public void handleSubmitRequest(RequestInvocationEvent event)
{
    // Do business logic here (this is still the submit cycle)
    ...
 
    // Display a ViewBean as a result
    ViewBean targetViewBean=
        event.getRequestContext().getViewBeanManager().getViewBean(
            ResponseViewBean.class);
    targetViewBean.forwardTo(event.getRequestContext()); // Start display cycle
 
    // Finish up (this occurs during the display cycle)
    ...
}

As you can see, the transition between the submit cycle and the display cycle is triggered by the developer's call to forwardTo(). This represents a significant opportunity--the developer could trigger this call at any point during his event handler. Furthermore, the forwardTo() method eventually returns, after which the developer has the opportunity to do some additional work during the display cycle (however, this is fairly uncommon).

Despite the emphasis on the submit and display phases, these phases are essentially logical in nature--they are just aspects of a single request to the application.

Display URLs and Parallel Content

So, how does a ViewBean know which JSP it should use to be displayed? There are two methods that allow the ViewBean to specify which URL should be used to render it when forwardTo() is called.

The first method is ViewBean.getDisplayURL(). This method returns a String containing the URL that should be forwarded to using the Servlet API RequestDispatcher mechanism. (this URL need not call out a JSP; it could instead call out a static HTML page (if it did not need to dynamically display data) or a page written using another (non-JSP) dynamic rendering mechanism. However, in practice, the majority of display URLs will refer to JSPs as these are the readily available J2EE mechanism.)

The value of the display URL is solely under the discretion of the ViewBean. For example, a ViewBean might use some information in the request, such as the client's locale, to decide between two different URLs, one in Spanish and another in French. In the core BasicViewBean implementation, if the developer does not provide alternative logic for the getDisplayURL() method, the method will simply return the value of the getDefaultDisplayURL() method. This value can be set by the developer in code, or automatically in the IDE by simply selecting a JSP under a ViewBean node, right-clicking, and selecting the Set Default option.

This ability for the ViewBean to decide on a particular URL from a set of URLs is the Sun ONE Application Framework's parallel content feature. Parallel content refers to the fact that developers frequently want to render the same dynamic data in several different ways. Using a single JSP, there is no way to accomplish this without using heavy conditionality or pulling static content out of the JSP. These approaches usually result in productivity and maintenance problems. Therefore, the Sun ONE Application Framework provides the ability to have multiple JSPs (or other URLs) associated with the same ViewBean. This allows the developer to provide parallel pages that present essentially the same dynamic data, but perhaps in radically different ways.

One use of this feature is to create pages that contain static content in different languages. For example, it would be difficult to create a single JSP that could present a ViewBean data in both English and Japanese. Not only are the character sets and languages extremely different, but the layout of the Japanese page will differ considerably from its English counterpart. Instead of writing a single, highly complex JSP, the developer can instead write two much simpler JSPs. Each one will refer to the same ViewBean, but will present the data in different ways. The ViewBean can make a decision on which JSP to use to display itself by examining the locale or the user's language preference and return the appropriate URL from its getDisplayURL() method.

Another use for parallel content is to target different device types. For example, a ViewBean could be rendered as either an HTML document or a WML document. It is not possible to create a common JSP to render both because the markup languages have incompatible differences. Instead, a developer can create JSPs in each markup language and allow the ViewBean to decide which to use. Again, the ViewBean would use some information to decide which URL to return from its getDisplayURL() method.

It would be remiss to imply that this decision making machinery is already built and ready to use in the core BasicViewBean class, when in fact it is not. There is a good reason for this: it is not possible for the Sun ONE Application Framework to know the range of application-specific variables that might play into the decision to display a particular URL over another. Furthermore, the URL scheme used to differentiate different versions of a JSP (say, English versus Japanese) is a decision the application developer must make. For these and other reasons, being prescriptive has been avoided in this area.

Therefore, when parallel content is required, the getDispayURL() method should be overridden by developers to supply the requisite decision logic. Also, it is expected that application developers and component providers will provide ViewBean components that build in a particular set of heuristics and schemes for determining and locating parallel JSPs. The users of such components would buy into a particular mechanism, with full knowledge of that decision, and with the ability to use different components with different mechanism as desired.

Although it is possible for other objects to call a ViewBean's setDefaultDisplayURL() method to change the URL that ViewBean will use during that request, this technique is discouraged because it violates the semantics of this method and leads to dependencies between objects that are hard to maintain.

J2EE Restrictions

The Servlet specification declares that it is illegal to call RequestDispatcher.forward() within a given request more than once, if the request has previously been committed to the client. This has implications for the ViewBean.forwardTo() method.

Generally, this restriction means that it is not possible to call ViewBean.forwardTo() multiple times within a single request. The only exception is if the current response has not yet been committed to the client. The response is committed to the client's output stream when the response buffer is filled to capacity and must be flushed to make room for more response data. After the first flush to the client, the response is considered committed, and trying to forward again will cause an IllegalStateException to be thrown by the servlet container. When using JSPs to render a response, the response buffer is configurable by setting an attribute in the page, so the developer has limited control over this restriction.

However, it would typically be uncommon to forward more than once within a given request--the developer chooses the response once and only once--so this restriction will not affect most applications. One possible exception is if the application encounters an error during the display cycle, after a forward, and needs to display an error page. When these conditions occur, be sure to set the response buffer size large enough to accommodate this eventuality.