Portlet Development Guide

     Previous  Next    Open TOC in new window    View as PDF - New Window  Get Adobe Reader - New Window
Content starts here

Working With JSF Portlets

This chapter provides an in-depth discussion on procedures and best practices for developing and configuring JSF portlets.

This chapter includes the following sections:

Note: For information about JSF portlet development, see JSF Portlet Development.

 


Overview

Oracle WebLogic Portal has supported the use of JSF portlets starting with WLP 9.2, and this support has been enhanced through the current release. JSF is supported as a specific portlet type within WebLogic Portal. Portlets implemented with JSF can leverage all of the powerful features of WLP.

This chapter provides a developer with a comprehensive guide for building JSF portlets in Oracle WebLogic Portal 10.3.0. It covers a wide variety of portlet development topics necessary to know to build JSF portlets.

 


Configuring JSF Within Weblogic Portal

This section discusses how to configure JSF within WLP. These configuration settings are specified in files such as web.xml and weblogic.xml. All of these files are scoped to the entire Web Project. Therefore, Faces configuration is also scoped to the entire web application.

This section contains the following topics:

JSF Library Modules in WebLogic Server

WebLogic Server provides a packaging feature called library modules that package up one or more jar files as a deployable feature. JSF support for a web application is one such usage of the library module packaging feature.

Table 12-1 lists the JSF library modules included in WebLogic Server 10gR3 (and therefore also WebLogic Portal 10gR3). This list is obtainable via the Manage WebLogic Shared Libraries link on the JSF library configuration dialog, or by inspecting the config.xml file for your domain.

Table 12-1 Supported JSF Implementations for WebLogic Server 10gR3
Library Module Name
Implementation
Version
Supported in WLP?
Jsf
Sun Reference
1.2.3.2
Yes, caveats
Jsf-ri
Sun Reference
1.1.1
Yes
Jsf-myfaces
MyFaces
1.1.3
No
Jsf-myfaces
MyFaces
1.1.1
No

For a Web Project, including WebLogic Portal Web Projects, you must choose just one version of JSF to use amongst the supported set. For WLP 10gR3, only the Sun RI implementations are officially supported. While it is possible to manually create a new JSF library module for a different JSF implementation, WebLogic Portal only officially supports the set provided in the installer. It is also possible to copy JSF implementation jar files directly into the WEB-INF/lib folder. This also is not officially supported with WLP.

The JSF portlet support in WebLogic Portal uses the same integration code regardless of the JSF implementation in use. However, Oracle has found the Sun RI to work best within WLP, and there are known issues with using MyFaces. Therefore, only the Sun RI is supported.

Caution: Workshop for WebLogic will by default configure an unsupported MyFaces JSF implementation. See the next section for instructions on changing it to Sun RI.

Installing the JSF Libraries into a Portal Web Project

For a WebLogic Portal Web Project to support JSF portlets, JSF itself must be installed into the project. JSF support is not enabled by default.

A plugin called Web Tools Project (WTP) is available for the Eclipse IDE which aids in building web applications. To help developers manage their web application libraries, WTP provides a feature called facets. A facet is a feature that is provisioned in a web application, like JSF for example. When a facet is added to a Web Project, WTP will add in the necessary libraries, files, and configuration artifacts. When deploying to WebLogic Server, a Facet often will configure the Web Project to use one or more library modules.

There are several paths to installing JSF in a Portal Web Project:

Once you have navigated to the facet selection dialog, follow these steps:

  1. Click the JSF facet checkbox to select it.
  2. Choose the desired version of JSF by clicking on the dropdown in the Version column. Selecting JSF 1.1 will eliminate the dependency errors. For the steps to configure JSF 1.2, see Configuring JSF 1.2 in WLP.
  3. Click Next. Do not click Finish. Caution: Clicking Finish on the facets selection dialog will result in an unsupported JSF implementation being deployed into the Web Project.
  4. You will be prompted to provide the specific library module version for some of the facets, including JSF. Click Next until you reach the JSF panel. On the JSF panel, you must choose the Sun RI, as shown in Figure 12-2.
  5. Click Finish.

The wizard will update your web project descriptors to include the appropriate JSF library module (see WEB-INF/weblogic.xml). It will also update web.xml with default Faces configuration settings, and insert a new faces-config.xml into your project.

Figure 12-2 New Portal Web Project Dialog

New Portal Web Project Dialog

Caution:

Configuring JSF 1.2 in WLP

Of the four JSF implementations installed with WebLogic Server, only one implements JSF 1.2. That implementation is the Sun RI. Normally, it would suffice to select the 1.2 version (which is actually the default) in the facet selection dialog. However, due to a dependency issue, configuring JSF 1.2 for a Portal Web Project using the facet selection dialog is not currently possible.

The core issue is that the Apache Beehive web framework has an integration with JSF (see Integrating Apache Beehive Pageflow Controller) which does not work correctly with JSF 1.2. In all releases through WLP 10gR3, Portal Web Projects have a hard dependency on Apache Beehive. Therefore, the facet selection dialog does not allow JSF 1.2 to be enabled.

However, for Portal Web Projects that do not use the Apache Beehive integration, this is an unnecessary limitation. Oracle offers limited support for JSF 1.2 when the Beehive Page Flow integration is not being used in the web application. Follow these instructions to work around the issue.

  1. Launch Workshop for WebLogic.
  2. Create a Portal Web Project. Add the JSF 1.1 facet, which will populate the project with the default JSF files.
  3. Navigate to Project > Properties > Java Build Path and select the Libraries tab.
  4. Remove the JSF 1.1 library from the list.
  5. Click Add Library and then WebLogic Shared Library.
  6. Choose the JSF 1.2 library from the list, and click OK.
  7. Open WEB-INF/weblogic.xml.
  8. Remove the entry for the JSF 1.1 library module, if it exists.
  9. Add an entry for the JSF 1.2 library, as shown in Listing 12-1.
  10. Update the entry for JSTL to take version 1.2, not 1.1.
  11. Remove the PageFlowApplicationFactory configuration artifact from WEB-INF/facesconfig.xml (see Installing the JSF Libraries into a Portal Web Project). This avoids a problem that occurs with using Apache Beehive with Sun RI 1.2.3.2.
  12. Clean and rebuild, then redeploy.
  13. Listing 12-1 The weblogic.xml Entry for Using JSF 1.2
    <wls:library-ref>
    	<wls:library-name>jsf</wls:library-name>
    	<wls:specification-version>1.2</wls:specification-version>
    	<wls:implementation-version>1.2.3.2</wls:implementation-version>
    </wls:library-ref>

Creating JSF Portlets

Once Faces is configured in WLP, then a JSF portlet can be created by the Portlet wizard in Oracle Enterprise Pack for Eclipse. See Building Portlets to learn how to create your first JSF portlet.

JSF Configuration Settings

In general, WebLogic Portal is agnostic to the various JSF configuration settings that can be manipulated. This section discusses how various JSF configuration choices are manifested when JSF is running within WebLogic Portal.

Client or Server State Storage

JSF is a stateful web framework - it maintains state for a user in between HTTP requests. JSF offers two state management options for JSF applications: client and server. It is configured in web.xml with the javax.faces.STATE_SAVING_METHOD context parameter.

While client state management with the JSF portlet native bridge works in most cases, Oracle only supports the server state management option. There are known issues, particularly when interportlet communication (IPC) is at work on the page, where client state management will cause the wrong portlet JSF view to be rendered. This is due to the fact that a single HTTP request may cause multiple JSF portlets to be invoked if IPC is in use. The HTTP request carries only the state of the targeted JSF portlet, and thus the listening JSF portlet(s) will use the wrong client state during restoration. For more information about IPC, see Interportlet Communication with JSF Portlets.

Also, there are several drawbacks with using client state saving in general:

Oracle therefore only supports the use of server state saving with WebLogic Portal. This mode works properly with IPC. Also, the WLP portal framework itself retains portal state for each active user session on the server, and thus the server state option for JSF portlets is more consistent with the behavior of the WLP framework.

Caution: Unfortunately, Workshop configures the STATE_SAVING_METHOD value as client by default. Developers need to manually change this value in web.xml to server after creating the Portal Web Project (Listing 12-2).
Listing 12-2 Supported State Storage Configuration in web.xml
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>

Prefix or Suffix Servlet Mapping

There are two servlet mapping schemes for the Faces servlet.

When deploying JSF portlets, the JSF portlet container invokes the Faces infrastructure directly. Therefore, WLP does not rely on any servlet mapping being configured. If you wish to have the portlets also available to direct access (i.e. not as a portlet), you can choose to use either JSF suffix or prefix mapping as with a normal JSF web application.

Listing 12-3 shows the prefix servlet mapping configuration in web.xml.

Listing 12-3 Prefix Servlet Mapping Configuration in web.xml
<servlet-mapping>
	<servlet-name>faces</servlet-name>
	<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
	<servlet-name>faces</servlet-name>
	<url-pattern>*.faces</url-pattern>
</servlet-mapping>

Other Settings

The STATE_SAVING_METHOD and servlet mapping settings are the most important, but they are far from the only settings available. The Sun RI currently has dozens of extra settings that can be configured. In general, these settings are completely independent of WLP, and so can be set at your discretion. However, due to the number of implementations and number of settings in each, WLP does not certify the integration with the non-default options.

Listing 12-4 shows a partial list of settings in the Sun RI v1.2.8 (see WebConfiguration.java in the source code).

Listing 12-4 Partial Listing of Additional Configuration Options for the Sun RI
com.sun.faces.managedBeanFactoryDecoratorClass
javax.faces.CONFIG_FILES
javax.faces.LIFECYCLE_ID
com.sun.faces.numberOfViewsInSession
com.sun.faces.numberOfLogicalViews
com.sun.faces.injectionProvider,
com.sun.faces.serializationProvider
com.sun.faces.responseBufferSize
com.sun.faces.clientStateWriteBufferSize,
com.sun.faces.expressionFactory
com.sun.faces.clientStateTimeout
com.sun.faces.compressViewState
com.sun.faces.compressJavaScript
com.sun.faces.externalizeJavaScript

 


Native Bridge Architecture

This section provides an architectural overview of how WebLogic Portal's JSF native portlet bridge operates. It shows the relationship between the different components in the implementation. This explanation is intended as an overview to help you understand how to best architect and debug your portlet when using this bridge.

This section contains the following topics:

Container Architecture Overview

Figure 12-3 depicts the logical relationship of the containers involved: Servlet, WLP Rendering, and JSF portlet containers. The containers have these properties:

Servlet Container

WebLogic Portal Rendering Container

Portlet JSF Container

Figure 12-3 shows a logical view of how the containers are related. Solid lines depict boundaries between containers, and dotted lines demark logical elements and objects within a container.

Figure 12-3 Logical Container Architecture of WebLogic Portal and JSF Portlet Native Bridge

Logical Container Architecture of WebLogic Portal and JSF Portlet Native Bridge

Note: This discussion applies specifically to local JSF portlets. A JSF portlet that is remote (i.e.via WSRP) has a different relationship to the parent containers.

Container Interactions

The following are some general principles to understand regarding interactions between containers:

 


Understanding WLP and JSF Rendering Life Cycles

This section explains WLP and JSF rendering life cycles. It contains the following topics:

WLP and JSF Life Cycles

Both WebLogic Portal and JSF frameworks support the concept of component trees that define the rendering of the HTML page. Both also rely on the concept of rendering life cycles. Each component tree is walked multiple times during the execution of the request. Each traversal is called a life cycle or phase.

When developing JSF portlets, it is helpful to understand how those life cycles interact. For more information on the phases of the portal life cycle, see "Understanding Portal Development" in the see the Portal Development Guide.

Invocation Order of WLP and JSF Life Cycle Methods

The following represents the merged life cycle execution order across the WLP and JSF containers:

Note:

Accessing WLP Context Objects from JSF Managed Beans

To enable portlets to programmatically interact with the portal framework, a set of context objects is available.

Table 12-2 shows what portlet context objects are in scope for different managed bean methods for different JSF life cycles. This chart is useful when implementing a managed bean that needs to obtain WLP context information. The key point is that property getters and setters need to be coded so that they work properly with either context object.

Table 12-2 Scope of Portlet Context Objects
JSF Life Cycle
Managed Bean Method
Portlet Backing Context
Portlet Presentation Context
Portal Use Case
PROCESS_VALIDATIONS
get property
Yes
No
Portlet receives a postback, input is being validated.
PROCESS_VALIDATIONS
set property
Yes
No
Portlet receives a postback, input is being validated.
UPDATE_MODEL_VALUES
set property
Yes
No
Portlet receives a postback, input has been validated.
INVOKE_APPLICATION
action method
Yes
No
Portlet is the target of a postback.
RENDER_RESPONSE
get property
No
Yes
Portlet is being rendered.
RENDER_RESPONSE
set property
No
Yes
Portlet is being rendered.

 


Understanding Scopes and JSF Portlets

This section covers several scoping topics that apply to JSF portlets.

Conceptual Scopes for Standard JSF Applications

The standard JSF scopes are interpreted differently in a portal environment. This section discusses the differences.

JSF Standard Scopes

JSF managed beans have well-defined scopes as defined in the JSF specification. The JSF 1.1 and 1.2 specifications provides three scopes for managed beans:

In addition to these, several additional scopes exist. Specifically, JSF 2.0 adds a View scope, and many web frameworks provide a Pageflow scope, as described below.

View Scope

View scope has been added to the JSF 2.0 specification. It enables managed beans to be attached to a specific view across multiple HTTP requests. Once a user navigates to a different view, the bean state is destroyed. This is a helpful pattern for scoping state to a single instance of a view for a user.

Pageflow/Conversation Scope

A Pageflow (also called a conversation) is a subset of the views and controller logic within a web application that pertains to a logical task or business process. Multiple Pageflows can exist within a web application, and each one usually carries state that should only be scoped to that Pageflow. With Pageflow scope, managed bean state is accessible across the life span of all requests within the session, limited to the time in which a user is interacting with the set of views within that Pageflow.

Conceptual Scopes for Portal Applications

Because of the composite nature of a portal user interface, there are more conceptual scopes for portals than for standard JSF applications.

The list of portal scopes includes:

Implementation Patterns for Portal Scopes

Table 12-3 describes how the standard JSF scopes map to the WLP scopes, and how the unrepresented JSF scopes are supported. Details about these implementation strategies are explained in the following sections.

Table 12-3  Managed Bean Scope Implementation Strategies
Portal Managed Bean Scope
Implementation Strategy for JSF Portlets
Application
faces-config.xml scope = application
Global Session
faces-config.xml scope = session, plus custom code
Portlet Group Session
faces-config.xml scope = session, plus custom code
Portlet Instance Session
faces-config.xml scope = session
Pageflow
Use an alternate navigation controller
View
Supported with JSF 2.0
Portal Aware Request
faces-config.xml scope = request

Reinterpretation of the JSF Session and Request Scopes

Table 12-4 compares JSF managed bean scoping levels between a JSF application and a WLP JSF portlet.

Table 12-4  Comparison of Scoping Levels
Faces-Config.xml Scope Label
Conceptual Scope for JSF Application
Conceptual Scope for JSF Portlet
Application
Application
Application
Session
Global Session
Portlet Instance Session
Request
HttpRequest
Portal Aware Request

Because a managed bean declared with session scope in faces-config.xml is interpreted as Portlet Instance Session scoped with the portlet bridge, it is possible to put multiple instances of that portlet on a page and not have conflicts. Each portlet instance that uses the managed bean will be provisioned with a distinct instance of the bean.

Also, the different interpretation of request scope prevents a JSF portlet from breaking if the user interacts with a second portlet while interacting with the first JSF portlet.

Pageflow Scope

The standard JSF navigation controller does not support the notion of a Pageflow scope. However, other controllers can be plugged into the JSF runtime to provide such a capability. For example, you can integrate an Apache Beehive Page Flow controller. For details, see Integrating Apache Beehive Pageflow Controller.

Global Session and Portlet Group Session Scopes

The remaining scopes for managed beans cannot be expressed in faces-config.xml alone. However, using code patterns involving the HttpSession, the remaining scopes can be achieved. For details, see section State Sharing Patterns.

 


State Sharing Patterns

This section contains the following topics:

State Sharing Concepts

JSF managed beans are intended to be the storage containers for application state within a JSF application. In general, this works well even within a portal environment. However, this standard JSF pattern is not sufficient. There are cases where state needs to be shared with something outside of the JSF portlet. For example:

But there are limitations that must be heeded when working within the JSF container:

This section discusses patterns that work despite these limitations.

HttpSession Versus HttpServletRequest

Some of the patterns in this section make use of the HttpSession. They set state into the HttpSession as attributes. The first issue to cover is why the HttpSession? In some cases is the HttpServletRequest a better place to store this state? While in certain cases the HttpServletRequest is suitable, in general it is a best practice to use the HttpSession rather than HttpServletRequest. This section explains why.

Store State in the HttpSession

In short, the use of the HttpSession is preferred because of simplicity. In a portal environment, the lifecycle of the request is not always straightforward.

Drawbacks of Using the HttpSession

Use of the HttpSession does not come for free. There are several drawbacks to be aware of:

A possible solution to the first two of these drawbacks is to mark some or all of the stored state as transient. Transient objects in Java are not serialized, and so it can be used to mitigate both of the issues.

Base Code for HttpSession Patterns

Some of the patterns below rely on scoping data in the HttpSession. The best approach is to provide a namespace for the attribute name used to set the attribute into the session. The patterns differ in how that namespace is computed. Since these patterns share common code aside from the namespace generation, the following base code is assumed for each of the patterns.

JSFPortletHelper

The code samples below rely on a common class called JSFPortletHelper. It provides a number of helper methods that are useful with a managed bean used in a JSF portlet. For source code, see The JSFPortletHelper Class.

SearchBeanBase (For HttpSession Patterns)

Listing 12-5 shows the code that serves as the base managed bean for illustrating the HttpSession based patterns.

Listing 12-5 The Base Managed Bean for the Examples
public abstract class SearchBeanBase {
	// Gets the search string from the HttpSession
	public String getSearchText() {
		HttpSession session = JSFPortletHelper.getSession();
		String namespace = getAttributeNamespace();
		return (String)session.getAttribute(namespace+"_searchText");
	}
	// Sets the search string into the HttpSession
	public void setSearchText(String search) {
		HttpSession session = JSFPortletHelper.getSession();
		String namespace = getAttributeNamespace();
		session.setAttribute(namespace+"_searchText", search);
	}
	// Each pattern below implements this method differently
	abstract public String getAttributeNamespace();
}

Single Portlet Pattern

When sharing state amongst components of a single portlet instance, the pattern is straightforward. There is only one pattern necessary.

Portlet Instance Session Scoped Data (uses HttpSession)

In this pattern, the state is to be shared only with other components affiliated with the portlet instance. The state is set into the HttpSession. The best namespace for this use case is the portlet's instance label. This pattern is most often used when sharing data between a portlet's JSF managed bean and the portlet's backing file. Both of those components have easy access to the portlet instance label via the PortletBackingContext or PortletPresentationContext objects, which provide access to the instance label.

Figure 12-4 shows an illustration of how a JSF managed bean and WLP backing file from the same portlet instance can share a stateful object.

Figure 12-4 JSF Managed Bean and WLP Backing File from the Same Portlet Instance Sharing a Stateful Object

JSF Managed Bean and WLP Backing File from the Same Portlet Instance Sharing a Stateful Object

The namespace is based simply off of the portlet’s instance label. Listing 12-6 shows the code that gets the namespace for the HttpSession attribute using the instance label.

Listing 12-6 Getting Namespace for the HttpSession Attribute using the Instance Label
public class SearchBean extends SearchBeanBase {
	public String getAttributeNamespace() {
		return JSFPortletHelper.getInstanceLabel();
	}
}

Multiple Portlet Patterns

These patterns support cases in which multiple portlets are sharing state. Several patterns are offered. Two use the HttpSession for state sharing, and one uses the WLP event mechanism. There are benefits and drawbacks to each:

Using the HttpSession (not recommended)

Using Events (best practice)

The section contains the following topics:

Pattern: Global Session Scoped Data (uses HttpSession)

In this pattern, the state is to be shared with any other component within the web application. All portlets, backing files, JSPs, and other objects need to have access to the same stateful object. In this pattern, the object is set into the HttpSession with an attribute name that is not namespaced. The object is truly global in scope.

Figure 12-5 shows an illustration of how Global Session scoped data is accessible to all components.

Figure 12-5 Global Session Scoped Data Being Accessible to all Components

Global Session Scoped Data Being Accessible to all Components

Note: Because it uses the HttpSession, this pattern may be sensitive to the order in which portlets are placed on the page.

Listing 12-7 shows the code that avoids any namespacing of the HttpSession attribute.

Listing 12-7 Code that Avoids any Namespacing of the HttpSession Attribute
public class SearchBean extends SearchBeanBase {
	public String getAttributeNamespace() {
		return "";
	}	
}

Pattern: Portlet Group Session Scoped Data (uses HttpSession)

This pattern applies when a group of portlets need to share a stateful object. This pattern employs the HttpSession to enable multiple portlet instances to share a reference to a stateful object. This pattern can also be made to work with a group of portlet definitions – simply replace the instance label pattern with a definition label. With this pattern there are two approaches to generating the namespace for the session attribute: instance label pattern or preference. Both are shown below.

Figure 12-6 shows how multiple portlets can share state via the HttpSession.

Figure 12-6 Multiple Portlets Sharing State via HttpSession

Multiple Portlets Sharing State via HttpSession

Note: Because it uses the HttpSession, this pattern may be sensitive to the order in which portlets are placed on the page.
Instance Label Pattern

In this pattern, all of the portlets in the group have an instance label that follow a particular pattern. The label pattern contains the attribute namespace in it. For example, the namespace may follow the last underscore character in the instance label. So portlets in the group have labels such as: master_scope1, detail_scope1, links_scope1. Portlets in another group of the same types of portlets would have instance labels like: master_scope2, detail_scope2, links_scope2.

Listing 12-8 shows the code for computing the HttpSession namespace from the portlet’s instance label.

Listing 12-8 Computing the HttpSession Namespace from Portlet’s Instance Label
public class SearchBean extends SearchBeanBase {
	// looks for a namespace in the instance label
	// assumes whatever is found after a trailing _ is the namespace
	public String getAttributeNamespace() {
		String label = JSFPortletHelper.getPortletInstanceLabel();
		String namespace = JSFPortletHelper.splitNamespaceFromLabel(
			label, "_");
		return namespace;
	}
}
Portlet Preference

Another approach is to use a portlet preference to establish the namespace. Every portlet in the group must then use the same value for the preference.

Listing 12-9 shows the code for retrieving a namespace from a portlet preference.

Listing 12-9 Retrieving a Namespace from a Portlet Preference
public class SearchBean extends SearchBeanBase {
	// Assumes a portlet preference called "state_namespace"
	// has been defined on each portlet in the group,
	// and contains the namespace key
	public String getAttributeNamespace() {
	PortletPreferences prefs = JSFPortletHelper.getPreferencesObject();
	return JSFPortletHelper.getPreference(prefs, "state_namespace", "");
	}
}

Pattern: Portlet Group Session Scoped Data (uses Events)

WebLogic Portal supports an event mechanism that can carry custom payloads of state from the triggering portlet to any number of listening portlets. This works in a predictable way, and is supported across WSRP. It is a best practice to use this pattern.

There are two sides to this pattern – the trigger and the listeners. The trigger fires a custom event programmatically with the stateful object as the payload. Listener portlets receive the event, and each stores the state in the HttpSession in a portlet instance scoped attribute. A JSF managed bean in that portlet instance can then read the stateful object out of the HttpSession (Figure 12-7).

Figure 12-7 Multiple Portlets Sharing State through Events

Multiple Portlets Sharing State through Events

Trigger Portlet

When a portlet instance needs to write the state object, it must trigger an event with the custom payload. This is easily done in either a portlet backing file or a JSF managed bean. The example below is a managed bean action method.

The code in Listing 12-10 shows how to trigger a WLP event from a JSF managed bean.

Listing 12-10 Triggering a WLP Event from a JSF Managed Bean
/**
	* Action method invoked when the user hits the "Search" button
	*/
public String doSearch() {
	// searchText is a String that was entered on the search form
	JSFPortletHelper.fireCustomEvent("doSearch", searchText);
	return null;
}
Listener Portlets

For any portlet that wishes to listen for the event and receive the stateful object, a portlet backing file must be implemented. It must have an event listener method. The job of the listener method is to set the stateful object into the HttpSession scoped to the single portlet pattern shown above. This implies that there is an HttpSession entry for every portlet instance listening for the event.

Listing 12-11 shows a backing file method for handling a WLP event and writing the payload into the HttpSession.

Listing 12-11 A Backing File Method for Handling a WLP Event and Writing the Payload into the HttpSession
public void handleSearchEvent(HttpServletRequest request,
		HttpServletResponse response, Event event) {
	try {
		String searchText = (String)event.getPayload();
		String namespace =
			JSFPortletHelper.getPortletInstanceLabel(request);
		String attributeName = namespace+"_search_query";
		request.getSession().setAttribute(attributeName, searchText);
	} catch (Exception e) {
		e.printStackTrace();
	}
}

Now, any component of the portlet instance, like a JSF managed bean, can access that state, as shown in Listing 12-12.

Listing 12-12 A JSF Managed Bean Reading the Event Payload out of the HttpSession
public String getSearchText() {
	String namespace = JSFPortletHelper.getPortletInstanceLabel();
	searchText = (String)JSFPortletHelper.getSession().
		getAttribute(namespace+"_search_query");
	return searchText;
}

To bring it all together, the listening portlet must be configured to listen for the event. This is done in the portlet editor. The portlet must listen for the custom event, and have an "Invoke BackingFile Method" handler defined (Figure 12-8).

Figure 12-8 Configuring a Portlet to Listen for an Event and Invoke a Backing File Method

Configuring a Portlet to Listen for an Event and Invoke a Backing File Method

 


Using Common WLP Features With JSF Portlets

This section describes how commonly used WebLogic Portal features are used in an environment with JSF portlets.

Portlet Container Features

This section discusses these portlet container features:

Support for Modes in JSF Portlets

When creating a new JSF Portlet, only the view mode supports JSF JSPs. The other modes require basic JSP or HTML pages. For more information on portlet modes, see Portlet Modes.

Portlet Error Page

A best practice is to configure an error page for every portlet. You set an error page using the portlet Error Page Path property. For all portlet types, including JSF portlets, this error page must be a standard JSP not a JSF JSP. For details on configuring an error page, see Portlet Properties.

Portlet Preferences

Portlet preferences provide the primary means of associating application data with portlets. Portlet preferences are accessible through the WLP portlet context objects. For detailed information on portlet preferences, see Portlet Properties.

In the context of a JSF portlet, note that after setting preferences values for the portlet, store() must be called. This call is best accomplished by setting preferences in JSF managed bean property setters, and then calling store() in an action method.

To illustrate this technique, consider a JSF portlet that lets a user get a stock quote. The last quote the user obtains is persisted using portlet preferences. The JSF view is shown in Listing 12-13. The view retrieves portlet preference values from a JSF managed bean. The managed bean, shown in Listing 12-14, sets and gets the preference values from WLP.

Listing 12-13 A JSF View
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri='http://bea.com/faces/adapter/tags-naming' prefix='jsf-naming' %>
<f:view>
<jsf-naming:namingContainer id="prefs">
<h:panelGrid columns="4" width="100%">
<h:form id="stockForm">
    <h:panelGroup>
        <h:outputText value="Stock Quote:"/>
    </h:panelGroup>
    <h:panelGroup>
        <h:inputText id="ticker" value="#{WLPPrefsRequestBean.ticker}" 
    required="true"/>
    </h:panelGroup>
    <h:panelGroup>
        <h:inputText id="shares" value="#{WLPPrefsRequestBean.shares}" 
        required="true"/>
    </h:panelGroup>
    <h:panelGroup>
        <h:outputText value="#{WLPPrefsRequestBean.currentValue} "/>
    </h:panelGroup>
    <h:panelGroup></h:panelGroup>
    <h:panelGroup></h:panelGroup>
    <h:panelGroup>
        <h:commandButton action="#{WLPPrefsRequestBean.getQuote}" 
        id="quote" value="Get Quote"/>
    </h:panelGroup>
    <h:panelGroup>
        <h:commandButton action="#{WLPPrefsRequestBean.resetQuote}" 
        id="reset" value="Reset"/>
    </h:panelGroup>
</h:form>
</h:panelGrid>
</jsf-naming:namingContainer>
</f:view>

The managed bean is listed in Listing 12-14.

Note: Listing 12-14 uses a utility class JSFPortletHelper. You can find a complete listing and description of this class in the section, The JSFPortletHelper Class.
Listing 12-14 The JSF Managed Bean
package oracle.samples.wlp.jsf;
import java.io.Serializable;
import javax.faces.context.FacesContext;
import javax.portlet.PortletPreferences;
import javax.servlet.http.HttpServletRequest;
import com.bea.netuix.servlets.controls.portlet.PortletPresentationContext;
import com.bea.netuix.servlets.controls.portlet.backing.PortletBackingContext;
/**
* An example that shows how to use WLP preferences with a JSF managed bean.
* This example makes the following assumptions for the preference writes to work properly:
*  1. The bean is request scoped
*  2. The user is authenticated
*  3. The portal is a streaming desktop, not a .portal
*/
public class WLPPrefsRequestBean implements Serializable {
    private static final long serialVersionUID = 1L;
    private static final String TICKER = "ticker";
    private static final String TICKER_DEF = "ORCL";
    private static final String SHARES = "shares";
    private static final String SHARES_DEF = "1000";
    /**
    * The request scoped preferences object.
    */
    private PortletPreferences prefs;
    
    /**
    * Constructor. Initializes the preference object.
    */
    public WLPPrefsRequestBean () {
    prefs = JSFPortletHelper.getPreferencesObject();
    }
    
    // ACTION METHODS
    
    /**
    * Updates the preference values set by the user.
    * @return always null, to retain the same JSF view
    */
    public String getQuote() {
    // all the setting work is done in the setters
    // what is left is to store the new prefs into the database
    JSFPortletHelper.storePreferences(prefs);
    return null;
    }
    
    /**
    * Resets the preferences back to their defaults.
    * @return always null, to retain the same JSF view
    */
    public String resetQuote() {
        JSFPortletHelper.setPreference(prefs, TICKER, TICKER_DEF);
        JSFPortletHelper.setPreference(prefs, SHARES, SHARES_DEF);
        JSFPortletHelper.storePreferences(prefs);
        return null;
    }
    
    // GETTERS AND SETTERS
    
    public String getShares() {
        return JSFPortletHelper.getPreference(prefs, SHARES, SHARES_DEF);
    }
    
    public void setShares(String shares) {
        JSFPortletHelper.setPreference(prefs, SHARES, shares);
    }
    
    public String getTicker() {
        return JSFPortletHelper.getPreference(prefs, TICKER, TICKER_DEF);
    }
    
    public void setTicker(String ticker) {
        JSFPortletHelper.setPreference(prefs, TICKER, ticker);
    }
    
    public int getCurrentValue() {
        // convert the String preference into an integer
        String sharesStr = getShares();
        int shares = 0;
        try { shares = Integer.parseInt(sharesStr); } 
        catch (Exception e) {}
        // compute some bogus value
        return shares * 52;
    }
}

Portal Container Features and JSF Portlets

This section discusses the following portal container features:

LocaleProvider

WebLogic Portal by default defers to the HttpServletRequest getLocales() method to determine the preferred list of locales for the user. JSF implementations do the same.

However, in some cases the portal may have better information about the user's preferred locale. It may use a user profile property for example to store the user's locale preference. In such cases, a developer would implement a WLP LocaleProvider to programmatically find the preferred locale in the user profile. In a similar way, with JSF the preferred locale calculation is pluggable. The ViewHandler interface has a method calculateLocale() that performs the same logic.

When working with JSF portlets, keep these mechanisms in sync. If you implement a custom LocaleProvider, use the same code in a custom ViewHandler implementation. This ensures that the user sees a portal rendered in a consistent locale.

Skeleton Files

Skeleton files control the rendering of each component of the WLP page. They are implemented as JSPs. The use of JSF components in these JSPs is not supported. The WLP framework renders the skeletons using standard JSP technology. For more information on skeletons, see the Portal Development Guide.

 


Understanding Navigation

This section discusses navigation within a JSF portlet and within the WLP portal environment when JSF portlets are used.

Navigating Within a Portlet with the JSF Controller

This section discusses the use case in which a user interacts with a portlet, triggering an update to that portlet.

It is standard to use Command Buttons and Command Links tied to actions to control navigation through the JSF application (see Listing 12-15 and Listing 12-16). With the standard JSF navigation controller, there are three approaches to defining the action attribute on a Command Button or Command Link:

Each of these approaches is valid when a JSF application is operating as a JSF portlet. The JSF portlet bridge makes sure the URLs are written properly to maintain correct behavior within a portal. JSF components consult the JSF ExternalContext object when constructing action URLs. WLP has implemented an ExternalContext that is portal aware, and it properly rewrites the URLs.

Listing 12-15 Navigation Configuration in faces-config.xml
<navigation-rule>
    <from-view-id>/portlets/sample/page2.jsp</from-view-id>
    <navigation-case>
        <from-outcome>gotoPage1</from-outcome>
        <to-view-id>/portlets/sample/page1.jsp</to-view-id>
    </navigation-case>
</navigation-rule>
Listing 12-16 Command Button That Uses the Navigation Rule
<h:commandButton action="gotoPage1" id="gotoPage1Button"
            value="Goto Page 1">
</h:commandButton>

Support for Redirects

The JSF navigation controller supports HTTP redirect as an annotation on a navigation case. The JSF controller issues an HTTP redirect to the client for the target page of the navigation case if configured to do so. Listing 12-17 illustrates a redirect in a navigation case. Note the use of the explicit <redirect/> element to indicate a redirect.

Listing 12-17 Redirect in a Navigation Case
<navigation-rule>
    <from-view-id>/portlets/redirect/page2.jsp</from-view-id>
    <navigation-case>
        <from-outcome>gotoPage1</from-outcome>
        <to-view-id>/portlets/redirect/page1.jsp</to-view-id>
        <redirect/>
    </navigation-case>
</navigation-rule>

The navigation case does not work properly when the redirect configuration is used within a JSF portlet in WLP. Depending on the context, the navigation case will not be followed or it will send the user to the target page via a redirect taking the user out of the portal context because the redirect URL is not rewritten to remain within the portal environment.

If you must use a redirect and cause the user to remain in the portal, it is possible to achieve using the sendRedirect() method on the PortletBackingContext.

The last chance to invoke this method is in the handlePostbackData() method of a portlet backing file. As discussed in "Understanding WLP and JSF Rendering Life Cycles, remember that all of the JSF phases for a portlet are processed after handlePostbackData(). Therefore, the backing file must decide when to do the redirect before the user interaction is processed by the JSF container. Unfortunately, this means that a redirect cannot be triggered based on the outcome of a JSF form validation.

Listing 12-18 shows a sample code for a backing file that always redirects when the user interacts with the portlet.

Listing 12-18 A Backing File that Redirects when a User Interacts with a Portlet
package oracle.samples.wlp.jsf;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.bea.netuix.servlets.controls.content.backing.AbstractJspBacking;
import com.bea.netuix.servlets.controls.portlet.backing.PortletBackingContext;
import com.bea.portlet.PageURL;
public class RedirectBackingFile extends AbstractJspBacking {
	private static final long serialVersionUID = 1L;
	@Override
	public boolean handlePostbackData(HttpServletRequest request,
	HttpServletResponse response) {
		// As per the design, this portlet will ALWAYS redirect
		// back to the same portal page
		// if the user interacts with the portlet.
		if (isRequestTargeted(request)) {
		 PageURL url = PageURL.createPageURL(request, response);
		 // make sure the URL uses the proper ampersands...
		 url.setForcedAmpForm(false);
		 // ...and is encoded with a session token if necessary
		 String redirectUrl = Response.encodeRedirectURL(url.toString());
		 PortletBackingContext pbc =
		 PortletBackingContext.getPortletBackingContext(request);
		pbc.sendRedirect(redirectUrl);
		}
		return super.handlePostbackData(request, response);
	}
}

 


Navigation Within a Portal Environment

The previous section discussed navigation techniques within a portlet. This sections covers navigations within the portal environment. It contains the following topics:

Programmatically Constructing JSF Portlet URLs

For most cases, WLP will automatically handle the construction of URLs that postback to a JSF portlet via the Command Link and Button capability discussed above. But there are use cases in which the portlet developer needs to construct URLs programmatically. The code snippet in Listing 12-19 shows how to do this.

Listing 12-19 Programmatically Constructing a Portlet Postback URL in a JSF Managed Bean
public String getJSFPortletPostbackURL() {
	HttpServletRequest request = JSFPortletHelper.getRequest();
	HttpServletResponse response = JSFPortletHelper.getResponse();
	String webapp = request.getContextPath();
	// Create base URL, which includes parameters to target current portlet
	WindowURL url = WindowURL.createWindowURL(request, response);
	// provide URL to the JSF page. Include webapp context root on the front
	url.addParameter("_nffvid",webapp+"/portlets/javascript/myJSFPage.faces");
	// make sure the toString() method writes "&" and not "&amp;"
	url.setForcedAmpForm(false);
	return url.toString();
}

Changing the Active Portal Page

The term "page" has many meanings within a portal environment. There is the (X)HTML document that is returned to the browser (the "browser page"), and there is a set of tabs rendered on the browser page, each representing a logical page (a "portal page"). The current visible portal page is called the "active" page.

Within WebLogic Portal, portal pages reside in a container called a book. There is always a main book, which contains the top level portal pages. But note that books can be nested inside of pages, thus creating the ability to create deeply nested user interfaces. This is important to understand in the context of this section because there can be multiple "active" portal pages (in different visible books) rendered in a single browser page.

Using an Output Link

The Output Link component is a perfect for creating link that unconditionally changes the active page. It is simpler to use an Output Link for this task as opposed to the solutions provided with the Command Button and Link. It does require some code to programmatically generate the correct URL.

The first step is to create a managed bean with a property that generates the URL to the appropriate page using a WLP API - the PageURL (Listing 12-20).

Listing 12-20 A Managed Bean Method for Creating a URL to Navigate to a Portal Page
// Creates a property "searchPageURL" that dynamically retrieves
// the right URL to change the page to my search page
public String getSearchPageURL() {
	HttpServletRequest request = JSFPortletHelper.getRequest();
	HttpServletResponse response = JSFPortletHelper.getResponse();
	// create the URL to the page with definition label "my_search_page"
return PageURL.createPageURL(request, response, "my_search_page").toString();
}

Second, simply add an Output Link component to the JSF portlet. Using JSF EL, bind the managed bean URL to the component (Listing 12-21).

Listing 12-21 Binding the Dynamic URL into a JSF OutputLink
<h:outputLink value="#{Portlet1RequestBean.searchPageURL}">
	<h:outputText value="Change to Search Page"/>
</h:outputLink>

Using a Command Link or Button With Events

The Command Link and Command Button components also offer rich capabilities for changing the active page. These features are of particular use when the page change is conditional on server logic.

Changing the Active Portal Page Using the Navigation Controller and a Portal Event

This use case is covered in Interportlet Communication with JSF Portlets. It allows users to implicitly cause a page change based on how they have navigated within a JSF portlet. This produces a loosely coupled approach to the page activation pattern. It is accomplished with the following configuration:

  1. The JSF portlet with the Command Button/Link uses standard navigation to change the current JSF view.
  2. The JSF portlet is configured to emit an event when that new view is rendered.
  3. Locate a listener portlet (it need not be implemented with JSF) that is on the page that is to be activated.
  4. That listener portlet is configured to listen for the event triggered by the JSF portlet.
  5. An Activate Page action is defined on the handler for the event.

Changing the Active Portal Page Programmatically

Changing the page programmatically with the Command Button and Link is useful when the page change is a conditional decision based on values entered in the accompanying form. There are two approaches.

Solution 1: Fire a Custom Event Programmatically

  1. Configure the JSF portlet with the Command Button/Link to use an action listener or method when the button or link is clicked.
  2. Implement the method such that it fires a custom event using the PortletBackingContext.
  3. Configure a listener portlet for the page to be activated, like in the previous use case.

Listing 12-22 shows how to fire a WLP event from a managed bean that will cause a listener portlet to activate a hidden page.

Listing 12-22 A WLP Event from a Managed Bean that Cause a Listener Portlet to Activate a Hidden Page
// Action Listener implemented in a managed bean
public void changeThePage(ActionEvent event)
{
	// fire the event
	// the second parameter can be used to pass arbitrary data
	JSFPortletHelper.fireCustomEvent("changeThePage", mySerializableObject);
}

Solution 2: Invoke a Page Change Programmatically

  1. Configure JSF portlet with the Command Button/Link to use an action listener or method when the button or link is clicked.
  2. In the method, obtain a reference to the PortletBackingContext.
  3. Invoke the setupPageChangeEvent() method on the PortletBackingContext, passing the definition label of the page to be activated.

The code snippet in Listing 12-23 shows how to directly trigger a page change event from a managed bean.

Listing 12-23 Triggering a Page Change Event from a Managed Bean
public void changeThePage(ActionEvent event) {
	HttpServletRequest request = JSFPortletHelper.getRequest();
	PortletBackingContext pbc =
		PortletBackingContext.getPortletBackingContext(request);
	// fire the page change event
	// my_search_page is the definition label for the page
	pbc.setupPageChangeEvent("my_search_page");
}

 


Interportlet Communication with JSF Portlets

Most portal implementations employ the pattern known as Interportlet Communication (IPC). IPC refers to the use case in which a portlet needs to notify another portlet, which may or may not be on the visible page, when a user has interacted with it. JSF portlets may participate in both sides of this mechanism, and this section explains how.

WLP provides several facilities for accomplishing IPC – events and notifications, in addition to the basic capability possible with HttpSession and HttpServletRequest attributes. Table 12-5, available at the end of the section, highlights the differences in capabilities in approaches. Developers are also free to use other approaches beyond what is offered in WLP – JMS for example.

Note: Before proceeding, a clarification must be made. Within WLP, there are two facilities referred to as "events". The first, the one discussed here, operates entirely within the context of the portal rendering framework. It is exposed during portlet configuration and when programmatically interacting with the portal framework context objects. The second, which is not discussed in this chapter, supports the personalization features of WLP, such as Behavior Tracking and Campaigns. That event system is not normally used for IPC.

This section contains the following topics:

Using Session and Request Attributes for IPC (Anti-pattern)

In some basic IPC use cases, it may appear sufficient to use a simple approach of passing state via the HttpSession and HttpServletRequest. Many developers starting with WLP will use this approach as a first step. However, this technique has many limitations and is not recommended. The drawbacks with this approach are explained in State Sharing Patterns.

Using the WLP Event Facility for IPC with JSF Portlets

This section shows how JSF portlets can participate in the eventing facility provided by the WLP portal framework. Events are extremely well integrated into the WLP portal framework. Therefore, in almost every IPC case, events are the favored approach. More advanced use cases for triggering and receiving events are covered in State Sharing Patterns.

Triggering a Portal Framework Event from a JSF Portlet

This section shows the simplest way in which a JSF portlet can trigger a WLP framework event.

Use case: A search box JSF portlet contains a Command Button that the user presses after entering a search term. The Command Button invokes a navigation rule that changes the view from searchBox.jsp to searchBoxIssued.jsp being rendered. The Command Button must also raise a WLP event when clicked.

Solution: The following procedure shows how to trigger an event when a user clicks on a JSF Command Link or Button:

  1. Create your JSF view for the portlet, which includes an h:form (e.g. /search/searchBox.jsp).
  2. Add a Command Link or Button, with its action defined as a hardcoded logical navigation path ("showResults") or an EL expression that will return one ("#{mybean.mymethod}").
  3. Create a navigation rule and case in faces-config.xml for that navigation path, directing towards a different JSF view (searchBoxIssued.jsp).
  4. Using the portlet editor, click on the button in the Faces Events property.
  5. For information about portlet editor, see the “Developing Portlets” chapter available here:

    http://download.oracle.com/docs/cd/E15919_01/wlp.1032/e14244/configure.htm

  6. Declare that the portlet raises the showResults event like the following: (Figure 12-9)
  7. Action: /search/searchBoxIssued.faces

    eventName: showResults

  8. Click OK.
  9. Figure 12-9 The IDE dialog for Declaring an Event to be Triggered from a JSF Portlet


    The IDE dialog for Declaring an Event to be Triggered from a JSF Portlet

Listing 12-24 shows the .portlet file for a JSF portlet that triggers an event.

Listing 12-24 The .portlet File for a JSF Portlet that Triggers an Event
<portal:root>
	<netuix:portlet backingFile="wlp.samples.portal.SearchBackingFile"
definitionLabel="searchBox" title="Search Box">
	 	<netuix:titlebar/>
	 	<netuix:content>
	 		<netuix:facesContent contentUri="/search/searchBox.faces">
		 	<netuix:facesEvents>
		 		<netuix:facesEvent action="/search/searchBoxIssued.faces"
					eventName="showResults"/>
		 	</netuix:facesEvents>
	 	</netuix:facesContent>
	</netuix:content>
	</netuix:portlet>
</portal:root>

The event will now be triggered in this scenario:

Notes:

Listening for a Portal Framework Event in a JSF Portlet

The previous section detailed how to trigger an event from a JSF portlet. This section explains how to listen for an event.

Use case: In a Master-Detail relationship, the Master is a search box portlet, and the Detail is a JSF search results portlet. When the user enters a query into the search box, the portlet triggers a “showResults” event as shown in the previous section. The search results Detail portlet must be notified such that it can change the view from the default "No Results" page to a view that displays the results.

Solution: A JSF portlet can declaratively listen for portal framework events, which can be used to change the view in the JSF application. This example shows how a portlet can listen for the showResults event from the search box portlet. If the search results portlet receives such an event, it changes the view to a different JSP.

The process of configuring a portlet to listen for an event is as follows:

  1. Open the portlet in the Workshop portlet editor.
  2. Click on the Event Handlers property, and click the button to display the configuration dialog.
  3. Click the Add Handler button and choose Custom Event.
  4. Give the name of the event to listen for (e.g. showResults).
  5. Click the Add Action button, and select Invoke Faces Action.
  6. Browse to the JSF view that should be displayed upon receiving the event.
  7. Click OK.

Listing 12-25 shows an example .portlet for a JSF search results portlet that listens for an event and changes the JSF view in response.

Listing 12-25 A JSF Search Results Portlet that Listens for an Event and Changes the JSF View in Response
<portal:root>
	<netuix:portlet definitionLabel="searchResults" title="Search Results">
		<netuix:handleFacesEvent
			eventLabel="doSearchEvent"
			eventName="showResults"
			fromSelfInstanceOnly="false"
			onlyIfDisplayed="false"
			sourceDefinitionLabels="searchBox"
		>
			<netuix:activatePage/>
			<netuix:invokeFacesAction action="/search/searchResults.faces"/>
		</netuix:handleFacesEvent>
		<netuix:titlebar>
			<netuix:maximize/>
		</netuix:titlebar>
		<netuix:content>
			<netuix:facesContent contentUri="/search/searchResults_none.faces"/>
		</netuix:content>
	</netuix:portlet>
</portal:root>

Notes:

Notifications

WebLogic Portal provides another facility for IPC – notifications. Notifications differ from events in that they are persisted to the database. This allows notifications to persist beyond a user's HttpSession. A notification also differs from an event in that it can be targeted to more than just the user that triggered it. This enables notifications to be used in cases such as sending announcements, advertising a change to a document, broadcasting system-wide messages, and more.

However, notifications do not have the ability to invoke portlet logic (like a backing file method) or activate a portlet's page like an event can. Also, notifications cannot support framework features such as Desktop Async and Portlet Render Cacheable (described below). In cases where those features are important, using a combination of notifications and events can provide the right solution.

Also, the persistence and broadcast features of notifications come at a performance cost. Due to the extra processing required to handle a notification, they are intended to be used sparingly. In short, the event mechanism is normally the correct facility for IPC, but notifications can also be helpful for certain use cases.

Comparison of the IPC Approaches

To make the differences in approaches more clear, Table 12-5 highlights the features supported with each approach:

Table 12-5 A Comparison of Several Implementation Approaches for IPC
FEATURE
SESSION/REQUEST
ATTRIBUTES
EVENTS
NOTIFICATION
Recommended?
No
Yes
In moderation
Subscribe or Poll
Poll
Subscribe
Poll
Layout Independent
No
Yes
No
Render Caching
No
Yes
No
Async Desktop
No
Yes
No
WSRP
No
Yes
No
Payload Type
Serializable
Serializable
String
Persistent
No
No
Yes

Legend

This section describes the rows of the table.

 


Namespacing

This section discusses several namespacing issues that must be addressed when building JSF portlets. It is important to remember in a portal environment, the portlet does not own the entire web page. Therefore, collisions in names can occur if the portlet developer is not careful.

Namespacing Managed Bean Names

With JSF, it is necessary to register each JSF managed bean used in the web application in facesconfig.xml. Each bean is given a name, which must be unique to the web application. Since multiple JSF portlets will be brought together into a single web application, it is possible for a naming collision to occur (Listing 12-26).

Listing 12-26 An Example of a Problematic Managed Bean Name
<managed-bean>
	<managed-bean-name>ValidationBean</managed-bean-name>
	<managed-bean-class>samples.ValidationBean</managed-bean-class>
	<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

It is a possibility for multiple portlets to define a bean named ValidationBean. A better name would be something like SearchBoxValidationBean, or some other name very specific to the portlet.

This can especially be an issue when aggregating multiple portlets from disparate development teams. It is therefore a best practice to include the portlet's definition label (or some similar pattern) in the managed-bean-name to create an informal namespace for the bean name.

Note that JSF does support dividing faces-config.xml into multiple configuration files, but this does not provide any namespacing capability and so the problem remains.

Client ID Namespacing with the View and Subview Components

When a JSF portlet is rendered onto a portal page, it can coexist with other JSF portlets on that same page. In JSF, like other web frameworks, it is critical that the id attribute on each element of the X/HTML browser page be unique. JSF has the concept of a naming container, which provides an id namespace to all components that exist within it. The most common naming container is the View component (the f:view tag), but it also provides the Subview component (the f:subview tag).

By virtue of the fact that all JSF portlets must contain an f:view tag as the root component, the WLP framework for most cases can correctly introduce a namespace for all component ids in each portlet. The framework uses the portlet's instance label as the namespace for the f:view. This works automatically, and for most use cases is sufficient.

Client ID Namespacing with the WLP NamingContainer

For the native JSF portlet bridge, WLP provides a NamingContainer component to strengthen scoping within the portal. Oracle recommends that you use this component whenever you are using the native JSF portlet bridge.

The purpose of the NamingContainer component is to provide a WLP integrated naming container as well as to expose a naming container instance that can be accessed through an EL expression for use in custom id rewriting in backing beans or input to other components.

Add the NamingContainer to the JSF view as a direct child of the f:view tag. This component takes an id attribute for use in EL expressions, which need not be unique across portlets. NamingContainer Use Cases illustrates several use cases that demonstrate the NamingContainer component.

NamingContainer Use Cases

This section presents several use cases that demonstrate the use of the NamingContainer component in JSF views.

Use Case 1: Multiple Portlet Instances on a Page with Desktop Asynchronous Mode Enabled

In general, the f:view tag is sufficient for scoping components in a portlet instance. However, if the Desktop Asynchronous Mode feature is enabled on the .portal or desktop, the NamingContainer is required if multiple instances of the same portlet is on the page. Failing to use the NamingContainer in this case can cause form submissions to be targeted to the wrong instance. Listing 12-27 illustrates the use of the NamingContainer component. For more information on Asynchronous Mode, see "Asynchronous Desktop Rendering" in the Portal Development Guide.

Listing 12-27 Use of the WLP NamingContainer Component
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri='http://bea.com/faces/adapter/tags-naming' prefix='jsf-naming' %>
<f:view>
<jsf-naming:NamingContainer id="zipcodeScope">
<h:form>
<h:outputLabel value="Enter zip code:" for="zipcode"/>
    <h:inputText id="zipcode" required="false"
        value="#{ZipcodeRequestBean.zipcode}" size="10"/>
    <h:commandButton action="#{ZipcodeRequestBean.submitZipcode}"
    id="submitter" value="Submit"/>
</h:form>
</jsf-naming:NamingContainer>
</f:view>
Use Case 2: Using EL to Connect Multiple Components on a Page

A case when the NamingContainer id attribute is significant is one in which the portlet view has components that must be connected using JSF EL expressions. In this case, the value binding expression needs to have access to the fully scoped name of the other component. The NamingContainer id attribute is referenced for this use case. The id maps to a binding context that is mapped for EL expressions. The binding context provides access to other component ids within the NamingContainer.

For example, consider a pair of custom components that are configured in master/detail relationship. The detail component needs to have a reference to the master component, but in such a way that will work even if multiple instances of the portlet are on the same page. Listing 12-28 illustrates this use case. Notice the EL expression used by the detail component to refer to the master. The EL expression resolves at runtime to a properly namespaced identifier.

Listing 12-28 JSF EL interacts with the NamingContainer Component
<%@ taglib uri=http://bea.com/faces/adapter/tags-naming" prefix="jsf-portlet" %>
<f:view>
<jsf-portlet:NamingContainer id="masterDetailScope">
    <a:myCustomMasterComponent id="masterComponent"/>
    <a:myCustomDetailComponent id="detailComponent"
        myMasterID="#{masterDetailScope.scopedId['masterComponent'].string}" />
</jsf-portlet:NamingContainer>
</f:view>
Use Case 3: Generating DOM Element IDs for Custom JavaScript

The NamingContainer is also required in cases where custom JavaScript needs access to the client id of a JSF component to perform dynamic DOM updates. See Using Custom JavaScript in JSF Portlets for a detailed example.

Best Practice: Always Use the NamingContainer

The specific use cases identified in this section require the NamingContainer, but it may not be easy to remember when exactly it is needed. There is no harm in adding the NamingContainer component to a portlet. Therefore, it is a best practice to simply add the NamingContainer to every portlet. This provides an assurance that users won't experience strange namespacing collisions while navigating the portal, regardless the combination of portlets on the page.

NamingContainer in EL Expressions

When used in an EL expression, the NamingContainer is accessed following this pattern:

<NamingContainer id>.scopedId[<quoted-string-target-component-id>].string

Terminate the JSF value binding expression with .string to yield the constructed scoped identifier. For advanced use cases, additional capabilities are available to decorate the generated id. Additional strings may be added to the beginning or end of the generated id:

For example, this JSF value binding expression

myPortletNamespace.scopedId['worldMap'].prefix['mytoken_'].string

    might produce an identifier like this on the client:
mytoken_worldMapPortlet_1:worldMap

 


Using Custom JavaScript in JSF Portlets

This section presents examples and discusses best practices for developing custom JavaScript for JSF portlets.

This section includes these topics:

Tip: For a summary of general considerations when writing client-side portal code, see "Client-Side Development Best Practices" in the Client-Side Developer’s Guide. That chapter discusses best practices like using a render dependencies file to specify .js files used by the portlet, using the wlp_rewrite_ token for namespacing, and other techniques.

DOM Manipulation within a JSF Portlet

This section demonstrates how to rewrite discrete pieces of the HTML page using client-side code.

Introduction to the Use Case

The need to rewrite pieces of HTML on the client is often called DOM manipulation. It is accomplished by writing custom JavaScript that locates an element on the rendered HTML page (a DOM element), and then programmatically changes that element. The key challenge for this use case for a JSF portlet is determining the target id of the element to be manipulated. DOM Manipulation Use Case shows how to do this.

Note: It is not generally advisable to manipulate a JSF component's client state via JavaScript, as it fails to properly update the view state stored on the server. But, for custom components or simple components this can be a useful technique.

DOM Manipulation Use Case

This sample shows how to build a simple JSF portlet that contains an Output Link and an Output Text component. The goal is to rewrite the text in the Output Text component when the Output Link is clicked. This happens entirely on the client using JavaScript with no server round trips.

The example starts with the JavaScript. Listing 12-29 shows a sample JavaScript file used by a JSF portlet. It contains very simple logic to find an HTML <div> element on the page and update the text. Note the tag wlp_rewrite. This tag is rewritten at runtime to the portlet's instance label, which namespaces the JavaScript function. For more information on wlp_rewrite, see Scoping JavaScript Variables and CSS Styles.

Listing 12-29 JavaScript File
// javascript.js
function wlp_rewrite_updateTarget(divId) {
    var theDiv = document.getElementById(divId);
    theDiv.innerHTML = "Target updated.";
}

Next, the JSF portlet’s Render Dependencies property is set to a .dependencies file. An example .dependencies file is shown in Listing 12-30. For more information on render dependencies, see Portlet Dependencies.

Listing 12-30 Sample .dependencies File
<?xml version="1.0" encoding="UTF-8"?>
<!-- Contents of javascriptPortlet.dependencies file ->
<window xmlns="http://www.bea.com/servers/portal/framework/laf/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.bea.com/servers/portal/framework/laf/1.0.0 laf-window-1_0_0.xsd">
    <render-dependencies><html>
        <scripts>
            <script type='text/javascript' content-uri="javascript.js" />
        </scripts>
    </html></render-dependencies>
</window>

Next, the JSF portlet has a backing bean that provides the portlet instance label, as shown in Listing 12-31. This bean must be registered in faces-config.xml (not shown).

Tip: For information about the JSFPortletHelper helper class, see The JSFPortletHelper Class.
Listing 12-31 The JSF Managed Bean
package oracle.samples.wlp.jsf.javascript;
public class JavaScriptPortletRequestBean {
    private String instanceLabel;

    public String getInstanceLabel() {
        if (instanceLabel == null) {
            instanceLabel = JSFPortletHelper.getInstanceLabel();
    }
    return instanceLabel;
}
}


The JSF JSP file shown in Listing 12-32 completes the example. Notice how it uses the backing bean to retrieve the portlet instance label. It also uses the NamingContainer EL expression capability introduced in Namespacing.

The onclick() function is the most important component in the code and performs these functions:

Working together, these files create a portlet that works properly by itself, even if multiple instances of the same portlet are on the page.

Form Validation within a JSF Portlet

This use case shows how to accomplish client-side form validation. This case is a common JavaScript use case. This use case follows a similar pattern to the previous use case in DOM Manipulation within a JSF Portlet

Note: This example is for demonstration purposes only. Oracle recommends that you use the form validation facilities provided by JSF whenever possible.

To start, define the JavaScript function in a .js file that performs the validation (Listing 12-33). Assume the form object is passed in as an argument to the function.

Listing 12-33 The Form Validation JavaScript Function
function wlp_rewrite_validateForm(myform) {
    if (myform.elements[0].value.length < 4) {
        alert("The username must be longer than 3 characters.");
        return false;
    }
    return true;
}

Using the Render Dependencies technique shown in the previous use case (DOM Manipulation Use Case):

  1. Link the .js file to the portlet using a .dependencies file.
  2. Create the JSF backing bean to accept the form parameters when the form is submitted to the server, as with any standard JSF form. The backing bean must provide the portlet instance label, as shown previously. For brevity, the backing bean is omitted here.
  3. Create the JSP JSF page that is the view for the portlet, shown in Listing 12-34. The form element in the JSP triggers client-side form validation. Notice how it uses the same technique used in the previous use case for calling the namespaced JavaScript function.
  4. Listing 12-34 The Form Element in the JSF JSP
    <h:form id="sampleForm"
        onsubmit="return #{JavaScriptPortletRequestBean.portletInstanceLabel}_validateForm(this);"><h:inputText id="username" value="#{JavaScriptPortletRequestBean.name}"
    size="40"/>
    <h:commandButton id="submitter" value="Submit"/>
    </h:form>

 


Ajax Enablement

This section contains the following topics:

Ajax in JSF Portlets

Many websites are Ajax enabled to provide a rich user experience. Ajax allows the browser to emulate the interactivity of traditional desktop applications. There are three primary patterns for using Ajax in a Portal. This section describes each, and explains how to implement the pattern with JSF portlets on WebLogic Portal.

Partial Page Rendering Pattern

The Partial Page Rendering (PPR) is the case in which an XmlHttpRequest is issued to the server, and the server responds with visual markup (XHTML or HTML). This markup is written directly into the browser page, updating the content that the user sees. There are several challenges for this capability:

Because of these complex issues, WLP supports official techniques for implementing PPR with WLP portlets – Asynchronous Desktop and Asynchronous Portlet modes. These facilities are available to all portlet types, and are transparent to the portlet developer. Thus, any JSF portlet can utilize any of these facilities without changes to the portlet implementation. These modes are configured using simple configuration settings.

Asynchronous Desktop Mode

Asynchronous Desktop mode causes all portlets on the portal to become asynchronous. The WLP framework rewrites all URLs on the portal pages such that they invoke Ajax requests (XMLHttpRequests). This facility supports all WLP framework features, including interportlet communication. This setting is either on or off for the entire desktop.

For more information, see the “Asynchronous Desktop Rendering” section in the Portal Development Guide.

Asynchronous Portlet Mode – Ajax or IFrame

Asynchronous Portlet mode is similar to Asychronous Desktop mode except that it is configured at the portlet level. This allows more fine-grained configuration of what is Ajax-enabled by the framework. This mode can also be configured to use IFrames instead of Ajax. The primary limitation with this mode is that interportlet communication is not supported.

For more information, see the Asynchronous Portlet Content Rendering.

Stateless API Request Pattern

Some use cases work better when the server does not serve up presentation markup, but raw data. In these cases, the client has the necessary code to process that data, and render the presentation markup appropriately.

The first type of this pattern is that of a stateless API. Such an API is not specific to the portal or even portlet; it is a general purpose API. In these cases, the XmlHttpRequest must pass all of the necessary information for the server to process the request. The classic example of this type of API is a search box autocomplete API. In this use case, after a user types a character in a search box, and XmlHttpRequest is sent to the server with the contents of the search box. The server responds with a list of possible matches, and JavaScript on the client renders them in a drop down list.

Such an API need not be aware of any portal context to fulfill the request. Therefore, any WebLogic Portal portlet (JSF or otherwise) may use such an API without restriction. The Ajax invocation in this case is fulfilled outside the context of the portal environment, and thus there aren't any unique issues related to WLP. For this reason, an example is not provided here. There are many examples available on the web. Searches for "javascript autocomplete example" will yield many results. Figure 12-10 shows an example of autocomplete.

Figure 12-10 An Example of Autocomplete

An Example of Autocomplete

Portlet Aware API Request Pattern

The third pattern is for Ajax requests that target data service APIs that have access to the portlet context. The service may need access to the portlet instance's preferences, for example. For these cases, WebLogic Portal's framework must be involved in the request processing. In support of this use case, WebLogic Portal must provide the following:

WebLogic Portal implements a wrapper for the standard XmlHttpRequest to provide these features. Portlet Aware Data API Example demonstrates its use.

Portlet Aware Data API Example

This example shows how to invoke an API via Ajax that operates within the JSF portlet's context. Meaning, the API implementation has access to portlet instance context such as preferences. The API can return the data in any textual format it chooses, with JSON, XML or simple text being common choices. To keep the example concise, the example as shown will not appear to do anything meaningful. Instead, the example shows how to bring the data back to the browser, and the DOM manipulation is left as an exercise to the reader. See Using Custom JavaScript in JSF Portlets.

Figure 12-11 shows the example. The example consists of a simple portlet with just a link. Clicking on the link on the portlet will cause an Ajax request to target a data API implemented in the JSF portlet. The data can best be seen in a browser debugger like Firebug or a network monitor that shows the response body.

Caution: Using Ajax within a portlet is problematic when that portlet is being offered over WSRP. The 1.0 specification made no allowance for Ajax capabilities, and thus there is no standard approach to solving this problem. Therefore, this example assumes that WSRP is not in use.
Figure 12-11 A View of the Example Portlet

A View of the Example Portlet

Note: This chapter will not explain render dependencies or the wlp_rewrite_ token. The example assumes you have already read about JavaScript and render dependencies in section Portlet Dependencies.

Step 1: Create the JavaScript function that issues the Ajax request using the WLP XmlHttpRequest wrapper. Allow the caller to pass in the URL into the function, as generating the proper URL in JavaScript is not easy.

Listing 12-35 shows the JavaScript function that invokes the WLP specific XMLHttpRequest.

Listing 12-35 Invoking the WLP Specific XMLHttpRequest
// ajaxPortlet.js
function wlp_rewrite_issueAjax(dataUrl) {
	var xmlhttp = new bea.wlp.disc.io.XMLHttpRequest();
	xmlhttp.onreadystatechange = function() {
		if ((xmlhttp.readyState == 4) && (xmlhttp.status == 200)) {
			var data = xmlhttp.responseText;
			// MODIFY: do something with the data, like DOM manipulation.
			// This example will appear to do nothing, but the data is
			// available at this point.
		}
	}
	xmlhttp.open('GET', dataUrl, true);
	xmlhttp.send();
}

Step 2: Create the JSF JSP. The URL that is invoked in the Ajax request is retrieved from a JSF backing bean via the EL expression #{JavaScriptPortletSessionBean.ajaxDataURL}. The backing bean implementation will be covered next. The portlet instance label is prepended to the function due to the use of the wlp_rewrite_ token in the JavaScript file.

The code in Listing 12-36 shows the JSF JSP that triggers the Ajax call using an onclick handler.

Listing 12-36 A JSF JSP Triggering the Ajax Call Using an onclick Handler
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri='http://bea.com/faces/adapter/tags-naming' prefix='jsf-naming' %>
<f:view>
<jsf-naming:namingContainer id="javascriptPortletNC">
<h:outputLink value="#"
onclick="#{JavaScriptPortletSessionBean.portletInstanceLabel}_issueAjax('#{JavaScr
iptPortletSessionBean.ajaxDataURL}'); return false;">
	<h:outputText value="Invoke Portlet Data API via Ajax"/>
</h:outputLink>
</jsf-naming:namingContainer>
</f:view>

Step 3: Implement a backing bean that provides the core logic for implementing the Ajax solution. The getPortletInstanceLabel() method can remain unchanged, but the getAjaxDataURL() and getJSONData() methods need to be modified to suit your needs.

Listing 12-37 shows the JSF managed bean that provides the Ajax data API.

Listing 12-37 The JSF Managed Bean that Provides the Ajax Data API
package oracle.samples.wlp.jsf;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.bea.portlet.WindowURL;
import com.bea.netuix.servlets.controls.portlet.PortletPresentationContext;
import com.bea.netuix.servlets.controls.portlet.backing.PortletBackingContext;
public class JavaScriptPortletSessionBean {
	// PORTLET INSTANCE LABEL
	private String portletInstanceLabel;
	public String getPortletInstanceLabel() {
	return JSFPortletHelper.getInstanceLabel();
	}
	// AJAX DATA API URL
	public String getAjaxDataURL() {
		HttpServletRequest request = JSFPortletHelper.getRequest();
		HttpServletResponse response = JSFPortletHelper.getResponse();
		String webapp = request.getContextPath();
		// Create the base URL, which includes parameters
		// to target the current portlet
		WindowURL url = WindowURL.createWindowURL(request, response);
		// provide the URL to the data JSF page, include the
		// webapp context root
		url.addParameter("_nffvid",
		webapp+"/portlets/javascript/dataJSF.faces");
		// make sure the toString() method writes "&" and not "&amp;"
		url.setForcedAmpForm(false);
		return url.toString();
	}
	// AJAX DATA API SERVICE IMPLEMENTATION
	public String getJSONData() {
		// Could return any text format, like JSON, XML, simple text
		// Data is hardcoded in this example, but could easily be dynamic.
		// The service may access the portlet instance context, using
		// a WLP context object like the PortletBackingContext.
		// JSON payload = {"menu": {"id": "file", "value": "File"}}
		return "{\"menu\": {\"id\": \"file\", \"value\": \"File\"}}";
	}
}

Step 4: Create the data API, which must be implemented using JSF. The example below uses a single OutputText component that obtains the JSON data from the backing bean. Take note that the contentType has been set properly because this API returns JSON, which is a good practice.

Listing 12-38 shows the code for the degenerate JSF view that provides the simple data API.

Listing 12-38 The Degenerate JSF View that Provides the Simple Data API
<%@ page language="java" contentType="application/json;charset=UTF-8"%>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<f:view>
<h:outputText value="#{JavaScriptPortletSessionBean.JSONData}"/>
</f:view>

Step 5: Create the portlet (.portlet file) using the New Portlet wizard. See JSF Portlets.

Step 6: Create the portlet dependencies file (.dependencies) to link in the JavaScript file. See Portlet Dependencies.

Step 7: Add the portlet to a portal (.portal file) and run. This portal must have DISC enabled. DISC can be enabled in the portal property sheet in the IDE for .portal files, or in the Portal Administration Tool for streaming desktops.

Controlling the WLP Ajax Framework

Forcing a Non-Targeted Portlet to Render

This section pertains to cases in which Desktop or Portlet Asynchronous Modes are enabled, or when the WLP specific XmlHttpRequest wrapper is in use. There are cases in which portlets that are not the target of the Ajax request need to be refreshed. If IPC is in use, this will happen automatically. If a user interacts with a portlet and that portlet emits an event that is handled by another portlet, both portlet's will be refreshed as a result of the Ajax interaction. The WLP XmlHttpRequest wrapper ensures this behavior.

However, there are cases where IPC is not being used, yet the same behavior is desired. There is an additional feature of the framework to solve this use case. It requires invoking the setRenderOnAjaxRequest() method on the PortletBackingContext during the WLP init or handlePostback lifecycles. This can be done either from a portlet backing file or a JSF portlet's managed bean. See the Understanding WLP and JSF Rendering Life Cycles section for more information on invoking context objects, portlet backing files, and WLP lifecycle methods.

The code snippet in Listing 12-39 shows the backing file method, which would be implemented on the portlet that is NOT the target of the Ajax request.

Listing 12-39 A Backing File that Causes the Portlet to Always be Processed if any Portlet Issues a WLP Ajax Request
public void init(HttpServletRequest request, HttpServletResponse response) {
	PortletBackingContext pbc =
		PortletBackingContext.getPortletBackingContext(request);
	pbc.setRenderOnAjaxRequest(true);
	super.init(request, response);
}

Disabling Partial Page Rendering Ajax for a Request

This section applies to cases in which Desktop or Portlet Asynchronous Modes are enabled. While it is useful to allow the framework to automatically rewrite all links and forms to use Ajax, there are times when a classic page request should be made. For JSF portlets implemented with JSP technology, it is possible to signal to the framework to disable the Ajax rewriting for the components on the portlet view. For more information, see Asynchronous Content Rendering and IPC. The documentation shows how the <render:context> tag can be used for this purpose. The way this works within a JSF page is best understood by looking at the following example. The render:context tag on the page has disabled the Ajax feature for the JSF form.

The code snippet in Listing 12-40 shows how to disable the Ajax feature for section of a JSF view.

Listing 12-40 Disabling the Ajax Feature for Section of a JSF View
<f:view>
<jsf-naming:namingContainer id="ajaxPortletNC">
<render:context asyncContentDisabled="true">
<h:form id="sampleForm">
	<h:inputText id="username" size="40"
		value="#{JavaScriptPortletSessionBean.name}" />
	<h:inputText id="city" size="40"
		value="#{JavaScriptPortletSessionBean.city}" size="40"/>
	<h:commandButton id="submitter" value="Submit"
		action="#{JavaScriptPortletSessionBean.submitForm}"/>
</h:form>
</render:context>
</jsf-naming:namingContainer>
</f:view>

 


Localizing JSF Portlets

This section discusses best practices and techniques for localizing JSF portlets. It contains the following topics:

Configuring the JSF Locale

By default, the WLP portal framework and JSF implementation compute the user's locale in the same way. They both call the HttpServletRequest getLocales() method to obtain a list of the user's preferred locales, in descending order of desirability. Then, both frameworks find the best match using the localized resource bundles defined for each user interface element.

Resource Bundles

In WebLogic Portal, the resource bundles are called localizations, and are defined using the WLP Administration Console. Localizations cannot be defined when serving a portal from a file (a .portal file). The portal must be a streaming desktop that is configured in the database to support localization. For more information on the difference between file based portals and streaming desktops, see "File-Based Portals and Streaming Portals" in the Portal Development Guide.

Each element of the portal framework can have one or more localized titles. Figure 12-12 shows how multiple localized titles for a portlet can be configured in the WLP Administration Console.

Figure 12-12 Defining Multiple Localized Titles for a Portlet

Defining Multiple Localized Titles for a Portlet

For more information on localizing artifacts in WebLogic Portal, see "Managing Portal Desktops" in the Portal Development Guide.

Listing Locales in faces-config.xml

In JSF, each supported locale must be listed in faces-config.xml, as illustrated in Listing 12-41. The views must use an f:loadBundle tag to load a resource bundle, as shown in Listing 12-42. That bundle must have a properties file for each supported locale.

