Design Time View Handlers
This document is provisional and subject to change
Note: this document is provisional and subject to change.
The JSF specification allows users to configure custom view handlers for their web applications. The custom view handler can change the following aspects of an application:
- The construction and initialization of the view root.
- The construction and initialization of the component tree.
- Adaptation of the component tree to one or more view specification meta-data (i.e. JSP, XHTML, XML).
- Rendering of the component tree to the target (i.e. typically rendering to HTML).
- Store and retrieve view state between requests.
- Calculate locale and character encoding information for the target.
- Map viewId's to url's (action URL) that when invoked on a request, will restore the corresponding view.
- A number of other issues that vary between the 1.1 and 1.2 specifications.
The wide range of capabilities means that assumptions made by the JSF design time can be seriously invalidated by the introduction of a custom view handler. This document covers the significant design time implications of custom view handlers and outlines the requirements for a Design Time View Handler extension mechanism to allow adopters to handle them.
View Root Construction
The view is the basic addressable unit for creating and rendering responses to servlet page requests. A view consists of a tree of UIComponent objects that represent the logical structure of a JSF user interface. Each component tree is rooted at a UIViewRoot, which is a special UI component that is defined by the JSF API framework. It is the responsibility of the view handler to create, and optionally populate, the UIViewRoot upon the request for a particular view. (18.104.22.168).
The createView method on the ViewHandler interface is used at runtime to delegate construction of the UIViewRoot to the view handler. The design time view handler needs a parallel method:
abstract DTUIViewRoot createView(DTFacesContext facesContext, String viewId);
Component Tree Construction
The view handler may optionally populate the component tree for view in createView (22.214.171.124). It must also re-initialize the component tree for a view on a postback through the restoreView API interface (2.2.1). Although the component tree may be modified at any time prior to (or even during) rendering, the view handler is the primary actor in tree creation. Therefore, the design time must provide a mechanism through which the DTUIRoot can be populated with component information:
abstract populateView(DTUIViewRoot viewRoot, DTFacesContext context, String viewId)
Note a key difference between the design time and run time here. First, the tree creation functions of createView and restoreView are folded into this method since the request vs. postback lifecycle stages that they demark at runtime, hold no meaning at design time (since the design time is simulating and not actually emulating the application).
View Meta-data Adaptation
The view handler as part of its responsibility to create and restore view, normally acts as the adapter to view definition meta-data. It may do this in one of several ways. In the default case, JSF uses the servlet containers resource handling mechanism to build (and render) its component tree using the RequestDispatcher.forward method. The most common configuration of JSF forward requests to the JSP dispatch handler and uses JSP tags as the view definition meta-data format.
Custom view handlers may choose to also dispatch view construction and rendering and rely on the web application to be configured correctly to handle the supported meta-data format, or (as in the case of Facelets) it may choose to define its own meta-data format. Several design time issues arise as a result.
The design time view handler must provide support for the editing of its meta-data format. This in itself raises several issues since the two most common view handlers (JSP and Facelets) use meta-data formats which are not specific to JSF (JSP and XHTML respectively). Therefore, in many cases the design time view handler need only provide an adaptation between the UI definition artifacts in the meta-data (typically these are XML tags) and the UIComponent tree will be built from them at runtime.
The design time view handler can be queried for the meta-data definition types it supports via a metadata factory:
JSFViewMetadataAdapterFactory getViewMetadataAdapter(DTFacesContext context)
The JSFViewMetadataAdapterFactory can be provided view ids in the current project's DTFacesContext and can return a JSFViewMetadataAdapter for that view:
JSFViewMetadataAdapter createJSFViewMetadataAdapter(DTFacesContext context, String viewId)
JSF View Metadata Adapter
Because the view meta-data is generally the artifact that the end user wants to use to construct their UI (i.e. the JSP or XHTML pages), the adapter must provide support common design time view and editing functions. The JSFViewMetadataAdapter implements IAdaptable so that it can adapt generically between metadata artifacts and component artifacts (here component artifacts include non-component classes that are often included in view definitions such as validators and converters). For example, given a design time component artifact called ComponentTypeInfo that describes a UIComponent and the WTP-defined TLDElementDeclaration used to describe the corresponding JSP tag, the adapter could be queried:
ComponentTypeInfo componentType = viewAdapter.getAdapter(TLDElementDeclaration.class);
or conversely, to map back to a tag definition from a component type:
TLDElementDeclaration tagDecl = viewAdapter.getAdapter(ComponentTypeInfo.class);
This basic adaptability supports view construction at design time since a client can traverse a meta-data document and adapt, for example, TLD-defined tags into components to derive the design-time component tree. Indeed, a design time view handler would likely use it's adapter to perform its populateView contract.
To fulfill editing of meta-data, the adapter requires the ability to enumerate the available meta-data artifacts for the framework to support features like content assist. TODO: how to generically provide the available features? Use the JSF meta-data framework's domain/entity key system?
Meta-data based composition
Since components can be added to the view at any time (126.96.36.199), view meta-data can be used to create new components by composing existing components (a real life example is seen with the ui:composition tag in Facelets). TODO: