Portlets and FacesClient Components are a winning combination. FacesClient Components can significantly enhance the user's experience with portlet applications since portals serve as a simple, unified access point to Web applications. With FacesClient Components, you can make portlets more responsive, interactive, and attractive.
Additionally, the benefits of portlet applications enabled with FacesClient Components include:
- Lower consumption of server-side resources by offloading processing from the server to the client.
- Fewer round trips to the server.
In this article (the second in a series), we will briefly describe the process for creating an FacesClient Components application and delineate the best practices for developers to follow when designing FacesClient Components portals. We also provide sample code that demonstrates how to implement these suggested best practices.
Create an FacesClient Components portlet application
As we noted in the first article of this series, a developer must complete several major tasks to create an FacesClient Components portlet application:
- Determine the dataset needed for the application and create an ECore file that contains a server-side Eclipse Modeling Framework (EMF) model of the dataset.
- Create a Service Data Objects (SDO) for JavaScript (SDO4JS) representation of the client data model. As described in the "FacesClient Components Developer's Guide" (see Resources), the terms Web Data Objects (WDO) and Service Data Objects (SDO) are somewhat synonymous.
- Generate a set of FacesClient Components mediator files in order to export the server-side model to the client browser as JavaScript.
- Finally, create the server-side model instance data needed to drive the application.
When a user accesses a Web page enabled with FacesClient Components, the server creates a stream of JavaScript and HTML and forwards it to the browser. As shown in Figure 1, the generated browser page may contain any or all of the following:
- An SDO4JS set
- The page runtime
- A control library
- The HTML used to lay out the page
Figure 1. Sample browser page
The controls display the instance data enclosed in the SDO4JS objects. The page runtime defines the page FacesClient Components services, bindings, and event handlers. When used in concert with the data model, the controls and event handlers can create a richer experience for the user.
The portlet structure and FacesClient Components
Portals provide aggregation of content from such diverse sources as rich text, video, or XML; they also provide personalized services, such as user customization of layout and content. To accommodate the aggregation and display of this diverse content, a portal server must provide a framework that breaks the different portal components into portlets. Each portlet is responsible for accessing content from its source (for example, a Web site, database, or e-mail server) and transforming the content so it can be rendered to the client.
A portlet is developed, deployed, managed, and displayed independent of other portlets. Administrators and users create personalized portal pages by choosing and arranging portlets, resulting in Web pages that present content tailored for individuals or teams. A portlet has no control or even awareness of the order in which the output from all of the portlets on the page is written.
The developer decides the working set for the data model needed for an application and develops the data model which is then shared by the portlets in the portlet application. Within each portlet, controls may dynamically bind to the shared data model.
User productivity can increase when working with a portlet enabled with FacesClient Components. Why? Designers can wire portlets together through FacesClient Components, easily enabling users of multiple portlets to send information from one portlet to another on the client-side within the browser. FacesClient Components provides the mechanism for portlets to communicate with each other, exchanging data or messages in response to events captured by the event handlers.
Some FacesClient Components best practices
We mentioned previously that a portlet possesses "no control or even awareness of the order in which the output from all of the portlets on the page is written." When developers use FacesClient Components in a portlet application, this lack of awareness presents a challenge.
Order: Using FacesClient Components event handlers
The following scenario further highlights the issue. First, look at Figure 2. (You can also view a larger version of Figure 2.)
Figure 2. Bank accounts and account details
Using the banking example from the Customer Loyalty Scenario shown in Figure 2, portlet A (eBank Accounts) and portlet B (eAccount Details) are part of the same portal page. Portlet A displays information about a user's checking and savings accounts using a DataGrid control while portlet B displays information using a DataGrid about transactions that have occurred for one of the accounts over the last 30 days.
The DataGrids in each portlet share the same data model. That sharing enables a designer to wire them so when a user selects his checking account in A, the corresponding transaction details of the checking account are displayed in B without making a roundtrip to the server. To do this, the transactions portlet needs to obtain the corresponding account information when it displays the transaction details.
This is accomplished through FacesClient Components event handlers that take an object or reference in an object selected in one control and sets that same object as the root for another control. When the checking account is selected in portlet A, the action listener for the page is called, which dynamically changes the bindings for the DataGrid in portlet B from inside the browser.
As shown in Figure 1, several framework components are needed to enable a portal/Web page with FacesClient Components. If we use a JSP file to hold the generated SDO4JS set, page runtime, and control library, and include the file only in portlet A, then referencing the generated JavaScript components in portlet B will prove problematic.
As previously stated, a portlet has no control of the order in which the output from all of the portlets on the page is written. JavaScript is a linear language -- you must define objects before you use them. So, browser errors occur if portlet B is rendered before portlet A.
Order: Using FacesClient Components to generate the data model
To reap the benefits of FacesClient Components in portlet applications, portlets must share objects (for instance, the data model and data instance). If multiple portlets enabled with FacesClient Components are placed together on a page, the order in which the portlets are rendered is unknown. Therefore, a best practice for developers is to create and invoke FacesClient Components code to generate the data model on each portlet enabled with FacesClient Components regardless of the other portlets on the Web page.
This presents challenges when writing cooperating portlets that are required to share the same data and models. If two portlets use the same model name, they better refer to the exact same model structure; otherwise, the JavaScript emitted will cause errors in the browser.
Additionally, portal pages containing duplicate copies of the data model, instance data, page runtime, and control libraries will cause errors in the browser. To manage these issues, the designers of FacesClient Components incorporated fail-safe methods for developers.
Managing FacesClient Components resources
The FacesClient Components PageContext object manages FacesClient Components
resources. This object is essential to the operation of the framework and it
keeps an accounting of the FacesClient Components resources and ensures that the mediators are not
exposed to infinite loops following a cycle in the data model/graph (for example, when a user has a banking account and the banking account points back to the user). Additionally, the object guarantees that a particular object or type is not produced more than once -- in other words, there won't be too many instances of the data model.
The PageContext maintains a single-page state and
guarantees coordination between multiple FacesClient Components portlets in a Web page. By
convention, put the PageContext in some
request-level container to make certain it is shared across multiple elements
called during the life cycle of the entire request.
Do not place the PageContext object in a
session or page-level container -- it is only valid for a single request and
sharing one across requests (throughout a session) has a negative effect, such as a missing data or type definition in a follow-up request. When portlet developers write cooperating portlets that share the same data models and data instance, they should use portlet APIs and FacesClient Components'sPageContext. The portlet API provides listeners which can add more functionality for a portlet.
The PortletPageListener allows a portlet to insert
markup at the beginning and ending of a page. At the beginning of each page and before any service() method of any portlet on the page is called, the beginPage() method is called for each portlet residing on the page. Like the service() method, the beginPage() method for each portlet on the page is not called in a guaranteed order and can even be called in a different order for each request.
The output of beginPage() is inserted into the page-aggregation area prior to the rendering of portlets on the page. At the end of each page, after all service() methods of all portlets on the page are called, the endPage() method is called for each portlet residing on the page. Like the service() method, the endPage() method is not called in a guaranteed order and can even be called in a different order for each request. For example, the portlet can insert JavaScript to the end of the page that needs to occur after all other portlets on the page have been written.
The ODCBankAccount (shown in Listing 1) and ODCAssetAccountsDetails (shown in Listing 2) portlet examples demonstrate our use of the aforementioned portlet and FacesClient Components APIs.
ODCBankAccount and ODCAssetAccountsDetails are cooperating portlets that share the same data model and instance. Both portlet examples implement the PortletPageListener to allow insertion of key FacesClient Components page-state management, initialization, and post-processing code in the aggregation area of the portlets prior to rendering. The beginPage() method in each portlet inserts the results of a call to the ODCDemoUtility initialization method (in Listing 3).
The following code examples illustrate our best practices.
Listing 1. The ODCBankAccount portlet
public class ODCBankAccounts extends PortletAdapter
implements PortletSessionListener, PortletPageListener {
......
public void login(PortletRequest request) throws PortletException {
}
public void logout(PortletSession session)throws PortletException {
}
/**
do the appropriate processing on the data model and
create the xhtml to send to the client
**/
public void doView(PortletRequest request, PortletResponse response)
throws PortletException, java.io.IOException {
PortletContext context = getPortletConfig().getContext();
context.include("resource/ODCBankAccounts.jsp", request, response);
}
public void beginPage(PortletRequest request, PortletResponse response)
throws PortletException, java.io.IOException {
ODCDemoUtility du = new ODCDemoUtility();
du.ODCDemoInitialization(request, response, getPortletConfig().getContext(),
"resource/ODC_Banking_Init.jsp");
}
public void endPage(PortletRequest request, PortletResponse response)
throws PortletException, java.io.IOException {
ODCDemoUtility du = new ODCDemoUtility();
du.ODCDemoPostProcessing(request, response, getPortletConfig().getContext(),
"resource/ODC_Banking_End.jsp");
}
} |
Listing 2. The ODCAssetAccountsDetails portlet
public class ODCAssetAccountsDetails extends PortletAdapter
implements PortletPageListener {
public void login(PortletRequest request) throws PortletException {
}
public void logout(PortletSession session)throws PortletException {
}
/**
do the appropriate processing on the data model and
create the xhtml to send to the client
**/
public void doView(PortletRequest request, PortletResponse response)
throws PortletException, java.io.IOException {
PortletContext context = getPortletConfig().getContext();
context.include("resource/ODCAssetAccountsDetails.jsp", request, response);
}
public void beginPage(PortletRequest request, PortletResponse response)
throws PortletException, java.io.IOException {
ODCDemoUtility du = new ODCDemoUtility();
du.ODCDemoInitialization(request, response, getPortletConfig().getContext(),
"resource/ODC_Banking_Init.jsp");
}
public void endPage(PortletRequest request, PortletResponse response)
throws PortletException, java.io.IOException {
ODCDemoUtility du = new ODCDemoUtility();
du.ODCDemoPostProcessing(request, response, getPortletConfig().getContext(),
"resource/ODC_Banking_End.jsp");
}
} |
Listing 3. The ODCDemoUtility initialization method
public class ODCDemoUtility {
.....
public void ODCDemoInitialization( PortletRequest request,PortletResponse response,
PortletContext context, String jspPage)
throws PortletException, java.io.IOException {
HttpServletRequest hsr = this.getHttpServletRequest(request);
String wdo4js_prefix = (String) hsr.getAttribute("ODC_DEMO_INIT");
// do this only once across all the portlets
if ((wdo4js_prefix == null) || (!wdo4js_prefix.equals("true"))) {
hsr.setAttribute("ODC_DEMO_INIT", "true");
User portletUser = request.getUser();
String userId = portletUser.getUserID();
init(userId, request, response);
context.include(jspPage, request, response);
}
}
public void ODCDemoPostProcessing(PortletRequest request,PortletResponse response,
PortletContext context,String jspPage)
throws PortletException, java.io.IOException {
HttpServletRequest hsr = this.getHttpServletRequest(request);
String wdo4js_end = (String) hsr.getAttribute("ODC_DEMO_END");
// do this only once across all the portlets
if ((wdo4js_end == null) || (!wdo4js_end.equals("true"))) {
hsr.setAttribute("ODC_DEMO_END", "true");
context.include(jspPage, request, response);
}
}
} |
The HttpServletRequest stores name value
pairs -- hsr.setAttribute("ODC_DEMO_INIT", "true") -- and the name value pairs ensure that the portlets on the Web page create only one data model and the data instance shared object.
Portlets placed on a Web page can be rendered in any order; therefore, create and invoke FacesClient Components code to generate the data model on each portlet enabled with FacesClient Components regardless of the other portlets on the Web page.
To wire events for FacesClient Components controls in multiple portlets, share the event objects. The endPage() method in each portlet inserts the results of a call to the ODCDemoUtility post-processing method. The HttpServletRequest stores name value pairs which ensure that the portlets on the Web page create only one event-shared object.
You can take two alternate approaches to enable portlets located on the same page to communicate with each other -- property broker and portlet messaging. The property broker's runtime is comprised of a generic wrapper portlet, which wraps each portlet enabled for cooperation, as well as a broker component. These components also interface with the WebSphere Portal core runtime. The purpose of the wrapper is to:
- Intercept calls to the application portlet and interface with the broker appropriately
- Transparently register actions supported by the portlet
- Initiate data transfer from source to target portlets using the property broker
In the portlet messaging approach, a portlet's action listener typically sends a message and another portlet's message listener receives it. If an action occurs in one portlet, the action event is captured and processed by the portlet. As a result of the action event, the portlet sends a message to other portlets using the send() method of the PortletContext object. (Find more on these approaches in Resources.)
In this article, we discussed the challenges that developers face when they create portlets enabled with FacesClient Components. We also demonstrated, through sample code, how to share data models and instance data between multiple portlets on a portal page. In a following article, we'll discuss how to update the client-side data model without refreshing the portal page.
| Description | Name | Size | Download method |
|---|---|---|---|
| FacesClient Developer Guide | FacesClient_developer_guide.pdf | 3.8 MB |
FTP
|
| Cooperative Portlets in WebSphere Portal V5 guide | CooperativePortlets.pdf | 0.7 MB | FTP |
| Source code, Cooperative Portlets guide | cooperativeportletsexamples.zip | 311 KB |
FTP
|
Information about download methods Get Adobe® Reader®
- Visit the WebSphere® site on developerWorks for software downloads, white papers, tutorials, and training for developers using the WebSphere platform.
- At the Eclipse Project, learn about the Eclipse Modeling Framework (EMF), a code-generating tool for building other tools and applications based on a structured data model as described in XMI.
- Check out the Portlet Development Guide for more information on how to develop a portlet using the Portlet API 1.2 and Portlet API concepts and its elements (developerWorks, March 2003).
- Read the FacesClient Components Developer's Guide (PDF file) for more information about different FacesClient Components, and how to use them with WebSphere Studio to build Web and portlet applications (developerWorks, November 2004).
- In Consumer self-service: Develop and deploy rich clients on the portal, explore how to fulfill the title's promise using FacesClient Components (developerWorks, November 2004).
- Review the first article in this series, FacesClient Components, Part 1: Portlet programming with FacesClient Components (developerWorks, November 2004).
- Get the details of FacesClient Components' cutting-edge, pattern-based structure in iSeries EXTRA: A Web Tooling Odyessy (IBM eServer Magazine, June 2004).
- Browse for books on these and other technical topics.
- Find step-by-step instructions for creating a portlet application that includes portlet messaging in Implementing portlet messaging using WebSphere Studio Application Developer V5 and the Portal Toolkit V5 (developerWorks, February 2004).
- Learn how to coordinate the behavior of multiple portlets in a seamless fashion in Using Cooperative Portlets in WebSphere Portal V5 (developerWorks, October 2003).
- Visit the developerWorks Web Architecture zone for numerous articles covering various Web-based solutions.

Rod Henderson is an Advisory Software Engineer in the IBM Software Group, System House, Advanced Technology Department located in Research Triangle Park, North Carolina. He received his Ph.D. in electrical engineering from North Carolina A&T State University in 2002. He is actively involved in advanced technology projects in the areas of rich client technology, solution integration, and scenario-based software development. Contact Rod at rodhende@us.ibm.com.

Yongcheng Li is a Senior Software Engineer in the IBM Software Group, System House, Advanced Technology Department located in Research Triangle Park, North Carolina. He received his Ph.D. in Computer Science from Tsinghua University in 1993. He is actively involved in advanced technology projects in the areas of rich client technology, data caching and replication, solution integration, and scenario-based software development. Send e-mail to Yongcheng at ycli@us.ibm.com.

Thomas McElroy is an Advisory Software Engineer in the IBM Software Group, System House, Advanced Technology Department located in Research Triangle Park, North Carolina. He has been working on Web application technology projects for the last three years, including projects with On-Demand Clients, Edge-Side Includes, Integrated Solutions Console, and a novel approach to a JDBC caching proxy. Reach Thomas at tmcelroy@us.ibm.com.




