Controller Framework

The controller framework consists of Java™ classes and interfaces that provide the runtime environment for the components used within an application/page. It is responsible for handling application level events such as page switching, dispatching events to UI modules, log on, and log off. The controller framework base class is the abstract WcmController.

Features of the controller framework are as follows:

See Also
Framework Page
Preferences API
Toolkit Implementation of MVC

ConfigurableController

The Toolkit provides ConfigurableController, an easily customizable, fully implemented controller. To configure the controller's behavior, you simply edit the Workplace/WEB-INF/p8controller.xml file.

ConfigurableController supports multiple named configurations in p8controller.xml. Each configuration can share a single static initializer which initializes all dependencies required by each defined controller configuration.

You can also implement multiple controllers in a single Web application by leveraging ConfigurableController features and implementation of the StaticInitializerInterface. This can be useful if you have two independently developed custom applications, and you want to merge part or more of these multiple applications into a single Web application.

With Web Application Toolkit, you have the following controller development options:

NOTE  If you are migrating a 2.x Toolkit application to Toolkit version 3.x or later libraries, set the backward compatibility options as follows: windowIdCompatibility to "true" and internalTokensEnabled to "false". If you implemented your own controller in the 2.x application, set the options in WEB-INF/web.xml; if you are using the ConfigurableController, set the options in WEB-INF/p8controller.xml.

See Also
ConfigurableController Preferences Classes
ConfigurableController Preferences

Page Cycle

A controller implementation is instantiated in the event JSP page. When the JSP page loads, the controller performs the following functions:

  1. Retrieves the current user session data store and initializes page specific values.
  2. Registers modules as follows:
  3. Verifies credentials as follows:
  4. Calls initialize() on registered modules in the order that they were registered as follows:
  5. If an event is specified on the request, the appropriate "on..." event handler is looked up and invoked.

    OR

    If a global event is specified on the request, the appropriate "on..." global event handler is looked up and invoked on all modules that have subscribed to that global event, assuming that one of the event handlers did not perform a client-side redirect.

  6. Calls onStartPage() on registered UI modules in the order that they were registered. The onStartPage method signals to the modules that the UI will be displayed.
  7. Performs a server-side redirect to the UI jsp page.

    The UI page makes calls to WcmUi.render(...) to render the registered UI modules onto the page, either by calling uiModule.render(...), running the XSL transform for XSL modules, or by a server-side include specifying the JSP for JSP-based modules.

    Note that all registered UI modules contain an "active flag" property. By default, the flags are initialized to boolean "true". The module can be inactivated by calling uiModule.setActive(false).

    When a UI module is inactivated, it means that the UI module and all of its descendants will not receive events and will not receive the onStartPage() call from the controller. It is then assumed that these modules will not be rendered onto the page.

  8. Calls render(...) on registered modules.

See Also
Event URLs

Phase Notification

The controller framework routes an event to a UI module as part of a four-phase process:

  1. Initialize
  2. Route Event
  3. Start page
  4. Render

As shown in the following diagram, these phases correspond with the methods in a UI module.

controller framework phases

See Also
Event URLs

Phase Notification Examples

The examples that follow illustrate the four phases of the controller when it receives a request. Each example shows a set of UI modules that have been registered into the controller on an event JSP page. The controller works from a hash table that uses a UI module's fully qualified name as the key.

UI modules support containment, meaning that a UI module can register other UI modules as its children. When this is done, the child UI modules have the qualified parent UI module's name specified as a qualifier with an exclamation point ( ! ) as the delimiter. In the examples, therefore, the layout UI module is the parent of "banner", "tabbar", " treeview", "footer", "navigation" and "contentsListView". For example:

layout!navigation

A child UI module can also be a parent. The "layout!navigation" child contains path and navList, for example:

layout!navigation!navList

The eventTarget parameter in an event URL always specifies the fully qualified UI module name.

The following examples describe the controller's phases based on the event URL type:

See Also
Event URLs

No Event Example

This example shows the sequence of UI module callbacks that the controller makes when an event JSP page is requested with no event on the request. One phase (represented by the columns left to right) must complete before the next phase commences.

