bea.com | products | dev2dev | support | askBEA

Download Docs | Site Map | Glossary
Search

Development Guide

Extending Portlets

To invoke advanced features in portlets, and make these portlets available to administrators, developers use several tools and many procedures. This section includes information on the following subjects:

- Basic Portlet Customization

- Moving a Portlet Between Portal Web Applications

- Moving a Portlet Between Domains

- Creating Categories for Portlets

- Portlets and the Framework

- Simple JSP Portlets

- WebFlow Portlets

- Web Service Portlets

- Portalizing an Existing Web Application

- Performance Tuning

Basic Portlet Customization

One of the most basic customizations is moving a portlet from one portal into another. Understanding this procedure will help you understand many of the other tasks in this section, since many procedures and tools are introduced here. This section covers the following basic portlet customizations:

- Moving a Portlet Between Portal Web Applications

- Moving a Portlet Between Domains

- Creating Categories for Portlets

Moving a Portlet Between Portal Web Applications

This section explains the process of moving a portlet from one portal Web application to another, and is based on the assumption that both portals have been deployed correctly. Figure 11-2 shows the two portals with their associated Web applications.

Figure 11-1 Portals and associated Web applications

This example illustrates moving a portlet called flowlet1, shown in Figure 11-2, from one portal Web application (NewPWApp) to another (NextPWApp).

Figure 11-2 flowLet1 portlet in the NewWPApp

Take the following steps to add the flowLet1 portlet to NextPWApp portal:

- Step 1: Copy J2EE Resources into New Web Application

- Step 2: Edit the Target Web Application Metadata

- Step 3: Synchronize the Project

- Step 4: Make the New Portlet Visible and Available

Step 1: Copy J2EE Resources into New Web Application

If you open the flowLet1 portlet inside the E-Business Control Center, you can see it is visible among the available portlets.

Because the original portlet uses a custom Webflow, this file must be moved before the target portal Web application can use this portlet. Figure 11-3 shows the flowLet1 Webflow file in the \webapps directory for NewPWApp being copied into the \webapps directory for NextPWApp.

Figure 11-3 Copying the navigation Webflow

Figure 11-4 shows the portlet folder flowLet1 being copied from the NewPWApp application folder into the NextPWApp Web application folder. The JSPs and images that make up your portlet are stored inside this directory.

Figure 11-4 Copying J2EE resources

Now that the J2EE resources have been copied into the new Web application, the metadata can be edited to point to these resources.

Step 2: Edit the Target Web Application Metadata

Use the E-Business Control Center to add the flowLet1 portlet to the ThatNewPortal portal:

1. From the Presentation Tab in the E-Business Control Center, click on portal and select the portal called That New Portal.

2. When the portal editor opens, click on the General tab to the top right.

3. Click on the portlets tab halfway down the General page, select the flowLet1 portlet from the list of available portlets, and click Add, as shown in Figure 11-5.

   Figure 11-5 Adding flowLet1 to ThatNewPortal

4. Close the General tab, click on the Pages tab, select the Home portal page and click Edit.

5. Select the flowLet1 portlet from the list of available portlets to the lower left of the definition screen for the Home portal page, and click Add. Click OK to close this window.

6. Save this project.

Step 3: Synchronize the Project

Use the E-Business Control Center to sync the project.

Note: For more details on the E-Business Control Center, consult "Setting up the E-Business Control Center" in the Administration Guide at http://edocs.bea.com/wlp/docs70/admin/sysadmin.htm.

1. From the E-Business Control Center toolbar, click the Synchronize button, as shown in Figure 11-6.

   Figure 11-6 Click Synchronization button

2. When the Synchronizing Application window shows that synchronization is complete, click Close.

Step 4: Make the New Portlet Visible and Available

The new portlet called flowLet1 is now deployed, but must be made available using the WebLogic Portal Administration Tools.

1. In your Web browser, navigate to the following URL: http://<hostname>:<port>/portalAppTools. Login as administrator/password, and click Portal Management, as shown in Figure 11-7.

   Figure 11-7 Go to Portal Management

2. From the Portal Management Home page, click the Default Portal under the NextPWApp, as shown in Figure 11-8.

   Figure 11-8 Select Default Group Portal

3. From the Group Portal Management Home page, click Manage Pages and Portlets as shown in Figure 11-9.

   Figure 11-9 Manage Pages and Portlets

4. Next to the portal page, click Edit Portlets, as shown in Figure 11-10.

   Figure 11-10 Click Edit Portlets

5. Select the flowLet1 portlet from the list and click Set Attributes, as shown in Figure 11-11.

   Figure 11-11 Select Set Attributes for flowLet1 portlet

6. Set the Portlet's attributes to Visible and Available and click Save, as shown in Figure 11-12.

   Figure 11-12 Set Portlet Attributes

7. Verify the results by navigating to http://<hostname>:<port>/NextPWApp/index.jsp. The result should resemble that shown in Figure 11-13.

   Figure 11-13 Viewing flowLet1 in NextPWApp

Moving a Portlet Between Domains

Assuming both domains are correctly installed and deployed instances of the latest release of WebLogic Portal, the procedure for moving a portlet from one domain to the other is almost identical to that used for Moving a Portlet Between Portal Web Applications.

1. When copying the J2EE files, also copy the .portlet file to the portalApp-project\portlets directory on the target server. Figure 11-14 shows where the .portlet file resides in the portalApp-project\portlets directory on the origin domain.

2. Complete the remainder of the steps listed in the section Moving a Portlet Between Portal Web Applications.

   Figure 11-14 The .portlet file

Finding Missing Resources Through Error Messages

If you are missing necessary portlet resources in a domain, you will receive error messages either at server startup or when you try to access portal pages that use those resources. (Missing portlet resources do not prevent the server from starting.)

For example, you may receive HTTP session errors in your browser such as 404, or render-time errors that say, for example, "Functionality temporarily unavailable." Missing metadata can also cause errors.

Look for error messages in your server's command window to determine which resources are missing. For example, Listing 11-1 shows that a portlet called WebFlowPortlet is missing a file called header.jsp. This message was generated in the command window when the portal page containing this portlet was accessed.

Listing 11-1 Error caused by missing portlet resources

>     <Jun 12, 2002 10:38:59 AM MDT> <Error> <HTTP> <101214> <Included resource or file "/NewWebApp/portlets/WebflowPortlet/header.jsp" not found from requested resource "/NewWebApp/framework/portal.jsp".>

The E-Business Control Center also catches some errors when you are editing portlets. For example, a warning dialog box alerts you if the portlet you are editing is missing an associated Webflow file.

Creating Categories for Portlets

The E-Business Control Center lets you group portlets into categories for easier management. This section illustrates how to create categories and manage portlets within them.

Preparing to Work With Categories

The steps in this section require that the following preparations be in place:

- Working instance of WebLogic Portal 7.0

- Fully deployed portal

- WebLogic Portal Server must be running.

Warning: Trying to create a new category before a portal has been defined in the E-Business Control Center will generate an error.

Creating Portlets and Categories

1. From the Presentation Tab in the E-Business Control Center, use the Portlet Wizard to create some generic portlets, as shown in Creating a New Portal in a New Domain. To follow along with this example, name the new portlets as follows:

- WallStreet

- MainStreet

- MidWest

- SouthEast

- LatinAmerica

1. From the Presentation Tab in the E-Business Control Center, click the Portlets icon and click the new folder icon, as shown in Figure 11-15.

   Figure 11-15 Creating a new category

2. The New Category screen appears. Type "Business" in the name field and click OK. Repeat this step to create the following new categories:

- Education

- Regional

- International

The resulting category list should resemble that shown in Figure 11-16.

Figure 11-16 New categories

Note: Selecting one of the portlets makes the three icons to the right available, as shown in Figure 11-17.

Figure 11-17 Category icons in toolbar

Moving Portlets and Categories

This section explains how to move portlets and categories using the E-Business Control Center.

1. Select the International and Regional categories, then click the Move icon on the far right of the toolbar, as shown in Figure 11-18.

   Figure 11-18 Click Move category

2. The Moving Category International screen appears. Select Education and click Move. When the Moving Category Regional window appears, do the same. The results should look similar to those in Figure 11-19.

   Figure 11-19 Categories and portlets

3. Select the Education category, then click the Rename icon second from the right in the toolbar, as shown in Figure 11-20.

   Figure 11-20 Select a category and click rename

4. The Rename category screen appears. Type in "Schools" and click Rename, as shown in Figure 11-21.

   Figure 11-21 Renaming a category

5. Move the MidWest and SouthEast portlets into the Schools category by selecting them, clicking the Move icon, shown in Figure 11-22, and selecting a destination as shown in Figure 11-23.

   Figure 11-22 Moving portlets into a Category

   Figure 11-23 Selecting destination folder

6. Using the category icons, move the MainStreet and WallStreet portlets into the Business category, the LatinAmerica portlet into the International category, and the MidWest and SouthEast portlets into the Regional categories. The results should look like those in Figure 11-24.

   Figure 11-24 Portlets and categories arranged

Adding Portlets to Existing Categories

This section explains how to place new portlets into existing categories. In this example, the following portlets are created:

- BondStreet

- UK

- Asia

To add portlets to existing categories, take the following steps:

1. From the Presentation Tab in the E-Business Control Center, use the Portlet Wizard to create the new portlets.

Note: When naming the portlets, click Select a Category, as shown in Figure 11-25.

Figure 11-25 Select a category for the portlet

1. The Select a portlet category screen appears, as shown in Figure 11-26. Select Business and click OK.

   Figure 11-26 Placing a new portlet inside an existing category

2. Proceed with the rest of the steps in the Portlet Wizard, and repeat for the BondStreet, UK, and Asia portlets.

3. The resulting portlets should resemble those shown in Figure 11-27.

   Figure 11-27 Portlets in their categories

Portlets and the Framework

The BEA WebLogic platform provides extensive support for customizing portlets, including JSP tag libraries designed to expose robust functionality while requiring minimal Java scripting within the actual JSPs that constitute a portlet. Use the information in this section to create the following portlet types:

- Simple JSP Portlets: These portlets can contain scriptlets and can invoke personalization features, but do not use individual WebFlows.

- WebFlow Portlets: The portal wizard can be used to create three different Webflow portlets. Navigation and inter-portlet scenarios can also be realized by customizing a WebFlow file and associating it with an individual portlet.

- Web Services Portlets: Code can be added to a portlet that invokes various interactions with other programs, either locally or across the Internet.

The remainder of this section explains each portlet type, providing several examples of each and explaining some techniques for creating portlets that best make use of the BEA WebLogic platform.

Simple JSP Portlets

To illustrate some of the power, flexibility, and ease-of-use inherent in the WebLogic Portal platform, this subsection includes the following examples:

- The scriptDemo Portlet

- Calling ActiveX Components from a Portlet

The scriptDemo Portlet

The scriptDemo portlet, shown in Figure 11-30, appears to the left on the Home page of an example portal created using the Portal Wizard.

Preparing

Make the following preparations to work through this example:

1. Create a new portal called "MyNewPortal1", and a new portal Web application "OldPortalWebApp", as explained in Step 2: Create the New Portal, in Creating a New Portal in a New Domain.

2. Create a new portlet, called "scriptDemo" as explained in Step 3: Add a Portlet, in Creating a New Portal in a New Domain.

3. Make the "scriptDemo" portlet visible, as explained in Step 4: Make New Portlet Visible, in Creating a New Portal in a New Domain.

Before Continuing

Ensure your portal looks similar to that shown in Figure 11-28 before a user is logged in, or that shown in Figure 11-29 with a user logged in.

Figure 11-28 Starting point with anonymous user

Figure 11-29 Starting Point with user logged on

Installing the scriptDemo portlet

With the raw materials are in place, you can now transform the portlet by replacing the content.jsp to change its behavior. Listing 11-2 shows a very simple scriptlet that illustrates how to use generic Java scriptlets to interact with the Portal framework in a portlet.

Listing 11-2 scriptDemo portlet version 1

>     <center> Test Portlet </center>
>     <br><hr>
>     <%

>     A Simple Java Scriptlet
>     <br>
>     /*
>     Create a new String variable and set the value to an empty string.
>     */
>       String userName = "";
>     /*

>     To get the actual user name, first get the java.security.Principal object from the Javax.servlet.http.HttpServletRequest object using the getUserPrincipal() method.  The request object is available to the JSP directly. For the Principal object, use the full package name.

>     */

>       java.security.Principal principal = request.getUserPrincipal();
>     /*

>     If the principal object is null then the user has not logged in. For this example, ignore the not-logged in case by using an if statement to only process the value if it is not null.

>     */
>       if (principal != null)
>       {
>     /*
>     */
>         userName = principal.getName();
>       }
>     %>
>     <%--

>     Display the value of the userName variable using a scriptlet. Note that the scriptlet is embedded in the HTML and is denoted by the <%= %> block.

>     --%>
>     The user name is : <%= userName %>
>     <br>

Steps

Take the following steps to place this new code inside the scriptDemo portlet:

1. In a text editor, save the code from Listing 11-2 as content.jsp in the following directory:

   >     <BEA_HOME>\portalDomain\beaApps\portalApp\
   >     <PortalWebApp>\portlets\scriptDemo\

2. Refresh the browser, and verify that the results resemble Figure 11-30. Notice that because the portlet content was altered, the user has been logged out. Because the portlet now appears with an anonymous user, you can see that no user name appears in the portlet.

   Figure 11-30 scriptDemo portlet with anonymous user

3. Click Login in the top right corner of the portal.

4. When the Portal Login page appears, click Sign up now under the New Users column to the right.

5. When the New User Registration page appears, create a new user called "bobjones", and enter "password" in the password fields, and click Submit.

Figure 11-31 shows what the code in the scriptDemo portlet displays when a user is logged on. Notice that the user name is filled in.

Figure 11-31 scriptDemo portlet with a user logged on

Note: For more information on using JSP tags in your custom portlets, consult the following resources:

- JavaServer Page Reference Guide

- WebLogic Portal Javadoc API documentation.

Calling ActiveX Components from a Portlet

To call an ActiveX component from within your portlet, use the HTML <OBJECT> tag, as shown in Listing 11-3 and Listing 11-4.

These examples include a CODEBASE parameter so that if the local machine doesn't have the component installed in their registry, the component can be downloaded from Microsoft.

Note: In these examples, the portal is only communicating with the ActiveX components through HTML, which comes back from the portal to the browser, and tells the browser to load and run the ActiveX component.

Listing 11-3 Calling Outlook Using Active X - Calendar Example

>     <OBJECT CLASSID="clsid:0006F063-0000-0000-C000-000000000046"

>     CODEBASE="http://activex.microsoft.com/activex/controls/office/
>     outlctlx.CAB#ver=9,0,0,3203"

>         id=OVCtl1 width=100% height=200>

>       <param name="Folder" value="Calendar">

>       <param name="Namespace" value="MAPI">

>       <param name="Restriction" value="">

>       <param name="DeferUpdate" value="0">

>     </OBJECT>

Listing 11-4 Calling Outlook Using Active X - Inbox Example

>     <OBJECT CLASSID="clsid:0006F063-0000-0000-C000-000000000046"

>     CODEBASE="http://activex.microsoft.com/activex/controls/office/outlctlx.CAB#

>     ver=9,0,0,3203"

>             id=OVCtl1 width=100% height=200>

>       <param name="Folder" value="Inbox">

>       <param name="Namespace" value="MAPI">

>       <param name="Restriction" value="">

>       <param name="DeferUpdate" value="0">

>     </OBJECT>

Note: ActiveX components only work inside Microsoft Internet Explorer with appropriate security settings which allow them to run.

WebFlow Portlets

This section begins by showing the types of webflow portlets that can be created by the portlet wizard. Next, some fundamental aspects of WebFlow are illustrated using simple scripting examples. The following topics are handled in the section:

- Three Webflow Portlets

- How a Portlet Handles a Refresh Event

- Making a Portlet Respond to a Custom Event

- Sharing State from One Portlet to Another

Three Webflow Portlets

The Portlet Wizard in the E-Business Control Center can now produce three different types of Webflow portlets:

- Navigation Bar, in which each page in the set has a navigation bar with links to every other page in the set.

- Sequential, in which pages are traversed in sequence via the Next and Previous buttons.

- Hierarchical, in which a parent page features links to each child page. Child pages link back to the parent, but not to one another.

Preparing

This section illustrates adding new Webflow portlets to the application NewPWApp, as shown throughout this chapter. To work through these examples, make sure the portal server is running, and that portal-project is open in the E-Business Control Center.

Creating a Navigation Bar Webflow Portlet

This procedure shows how to use the portlet wizard to create a Navigation Bar Webflow portlet.

1. From the Presentation Tab in the E-Business Control Center, select New Portlet, as shown in Figure 11-32.

   Figure 11-32 Starting the Portlet Wizard

2. Elect to use the portlet wizard, as shown in Figure 11-33, and click OK.

   Figure 11-33 Elect to use the Portlet Wizard

3. Name the portlet Navigation, as shown in Figure 11-34, then click Next.

   Figure 11-34 Naming the Navigation Portlet

4. Associate the new portlet with the Home page, as shown in Figure 11-35, and click Next.

   Figure 11-35 Associate the portlet with the Home page

5. Select portlet components, as shown in Figure 11-36, and click Next.

   Figure 11-36 Select components

6. Select webflow content type, as shown in Figure 11-37, and click Next.

   Figure 11-37 Select Webflow content type

7. Select Navigation Bar model, as shown in Figure 11-38, and click Next.

   Figure 11-38 Select Navigation Bar Model

8. Select number of pages, as shown in Figure 11-39, and click Next.

   Figure 11-39 Select number of pages

9. Confirm resource files location, as shown in Figure 11-40, and click Next.

   Figure 11-40 Confirm Resource Files Location

10. Confirm summary of files to be created, as shown in Figure 11-41, and click Create.

    Figure 11-41 Confirm Summary

11. Confirm next steps, as shown in Figure 11-42, and click Close.

    Figure 11-42 Confirm Next Steps

12. Synchronize the project, as shown in Figure 11-43.

    Figure 11-43 Synchronize project

13. Use the WebLogic Portal Administration Tools to make the portlet visible and available, as shown in the section called Step 4: Make the New Portlet Visible and Available" on page 5.

14. View the portlet, as shown in Figure 11-44.

    Figure 11-44 Viewing the Navigation Bar Portlet

Creating a Sequential Webflow Portlet

This procedure shows how to use the portlet wizard to create a Sequential Webflow portlet.

1. From the Presentation Tab in the E-Business Control Center, select New Portlet, as shown in Figure 11-45.

   Figure 11-45 Starting the Portlet Wizard

2. Elect to use the portlet wizard, as shown in Figure 11-46, and click OK.

   Figure 11-46 Elect to use the Portlet Wizard

3. Name the portlet Sequential, as shown in Figure 11-47, then click Next.

   Figure 11-47 Naming the Sequential Webflow Portlet

4. Associate the portlet with the Home page, as shown in Figure 11-48, and click Next.

   Figure 11-48 Associate the portlet with the Home page

5. Select portlet components, as shown in Figure 11-49, and click Next.

   Figure 11-49 Select Portlet Components

6. Select webflow content type, as shown in Figure 11-50, and click Next.

   Figure 11-50 Select Webflow content type

7. Select Sequential Navigation model, as shown in Figure 11-51, and click Next.

   Figure 11-51 Select Sequential model

8. Select number of pages, as shown in Figure 11-52, and click Next.

   Figure 11-52 Select number of pages

9. Confirm resource files Location, as shown in Figure 11-53, and click Next.

   Figure 11-53 Confirm Resource Files Location

10. Confirm summary of files to be created, as shown in Figure 11-54, and click Create.

    Figure 11-54 Confirm Summary

11. Confirm next steps, as shown in Figure 11-55, and click Close.

    Figure 11-55 Confirm Next Steps

12. Synchronize the project, as shown in Figure 11-56.

    Figure 11-56 Synchronize project

13. Use the WebLogic Portal Administration Tools to make the portlet visible and available, as shown in the section called Step 4: Make the New Portlet Visible and Available.

14. View the portlet, as shown in Figure 11-57.

    Figure 11-57 Viewing the Sequential Webflow Portlet

Creating a Hierarchical Webflow Portlet

This procedure shows how to use the portlet wizard to create a Hierarchical Webflow portlet.

1. From the Presentation Tab in the E-Business Control Center, select New Portlet, as shown in Figure 11-58.

   Figure 11-58 Starting the Portlet Wizard

2. Elect to use the portlet wizard, as shown in Figure 11-59, and click OK.

   Figure 11-59 Elect to use the Portlet Wizard

3. Name the portlet Hierarchical, as shown in Figure 11-60, then click Next.

   Figure 11-60 Naming the Hierarchical Portlet

4. Associate the new portlet with the Home page, as shown in Figure 11-61, and click Next.

   Figure 11-61 Associate the portlet with the Home page

5. Select portlet components, as shown in Figure 11-62, and click Next.

   Figure 11-62 Select components

6. Select webflow content type, as shown in Figure 11-63, and click Next.

   Figure 11-63 Select Webflow content type

7. Select Hierarchical model, as shown in Figure 11-64, and click Next.

   Figure 11-64 Select Hierarchical Model

8. Select number of pages, as shown in Figure 11-65, and click Next.

   Figure 11-65 Select number of pages

9. Confirm resource files location, as shown in Figure 11-66, and click Next.

   Figure 11-66 Confirm Resource Files Location

10. Confirm summary of files to be created, as shown in Figure 11-67, and click Create.

    Figure 11-67 Confirm Summary

11. Confirm next steps, as shown in Figure 11-68, and click Close.

    Figure 11-68 Confirm Next Steps

12. Synchronize the project, as shown in Figure 11-69.

    Figure 11-69 Synchronize project

13. Use the WebLogic Portal Administration Tools to make the portlet visible and available, as shown in the section called Step 4: Make the New Portlet Visible and Available.

14. View the portlet, as shown in Figure 11-70.

    Figure 11-70 Viewing the Hierarchical Portlet

How a Portlet Handles a Refresh Event

To illustrate how portlets can use Webflow, observe how portlets handle the refresh event, as demonstrated in the bold code in Listing 11-5.

Listing 11-5 Adding refresh notification to a portlet

>     <%@ taglib uri="portlet.tld" prefix="portlet" %>
>     <%
>     System.out.println("Calling refresh on flowLet1 portlet.");
>     %>
>     <center>
>     <font size="6" color="green">Portlet 1</font><BR>
>     <p>
>     Portlet content with Webflow
>     <p>
>     <a href="<portlet:createWebflowURL event="switch1"/>">Next Page</a>
>     <p>
>     </center>

Continuing from the previous example, edit the text in the scriptDemo portlet as shown in the following steps:

1. Open the console by selecting it from the taskbar, as shown in Figure 11-71.

   Figure 11-71 Open console window

   The console should resemble figure Figure 11-72.

   Figure 11-72 Console window

2. In a text editor, save the code from Listing 11-2 as content.jsp in the following directory:

   >     <BEA_HOME>\portalDomain\beaApps\portalApp\<PortalWebApp>\
   >     portlets\scriptDemo\

3. Refresh the browser, and verify that the portlets have not changed. Click the Webflows within each of the portlets, navigating back and forth a few times.

4. Return to the console and notice the output from flowLet1, as shown in Figure 11-73.

   Figure 11-73 Refresh messages in Console

Understanding Webflow Refresh Events in a Portlet

In Webflow, the Refresh event amounts to calling an entity called lastContentUrl, which merely allows you to trigger a portlet to refresh itself without specifying its name. By navigating through the various buttons and controls in the portal in this example while observing the console window for refresh messages, you can see when refresh events are caused by certain actions. To look more closely at the Webflow associated with flowLet1, take the following steps:

1. Looking at a Webflow: From the Site Infrastructure tab of the E-Business Control Center, select WebFlows/Pipelines.

2. Open NewPWApp1 by double-clicking it, as shown in Figure 11-74.

   Figure 11-74 Opening Webflows within Portal Web Application

3. Open the Webflow named flowLet1 by double-clicking it, and examine the image that appears in the editor window. To the right side of the navigation mapping, notice that the minimize, maximize, unMinimize and unMaximize nodes are linked to portal_lastContentUrl, as shown in Figure 11-75.

   Figure 11-75 Nodes linked to portal_lastContentUrl

By default, refresh is always invoked on an entire portal, and can be called on every portlet. Any portlet with its own Webflow can be made to respond to all refresh events. To make this default behavior for a portlet, use the Webflow editor to open the portlet's Webflow and set *.refresh proxynode to lastContentUrl.

For an in-depth look at using Webflow, consult Setting Up Portal Navigation.

Making a Portlet Respond to a Custom Event

To explain custom events, consider the navigation mapping in the Webflow for flowLet1 portlet, shown in Figure 11-76.

Figure 11-76 Navigation nodes in flowLet1 Webflow

The navigation between content1.jsp and content2.jsp is accomplished using pre-defined events called switch1 and switch2.

By selecting one of the content nodes, you can examine the properties of the Webflow that links content1.jsp with content2.jsp in the flowLet1 portlet. The properties of the content2 presentation node are shown in detail in Figure 11-77.

Figure 11-77 Mappings for content2

Defining a Custom Event

Figure 11-78 shows how a custom event is assigned to a new presentation node. This event is named myCustomEvent, and the Event connector tool is used to link presentation node content2 with presentation node content3.

Figure 11-78 Defining myCustomEvent

Invoking the Custom Event

To call the custom event in the portlet, include the following code in your JSP:

>     <a href="<portlet:createWebflowURL event="myCustomEvent"/>">Next Page</a>

Figure 11-79 shows the third screen of flowLet1 after a new presentation node, called content3.jsp, has been added.

Figure 11-79 The third page of flowLet1 portlet

Sharing State from One Portlet to Another

Share state from one portlet to another by placing the arguments into the HttpSession object using an Input Processor. For instance, if portletA uses a form named "foo", use the IP to extract the "foo" form data, and portletB can get the form data from the Pipeline Session.

Note: For more information on Input Processors, consult Setting Up Portal Navigation.

Web Service Portlets

Web Services are reusable software components that enable applications to interact efficiently and in a loosely-coupled manner; they are used internally for fast and low-cost application integration, or made available to customers, suppliers or partners over the Internet. Enabling portlets to consume Web Services, either internally or over the Internet, introduces a range of new benefits - and introduces some new developer issues as well.

Note: For the sake of simplicity, the examples shown in this section show portlets connecting to Web Services that are locally hosted.

This section contains information on the following topics:

- Using the Portlet Wizard to Create Web Services Portlets

- Creating a Simple Form-Driven Web Service Portlet

- Creating a Call-Generation Web Service Portlet

- Creating a Web Services Interface Portlet

- Deploying the Web Services Portlets

- Error Handling within Web Services Portlets

- Calling Web Services Asynchronously

Using the Portlet Wizard to Create Web Services Portlets

The Portlet Wizard can create portlets that consume Web Services in three different ways:

- Simple Web Service Form: This is the simplest mode of interacting with a Web Service, whereby a simple parameter is sent to the Web Service class using the httpSession, and a primitive value is printed into the resulting HTML.

- Call Generation: Slightly more complex is the Call Generation type portlet, in which classes hosted by the Web Service are listed in an object called the WSDL (Web Services Definition Language). The portlet makes remote calls to these classes and consumes the returned objects. In the Portlet Wizard, the Call Generation option creates a stubbed out portlet that calls into the designated Web service. You are required to set the __REPLACE_ME__ variables with output from sources such as the user profile, the request, and the session.

- Web Service(s) Interface: This option allows you to select multiple Web services and extract interface documentation into the portlet itself. Use this option when parameters or return values require complex data types.

This option can be used to create a portlet that calls a Web Service asynchronously through client polling. The section "Calling Web Services Asynchronously" includes instructions on creating this type of portlet.

This section shows how to use the Portlet Wizard to create a portlet of each type.

Preparation

Start the WebLogic Workshop Examples Server by navigating to Programs —> BEA WebLogic Platform 7.0 —> WebLogic Workshop Example —> Start Examples Server. Begin with the sample portal described in the section The scriptDemo Portlet.

Note: This example shows the scriptDemo, flowLet1 and flowLet2 portlets removed, but you complete these Web Service portlet examples without removing the old portlets from the portal.

Avoiding Namespace Collisions

Both the previous Call Generation and the Interface examples create instances of identical classes which run within the same portal namespace. To prevent namespace collision, the local instances of each class must be given unique names. In the second and third portlets, the implementation classes are re-named, as shown before the code samples.

Creating a Simple Form-Driven Web Service Portlet

The first portlet sends simple form input to the AccountEJBClient Web Service, creating a simple bank account object hosted at the WebLogic Workshop examples server.

Create the Portlet Called formLet Using the Portlet Wizard

1. Follow the steps outlined in Figure 11-32 through Figure 11-36.

2. When the Content Types screen appears, select Web Service and click Next, as shown in Figure 11-80.

   Figure 11-80 Select Generated Code type

3. When the Server Location screen appears, navigate to an instance of WebLogic Server, as shown in Figure 11-81, and click Next.

   Figure 11-81 Select Server Location

4. When the Generated Code Types screen appears, select Form, as shown in Figure 11-82, and click Next.

   Figure 11-82 Select Generated Code Types

5. When the Select a Web Service screen appears, click Add Web Services, as shown in Figure 11-83.

   Figure 11-83 Click Add Web Services

6. Type in the URL of the WSDL, as shown in Figure 11-84, then click ADD URL.

   Figure 11-84 Enter the URL of the WSDL

7. When the AccountEJBClient Web Service appears in the list, click Close.

8. When the Web Services screen re-appears, click the newly added Web Service. A small window entitled "Retrieving Operations" appears in front of the Web Services screen, as shown in Figure 11-85.

   Figure 11-85 Retrieving Operations

9. When the Retrieving Operations screen disappears, a list of operations should be available in the listbox to the right. Select the CreateNewAccount operation from this list, as shown in Figure 11-86 and click Next.

   Figure 11-86 Select the createNewAccount operation

10. When the Code Preview screen appears, scroll down in the generated code to begin to familiarize yourself with taglib includes and portal refresh events. You can also click Copy to Clipboard and paste the code into an editor for viewing.

11. Click Next, as shown in Figure 11-87.

    Figure 11-87 Code Preview

12. When the Resource Files location screen appears, as shown in Figure 11-88, confirm the portlet JSPs will be placed in the correct directory, then click Next.

Note: The directory specified in this screen will act as the parent directory for the newly created portlet files. This directory should exist under the WLP web application directory. A sub-directory with the same name as the new portlet will be created where users can find the files generated by this wizard.

In addition, a WEB-INF/lib directory will be created in this location. This directory will contain a .jar file that the portlet references at runtime.

If the directory specified in this screen was not under a WLP web application, users will need to copy the created portlets sub-directory containing the generated files and the .jar file to the portlets directory and the WEB-INF/lib directory, respectively, of the intended Portal Web application.

Figure 11-88 Select/Confirm Resource Files location

1. When the Summary page appears, as shown in Figure 11-89, verify the files to be created and click Create.

   Figure 11-89 Confirm Summary of Files

2. When the Next Steps screen appears, as shown in Figure 11-90, click Close.

   Figure 11-90 Choose Next Steps

Note: For this example, we'll create all three portlets first, then deploy them at once at the end.

Creating a Call-Generation Web Service Portlet

The Call Generation portlet enables the user to list big accounts by remotely invoking classes hosted within the Web Service hosted on the WebLogic Workshop examples server.

Create the Portlet Called callgenLet Using the Portlet Wizard

1. Follow the steps outlined in Creating a Simple Form-Driven Web Service Portlet up to Step 4.

2. When the Generated Code Types screen appears, select Call Generation, as shown in Figure 11-91, and click Next.

   Figure 11-91 Select Generated Code type

3. When the Web Service(s) List appears, click Edit List, as shown in Figure 11-92.

   Figure 11-92 Web Service(s) screen

4. When the Web Service(s) List appears, as shown in Figure 11-93, enter the following WSDL and click Add URL:

   >     http://localhost:7001/samples/ejbControl/
   >     AccountEJBClient.jws?WSDL

   Figure 11-93 Adding another Web Service WSDL

5. When the URL you entered has been added to the Web Services list, click Close. The Web Service(s) screen reappears, with the newly-added Web Service listed to the left, and Operation listed to the right.

6. Click the AccountEJBClient Web Service and wait for its operations to be retrieved and listed to the right.

7. In the list of operations for AccountEJBClient, click listBigAccounts, as shown in Figure 11-94, and click Next.

Note: Notice the parameter list below the operation.

Figure 11-94 Selecting the listBigAccounts operation

1. When the Code Preview page appears, as shown in Figure 11-95, notice the string _REPLACE ME_ occurring in place of the threshold parameter, visible in Listing 11-6. After replacing these parameter values with those in bold in Listing 11-6, click Next.

   Figure 11-95 Code Preview

Note: Within Listing 11-6, the following entries, in boldface within the code, have been shortened:

>     callImpl was originally p_sdl_AccountEJBClient_AccountEJBClient_Impl

>     callSoap was originally p_sdl_AccountEJBClient_AccountEJBClientSoap

Listing 11-6 Call Generation Portlet code

>     <%@ include file="callgenlet1_include.inc" %>

>     <%@ taglib uri="portlet.tld" prefix="portlet" %>

>     <%@ taglib uri="i18n.tld" prefix="i18n" %>

>     <%@ page import="com.bea.portal.appflow.PortalAppflowConstants"%>

>     <%@ include file="/framework/resourceURL.inc"%>

>     <%

>      sdl_AccountEJBClient.AccountEJBClient_Impl callImpl = new sdl_AccountEJBClient.AccountEJBClient_Impl();

>      sdl_AccountEJBClient.AccountEJBClientSoap callSoap = callImpl.getAccountEJBClientSoap();

>     %>

>     <%

>         double threshold = 1000;

>     %>

>     <%=cnvrtSC(String.valueOf(callSoap.listBigAccounts(threshold)))%>

1. When the Resource Files Location screen appears, as shown in Figure 11-96, ensure the files are going to be installed in the correct directory and click Next.

   Figure 11-96 Select/Confirm Resource Files location

2. When the Summary files screen appears, as shown in Figure 11-97, verify the correct files are to be created and click Create.

   Figure 11-97 Confirm Summary of Files

3. When the Next Steps screen appears, as shown in Figure 11-98, click Close.

   Figure 11-98 Choose Next Steps

Creating a Web Services Interface Portlet

This portlet searches for accounts with a balance over a threshold set within the portlet, and lists them in the portlet. What is significant is the way in which this portlet communicates with the Web Service: the portlet uses classes implemented according to the self-describing WSDL called listBigAccounts.

Create the Portlet Called interFaceLet Using the Portlet Wizard

1. Follow the steps outlined in Creating a Simple Form-Driven Web Service Portlet up to Step 4.

2. When the Generated Code Types screen appears, select Web service(s) Interface, as shown in Figure 11-99, and click Next.

   Figure 11-99 Select Generated Code Type

Note: In the Web Service(s) screen for Interface Generation portlets, notice that no operations are available. This is because you are being provided the interface description and must implement the required methods yourself.

1. Edit the portlet code within the Code Preview screen, as shown in Figure 11-100, and click Next.

   Figure 11-100 Code Preview screen for interFaceLet

2. Implement interfaces required for listing big Accounts. Use the generated code as your starting point, shown in Listing 11-7.

   Note: Within Listing 11-7, the following entries, in boldface within the code, have been shortened:

   >     intImpl was originally p_sdl_AccountEJBClient_AccountEJBClient_Impl

   >     intSoap was originally sdl_AccountEJBClient.AccountEJBClientSoap

Listing 11-7 Code for interFaceLet

>     <%@ include file="interFaceLet_include.inc" %>
>     <%@ taglib uri="portlet.tld" prefix="portlet" %>
>     <%@ taglib uri="i18n.tld" prefix="i18n" %>
>     <%@ page import="com.bea.portal.appflow.PortalAppflowConstants"%>
>     <%@ include file="/framework/resourceURL.inc"%>
>     <%

>     sdl_AccountEJBClient.AccountEJBClient_Impl intImpl = new
>         sdl_AccountEJBClient.AccountEJBClient_Impl();

>     sdl_AccountEJBClient.AccountEJBClientSoap intSoap =
>         intImpl.getAccountEJBClientSoap();

>     ...

>     */%>

1. When the Resource Files Location screen appears, as shown in Figure 11-101, ensure the files are going to be installed in the correct directory and click Next.

   Figure 11-101 Select/Confirm Resource Files location

2. When the Summary files screen appears, as shown in Figure 11-102, verify the correct files are to be created and click Create.

   Figure 11-102 Confirm Summary of Files

3. When the Next Steps screen appears, as shown in Figure 11-103, click Close.

   Figure 11-103 Choose Next Steps

4. From the E-Business Control Center toolbar, click the Synchronize button.

5. When the Synchronizing Application window shows that synchronization is complete, click Close, as shown in Figure 11-104.

   Figure 11-104 Synchronization Complete

Deploying the Web Services Portlets

Now that they are all created and installed, what remains is to make them available to the WebLogic Server instance. This is done by simply re-deploying the Portal Web Application in which these portlets are to run, according to the following procedures:

1. In your Web browser, navigate to the WebLogic Server console at the following URL:

   >     http://<host>:<port>/console

2. Login as weblogic/weblogic.

3. Select Deployments —> Applications —> NewPWApp, and click the Deploy tab in the right pane, as shown in Figure 11-105.

   Figure 11-105 Left tab of console: Deployments —> Applications —> NewPWApp

4. UnDeploy the NewPWApp by clicking the Undeploy button to the right of portalServer target. When the UnDeployment Activity status turns to Complete, click Deploy.

5. When the status on the Deployment Activity screen turns to Complete, the new portlets have been re-deployed.

6. Make the new portlets visible and available using the WebLogic Portal Administration Tools: In your Web browser, navigate to the following URL: http://<hostname>:<port>/portalAppTools.

7. Login as administrator/password, and click Portal Management, as shown in Figure 11-106.

   Figure 11-106 Go to Portal Management

8. From the Portal Management Home page, Click the Default Portal, as shown in Figure 11-107.

   Figure 11-107 Select Default Group Portal

9. From the Group Portal Management Home page, click Manage Pages and Portlets as shown in Figure 11-108.

   Figure 11-108 Manage Pages and Portlets

10. Next to the portal page, click Edit Portlets, as shown in Figure 11-109.

    Figure 11-109 Click Edit Portlets

11. Set all three portlets attributes to Visible and Available, and click Save.

12. Click Save: The attributes of formLet, callGenLet and interFaceLet portlets are now correctly set.

Viewing the Web Services Portlets

Now that they are all deployed and placed within the same portal page, observe the functionality they provide by taking the following steps:

1. Verify the portlets can be accessed by navigating to the following URL:

http://<host>:<port>/NewPWApp/

The result should resemble that shown in Figure 11-110.

1. Logon as a valid user and two new accounts; one with a balance of 1001 threshold, one 751. Notice what appears in the List big accounts portlet.

2. Change threshold in the content.jsp of the callGenlet portlet to 750.

3. Create a new account with a balance of 749. List big accounts.

   Figure 11-110 Web Services portlets before accounts have been entered

   Figure 11-111 Web services portlets with some account activity

Note: For more information on Web Services, consult "Building Web Services on WebLogic Platform" at http://edocs.bea.com/platform/docs70/interm/webserv.html and "Introduction to WebLogic Workshop" at http://edocs.bea.com/workshop/docs70/index.html.

Calling Web Services Asynchronously

BEA WebLogic Portal 7.0 enables portlets to participate in asynchronous communication with Web Services such as conversations. This example shows how to create a simple conversation portlet that interacts with a Web Service hosted on the local server.

Figure 11-112 Conversation Web Services Portlet

About the Conversation Portlet

The portlet created in this example contains three button-activated actions:

- The Start button sends a session id to the Web Service, which holds this as a token for the conversation.

- The Continue button requests status on the token.

- The Finish button ends the conversation, causing the Web Service to relinquish the token and stop waiting for more messages.

Preparation

- Start the WebLogic Workshop Examples Server by navigating to Programs —> BEA WebLogic Platform 7.0 —> WebLogic Workshop Example —> Start Examples Server. Begin with the sample portal described in the section The scriptDemo Portlet.

- Start the portal server for your domain. In this example, this is done by navigating to Programs —> BEA WebLogic Platform 7.0 —> User Projects —> MyNewDomain —> Start Portal Server.

Creating the Conversation Portlet

To create and deploy a sample Conversation portlet, follow these steps.

1. Use the Portlet Wizard to create a Web Services Interface portlet, as shown in the Creating a Web Services Interface Portlet section. Name this portlet "conversation", as shown in Figure 11-113, and click Next.

   Figure 11-113 Creating the conversation portlet

2. Associate the new portlet with the portal page called "home" and click Next.

3. When the Select Portlet Components page appears, click Next without designating any extra components.

4. When the Content Types screen appears, select Web Service and click Next.

5. When the Server Location screen appears, navigate to an instance of WebLogic Server and click Next.

6. When the Generated Code Types screen appears, select Web Service(s) Interfaces, and click Next.

7. When the Select a Web Service screen appears, click Add Web Services, type in the following URL: http://localhost:7001/samples/async/Conversation.jws?WSDL. Click Add URL.

8. After the Conversation Web Service appears in the list, click Close.

9. Select the Conversation Web Service from the list on the left, and click Next.

10. When the Code Preview screen appears, click Next. This code will be replaced later in this procedure.

11. When the Resource Files location screen appears, confirm the portlet JSPs will be placed in the correct directory, then click Next.

12. When the Summary page appears, verify the files to be created and click Create.

13. When the Next Steps screen appears, make sure all the checkboxes are unselected, then click Close.

14. In a text editor, enter the code in Listing 11-8 and save it as content.jsp in the following directory: myNewDomain\beaApps\portalApp\NewPWApp\portlets\conversation\.

Listing 11-8 content.jsp for Conversation Web Services Portlet

>     <%@ include file="Conversation_include.inc" %>
>     <%@ taglib uri="portlet.tld" prefix="portlet" %>
>     <%@ taglib uri="i18n.tld" prefix="i18n" %>
>     <%@ page import="org.openuri.www.StartRequest"%>
>     <%@ page import="org.openuri.www.GetRequestStatusResponse"%>
>     <%@ page import="org.openuri.www.x2002.x04.soap.conversation.StartHeader"%>
>     <%@ page import="org.openuri.www.x2002.x04.soap.conversation.ContinueHeader"%>
>     <%@ page import="weblogic.xml.schema.binding.internal.builtin.VoidType"%>
>     <%@ page import="com.bea.portal.appflow.PortalAppflowConstants"%>
>     <%@ page import="com.bea.portal.appflow.PortalAppflowConstants"%>
>     <%@ include file="/framework/resourceURL.inc"%>

>     <%
>         DL_wsdl_Conversation.Conversation_Impl conversationImpl = new
>     DL_wsdl_Conversation.Conversation_Impl();
>         DL_wsdl_Conversation.ConversationSoap soap =
>     conversationImpl.getConversationSoap();
>     %>

>     <%
>         String target = request.getParameter("target");
>         String conversationID = session.getId();
>             if ( conversationID == null )
>                 conversationID = "";
>     %>

>     <portlet:form event="<%= PortalAppflowConstants.PORTLET_REFRESH %>">
>         <table border="0" align="center">
>             <tr>
>                 <td width="100%" align="center">
>                 <table border="0" align="left">
>                 <tr>
>     <%
>                     if ( target != null
>                          && target.equals("start")
>                          &&  true  )
>                     {
>                         try
>                         {
>                          StartHeader startHeader = new StartHeader(conversationID,
>     "http://localhost:7001/samples/async/Conversation.jws");
>                 VoidType startResponse = new VoidType();

>                 StartRequest begin = new StartRequest(false);

>                 startResponse = soap.startRequest(begin, startHeader);
>     %>
>                 <td><%=cnvrtSC("Conversation started with ID: " +
>     String.valueOf(conversationID))%></td>
>     <%
>                   }
>                    catch (java.rmi.RemoteException e)
>                   {
>     %>
>                 <td><%=cnvrtSC("Duplicate conversation id for start: " +
>     String.valueOf(conversationID))%></td>
>     <%
>                 e.printStackTrace();
>                  }
>                     }
>     %>
>                 </tr>
>                 </table>
>                 </td>
>             </tr>
>             <tr>
>                 <td width="100%" align="center"><input type="submit" name="start"
>     value="Start"></td>
>             </tr>
>         </table>
>         <br><br>
>         <input type="hidden" name="target" value="start">
>     </portlet:form>

>     <portlet:form event="<%= PortalAppflowConstants.PORTLET_REFRESH %>">
>         <table border="0" align="center">
>             <tr>
>                 <td width="100%" align="center">
>                 <table border="0" align="left">
>                 <tr>
>     <%
>                     if ( target != null
>                          && target.equals("continue")
>                          &&  true  )
>                     {
>                         try
>                         {
>                 ContinueHeader continueHeader = new
>     ContinueHeader(conversationID);
>                 GetRequestStatusResponse status = soap.getRequestStatus(null,
>     continueHeader);
>                 String result = status.getGetRequestStatusResult();
>     %>
>                 <td><%=cnvrtSC("Response: " + String.valueOf(result))%></td>
>     <%
>                     }
>                     catch ( Exception e )
>                     {
>                         e.printStackTrace();
>                      }
>                  }
>     %>
>                 </tr>
>                 </table>
>                 </td>
>             </tr>
>             <tr>
>                 <td width="100%" align="center"><input type="submit" name="continue"
>     value="Continue"></td>
>             </tr>
>         </table>
>         <br><br>
>         <input type="hidden" name="target" value="continue">
>     </portlet:form>

>     <portlet:form event="<%= PortalAppflowConstants.PORTLET_REFRESH %>">
>         <table border="0" align="center">
>             <tr>
>                 <td width="100%" align="center">
>                 <table border="0" align="left">
>                 <tr>
>     <%
>                     if ( target != null
>                          && target.equals("finish")
>                          &&  true  )
>                     {
>                         try
>                         {
>                          VoidType terminateResponse = new VoidType();
>                          ContinueHeader finishHeader = new
>     ContinueHeader(conversationID);
>                          terminateResponse = soap.terminateRequest(null, finishHeader);
>     %>
>                     <td><%=cnvrtSC("Conversation terminated.")%></td>
>     <%
>                         }
>                         catch ( java.rmi.RemoteException e )
>                         {
>     %>
>                     <td><%=cnvrtSC("Conversation already terminated.")%></td>
>     <%
>                             e.printStackTrace();
>                         }
>                     }
>     %>
>                 </tr>
>                 </table>
>                 </td>
>             </tr>
>             <tr>
>                 <td width="100%" align="center"><input type="submit" name="finish"
>     value="Finish"></td>
>             </tr>
>         </table>
>         <br><br>
>         <input type="hidden" name="target" value="finish">
>     </portlet:form>

1. Deploy the conversation portlet according to the instructions in the section Deploying the Web Services Portlets.

2. Test the new portlet by clicking on each of the buttons and verifying the results, as shown in Figure 11-114.

   Figure 11-114 Starting the conversation

Error Handling within Web Services Portlets

In a production scenario, the Web Services to which your portlets connect are typically hosted elsewhere, and are out of your control. The portal framework enables portlets to generate two errors specifically designed to handle Web Services problems:

JAXRPCException: If a Web service is unavailable at run-time, the portlet will cause the throw a javax.xml.rpc.JAXRPCException. Add error handling to your .JSP by catching the exception in a generated portlet.

Note: The JAXRPCException applies to cases where the connection is refused, not when there is a delay in service.

SOAPFaultException: When a Web service cannot handle the SOAP request generated from the Web Service Portlet Wizard, a javax.xml.rpc.soap.SOAPFaultException is thrown. You should catch this exception within your .JSP to protect from compile failures.

Portalizing an Existing Web Application

To move an existing non-portal Web application into the portal framework, certain modifications are necessary. This section outlines the process using an example provided with the WebLogic Platform installation.

Getting Started

One strategy for adding functionality to a portlet is to graft JSP code from an existing (non-portal) Web application into the JSPs that constitute a portlet. This tutorial uses refactored sample code from the Internationalization portlet included with the product such that the functionality is replicated within a portlet. Figure 11-115 and Figure 11-116 show the Internationalization sample application displaying language-specific content based on user input.

Note: For detailed instructions on launching and exploring this application, consult the Personalization Examples section of the WebLogic Platform documentation.

Figure 11-115 Internationalization Input

Figure 11-116 Internationalization Results

Requirements

WebLogic Portal 7.0 with Service Pack 1 must be successfully installed.

Process Overview

This process includes the following steps:

Step 1: Create a Portal Web Application

Step 2: Build a 2-page WebFlow Portlet

Step 3: Edit Portlet Code

Step 4: Load Content Resources

Step 5: Test the application

Step 1: Create a Portal Web Application

For instructions on creating a new portal Web application to use as the basic structure for this new application, consult the tutorial called Creating the New Portal in the WebLogic Portal 7.0 Development Guide.

For this example, the portal Web application will be called NewPWApp.

Note: If your application makes use of portal services such as Personalization, Internationalization, etc., you must add support for this functionality to the portal created using the portal Wizard. For detailed instructions on adding these features to your portal, consult the section called Adding All Portal Services to Your Domain in the Building Custom Templates chapter of the WebLogic Portal 7.0 Development Guide.

Step 2: Build a 2-page WebFlow Portlet

While the portal server created in the new domain is running, use the E-Business Control Center to launch the Portlet Wizard. Create a 2-page Webflow portlet, naming it i18n. For detailed instructions on creating Webflow portlets this way, consult the section Creating a Sequential Webflow Portlet.

Note: Don't forget to make the portlet visible and available using the WebLogic Portal Administration Tools.

Step 3: Edit Portlet Code

In this step, JSPs and properties files are edited to use the portlet Webflow and to invoke personalization.

Replace Portlet JSPs

First, the JSPs generated by the Portlet Wizard need are replaced with JSPs that make calls to Personalization services and act upon content. Save the contents of Listing 11-9 and Listing 11-10 in the following directory:

<BEA_HOME>beaApps\portalApp\NewPWApp\portlets\i18n

Listing 11-9 Page1.jsp

>     <%---------------------------------------------------------

>     Copyright (c) 2000-2002  BEA Systems, Inc.  All rights reserved.

>     --------------------------------------------------------%>