Listing 12-41 faces-config.xml Showing Multiple Configured Locales
<application>
    <locale-config>
        <default-locale>en</default-locale>
        <supported-locale>en</supported-locale>
        <supported-locale>fr</supported-locale>
    </locale-config>
</application>
Listing 12-42 Using an f:loadBundle Tag to Load a Resource Bundle
<f:loadBundle basename="oracle.samples.wlp.jsf.login_portlet" var="i18n" />

Ensuring Parity in Configured WLP and JSF Locales

Because both WLP and JSF compute the desired locale in the same way, the titles written by the portal framework are always in the same locale as the messages written by the JSF implementation. This assumes that WLP localizations and JSF resource bundles support the same locales.

It is a best practice to make sure WLP and JSF are both configured with the same set of locales. This ensures a consistent localized experience for a rendered page.

Modularizing Resource Bundles

JSF portlets support the standard JSF localization facility of resource bundles to provide a localized user experience.

In a portal environment, you need to consider modularizing the resource bundles. In typical JSF applications, one large bundle is created for the entire application. When developing JSF portlets, it is a best practice to create a bundle for each individual portlet definition. Or, if several portlets are always to be used together, a resource bundle can be shared between a group of portlets. This enables portlets to be reused more easily across portal projects.

 


Preparing JSF Portlets for Production

This section discusses best practices to follow before deploying a JSF portlet into a production environment.

Configuration Tasks

This section discusses configuration tasks to perform before deploying a JSF portlet to a production environment.

Configuring URL Templates for Proxy Servers

WLP is responsible for generating URLs that properly stay within the context of the portal. WLP does this for page tabs and also for portlet links. Understanding Navigation describes how WLP rewrites links for JSF Command Button and Link components automatically.

In production, the URL that a user enters to navigate to a WebLogic Portal instance must not target the machine hosting that instance. Instead, route the user through a proxy server or load balancer. This is a best practice for scalability and for security. WLP provides a configuration facility for configuring URLs properly in such an environment. The JSF link rewriting honors this facility, and so there is nothing JSF-specific about this configuration.

For more information on the WLP URL template facility, see "Working with URLs" in the Portal Development Guide.

The steps for configuring URLs to make use of a proxy server are:

  1. Go to the Merged Resources view of your Portal Web Project in Eclipse.
  2. Find WEB-INF/beehive-url-template-config.xml, right click on it, and choose Copy to Project.
  3. Go to the Project Navigation view and double-click the copied file.
  4. Add the URL template entry shown in Listing 12-43, replacing the IP address with the IP address of the proxy server or load balancer.
  5. Configure your proxy server to forward to WebLogic Portal.
  6. Listing 12-43 Configure URL Generation That Refers to a Proxy Server
    <url-template>
        <name>default</name>
    <value>http://192.168.0.5:{url:port}/{url:path}?{url:queryString}{url:currentPage}</value>
    </url-template>

If using Weblogic Server as your proxy server, see Oracle WebLogic Server proxy plug-in documentation otherwise consult your vendor's proxy server documentation. See the Oracle WebLogic Server proxy plug-in documentation here:

http://download.oracle.com/docs/cd/E12840_01/wls/docs103/plugins/index.html

JSF Portlets with WSRP

When developing portlets with JSF, the WSRP capabilities of WLP work correctly. JSF portlets can be exposed as WSRP portlets, just as with any other portlet type. For detailed information on WSRP portlets, see Federated Portals Guide.

Caution: It is not recommended to attempt to implement Ajax features within any portlet, JSF or otherwise, that will be offered over WSRP.

Defining Error Pages

A best practice is to make sure each portlet has a configured error page. This allows the portal framework to provide a user friendly error screen in case of a problem.

A portlet error page is configured as the Error Page Path property in the portlet editor. For more information, see Portlet Properties in the Portlet Properties View.

Performance and Scalability

This section discusses best practices for developing JSF portlets that perform well and are scalable.

JSF Portlets in a Clustered Environment

WebLogic Portal runs on WebLogic Server, which includes industry-leading clustering technology. Clustering provides for both load balancing and failover capabilities. For the most part, WebLogic Server achieves both transparently. You do not need to know about the underlying clustering capabilities.

However, for failover to work properly, WebLogic Server must replicate a user's HttpSession to a secondary node in the cluster. This enables the user to have a seamless experience if one node were to fail. But in order for an HttpSession to be replicated without loss of data, the objects set as attributes within it must be Serializable. For more information, see "Failover and Replication in a Cluster" in the Oracle Fusion Middleware Using Clusters for Oracle WebLogic Server guide available here:

http://download.oracle.com/docs/cd/E12839_01/web.1111/e13709/toc.htm

For JSF portlets to work well in a failover use case, all of the JSF portlet state must be in the HttpSession and be Serializable. As discussed in Tips for Logging, Iterative Development, and Debugging of JSF Portlets, even request-scoped managed beans are written into the HttpSession in a portal environment. Therefore, it is a best practice for all managed beans, even those that are request scoped, to be Serializable.

Portlet Render Caching

The WLP portal framework provides an easy solution for improving portlet rendering performance. When a portlet is not the target of a user interaction or does not handle an interportlet communication event during the request, the portlet's markup can be served from cache. By default, a portlet's rendered markup is not cached. To enable portlet caching, set the following values in the Portlet Properties view (see Figure 12-13).

Note: When a JSF portlet's markup is rendered from cache, none of the JSF life cycle methods are invoked during the request.
Figure 12-13 Portlet Cache Configuration
Defining Multiple Localized Titles for a Portlet

Securing JSF Portlets

This section discusses best practices for securing JSF portlets.

Deny Direct Access to the Portlet Views

It is common for developers to develop JSF portlets as standalone JSF applications, in isolation of the portal framework. For this development technique, the Faces servlet must be mapped in web.xml, as shown in Listing 12-44.

Listing 12-44 Prefix Servlet Mapping in web.xml
<servlet-mapping>
    <servlet-name>faces</servlet-name>
    <url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>faces</servlet-name>
    <url-pattern>*.faces</url-pattern>
</servlet-mapping>

Note that these mappings exist in web.xml only to support the direct access use case. Generally, in production it is not recommended to allow users to target the JSF views directly. It is better to force users to navigate to those views through the portal user interface. This can be enforced by removing the prefix and suffix mappings to the Faces servlet in web.xml.

Session Timeouts

It is always a good idea to test the behavior of a web application for the request immediately following an HttpSession timeout. JSF portlets behave the same as traditional JSF applications – the former state of the portlet is forgotten and the user is taken back to the initial state of the JSF portlet.

 


Tips for Logging, Iterative Development, and Debugging of JSF Portlets

This section includes these topics:

Enabling Logging

For WebLogic Portal Web Projects the integration of logging is pre-configured. The WebLogic Integrated Commons Logging facet is a required facet for any Portal Web Project. Follow these steps to increase the log sensitivity level to enable Debug messages to be output to the console:

  1. Log on to the WebLogic Console, usually at a URL like http://localhost:7001/console.
  2. Navigate to the Servers > AdminServer > Logging tab.
  3. Click the Advanced link to get the full set of controls.
  4. In the Log file section, set the Severity Level to Debug.
  5. In the Standard out section, set the Severity Level to Debug.
  6. Click Save.
  7. On the next request to a portal page that contains JSF portlets, you will see debug output on the server console window.

It may also be beneficial to enable logging for the Sun Reference Implementation of JSF in order to access the JSF debugging messages. The Sun RI of JSF uses Commons Logging for its logging functionality. WebLogic Server has general instructions on integrating Commons Logging into the WebLogic Server. Those instructions can be found at:

http://edocs.beasys.com/wls/docs103/logging/config_logs.html

Using Iterative Development for JSF Portlets

This section discusses techniques for iterative development of JSF portlets.

Testing Outside of the Portlet Container

It is often possible to test a JSF portlet outside of the portlet container. Meaning, it is possible to target the view file directly as with a standard JSF application. In cases where this is possible, this is a good way to develop the portlet. It isolates the JSF container from the portlet container, and so aids in identifying where to look for a solution to a problem. (See also Securing JSF Portlets)

The NamingContainer tag does work correctly outside of the portlet container. But if the portlet relies on features such as backing files or events to work correctly, this approach may not be viable. NamingContainer is discussed in Namespacing.

Using Application Republish

WebLogic Server automatically republishes changes to JSP files; however, changes to source code or deployment descriptors however require an explicit republish in Eclipse (if auto publishing is disabled). This can be done from the Server pane in Eclipse, among other ways. This process is not specific to Portal Web Projects.

HttpSession Caching

JSF caches the user's views in the HttpSession. Therefore, while WebLogic Server detects that a JSP has been updated, any existing session will contain an out of date copy of the view. It is therefore necessary to begin a new HttpSession after modifying a JSF JSP. This issue is not specific to Portal Web Projects.

Handling OutOfMemory Errors

Unfortunately, certain implementations of JSF have memory leaks that occur during a web application redeploy. During long development sessions across many redeployments, the server may fail with an OutOfMemoryException. Unfortunately, there is no solution for this issue – a server restart is required. This issue is not specific to Portal Web Projects.

Debugging

This section discusses how to use the Eclipse debugger to troubleshoot JSF portlets. See the Eclipse documentation for information on enabling the Eclipse debugger. This section discusses topics specific to JSF portlets.

Usually the best place to start when debugging a portlet is to set breakpoints in all of the code that you have written. This includes managed bean methods and backing file methods.

But sometimes you need to look into the portal framework. The JSF bridge invokes the JSF implementation, which in turn processes and renders the portlet. For this reason, it’s typically best to set break points in the JSF implementation. This is fortunate, as source code is available for the JSF implementations, whereas with the WLP framework source code is not available.

Step 1: Attaching Source

You can investigate resources on the web that explain how to attach source code to the JAR files in your project (for example, you can search for "eclipse attach source"). The main issue for JSF development is locating the proper source files for the JSF implementation used in your web project.

You can download the Sun reference implementation (RI) code from the Mojarra project site at https://javaserverfaces.dev.java.net.

Step 2: Suggested JSF Framework Break Points

The following list provides some JSF implementation break points to get started (assumes Sun RI):

 


Consolidated List of Best Practices

This section provides a consolidated list of best practices. It contains the following topics:

Configuration

Namespacing

Logging, Iterative Development, Debugging

Custom JavaScript

Preparing JSF Portlets for Production

Interportlet Communication

Scopes

State Sharing Patterns

Rendering Lifecycles

Ajax Enablement

Login Portlet


  Back to Top       Previous  Next