http://host:port/customApp/MyPage.jsp
controller.handleEvent(...):

 
initialize()
onClick(req, resp)
onStartPage(req, resp)
render(out)
headerModule 1   1 render
layout 2   2 render
layout!banner 3   3 render
layout!tabbar 4   4 render
layout!treeview 5   5 render
layout!footer 6   6 render
layout!navigation 7   7 render
layout!navigation!path 8   8 render
layout!navigation!navList 9   9 render
layout!contentsListView 10   10 render

See Also
Phase Notification Examples

Targeted Event Routing Example

This example shows the sequence of UI module callbacks that the controller makes when a click event is targeted to a UI module. One phase (represented by the columns left to right) must complete before the next phase commences.

http://host:port/customApp/MyPage.jsp?eventTarget=layout!navigation&eventName=Click&otherParam=otherValue
controller.handleEvent(...):

 
initialize()
onClick(req, resp)
onStartPage(req, resp)
render(out)
headerModule 1   1 render
layout 2   2 render
layout!banner 3   3 render
layout!tabbar 4   4 render
layout!treeview 5   5 render
layout!footer 6   6 render
layout!navigation 7 1 7 render
layout!navigation!path 8   8 render
layout!navigation!navList 9   9 render
layout!contentsListView 10   10 render

See Also
Phase Notification Examples

Child-to-Parent Event Routing Example

This example shows the sequence of UI module callbacks that the controller makes when a click event is targeted to a child UI module, which then routes the event to its parent. One phase (represented by the columns left to right) must complete before the next phase commences.

http://host:port/customApp/MyPage.jsp?eventTarget=layout!navigation&eventName=Click&otherParam=otherValue
controller.handleEvent(...):

 
initialize()
onClick(req, resp)
onStartPage(req, resp)
render(out)
headerModule 1   1 render
layout 2 2 2 render
layout!banner 3   3 render
layout!tabbar 4   4 render
layout!treeview 5   5 render
layout!footer 6   6 render
layout!navigation 7 1 7 render
layout!navigation!path 8   8 render
layout!navigation!navList 9   9 render
layout!contentsListView 10   10 render

See Also
Phase Notification Examples

Global Event Routing Example

This example shows the sequence of UI module callbacks that the controller makes when a global click event is targeted to multiple UI modules. One phase (represented by the columns left to right) must complete before the next phase commences.

NOTE  Event methods are invoked in the order that UI modules subscribed to the global event.

http://host:port/customApp/MyPage.jsp?eventName=Click&otherParam=otherValue
controller.handleEvent(...):

 
initialize()
onClick(req, resp)
onStartPage(req, resp)
render(out)
headerModule 1   1 render
layout 2   2 render
layout!banner 3   3 render
layout!tabbar 4   4 render
layout!treeview 5 1 5 render
layout!footer 6   6 render
layout!navigation 7 2 7 render
layout!navigation!path 8 3 8 render
layout!navigation!navList 9   9 render
layout!contentsListView 10 4 10 render
Event that Redirects Example

This example shows the sequence of UI module callbacks that the controller makes when a click event is targeted to a UI module, and the event handler redirects to another event JSP page. One phase (represented by the columns left to right) must complete before the next phase commences.

The controller detects that a redirect call was made, and skips the start page and render phases. In the controller framework, redirect calls automatically cancel all further operation on a page, thus reducing overhead.

http://host:port/customApp/MyPage.jsp?eventTarget=layout!navigation&eventName=Click&otherParam=Redirect
controller.handleEvent(...):

 
initialize()
onClick(req, resp)
onStartPage(req, resp)
render(out)
headerModule 1   skipped skipped
layout 2   skipped skipped
layout!banner 3   skipped skipped
layout!tabbar 4   skipped skipped
layout!treeview 5   skipped skipped
layout!footer 6   skipped skipped
layout!navigation 7 1 skipped skipped
layout!navigation!path 8   skipped skipped
layout!navigation!navList 9   skipped skipped
layout!contentsListView 10   skipped skipped

See Also
Phase Notification Examples

Inactive UI Modules Example

This example shows the sequence of UI module callbacks that the controller makes when a click event is targeted to a UI module, and one of the UI modules is no longer active. One phase (represented by the columns left to right) must complete before the next phase commences.

All UI modules in the framework include an "active" attribute, which can be set to true or false.

http://host:port/customApp/MyPage.jsp?eventTarget=layout!navigation&eventName=Click&otherParam=otherValue
controller.handleEvent(...):

 
initialize()
onClick(req, resp)
onStartPage(req, resp)
render(out)
headerModule 1   1 render
layout 2   2 render
layout!banner 3   3 render
layout!tabbar 4   4 render
layout!treeview 5   5 render
layout!footer 6   6 render
layout!navigation 7 1 7 render
layout!navigation!path 8   8 render
layout!navigation!navList 9   9 render
layout!contentsListView 10   skipped skipped

See Also
Phase Notification Examples

Event URLs

The framework supports targeted and global event URLs. A targeted event URL is addressed to a specific, single UI module on a page, whereas a global event URL is addressed to multiple UI modules that have subscribed to the same event.

A targeted event URL specifies eventTarget and eventName parameters that identify the UI module that the event is targeted for, and the name of the event being triggered. When a user clicks a link with a targeted event URL, the controller detects the eventTarget and eventName, and routes the event to the appropriate handler in the targeted UI module, if defined.

The following example shows an event link targeted to a UI module. The event target is "layout!navigation", in the event JSP page WcmBrowse.jsp. The event target is the fully qualified name of the UI module as bound to the JSP variables "layout" and "navigation". (The concatenation of the two JSP variables indicates a containment relationship, where "layout" is the containing UI module, and "navigation" is a contained UI module.) The name of the event is "Select", and the controller routes this event to the onSelect method in the targeted UI module.

href="http://comstock:8080/customApp/WcmBrowse.jsp?eventTarget=layout!navigation&eventName=Select&library=&label=Choose+Library&lid="

The next example shows an event link targeted to the controller. The name of the event is ChangePage, and it is handled by the controller's onChangePage method, which directs the controller to redirect to a new event JSP page specified in the targetUrl parameter (WcmSearch.jsp).

href="http://comstock:8080/customApp/WcmBrowse.jsp?eventTarget=WcmController&eventName=ChangePage&targetUrl=http://comstock:8080/customApp/WcmSearch.jsp"

Global event links differ only by excluding the eventTarget parameter. For example:

href="http://comstock:8080/customApp/WcmBrowse.jsp?eventName=Select&library=&label=Choose+Library&lid="

In this case, all UI modules that have subscribed to the "Select" global event will have their onSelect global event handler called, if defined.

Note that the base UI module class, WcmUiModule, provides methods that generate URLs for you. For example, getEventUrl(...) is for straight click events, and getFormSubmitUrl(...) is for events that will be accompanied by form data. For a containment relationship, WcmUiModule includes methods for routing an event from a child UI module to its parent. See Containment: Routing an Event to the Parent.

Data Store

All stateful data for a user session is stored in the data store (WcmDataStore). Scoped to the duration of a JSP session, the data store is cleared when a session expires or ends.

Information stored in the data store can be accessed directly, or can be accessed via a variety of set...Property methods as listed below:

Method Scoping
Module.setModuleProperty(key, value)
Module.getModuleProperty(key)
Scoped to an instance of a module on a page.
Module.setClassProperty(key, value)
Module.getClassProperty(key)
Scoped to all instances of a module of a specific class.
Module.setWindowProperty(key, value)
Module.getWindowProperty(key)
Scoped to an instance of a module on a page referenced in a popup window.
Controller.setProperty(key, value)
Controller.getProperty(key)
Scoped to a particular controller instance on a page (page scoping).

Any modules, utility classes, or JSP pages may optionally use the data store to cache some temporary data or state that will be persisted across requests. As shown in the diagram below, a data provider can cache its data, initially retrieved from the Java API, to the data store. A UI module can use the data store to cache current user settings. For example, if a user changes the default list view style from Magazine to Detail, the list UI module can cache that setting to the data store. Later, when the page reloads, the list UI module will check the data store for the current user settings and overwrite the site preferences settings.

Data store clients should determine when it is best to cache data and state information to the data store, and what is the most efficient representation of cached data (object, XML, and so on) Algorithms for data store caching should balance the factors of memory consumption, scalability, and performance.

Several utility classes are provided, as well as features in the data store to aid in caching. These leverage Java soft referencing and MRU data structures. Two examples are the WcmSoftReferenceMap and the WcmMRUMap classes.

data store diagram

See Also
Toolkit Implementation of MVC
Data Providers
Base UI Modules
Utilities

Window Management

Prior to the 3.0 version of Web Application Toolkit, the framework provided a window ID mechanism for managing pages that appeared in popup (secondary) windows from the main browser window of an application. A window ID was simply a token to indicate that the browser window where the ID was present was a popup window. In response to a window ID, the framework provided stateful scoping for each popup window, with the capability to differentiate between the same page in different browser windows.

While this version of the Toolkit includes full backward compatibility with window ID behavior in previous releases, it also extends the window ID mechanism in the following ways.

This section describes the window ID mechanism that provides the above-listed features. It also discusses propagation, window ID encoding, and use cases in the FileNet P8 Workplace application.

NOTE  If you are migrating a 2.x Toolkit application to Toolkit version 3.x or later libraries, set the backward compatibility options as follows: windowIdCompatibility to "true" and internalTokensEnabled to "false". If you implemented your own controller in the 2.x application, set the options in WEB-INF/web.xml; if you are using the ConfigurableController, set the options in WEB-INF/p8controller.xml.

Window ID Mechanism

The window ID mechanism consists of the following parts:

URL Rewriting

The controller can detect when a window ID has been dropped from a request. When this happens, the controller will rewrite the request with the window ID. How the controller rewrites the request depends on the request type:

Window ID Class

Toolkit provides the com.filenet.toolkit.server.util.WindowID class, an instance of which represents a window ID. WindowID objects are constructed in one of two possible ways: either by the constructor WindowID(String value), or by the static method WindowID, createFlaggedWindowID(String value).

The format of the String passed to the WindowID constructor determines whether the WindowID object is constructed in default (flagged) mode or compatibility mode. When the window ID is formatted with an encode prefix ( _ ), the WindowID constructor constructs the object in default mode; otherwise, it constructs the object in compatibility mode. In compatibility mode, the WindowID object identifies itself as a popup window ID via the "popup" flag, described in the next section.

The static createFlaggedWindowID method constructs a new WindowID object in default mode, which allows for the setting and retrieval of up to 30 flags.

Window ID Flags

A WindowID object defines one or more internal use flags. The flags set depend on the usage of the window ID. The only flag currently defined is "popup" (WindowID.POPUP_FLAG).

Window ID Serialization

If a WindowID object is in compatibility mode, calling its toString() method will output exactly the same string that was passed in the constructor.

In default (flagged) mode, when WindowID.toString() is called, the window ID is serialized out with its flags encoded in a specific format: _<<flags>>.<<value>>

So, for example, if WindowID.createFlaggedWindowID("1234567") were called, and then setFlag(WindowID.POPUP_FLAG, true) were called on it, WindowID.toString would produce this: _1.1234567

Window ID Stacking

The WindowID class also provides a simple stacking mechanism via its setPrevId and getPrevId methods. For example:

WindowID wid1 = WindowID.createFlaggedWindowID("12345");
WindowID wid2 = WindowID.createFlaggedWindowID("98765");

wid1.setPrevId(wid2.toString());

In this case, wid1.toString() will generate this: _0.12345/_0.98765

The "/" delimiter is used to delimit the current window ID from the previous. This serialized form can also be passed into setPrevId, allowing for multiple levels of stacking.

When a new WindowID is constructed with a stacked window ID, it is deserialized such that the first window ID in the stack is taken as the current windowID, and the string to the right of the first slash is taken as the previous window ID, so that getPrevId() returns the correct value.

Modes of Behavior

The event JSP for a framework page can configure itself to generate a new popup window ID when new page parameters are present on the page. This is done by calling the controller.configurePage, specifying a third boolean parameter as "true". For example:

controller.configurePage(application, request, true);

For Toolkit version 3.0 and later, several window ID modes of behavior are required. In addition to the above configurePage signature, two additional configurePage signatures are included. One signature has a third parameter of type long, which specifies a window ID mode. The other signature also includes the third parameter of type long, plus a fourth parameter of type String[], for specifying window ID parameters. For example:

controller.configurePage(application, request, windowIdMode);

The windowIDMode parameter extends the two possible boolean values of true/false to specify one of many possible window ID modes. This configurePage method calls into controller.configureWindowId, which creates a WindowID object and configures how it will be used based on the window ID-related values passed into configurePage.

Alternatively, the windowIdMode can be specified dynamically by passing "windowIdMode=" (WcmParameter.WINDOW_ID_MODE) as a request parameter, for example, "...&windowIdMode=CREATE_INLINE&...".

The window ID modes, defined as symbolic constants in WcmController, are summarized in the following table. For new application development that requires the use of windowIds, the use of the dynamic parameters CREATE_POPUP or CREATE_INLINE are recommended for creating window IDs. More details are provided on windowIdMode and other override options in the next section.

Description Window ID Mode
NO_WINDOW_ID The page never tracks a window ID.

If called with a window ID it will be dropped from the URL via rewriting.
PROPOGATE_WINDOW_ID (default) If a window ID is found, and it has only the "popup" flag set on it, propagate it. Rewrite it if it is not present on the current URL request.

If the window ID has the "object" flag set, pop window IDs off of its stack, if any, until either a window ID with the "object" flag unset is found, or there are no previous window IDs left.

This is equivalent, though not identical, to default controller behavior in Toolkit releases earlier than 3.0.
REQUIRE_WINDOW_ID Behavior of PROPOGATE_WINDOW_ID + ...

When there are new page parameters on the request, and there is no window ID on the request, generate a new popup window ID.

This is equivalent, though not identical, to popup mode window ID behavior in Toolkit releases earlier than 3.0 (that is, with configurePage called with the third boolean parameter set to "true").
CREATE_POPUP This mode must be passed dynamically as a windowIdMode parameter.

This mode tells the server to create a new WindowID and use it, replacing any window ID that may have been on the request already.

Use this mode on any URL that is being opened in a new window (popup).
CREATE_INLINE This mode must be passed dynamically as a windowIdMode parameter.

This mode tells the server to create a new WindowID and use it, stacking on top of the previous window ID, if defined.

Use this mode on any URL representing a page that can launch a second copy of itself (within the same browser window) either directly or indirectly through a set of intermediate pages.
Request Parameters

As mentioned in the previous section, the controller.configureWindowId method configures how a WindowID object is created, and the purpose it will serve -- based on window ID-related values passed into configurePage. To override the WindowID configuration performed by the configureWindowId method, the Toolkit provides the following request parameters:

Propagation

Window IDs will automatically propagate from one page to the next. By using getEventUrl and getFormSubmitUrl signatures of WcmUiModule, and through the use of WcmUi.encodeWindowId, it is possible for an application to maintain the windowId on URLs within a browser window.

If for some reason, however, the windowId is not passed forward, the controller's autorecovery logic will attempt to fix the problem by looking at the browser referer. If a recoverable windowId is found, it will rewrite the URL to the browser with the recovered windowId.

Return/Refresh windowId Encoding

In most cases, return and/or refresh URLs are desirable. The exception is when returning from a page where the caller had one windowId, and the called page is using a different windowId.

When passing return and/or refresh URLs to pages opened with new popup or stacked windowIds, it is up to the developer to ensure that the returnUrl passed into the called page is encoded with its windowId so that context is maintained on return.

Window ID Use Cases

The Web Application Toolkit window ID mechanism broadly addresses two kinds of window ID uses. The first is the mapping of a window ID to a particular browser window. These are called popup window IDs. The second is the mapping of a window ID to a particular object, for example, a Document object stored in the Content Engine.

This section shows both kinds of window ID uses in Workplace and FileNet P8 Portlets, versions 3.0 and later. It starts with an overview of Workplace management of window IDs, then describes the following specific page implementations of window IDs:

Workplace Management of Window IDs

The following diagram shows how the window ID mechanism is used by Workplace. Note that custom Toolkit-based applications should use the window ID mechanism in the same way.

window ID diagram

The red arrow indicates a link that opens a new (popup) window. A page loaded in a new popup window must contain a new popup window ID. The recommended best practice for accomplishing this is to include "windowIdMode=CREATE_POPUP" as a request parameter on the URL being loaded in the popup browser window.

The blue arrow indicates a link to an Info page. Since the Info page can contain a link to itself, it is required to have a new inline window ID to distinguish the successive invocations of itself. Therefore, any link to ObjectInfo.jsp to view a new or different object must contain "windowIdMode=CREATE_INLINE" so that each invocation of the page gets its own unique windowId (or context).