>     <%--------------------------------------------------------

>     File: Page1.jsp

>     Purpose: Gathers form input for I18N language of choice.

>     ----------------------------------------------------------%>

>     <%@ taglib uri="webflow.tld" prefix="webflow"%>

>     <%@ taglib uri="portlet.tld" prefix="portlet"%>

>     <%----------------------------------------------------------

>     Declare html font styles for valid and invalid form entries, to be

>     used with webflow validated form.

>     ---------------------------------------------------------%>

>     <% String validStyle = "background: white; color: black; font-family: Arial"; %>

>     <% String invalidStyle = "background: white; color: red; font-style: italic"; %>

>     <center>

>     <%-------------------------------------------------------

>     Using portlet validated form.

>     ---------------------------------------------------------%>

>     <portlet:validatedForm event="switch2" applyStyle="message"

>          messageAlign="right" validStyle="<%= validStyle %>"

>          invalidStyle="<%= invalidStyle %>" unspecifiedStyle="<%= validStyle %>">

>     <table border="0" cellspacing="0" cellpadding="0" width="100%">

>       <tr>

>         <td>

>           <table border="0" cellpadding="6" cellspacing="1" width="100%">

>             <tr class="header">

>               <td colspan="2">

>                 Localization of Flickerstick Band Information

>               </td>

>             </tr>

>             <tr class="tablerow1">

>               <td align="right" valign="top" width="1%">Languages:</td>

>               <td>

>     <%----------------------------------------------------------

>     Using <webflow:select> and <webflow:option> in place of standard html select and option to enable form validation.

>     ----------------------------------------------------------%>

>                 <webflow:select name="language" size="5">

>                   <webflow:option value="en"/>English

>                   <webflow:option value="fr"/>French

>                   <webflow:option value="es"/>Spanish

>                 </webflow:select>

>               </td>

>             </tr>

>             <tr class="tablerow1">

>               <td align="right" valign="top" width="1%">&nbsp;</td>

>               <td>

>                 <input type="submit" name="Submit" value="Show Me!">

>               </td>

>             </tr>

>             <tr class="tablerow2">

>               <td class="label" colspan="2">

>                 Select the language in which you would like to view Flickerstick information.

>               </td>

>             </tr>

>           </table>

>           <input type="hidden" name="resultFile" value="Page2.jsp">

>           <input type="hidden" name="sample" value="<%= request.getParameter("sample") %>">

>         </td>

>       </tr>

>     </table>

>     </portlet:validatedForm>

>     </center>

Listing 11-10 Page2.jsp

>     <%-----------------------------------------------------------

>     Copyright (c) 2000-2002  BEA Systems, Inc.  All rights reserved.

>     ------------------------------------------------------------%>

>     <%-----------------------------------------------------------

>     File: Page2.jsp

>     Purpose: Gathers form input for I18N language of choice.

>     ----------------------------------------------------------%>

>     <%@ page import="com.bea.p13n.content.ContentHelper"%>

>     <%@ page import="com.bea.p13n.content.Content" %>

>     <%@ taglib uri="cm.tld" prefix="cm" %>

>     <%@ taglib uri="es.tld" prefix="es" %>

>     <%@ taglib uri="i18n.tld" prefix="i18n" %>

>     <%@ taglib uri="portlet.tld" prefix="portlet" %>

>     <%---------------------------------------------------------

>     Contruct the query string.

>     Example: isTrackIdentifier='true' && bandName='Flickerstick' && language='en'

>     ----------------------------------------------------------%>

>     <%

>         StringBuffer queryStr = null;

>         String language = request.getParameter("language");

>         if (language != null)

>         {

>            // Build the query string

>            queryStr = new StringBuffer();

>            queryStr.append("isTrackIdentifier = 'true' && bandName = 'Flickerstick' && language = '");

>            queryStr.append(language);

>            queryStr.append("'");

>         }

>         //queryStr = new StringBuffer();

>         //queryStr.append("bandName = 'Flickerstick'");

>         if (queryStr != null)

>         {

>     %>

>     <% System.out.println("\n\nqueryStr=" + queryStr + "-------------------------------------------\n\n"); %>

>     <br>Language is: <%= language %><br>

>     <br>Query String is: <%= queryStr %><br>

>     <br>ContentHelper.DEF_CONTENT_MANAGER_HOME is : <%= ContentHelper.DEF_CONTENT_MANAGER_HOME %><br>

>     <%----------------------------------------------------------

>     Localize the page with the selected language. Future invocations of

>     i18n tags in this request will default to this language.

>     -----------------------------------------------------------%>

>        <i18n:localize language="<%= language %>"/>

>     <%-----------------------------------------------------------

>     Using the constructed query string retrieve the track names for

>     Flickerstick.

>     -------------------------------------------------------------%>

>        <cm:select contentHome="<%= ContentHelper.DEF_CONTENT_MANAGER_HOME %>"

>           sortBy="trackNum" query="<%= queryStr.toString() %>" id="contentArray" failOnError="true"/>

>         <table border="0" cellspacing="0" cellpadding="0" width="100%">

>           <tr>

>             <td>

>               <table border="0" cellspacing="1" cellpadding="6" width="100%">

>                 <tr class="tableheader">

>     <%---------------------------------------------------------

>     Retrieved localized messages for track name and track number.

>     ----------------------------------------------------------%>

>          <td><i18n:getMessage messageName="trackName" bundleName="Page2"/></td>

>          <td><i18n:getMessage messageName="trackNum" bundleName="Page2"/></td>

>                 </tr>

>                 <% int row = 0; %>

>              <br>contentArray length is : <%= contentArray.length %><br>

>           <es:forEachInArray id="nextDoc" array="<%= contentArray %>" type="Content">

>         <tr class="<%= (row % 2 == 0) ? "tablerow1" : "tablerow2" %>">

>     <%-------------------------------------------------------------

>     Get the bandName property using the cm:getProperty tag and use it to

>     construct the parameters to pass to the Webflow.

>     ----------------------------------------------------------%>

>               <td>

>        <cm:printProperty id="nextDoc" name="trackName" encode="html"/>

>              </td>

>              <td>

>        <cm:printProperty id="nextDoc" name="trackNum" encode="html"/>

>               </td>

>              </tr>

>              <% row++; %>

>                 </es:forEachInArray>

>               </table>

>             </td>

>           </tr>

>         </table>

>     <%

>         }

>         else

>         {

>     %>

>             <b>Please specify one language in your request!</b>

>     <%

>         }

>     %>

>     <center>

>     <a href="<portlet:createWebflowURL event="switch1"/>">Previous Page</a>

>     </center>

Save Properties Fies for Internationalization

Save the contents of the following listings in this directory:

<BEA_HOME>beaApps\portalApp\NewPWApp\portlets\i18n

For example, Listing 11-11 would be saved as Page2_en.properties.

Listing 11-11 Page2_en.properties

>     trackName=Track Name

>     trackNum=Track Number

Listing 11-12 Page2_fr.properties

>     trackName=Nom de Piste

>     trackNum=Numero do Piste

Listing 11-13 Page2_sp.properties

>     trackName=Nombre de la canción

>     trackNum=Número de la canción

Step 4: Load Content Resources

In this step, content resources are imported from the Personalization domain.

1. Replace the dmsBase folder in your portal domain by copying the entire dmsBase folder (including its contents) from <BEA_HOME>weblogic700\samples\portal\p13nDomain into the following directory:

   >     <BEA_HOME>\user_projects\myNewDomain

2. To make this content available to the Portal framework, the metadata must be loaded into the server. While the server is running, execute the loaddata script in the following directory:

   >     <BEA_HOME>\user_projects\myNewDomain

Step 5: Test the application

Now that the JSPs are edited, observe the functionality of the new portlet by taking the following steps:

1. Verify the portlet can be accessed by navigating to the following URL:

http://<host>:<port>/NewPWApp/

The result should resemble that shown in Figure 11-117.

Figure 11-117 Verifying the i18n Portlet

1. Select language and click Show Me. The results should resemble those shown in Figure 11-117.

   Figure 11-118 Results page of i18n Portlet

Performance Tuning

This section covers performance issues related specifically to WebLogic Portal, including JDBC and Thread settings and several cache settings. Many factors effecting the performance of your portal application are specific to WebLogic Server. For information on making those adjustments, consult the WebLogic Server Performance and Tuning guide at http://edocs.bea.com/wls/docs70/perform/index.htmll.

Using Caches to Tune Performance

To adjust caching for production Web site, examine the following factors:

- Adjust Caching for Content Management

- Property Caching in a Clustered Environment

- Adjust Caching for the Discount Service

- Adjusting the discountCache

- Adjusting the globalDiscountCache

- Discount-Service Caches in Clustered and Non-Clustered Environments

- Adjust Group Membership TTL in the Caching Realm

- Tuning Thread / Connection Parameters in JDBC

Adjust Caching for Content Management

To optimize content-management performance for your production Web site, the Content Manager uses the caching framework to configure and manage the following caches:

>     documentContentCache

>     documentMetadataCache

>     documentIdCache

The content management JSP tags provide an additional set of caches, which you can access by doing the following:

For the cm:select, cm:selectById, pz:contentQuery, and pz:contentSelector JSP tags, use the useCache attribute whenever possible. Doing so avoids a call to DocumentManager and, in the case of pz:ContentSelector, to the Rules Manager.

To clear cached content when user and/or document attributes change, use the remove method of com.bea.p13n.content.ContentCache. For more information, see the WebLogic Portal Javadoc. for com.bea.p13n.content.ContentCache.

For the cm:select, cm:selectById, pz:contentQuery, and pz:contentSelector JSP tags, set the cacheScope attribute to application whenever possible. This application scope applies to the Web application, not to the enterprise application, as shown in Listing 11-14.

Listing 11-14 Setting cacheScope to application

>     <cm:select id="myDocs" query="riskFactor = 'Low'"

>     useCache="true" cacheId="myDocs"

>     cacheScope="application"

>     max="10" cacheTimeout="300000" />

The application cache type is global instead of per-user and should speed up queries by avoiding a call to the DocumentManager EJB.

For pz:contentSelector, set the cacheScope attribute to application only when you want to select shared content. For example, you create an application that uses an application-scoped cache to select content for non-authenticated users. Because it uses the application scope, all non-authenticated users see the same content. For authenticated users, your application provides personalized content by switching to a session scoped cache.

Whenever you can predict the next document that users will view based on the document that they are currently viewing, load the next document into the cache before users request it. This "forward caching" will greatly improve the speed at which WebLogic Portal responds to user requests (assuming that your prediction is correct; forward caching a document that no one requests will only degrade performance and scalability).

Listing 11-15 contains a snippet of a JSP with an example of forward caching a document:

Listing 11-15 Forward caching a document

>     <%-- Get the first set of content --%>

>     <cm:select id="myDocs" query="riskFactor = 'Low'"

>     useCache="true" cacheId="myDocs"

>     cacheScope="application"

>     max="10" cacheTimeout="300000" />

>     <%-- Generate a query from each content's relatedDocId --%>

>     <% String query = null; %>

>     <es:forEachInArray array="<%=myDocs%>" id="myDoc" type="com.bea.p13n.content.Content">

>     <% String relId = (String)myDoc.getProperty("relatedDocId", null); %>

>     <es:notNull item="<%=relId%>">

>     <%

>     if (query != null)

>     query += " || ";

>     else

>     query = "";

>     query += "identifier = '" +

>     ExpressionHelper.toStringLiteral(relId) + "'";

>     %>

>     </es:notNull>

>     </es:forEachInArray>

>     <%-- Load the related content into the cache via cm:select --%>

>     <es:notNull item="<%=query%>">

>     <cm:select query="<%=query%>" id="foo" useCache="true" cacheId="relatedDocs"

>     cacheScope="session" max="10" cacheTimeout="300000" />

>     </es:notNull>

For more information on content management JSP tags, see "Personalization JSP Tags" in the JavaServer Page Guide at http://edocs.bea.com/wlp/docs70/jsp/p13njsp.htm.

Property Caching in a Clustered Environment

To decrease the amount of time needed to access user, group, and other properties data, the WebLogic Server Configurable Entity and Entity Property Manager use the cache framework to configure and manage the following caches:

>     ldapGroupCache

>     ldapUserCache

>     entityPropertyCache

>     entityIdCache

>     unifiedProfiletypeCache

>     propertyKeyIdCache

Note: By default, these property caches are enabled.

With property caching enabled in a clustered environment, each server in a cluster maintains its own cache; the cache is not replicated on other servers. In this environment, when properties that are stored in the caches change on one server, they may not change on another server in a timely fashion. In most cases, immediate or quick access to properties on another server is not necessary: user sessions are pinned to a single server, and even with caching enabled, users immediately see changes they make to their own settings on the server.

If a user and an administrator are pinned to different servers in the cluster and the administrator changes a user's properties, the user may not see the changes during the current session. You can mitigate this situation by specifying a small Time-To-Live (TTL) setting.

If you require multiple servers in a cluster to have immediate access to modified properties, disable property caching.

Adjust Caching for the Discount Service

To reduce the amount of time the Order and Shopping Cart services need to calculate order and price information that include discounts, the Discount Service uses the caching framework to create and manage the following caches:

- discountCache, which contains data for campaign discounts. Campaign discounts are targeted to specific customers or customer segments, and are available only in the context of a campaign.

- globalDiscountCache, which contains data for global discounts. Global discounts apply to all customers, regardless of customer properties or customer segments.

When a customer adds an item to the shopping cart, removes an item from the shopping cart, checks out, or confirms an order, the Pricing Service is responsible for determining the price of the items in the cart. To calculate the effect of discounts on the shopping cart, the Pricing Service requests the Discount Service to retrieve information about all global discounts and about any campaign discounts that apply to the current customer.

The first request for information about discounts requires a separate call to the database for each discount that applies. For example, if you have defined one global discount and if a customer is eligible for two campaign-related discounts, the Discount Service makes three calls to the database. To decrease the response time for any subsequent requests, the Discount Service uses the caches.

Adjusting the discountCache

The discountCache contains data for campaign discounts. For maximum performance, set the capacity to the number of campaign discounts that are currently deployed. A larger capacity will potentially use more memory than a smaller capacity.

The Time-To-Live (TTL) property determines the number of milliseconds that the Discount Service keeps the information in the cache. After the cache value times out, the next request for the value requires the Discount Service to call the database to retrieve the information and then cache the value. A longer TTL decreases the number of database calls made over time when requesting cached objects. In a clustered environment, the TTL is the maximum time required to guarantee that any changes to global discounts are available on all servers.

Adjusting the globalDiscountCache

The Maximum Number of Entries property for global caches does not need to be modified.

The time-to-live property determines the number of milliseconds that the Discount Service keeps information in the global-discount cache. After the Time-To-Live (TTL) expires, the next request for global discount information requires the Discount Service to call the database to retrieve the information and then cache the value. A longer TTL decreases the number of database calls made over time when requesting cached objects. In a clustered environment, the TTL is the maximum time required to guarantee that any changes to campaign discounts are available on all servers.

Discount-Service Caches in Clustered and Non-Clustered Environments

In either environment (clustered or non-clustered), when you change a discount priority, end date, or its active/inactive state, WebLogic Portal flushes the discount from the appropriate cache. Changes to a campaign discount flush only the specific discount from the campaign-discount cache. Changes to a global discount flush all discounts from the global-discount cache.

For example, you log in to a WebLogic Portal host named bread and deactivate a campaign discount named CampaignDiscount1. WebLogic Portal flushes the CampaignDiscount1 from the campaign-discount cache on bread.

In a clustered environment, other machines in the cluster continue to use their cached copy of the discount until the TTL for that discount expires.

Adjust Group Membership TTL in the Caching Realm

The WebLogic Server Caching realm stores the results of both successful and unsuccessful realm lookups. It does not use the WebLogic Portal caching framework.

The Caching realm manages separate caches for Users, Groups, permissions, ACLs, and authentication requests. It improves the performance of WebLogic Server by caching lookups, thereby reducing the number of calls into other security realms.

WebLogic Portal enables the Caching realm by default. While all of the caches in the Caching realm can improve performance, the Time-To-Live (TTL) value for the Group Membership Cache in particular can affect the performance of WebLogic Portal.

In addition, note that if you delete a user from the system without first removing the user from a group, then the system continues to recognize the user until the TTL for the Group Membership Cache expires.

For information on adjusting the Group Membership TTL, refer to the WebLogic Server Administration Guide at http://edocs.bea.com/wls/docs70/adminguide/index.html.

Tuning Thread / Connection Parameters in JDBC

Certain performance problems encountered in the portal may be corrected by changing config.xml entries to reduce to thread count for the default execute queue in WLS lower than the connection pool maximum capacity specified for the commercePool. The basic formula should make the number of connections in the connection pool equal to the number of threads + 1.

For information on adjusting threads and connection pools, consult "Tuning JDBC Connection Pool Maximum Capacity" at

http://edocs.bea.com/wls/docs70/perform/WLSTuning.html#1117878.