The green arrows indicate scenarios where control is being returned to either a refresh URL or a return URL. In either case, the return/refresh URL passed to another page must contain its windowId so that the context being referenced is fully qualified.

For example, let's say "WcmObjectBookmark.jsp?windowId=_1.T123" contains a link to ObjectInfo.jsp. Since ObjectInfo.jsp is dependent on a unique context each time it is newly opened to view a certain object's properties, the link to it must contain "windowIdMode=CREATE_INLINE". This will result in the ObjectInfo.jsp being defined as something like "ObjectInfo.jsp?windowId=_1.S5/_1.T123".

Since ObjectInfo.jsp provides a return link to get back, its link, in addition to "windowIdMode=CREATE_INLINE" must contain "returnUrl=[WcmObjectBookmark.jsp?windowId=_1.T123]" (brackets indicate URL encoded). This way, when the user clicks return on the ObjectInfo.jsp page, the browser loads "WcmObjectBookmark.jsp?windowId=_T.123", rather than just "WcmObjectBookmark.jsp".

If, in the above example, no windowId were defined on the returnUrl, the controller's autorecovery logic would attempt to use the referer's windowId, which would cause the page to be loaded as WcmObjectBookmark.jsp?windowId=_1.S5/_1.T123. This is not the context (windowId) that ObjectInfo.jsp was launched from. At this point, the application would crash because UI modules' module properties and window properties were maintained under the context corresponding to "_1.T123" and not "_1.S5/_1.T123". The properties would no longer be visible.

Workplace Bookmark Pages

In the Workplace browse and search pages, when navigated to a folder, stored search or search template, a link is provided that allows the user to open a "bookmarkable" or URL addressable version of the page.

When the bookmark link is clicked, a second browser window is opened containing the bookmarkable version of the page. For example:

Workplace bookmark pages

The bookmark page uses REQUIRE_WINDOW_ID mode, which generates a new window ID when new page parameters are present. The new window ID will have its popup flag set, and will therefore be interpreted by the framework as a popup window ID. Certain UI modules in Workplace key off of this fact and adjust their UI accordingly. For example, the page banner UI module shows only "help | close" links instead of "help | home | preferences | signout" links.

Alternatively, the main page can have the bookmark link include "windowIdMode=CREATE_POPUP" to achieve the same behavior.

From either the main browse page or the bookmarkable version of the browse page, the user can click links and access the same pages within Workplace. The popup window ID on the bookmark window keeps separate contexts for each browser window. Therefore, if from each browser window the user clicks to the same page, the two browser windows do not interfere with one another in their module or window properties.

Workplace Info Pages

From Workplace, it is possible to launch an Info page as either a popup or inline, depending on how it is configured in <app_root>/WEB-INF/InfoPages.xml. When launched as a popup, it is launched using the dynamic mode CREATE_POPUP.

When launched within the same browser window, it is launched using the dynamic mode CREATE_INLINE.

The return URL passed into the Info page will be required to specify its windowId if defined, since it is required to fully address the return page.

If the Info page is accessed inline from a popup (containing a popup window ID), the window ID is created as before, but the generated window ID that is stacked on top propagates the "popup" flag. By propagating the popup flag up the stack, the fact that the window is a popup is never lost.

Workplace Actions

In Workplace, actions may also be configured to operate as popups, or inline. These are handled similarly to Info pages as described in the previous section.

When launched in a new browser window, the action is launched using the dynamic CREATE_POPUP mode. When launched inline, the action is launched using the dynamic CREATE_INLINE mode.

FileNet P8 Portlets - Portlet Popups

In the FileNet P8 Portlets integration, most clicks in the Workplace portlets result in a popup window being opened. For example, when you click the "more..." link from the browse portlet, a popup window is opened that shows the folder bookmark view corresponding to the selected folder.

portlet popup

To prevent the user's desktop from getting needlessly cluttered, portlets are designed so that links that open these popup windows open a named browser window through JavaScript. When the named browser window already exists, the JavaScript pops it to the foreground.

The URL that is loaded in these named popups contains the setWindowId request parameter. When the JavaScript executes, it opens a named browser window and passes the browser window name as the value of the setWindowId request parameter. No hashing is needed, since there is a one-to-one relationship between the window ID and the browser window, and the portlet, in context is able to create its own unique window ID to be used.