Skip Headers
Oracle® Fusion Middleware Developer's Guide for Oracle WebCenter
11g Release 1 (11.1.1.4.0)
E10148-12
  Go To Documentation Library
Library
Go To Product List
Product
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

56 Coding Portlets

This chapter explains how you can enhance the Java portlets you created with the Oracle JDeveloper Create Java Portlet wizards.

This chapter includes the following sections:

Before You Begin

Before you begin looking through this chapter ensure that:

56.1 General Guidelines for Coding Java Portlets

When you write your portlets in Java for either JSR 286 or PDK-Java, you should follow the best practices described in this section.

This section includes the following subsections:

56.1.1 Guidelines for Portlet Modes

Portlet modes exhibit the runtime portlet functionality seen by users. You can provide an extended set of modes in addition to the standard ones provided with Oracle WebCenter. Different portal products support extended portlet modes as follows:

  • Oracle WebCenter has defined an extended set of portlet modes. Different modes are available for both PDK-Java and JSR 286 portlets. For example, the JSR 286 Java Portlet wizard for JSR 286 portlets includes an extended mode called print, which you can use to provide a printer friendly version of the portlet. PDK-Java offers some modes not offered by JSR 286. If you are coding portlets to JSR 286, then you can declare custom portlet modes in the portlet.xml file that map to the extended modes offered by PDK-Java, or to accommodate any other functionality you may want to provide.

    Defining custom modes is especially useful if the portlet must interoperate with portal implementations from other vendors. You can offer any of these modes to users. In fact, it is recommended that some modes like Edit Defaults are offered.

  • Third party portal products may have their own set of extended modes (JSR 286 custom modes) that producers can offer. In WebCenter Portal applications, the portlet chrome shows only the custom modes that are defined in Oracle WebCenter Framework. Arbitrary custom modes that a third party or custom portlet producer offers are ignored and therefore not supported.

This section includes the following subsections that discuss each of the standard portlet modes:

56.1.1.1 Guidelines for View Mode

View mode is known as Shared Screen mode in PDK-Java. For information about View mode, see Section 53.1.3.1, "View Mode."

When developing portlets, you must consider all of the factors that may influence the portlet's appearance on the page, such as the portlet's containing object and the other portlets with which your portlet shares the page. For example, suppose you choose to place your portlet inside an HTML table cell. The portlet should display only content that can be rendered within a table cell. Furthermore, the actual size of the table cell may vary depending on user settings, the browser width, and the amount and style of content in the portlet.

56.1.1.1.1 HTML Guidelines for Rendering Portlets

Plain HTML is the most basic way to render portlets and provides a great deal of flexibility to portlet developers. You can use almost any standard HTML paradigm, such as links, forms, images, tables, if it can display within an HTML table cell. Improperly written HTML may appear inconsistently across different browsers and, in the worst case, could cause parts of your page not to appear at all. Ensure that you adhere to the following rules:

  • Use standard HTML: The official HTML specification is available from the W3C (more information available at: http://www.w3.org/).

  • Avoid unterminated and extraneous tags: The behavior of pages with improperly terminated tags is unpredictable because it depends on what the browser chooses to do. Tools like weblint and HTML Tidy can help detect and fix hanging and unnecessary tags.

  • Consider restrictions imposed by container objects: If your portlet is contained inside of an HTML element, such as a table cell, then you must ensure that your portlet can be rendered within that container. For example, if you place a portlet in a table cell, then you could not use frames in the portlet because they do not appear when inserted in a table.

  • Keep portlet content concise: Do not try to take full screen content and expose it through a small portlet. You may end up with portlet content too small or cramped for smaller monitors. Full screen content is best viewed in Full Screen mode of PDK-Java.

  • Do not create fixed-width HTML tables in portlets: You have no way to tell how wide a column your portlet has on a user's page. If your portlet requires more room than given, then it might overlap with another portlet in certain browsers.

  • Avoid long, unbroken lines of text: The result is similar to what happens with wide fixed-width tables. Your portlet might overlap other portlets in certain browsers.

  • Check behavior when resizing the page: Test your portlet's behavior when the browser window is resized to ensure that it works in different browser window sizes.

  • Check behavior when the default browser font changes: People may choose whatever font size they want and they can change it at any time. Your portlet should handle these situations gracefully.

The HTML you use also affects the perceived performance of your site. Users judge performance based on how long it takes for them to see the page they requested, and browsers require time to interpret and display HTML. Given that, you should consider the following:

  • Avoid lengthy, complex HTML: Portlets share a page with other portlets. Thus, portlet generation times can significantly effect the overall performance of the page. If portlets must render complex HTML or wait for external resources, such as third-party applications, then it can greatly slow the rendering of the page.

56.1.1.1.2 Cascading Style Sheet Guidelines for Rendering Portlets

The fonts and colors of every portlet on a page should match the style settings chosen by the user. To accomplish this goal, these style selections are embedded automatically using a Cascading Style Sheet (CSS) on each page. The portlets access these settings for their fonts and colors, either directly or using the Application Programming Interface (API).

While different browsers have implemented varying levels of the full CSS specification, Oracle WebCenter Framework uses a very basic subset of this specification to allow for consistent fonts and colors. CSS implementation levels should not affect the consistency of your pages across browsers. Follow these guidelines for using CSS:

  • Use CSS instead of hard coding: Hard coding fonts and colors is extremely dangerous. If you hard code fonts and colors, then your portlet may look out of place when the user changes the page style settings. Since you have no way of knowing the user's font and color preference choices, you might also choose to hard code a font color that turns out to be the same as the user's chosen background color, in which case your portlet appears to be invisible to that user.

  • Use the CSS APIs to format your text: The style sheet definition is available at the top of pages, but you should not call it directly. Instead, use the APIs provided to format your text appropriately. This method ensures that your portlets work even if the style sheet changes in the future.

  • Avoid using CSS for absolute positioning: Since users can personalize their pages, you cannot guarantee that your portlet can appear in a particular spot.

  • Follow Accessibility Standards: You should ensure that you code your style sheets according to existing accessibility standards (more information available at http://www.w3.org/TR/WCAG10-CSS-TECHS/).

56.1.1.2 Guidelines for Edit Mode

For information about Edit mode, see Section 53.1.3.2, "Edit Mode."

56.1.1.2.1 Guidelines for Edit Mode Operations

The following guidelines should govern what you expose to users in Edit mode:

  • Enable users to personalize the title of the portlet: The same portlet may be added to the same page several times. Enabling the user to personalize the title helps alleviate confusion.

  • If using caching, invalidate the content: If personalizations cause a change in portlet display or content, then you must ensure that the portlet content is regenerated and not returned from the cache. Otherwise, the user may see incorrect content.

  • Do not use Edit mode as an administrative tool: Edit mode is meant to give users a way of changing the behavior of their portlets. If you want to change producer settings or do other administrative tasks, then you should create secured portlets specifically for those tasks.

56.1.1.2.2 Guidelines for Buttons in Edit Mode

For consistency and user convenience, Edit mode should implement the following buttons in the following order:

  • OK saves the user personalizations and returns the portlet to view mode.

  • Apply saves the user personalizations and reloads the current page.

  • Cancel returns the portlet to view mode without saving changes.

56.1.1.2.3 Guidelines for Rendering Personalization Values

When you show the forms used to change personalization settings, you should default the values such that the user does not have to constantly reenter settings. When rendering the personalization values, use the following sequence to provide consistent behavior:

  1. User preference: Query and display this user's personalizations, if available.

  2. Instance defaults: If no user personalizations are found, then query and display system defaults for the portlet instance. These are set in Edit Defaults mode and apply only to this portlet instance.

  3. Portlet defaults: If no system default personalizations are found, then display general portlet defaults, which may be blank. General portlet defaults are sometimes hard coded into the portlet but should be overridden if either of the two previous conditions apply.

This logic enables the personalizations to be presented in a predictable way, consistent with the other portlets in the WebCenter Portal application.

56.1.1.3 Guidelines for Edit Defaults Mode

For information about Edit Defaults mode, see Section 53.1.3.3, "Edit Defaults Mode."

56.1.1.3.1 Guideline for Edit Default Mode Options

The following guideline should govern what you expose to page designers in Edit Defaults mode:

  • Do not use Edit Defaults mode as an administrative tool. Edit Defaults mode gives users a way of changing the behavior of their portlets. If you want to change producer settings or do other administrative tasks, then you should create secured portlets specifically for those tasks.

56.1.1.3.2 Guidelines for Buttons in Edit Defaults Mode

For consistency and user convenience, Edit Defaults mode should implement the following buttons in the following order:

  • OK saves the user personalizations and returns the portlet to view mode.

  • Apply saves the user personalizations and reloads the current page.

  • Cancel returns the portlet to view mode without saving changes.

56.1.1.3.3 Guidelines for Rendering Personalization Values

When you show the forms used to change personalization settings, you should default the values so that the application developer does not have to constantly reenter settings. When rendering personalization values, use the following sequence to provide consistent behavior:

  1. Instance preferences: Query and display system defaults for the portlet instance.

  2. Portlet defaults: If no system default personalizations are found, then display general portlet defaults, which may be blank. General portlet defaults are sometimes hard coded into the portlet but should be overridden by system defaults.

This logic enables the personalizations to be presented in a predictable way, consistent with the other portlets in the WebCenter Portal application.

56.1.1.4 Guidelines for Help Mode

For information about Help mode, see Section 53.1.3.4, "Help Mode."

The following guideline should govern what you expose to users in Help mode:

  • Describe how to use the portlet. Users may not know all the features your portlet provides just from its interface. Describe the features and how to get the most out of them.

56.1.1.5 Guidelines for About Mode

For information about About mode, see Section 53.1.3.5, "About Mode."

The following guideline should govern what you expose to users in About mode:

  • Display relevant copyright, version, and author information. Users want to know what portlet they are using and where they can get more information. The about page may become important when supporting your portlets.

56.1.1.6 Guidelines for Preview Mode

For information about Preview mode, see Section 53.1.3.6, "Preview Mode."


Note:

This mode has no particular application in WebCenter Portal applications, but used in Oracle Portal's Portlet Repository.

The following guidelines should govern what you expose to users in Preview mode:

  • Provide an idea of what the portlet does. Preview mode should generate enough content for the user to get an idea of the actual content and functionality of the portlet.

  • Keep your portlet previews small. The amount of data produced in this mode should not exceed a few lines of HTML or a screen shot. Preview mode appears in a small area, and exceeding the window's size looks unprofessional and forces users to scroll.

  • Do not use live hyperlinks. Links may not work as expected when rendered in Preview mode. Hyperlinks can be simulated using the underline font.

  • Do not use active form buttons. Forms may not work as you expect them to when rendered in Preview mode. If you decide to render form elements, then do not link them to anything.

56.1.1.7 Guidelines for Full Screen Mode (PDK-Java Only)

For information about Full Screen mode, see Section 53.1.3.7, "Full Screen Mode (PDK-Java)."

Technically, JSR 286 portlets do not have Full Screen mode. However, you can implement the equivalent of Full Screen mode for a JSR 286 portlet with View mode and a maximized state for the window.

56.1.2 Guidelines for Navigation within a Portlet

In some ways, navigation between different sections or pages of a single portlet is identical to navigation between standard web pages. Users can submit forms and click links. In typical, simple web pages, both of these actions involve sending a message directly to the server responsible for rendering the new content, which is then returned to the client. In portlets, which comprise only part of a page, the form submission or link rendered within the portlet does not directly target the portlet. It passes information to the portlet through the WebCenter Portal application. If a link or form within a portlet does not refer back to the application, then following that link takes the user away from the application, which is not typically the desired behavior.

The component developer does not need to know the detailed mechanics of how the parameters of a form or link get passed around between the user, application, and portlet. However, they must understand that they cannot write links in a portlet the same way they do for typical, simple web pages.

Types of Links for Portlets

A portlet may render links of four classes, as follows:

  • Intraportlet links require the portlet to be aware of the address of the WebCenter Portal application because they actually refer to it in some way.

  • Application links, like intraportlet links, must be aware of the address of the WebCenter Portal application for the same reason.

  • External links make no reference to the WebCenter Portal application and work in portlets as they would do in a normal web page.

  • Internal/Resource links, like external links, also make no reference to the WebCenter Portal application.

Figure 56-1 contains a summary of these link types. The arrows indicate how the links reference the resources to which they logically refer.

Figure 56-1 WebCenter Portal Application Link Types

Description of Figure 56-1 follows
Description of "Figure 56-1 WebCenter Portal Application Link Types"

This section includes the following subsections:

56.1.2.1 Intraportlet Links

Intraportlet links go to different sections or pages within a given portlet. Strictly speaking, they refer to the page containing the portlet, but they contain parameters that cause the portlet to render a different section or page within that page when it is requested by the user.

As a direct consequence, a portlet cannot expect to render links to different sections or pages of itself using relative links or absolute links based on its own server context. Intraportlet link are useful for intraportlet navigation, either as links or form submission targets.

56.1.2.2 Application Links

Application links refer to significant pages within the WebCenter Portal application, such as the user's home page.

56.1.2.3 External Links

External links refer neither to the portlet (through a page) nor to any part of the WebCenter Portal application. If selected, these links take the user away from the application, for example, www.oracle.com.

56.1.2.4 Internal/Resource Links

Internal/Resource links refer to internal (to the portlet) resources. Sometimes they are exclusively used internally during portlet rendering, for example as a server side include. On other occasions, they may be used externally to reference portlet resources like images. In this latter case, you can use the PDK-Java constructResourceURL method in the UrlUtils class to retrieve images from behind a firewall using resource proxy. Note that in order for resource proxying to work, you must first set the JNDI variable, oracle/portal/provider/sample/resourceUrlKey, for the producer. For more information about setting JNDI variables, see Section 56.3.5.2, "Setting JNDI Variable Values."

For example, lottery.jsp of the lottery sample, which is available with PDK-Java, contains resource proxy requests for images.

<%@ page contentType="text/html;charset=UTF-8" %>
<%@ page session="false" import="oracle.portal.provider.v2.render.*" %>
<%@ page import="oracle.portal.provider.v2.render.http.HttpPortletRendererUtil" %>
<%@ page import="oracle.portal.provider.v2.url.UrlUtils" %>
<%@ page import="oracle.portal.sample.v2.devguide.lottery.*" %>
<%
  LottoPicker picker = new LottoPicker();
  picker.setIdentity(request.getRemoteAddr() ); %>
<% PortletRenderRequest portletRequest = (PortletRenderRequest)
request.getAttribute("oracle.portal.PortletRenderRequest"); %>
<% String name = portletRequest.getUser().getName(); %>
<P class="PortletHeading1" ALIGN="CENTER">Hi <%= name %>, Your Specially
  Picked</P><P ALIGN="CENTER"><IMG SRC="<%= UrlUtils.constructResourceURL(portletRequest,
  HttpPortletRendererUtil.absoluteLink(request, "images/winningnumbers.gif")) %>"
  WIDTH="450" HEIGHT="69" ALIGN="BOTTOM" BORDER="0"></P>
<P>
<P ALIGN="CENTER">
<TABLE ALIGN="CENTER" BORDER="0" CELLPADDING="0" CELLSPACING="0">
<TR>
<% 
     int [] picks = picker.getPicks();
     for (int i = 0; i < picks.length; i++) { 
%> 
             <TD>
    <IMG SRC="<%= UrlUtils.constructResourceURL(portletRequest,
      HttpPortletRendererUtil.absoluteLink(request, "images/ball" + picks[i])) %>
      .gif" WIDTH="68" HEIGHT="76" ALIGN="BOTTOM" BORDER="0">
     </TD>
<%
     }
 

For session-based producers, any cookies returned from the original initSession call to the producer are sent with the request back to the producer to maintain the right session context.

56.1.3 Guidelines for JavaScript

JavaScript can often be useful within a portlet, but bear in mind the following guidelines within your portlets:

  • You should never use JavaScript to redirect the page in which the portlet is rendered. If you want to direct users elsewhere, then you should do so in your portlet action handling code or open a new window in the browser.

  • Ensure that identifiers in your JavaScript are qualified. By qualifying your identifiers, you ensure that they are unique and do not clash with any JavaScript on the page.

56.2 Enhancing JSR 286 Java Portlets

When you have built your initial portlet in the Create JSR 286 Java Portlet wizard as described in Section 55.2.1, "How to Create a JSR 286 Java Portlet," the next step is to enhance it. Because JSR 286 portlets adhere to the Java standards, you can find substantial information about enhancing them from many different sources, such as third-party books and web pages.

This section includes the following subsections:

56.2.1 How to Edit the Portlet Deployment Descriptor File

The portlet deployment descriptor file for the application, portlet.xml, specifies the portlet resources in the application. After you have created your JSR 286 portlet using the Portlet Wizard, you can edit the portlet.xml file to edit those resources.

When you open the portlet.xml file in JDeveloper, you can edit the source code or you can use the Overview Editor to edit portlet resources without having to manually modify it in Source mode.

To edit the portlet deployment file:

  1. In the JDeveloper Application Navigator, open the portlet producer application.

  2. Expand the portlet project.

  3. Expand the Web Content node and then the WEB-INF node.

  4. Right-click portlet.xml and choose Open.

  5. Click the Design tab to open the Overview Editor for portlet.xml.

  6. The Overview Editor for portlet.xml contains the following tabs:

    • Application—Use to specify general information for the portlet producer application. These properties apply to all portlets within the application.

    • Portlets—Use to specify information for individual portlets within the application. For example, you can specify the portlet events and public render parameters supported by a portlet.

    • Events—Use to create and manage portlet events for use by all portlets in the application. For more information, see Section 56.2.5, "How to Use Portlet Events."

    • Parameters—Use to create and manage public render parameters for use by all portlets in the application. For more information, see Section 56.2.6, "How to Use Public Render Parameters."

    • Filters—Use to specify filter information for the portlets in the application. For more information, see Section 56.2.8, "How to Use Portlet Filters."

    • Filter Mappings—Use to assign portlet filters to individual portlets. For more information, see Section 56.2.8, "How to Use Portlet Filters."

56.2.2 How to Add Custom Portlet Modes

In the Create JSR 286 Java Portlet wizard, you add portlet modes by adding them to a list on the Content Types and Portlet Modes page. For more information about using the wizard, see Section 55.2.1, "How to Create a JSR 286 Java Portlet." The wizard enables you to implement the standard modes supported by JSR 286 and the extended modes provided by WebCenter.

The standard modes supported by JSR 286 are:

  • View

  • Edit

  • Help

WebCenter supports the following additional custom modes:

  • about

  • config

  • edit_defaults

  • preview

  • print

After the initial creation of the portlet, you can also define your own custom portlet modes. You can add custom modes to map to the extra modes offered by PDK-Java (for example, Full Screen mode), or to accommodate any other unique functionality you may want to provide.

The principles of implementing portlet modes are the same for all modes.

Before You Begin

The steps that follow assume that you have:

  • Built a portlet using the Create JSR 286 Java Portlet wizard

  • Successfully registered the portlet's producer

  • Added the portlet to a page

To add a custom portlet mode:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Application tab, if necessary.

  3. Expand the Custom Modes section, if necessary.

    This section lists all the custom modes available to the portlets within the application. It includes the WebCenter extended portlet modes.

  4. Click the Add Custom Mode icon to create a new row for the portlet mode.

  5. In the Portlet Mode field, enter the name of the portlet mode.

    The name must be unique within the application.

  6. In the Description field, enter a brief description to explain the purpose of the mode.

  7. Deselect the Portal Managed checkbox if the portlet mode is not managed by the portal

  8. Save the portlet.xml file.

  9. After adding the custom portlet mode to the application, you must then create the code for the mode in the portlet implementation file.

56.2.3 How to Access User Information

You can create user attributes in the portlet application to access commonly used user information, such as user.login.id or user.name.family. At runtime, these user attributes are mapped to the actual attributes of the current user. Portlets can use this information to obtain information about the current user.

To access user information:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Application tab, if necessary.

  3. Expand the User Attributes section, if necessary.

  4. Click the Add User Attribute icon to create a new row for the attribute.

  5. In the Name field, enter the name of the user attribute, for example user.login.id.

  6. In the Description field, enter a description for the user attribute.

    At runtime, the portlet container maps this attribute to the appropriate value. For example, if the current user is John Doe, then the user.name.family user attribute is mapped to Doe. Portlets can obtain a Map object containing the user attributes from the PortletRequest interface.

  7. Save the portlet.xml file.

56.2.4 How to Customize the Runtime Environment

When a portlet is run, the portlet container provides the runtime environment and provides an interface between the portlet application and the portlet.

Container runtime options provide a way to customize the behavior of the portlet container and therefore customize the runtime environment.

This section includes the following subsections:

56.2.4.1 Supported Container Runtime Options

This section describes the container runtime options supported by the WebCenter portlet container.

Table 56-1 lists the container runtime options that are defined in the JSR 286 specification. For more information about these options, see the JSR 286 specification at:

http://jcp.org/en/jsr/detail?id=286

Table 56-1 JSR 286 Container Runtime Options

Container Runtime Option Supported by Valid Values Description

javax.portlet.actionScopedRequestAttributes

Application

Portlet

true

false

Specifies whether to store action-scoped request attributes so that they are available to portlets until a new action occurs.

If set to true, you can specify a second value of numberOfCachedScopes and a third value indicating the number of scopes to be cached by the portlet container.

You can use the WebCenter-specific excludedActionScopeRequestAttributes container runtime option to limit which request attributes are stored in the scopes.

javax.portlet.escapeXml

Application

Portlet

true

false

Specifies whether to XML-encode URLs returned from actionUrl, renderUrl, and resourceUrl JSR 286 tag library tags.

Note: This option does not have any effect on the return value of PortletURL.toString() or ResourceURL.toString(); in both cases, for JSR 286, the output uses only ampersand characters. To use ampersand entities or be able to specify the XML encoding to use when generating URLs not using the tag libraries, see the BaseURL.write() methods.

You can override this option on a per-tag basis using the encodeXml attribute.

java.portlet.renderHeaders

Not supported

Not supported

Not supported by WebCenter.

javax.portlet.servletDefaultSessionScope

Application

Portlet

APPLICATION_SCOPE

PORTLET_SCOPE

Specifies the scope of the session object provided to servlets or JSPs that are included or forwarded from a Java portlet.


Table 56-2 lists the additional container runtime options supported by WebCenter.

Table 56-2 WebCenter Container Runtime Options

Container Runtime Option Supported by Valid Values Description

com.oracle.portlet.allowEventPayloadsWithoutJAXBBindings

Application

true

false

Allows event payload types declared in portlet.xml and event payloads sent from JSR286 portlets to bypass the JSR286 spec requirement that these types have a valid JAXB binding.

com.oracle.portlet.allowWsrpExport

Application

true

false

Specifies whether the WSRP export-portlets operation should be supported for the web application.

If set to false, this overrides the setting in WEB-INF/wsrp-producer-config.xml and turns off the WSRP export-portlets operation.

This option is used mainly for backward-compatibility; it is preferred to control the export-portlets operation through the wsrp-producer-config.xml setting.

com.oracle.portlet.compatibilityMode

Application

Portlet

owc168

Invokes the WebCenter JSR286 container JSR168 compatibility mode.

Also automatically sets the disallowResourceServing runtime option to true if no other value for that option is specified.

com.oracle.portlet.disallowResourceServing

Application

Portlet

true

false

If true, portlets will not be allowed to serve resources.

This is useful if JSR 168 portlets are run in the 286 container, as any JSR168 portlet extending javax.portlet.GenericPortlet will automatically inherit the JSR 286 functionality, which automatically forwards resource requests to a file in the web application named after the resource ID, creating a potential security problem. For the same security reason, JSR 286 portlets that do not serve resources are safest to disallow resource serving.

If false, portlets will be allowed to serve resources.

com.oracle.portlet.excludedActionScopeRequestAttributes

Application

Portlet

Multi-valued property, with each value being a regular expression

Request attributes which match any of the regular expressions are not stored as action-scoped request attributes if the javax.portlet.actionScopedRequestAttributes container runtime option is used, in addition to any request parameters whose values match the regular expressions defined in the com.oracle.portlet.externalScopeRequestAttributes container runtime option.

com.oracle.portlet.externalScopeRequestAttributes

Application

Portlet

Multi-valued property, with each value being a regular expression

Request attributes which match any of the regular expressions are considered outside of portlet scope, and are shared with the underlying Portal request.

If the javax.portlet.actionScopedRequestAttributes option is used, any request attributes matching the regular expressions declared in externalScopeRequestAttributes are not stored in the action scope request attributes.

com.oracle.portlet.minimumWsrpVersion

Application

Portlet

1

2

Specifies minimum required WSRP version for the portlet to work. If the WSRP version being used is less than the value specified, the portlet will not be included in a WSRP GetServiceDescription, GetPortletDescription, GetMarkup and other WSRP responses.

com.oracle.portlet.offerPortletOverWsrp

Application

Portlet

true

false

If true (the default value), the portlet is offered in the WSRP producer's service description

If false the portlet will not be included in the service description.

If not specified at all, the default value specified in the WEB-INF/producer-config.xml is used.

Any offerRemote setting in a .portlet file referencing the JSR 168/286 portlet overrides this container runtime option.

com.oracle.portlet.redirectAfterAction

Application

Portlet

true

false

Causes the JSR 286 container to send a redirect to the browser to the portlet's render URL after a processAction is run (and after events are handled) so that reloading the resulting page will not result in another processAction.

If true, a redirect will be issued after every portlet action.

If false, no redirect will be automatically issued after portlet actions.

com.oracle.portlet.requireIFrame

Application

Portlet

true

false

Specifies that the portlet needs to be rendered inside an IFRAME.

com.oracle.portlet.streamingOptimized

Application

Portlet

true

false

Indicates the portlet is optimized to run in streaming mode, which may enhance performance.

com.oracle.portlet.suppressWsrpOptimisticRender

Application

Portlet

true

false

Suppresses the optimistic render of a portlet after the action and/or event lifecycles if the portlet is being run over WSRP.

com.oracle.portlet.useWsrpUserContextForUserAuthenticationInfo

Application

true

false

Specifies whether the PortletRequest methods getRemoteUser(), getUserPrincipal() and isUserInRole() are based on the WSRP user context information or on standard J2EE security.

Note: Basing user information on the WSRP user context can be a security problem so this option should be used with care.

com.oracle.portlet.wsrpHeaderMode

Application

Portlet

client

consumer

both

Used only when portlets are being rendered as WSRP remote portlets, to indicate where cookies and headers should be put in the WSRP SOAP response as a hint to the WSRP consumer for the header or cookie's intended final destination.

When portlets are run locally (not over WSRP), headers and cookies set by portlets are always assumed to go to the client. Setting this container runtime option sets a default value for the PortletRequest attribute com.oracle.portlet.wsrpHeaderMode, which can still be overridden by the portlet at runtime on a per-header basis.

com.oracle.portlet.wsrpLegacyPortletHandle

Portlet

true

false

Allows the specification of a legacy WSRP portlet handle to be used for the portlet, which must be unique within the web application. This is useful for backward-compatibility with WebCenter consumers that use the legacy, portlet-position-based WSRP portlet handles.

If specified, the legacy portlet handle will be published in the WSRP serviceDescription as a legacy-handle extension on the portlet, and consumers will be able to access the portlet using the legacy portlet handle, although the portlet will not be published in the WSRP serviceDescription under the legacy portlet handle.

com.oracle.portlet.wsrpPortletHandle

Portlet

true

false

Allows the specification of the WSRP portlet handle to be used for the portlet, which must be unique within the web application.


56.2.4.2 Setting Container Runtime Options for All Portlets in an Application

Setting container runtime options at the application level affects all the portlets in the application.

To set application-level container runtime options:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Application tab, if necessary.

  3. Expand the Container Runtime Options section, if necessary.

  4. Click the Add Container Runtime Option icon to display a list of available options.

    The list includes all container runtime options supported by the WebCenter portlet container, which are listed in Table 56-1 and Table 56-2.

    If you are using a different portlet container that supports additional container runtime options that are not listed, select <Customize> and enter the name of the option in the Name field.

    If you specify a container runtime option that is not supported by the portlet container, it is ignored.

  5. In the Value field, enter a value for the container runtime option.

    The container runtime option is added to the portlet.xml code.

    <container-runtime-option>
       <name>com.oracle.portlet.requireIFrame</name>
       <value>true</value>
    </containter-runtime-option>
    
  6. Save the portlet.xml file.

56.2.4.3 Setting Container Runtime Options for Individual Portlets

You can set container runtime options at the individual portlet level to override the application-wide settings.

To set portlet-level container runtime options:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Portlets tab, if necessary.

  3. Click the Advanced tab.

  4. Click the Add Container Runtime Option icon to display a list of available options.

    The list includes all container runtime options supported by the WebCenter portlet container, which are listed in Table 56-1 and Table 56-2.

    If you are using a different portlet container that supports additional container runtime options that are not listed, select <Customize> and enter the name of the option in the Name field.

    If you specify a container runtime option that is not supported by the portlet container, it is ignored.

  5. In the Value field, enter a value for the container runtime option.

    The container runtime option is added to the portlet.xml code.

    <container-runtime-option>
       <name>com.oracle.portlet.requireIFrame</name>
       <value>false</value>
    </containter-runtime-option>
    
  6. Save the portlet.xml file.

56.2.5 How to Use Portlet Events

Portlet events are a JSR 286 feature that enable inter-portlet communication by providing portlets with the ability to respond to actions that occur outside of the portlet itself, for example an action performed on the page that contains the portlet or on another portlet on the same page. Portlet events can be cascaded so that a portlet may respond to an event by triggering an event of its own, which in turn affects other portlets on the page.

Any portlet events supported by a portlet must be declared in the application section of the portlet deployment descriptor (portlet.xml). Portlet events defined at the application level in this way are available to all the portlets in the application.

Individual portlets within the application can then specify which of these portlet events they want to use. Portlets can declare events that they are interested in receiving, called processing events, and events that they trigger, called publishing events.

This section includes the following subsections:

For more information about portlet events and how to implement them, see the JSR 286 specification at:

http://jcp.org/en/jsr/detail?id=286

56.2.5.1 Defining a Portlet Event at the Application Level

For a portlet event to be available to a portlet, it must first be declared in the application section of the portlet deployment descriptor (portlet.xml).

To define a portlet event at the application level:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Events tab.

  3. Click the Add icon to create a new portlet event.

  4. From the dropdown list, select whether you are specifying a fully qualified name (QName) for the portlet event, or just the local part of the name.

    A QName uniquely identifies the portlet event across applications by specifying a namespace for the parameter as well as a local name. A page typically contains multiple portlets which may come from different applications. Using QNames ensures that portlet events from one portlet do not unintentionally interfere with the other portlets on a page regardless of where those portlets come from.

    If the namespace for the portlet event is the same as the application default namespace, you can omit the namespace when defining the event by specifying an unqualified name. If the application default namespace has not been defined, a portlet event with an unqualified name uses the XML default namespace.

  5. If you selected Qualified Name:

    1. In the Namespace field, enter the namespace for the portlet event.

    2. In the Name field, enter the local part of the portlet event name.

  6. If you selected Unqualified Name, in the Name field, enter the local part of the portlet event name. The event uses the application default namespace as the namespace for the event (or the XML default namespace if no namespace is defined for the application).

  7. In the Payload field, enter or browse for the data type of the payload provided by the portlet event.

  8. In the Description field, enter a description for the portlet event.

  9. (Optional) In the Aliases panel, you can provide a list of aliases so that a portlet event can be recognized by the portlet even if it has a different QName from the one defined by the portlet.

    1. Click the Create icon to create a new alias for the portlet event.

    2. In the Namespace field, enter the namespace of the portlet event to use for the alias.

    3. In the Name field, enter the local part of the portlet event to use for the alias.

  10. The portlet event is added to the application definition section of the portlet.xml file:

    <event-definition>
       <description>This is my event</description>
       <qname xmlns:x="http://example.com/events">myEvent</qname>
       <value-type>java.lang.String</value-type>
    </event-definition>
    
  11. Save the portlet.xml file.

56.2.5.2 Adding a Processing Event to a Portlet

If your want a portlet to listen for a particular portlet event, define it as a processing event.

To add a processing event to a portlet:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. If the portlet event has not yet been defined within the portlet application, you must do this first, for more information, see Section 56.2.5.1, "Defining a Portlet Event at the Application Level."

  3. Click the Portlets tab and select the portlet in which you want to use the portlet event.

  4. Click the Events tab.

    In the Processing Events panel, the Available list shows all the portlet events that have been defined for the application.

  5. Select the portlet event that you want to use in the portlet and click the Add icon to move it to the Selected list.

    This adds the portlet event as a processing event to the portlet definition in portlet.xml:

    <portlet id="1234567890">
       ...
       <supported-processing-event>
          <name>myParam</name>
       </supported-processing-event>
       ...
    </portlet>
    
  6. Save the portlet.xml file.

  7. You can now use this portlet event in the code for your portlet.

56.2.5.3 Adding a Publishing Event to a Portlet

If you want a portlet to trigger a particular portlet event, define it as a publishing event.

To add a publishing event to a portlet:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. If the portlet event has not yet been defined within the portlet application, you must do this first, for more information, see Section 56.2.5.1, "Defining a Portlet Event at the Application Level."

  3. Click the Portlets tab and select the portlet in which you want to use the portlet event.

  4. Click the Events tab.

    In the Publishing Events panel, the Available list shows all the portlet events that have been defined for the application.

  5. Select the portlet event that you want to use in the portlet and click the Add icon to move it to the Selected list.

    This adds the portlet event as a publishing event to the portlet definition in portlet.xml:

    <portlet id="1234567890">
       ...
       <supported-publishing-event>
          <name>myParam</name>
       </supported-publishing-parameter>
       ...
    </portlet>
    
  6. Save the portlet.xml file.

  7. You can now use this portlet event in the code for your portlet.

56.2.6 How to Use Public Render Parameters

Public render parameters are a JSR 286 feature that enable portlets to share parameter values, allowing a form of inter-portlet communication.

For example, if a Map portlet and a Weather portlet are both configured to use a Zipcode public render parameter, entering a zip code in the Map portlet updates the same parameter value in the Weather portlet.

Any public render parameters supported by a portlet must be declared in the application section of the portlet deployment descriptor (portlet.xml). Public render parameters defined at the application level in this way are available to all the portlets in the application.

Individual portlets within the application can then specify which of these public render parameters they want to use.

This section includes the following subsections:

For more information about public render parameters and how to implement them, see the JSR 286 specification at:

http://jcp.org/en/jsr/detail?id=286

56.2.6.1 Defining a Public Render Parameter at the Application Level

For a public render parameter to be available to a portlet, it must first be declared in the application section of the portlet deployment descriptor (portlet.xml).

To define a public render parameter at the application level:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Parameters tab.

  3. Click the Add icon to create a new public render parameter.

  4. From the dropdown list, select whether you are specifying a fully qualified name (QName) for the parameter, or just the local part of the name.

    A QName uniquely identifies the public render parameter across applications by specifying a namespace for the parameter as well as a local name. Within the portlet code, a public render parameter is accessed by its identifier, which identifies the parameter uniquely within the application. However, a page typically contains multiple portlets which may come from different applications. Using QNames ensures that public render parameters from one portlet do not unintentional interfere with the other portlets on a page regardless of where those portlets come from.

    If the namespace for the parameter is the same as the application default namespace, you can omit the namespace when defining the parameter by specifying an unqualified name. If the application default namespace has not been defined, a parameter with an unqualified name uses the XML default namespace.

  5. If you selected Qualified Name:

    1. In the Namespace field, enter the namespace for the parameter.

    2. In the Name field, enter the local part of the parameter name.

  6. If you selected Unqualified Name, in the Name field, enter the local part of the parameter name. The parameter uses the application default namespace as the namespace for the parameter (or the XML default namespace if no default namespace is defined for the application).

  7. In the Identifier field, enter a name to identify the public render parameter within the application.

    The identifier must be unique within the application and is used to identify the parameters used by a portlet and in the portlet code to access the parameter. Using the identifier means that portlet developers do not need to be aware of the parameter's fully qualified name; they simply need to know the simpler application-specific identifier.

  8. In the Description field, enter a description for the public render parameter. The description should provide enough information so that portlet developers can determine how to use this parameter in their portlets.

  9. (Optional) In the Aliases panel, you can provide a list of aliases so that the parameter can accept values from other public render parameters even if they have different QNames.

    1. Click the Create icon to create a new alias for the parameter.

    2. In the Namespace field, enter the namespace of the parameter to use for the alias.

    3. In the Name field, enter the local part of the parameter to use for the alias.


    Note:

    When creating aliases for public render parameters, it is a good idea to set up reciprocal aliases. So if a parameter in portlet A has an alias to a parameter in portlet B, you should also, if possible, create an alias for the parameter in portlet B to the parameter in portlet A.

  10. The public render parameter is added to the application definition section of the portlet.xml file:

    <public-render-parameter>
       <description>This is my parameter</description>
       <identifier>myParam</identifier>
       <qname xmlns:x="http://example.com/params">x:myParam</qname>
       <alias xmlns:x="http://example.com/params">x:yourParam</alias>
    </public-render-parameter>
    
  11. Save the portlet.xml file.

56.2.6.2 Adding a Public Render Parameter to a Portlet

If you want a portlet to support a public render parameter, add it to the portlet.

To add a public render parameter to a portlet:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. If the public render parameter has not yet been defined within the portlet application, you must do this first, for more information, see Section 56.2.6.1, "Defining a Public Render Parameter at the Application Level."

  3. Click the Portlets tab and select the portlet in which you want to use the public render parameter.

  4. Click the Parameters tab.

    In the Publishing Events panel, the Available list shows all the portlet events that have been defined for the application.

  5. Click the Parameters tab.

    In the Public Render Parameters panel, the Available list shows all the public render parameters that have been defined for the application.

  6. Select the public render parameter that you want to use in the portlet and click the Add icon to move it to the Selected list.

    This adds the public render parameter to the portlet definition in portlet.xml:

    <portlet id="1234567890">
     ...
     <supported-public-render-parameter>myParam</supported-public-render-parameter>
     ...
    </portlet>
    
  7. Save the portlet.xml file.

  8. You can now use this public render parameter in the code for your portlet.

56.2.7 How to Add Personalization

Portlet preferences enable end users to personalize the portlet at runtime. These personalizations are visible only to the user that performed them; not to other users. By default, when you create a JSR 286 portlet using the JDeveloper wizard, a portlet preference is created to enable users to personalize the title of the portlet at runtime. You can create additional portlet preferences, either during portlet creation or by editing the portlet.xml file after portlet creation, to enable end users to perform other personalizations on the portlet at runtime.

This section includes the following subsections:

56.2.7.1 Adding a Portlet Preference to a Portlet

To add portlet personalization, you must create portlet preferences for those attributes of the portlet that you want users to be able to personalize.

To add a portlet preference to a portlet:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Portlets tab and select the portlet for which you want to add personalization.

  3. Click the Advanced tab.

    The Preferences panel lists any existing portlet preferences that exist for the portlet, for example, the portletTitle preference.

  4. Click the Add icon to create a new portlet preference.

  5. In the Name field, enter a name for the preference.

    The name must be unique within the portlet and use only letters, numbers, and the underscore character.

  6. In the Value field, enter one or more default values for the preference. Separate multiple entries with commas.

  7. Select Read-only if you do not want users to be able to update the value of the preference.

  8. You can now use this preference in your portlet code using the getPreference method.


    Note:

    If you want the preference to be translatable, you must add the appropriate key-value pairs to the resource bundle class.

56.2.7.2 Simple Portlet Personalization Example

The following example provides a simple illustration of how you can enable personalization in portlets.

To add simple personalization to a portlet:

  1. In the JDeveloper Application Navigator, open the application that contains the portlet.

  2. Expand the project that contains the portlet.

  3. Right-click view.jsp and choose Open.

  4. In the visual editor, click the Source tab and add the code indicated in bold in Example 56-1 to display the portletContent customization preference:

    Example 56-1 view.jsp Sample Code

    <%@ page contentType="text/html"
        import="javax.portlet.*,java.util.*,Portlets.Portlet1,
        Portlets.resource.Portlet1Bundle"%>
    <%@ taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
    
    <portlet:defineObjects/>
    <%
    String[] str = {"Portlet Content"};
    PortletPreferences prefs = renderRequest.getPreferences();
    str = prefs.getValues("portletContent",str);
    for (int i=0; i<str.length; i++)
    {
    %><%=(i<str.length-1)?str[i]+", ":str[i]%><%}%> 
    
  5. In the Application Navigator, right-click edit.jsp and choose Open.

    Notice that the JSP consists of a form field, a form input field, and two form button fields.

  6. In the visual editor, click the Source tab and add the code indicated in bold in Example 56-2 to implement a form field for users to enter a value for the portletContent customization preference:

    Example 56-2 edit.jsp Sample Code

    <%@ page contentType = "text/html; charset=windows-1252"
             pageEncoding = "windows-1252"
             import = "javax.portlet.*, java.util.*,
    Portletenhance.Portletenhance,
    Portletenhance.resource.PortletenhanceBundle"%>
    @ <%@ taglib uri = "http://java.sun.com/portlet" prefix="portlet"%>
    <portlet:defineObjects/>
    <%
        PortletPreferences prefs = renderRequest.getPreferences();
        ResourceBundle res =
            portletConfig.getResourceBundle(renderRequest.getLocale());
    %>
    <form action="<portlet:actionURL/>" method="POST">
      <table border="0">
        <tr>
          <td width="20%">
            <p class="portlet-form-field" align="right">
              <%=  res.getString(PortletenhanceBundle.PORTLETCONTENT) %>
            </p>
          </td>
          <td width="80%">
            <input class="portlet-form-input-field"
                   type="TEXT"
                   name="<%= Portletenhance.PORTLETCONTENT_KEY %>"
                   value="<%= Portletenhance.buildValue(prefs,
    Portletenhance.PORTLETCONTENT_KEY) %>"
                   size="20">
          </td>
        </tr>    <tr>
          <td width="20%">
            <p class="portlet-form-field" align="right">
              <%=  res.getString(PortletenhanceBundle.PORTLETTITLE) %>
            </p>
          </td>
          <td width="80%">
            <input class="portlet-form-input-field"
                   type="TEXT"
                   name="<%= Portletenhance.PORTLETTITLE_KEY %>"
                   value="<%= prefs.getValue(Portletenhance.PORTLETTITLE_KEY,
    res.getString("javax.portlet.title")) %>"
                   size="20">
          </td>
        </tr>
        <%
        String[] str = {"Portlet Content"};
        str = prefs.getValues("portletContent",str);
    %>
    <tr><td width="20%">
    <p class="portlet-form-field" align="right">
    Content
    </p>
    </td><td width="80%">
    <textarea rows="10" cols="60" class="portlet-form-input-field"
      name="portletContent"><%
    for (int i=0; i<str.length; i++)
    {%><%= (i<str.length-1) ? str[i]+", " : str[i] %><%}%>
    </textarea>
    </td></tr>
        <tr>
          <td colspan="2" align="center">
            <input class="portlet-form-button" type="submit"
                                                
    name="<%=Portletenhance.OK_ACTION%>"
                                                
    value="<%=res.getString(PortletenhanceBundle.OK_LABEL)%>">
            <input class="portlet-form-button" type="submit"
                                                
    name="<%=Portletenhance.APPLY_ACTION%>"
                                                
    value="<%=res.getString(PortletenhanceBundle.APPLY_LABEL)%>">
          </td>
        </tr>
      </table>
    </form>
    
  7. In the Application Navigator, right-click portletName.java and choose Open.

  8. In the visual editor, click the Source tab and add the following two lines of code (indicated in bold) to the processAction method:

    // Save the preferences.
    PortletPreferences prefs = request.getPreferences();
    String param = request.getParameter(PORTLETTITLE_KEY);
    prefs.setValues(PORTLETTITLE_KEY, buildValueArray(param));
    String contentParam = request.getParameter("portletContent");
    if (contentParam != null)
    {
      prefs.setValues("portletContent", buildValueArray(contentParam));
    }
    prefs.store();
    
  9. Redeploy the portlet.

    Notice that JDeveloper automatically saves and compiles the code before deploying the portlet. For a reminder of how to perform this step, see Chapter 57, "Testing and Deploying Your Portlets."

  10. Reload the page that contains the portlet and you can see that the portlet now displays the text Portlet Content, which was one of the changes you made.

  11. Click the Personalize link to see the form field that you added. Enter some text in this field and close the dialog. You can see the new text displayed in the portlet.

56.2.8 How to Use Portlet Filters

Portlet filters are a JSR 286 feature that enable you to alter the content of a portlet at runtime. A portlet filter is a reusable Java component that can transform the content of portlet requests and portlet responses. Filters do not generally create a response or respond to a request as portlets do, rather they modify or adapt the requests and responses.

This section includes the following subsections:

For more information about portlet filters and how to implement them, see the JSR 286 specification at:

http://jcp.org/en/jsr/detail?id=286

56.2.8.1 Adding a Portlet Filter to an Application

For a portlet to be able to use a portlet filter, the filter must first be defined within the application.

To add a portlet filter to an application:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Filters tab.

  3. Click the Add icon to create a new portlet filter.

  4. In the Create Portlet Filter dialog, select New Portlet Filter to create a new filter class to implement the portlet filter. Go to step 5.

    Select Choose from Existing Class, and enter or browse for the filter class, if the filter class that implements the portlet filter already exists. Go to step 9.

  5. In the Name field, enter a name for the portlet filter.

    The name must be unique within the application and use only letters, numbers, and the underscore character.

  6. In the Package field, enter or browse for the package to contain the new filter class.

  7. Select one or more of the Lifecycle Phase checkboxes to specify which of the javax.portlet.filter interfaces the filter class implements:

    • Action—The filter class implements the ActionFilter interface

    • Event—The filter class implements the EventFilter interface.

    • Render—The filter class implements the RenderFilter interface.

    • Resource—The filter class implements the ResourceFilter interface.


    Note:

    When you create a new filter class using the Create Portlet Filter dialog, you can specify which of the filter interfaces the filter class implements. After the filter class has been created, you cannot add or remove filter interfaces through the Overview Editor. Instead, you must edit the source of the filter class directly to manually add or remove the interfaces and the doFilter methods defined for those interfaces.

  8. Click OK.

  9. In the Display Name field, enter a more user-friendly name for the portlet filter.

  10. In the Description field, enter a description for the portlet filter.

  11. In the Initialization Parameters panel, you can specify initialization parameters that pass values to the init() method of the filter class.

    1. Click the Add icon to specify an initialization parameter for the portlet filter.

    2. In the Name field, enter the name of the initialization parameter.

    3. In the Value field, enter the value to pass to the initialization parameter.

    4. In the Description field, enter a description of the initialization parameter.

  12. The portlet filter is added to the application definition section of the portlet.xml file:

    <filter>
        <display-name>Test Filter</display-name>
        <filter-name>filter_1</filter-name>
        <filter-class>javaportlets.MyFilter</filter-class>
        <lifecycle>ACTION_PHASE</lifecycle>
        <lifecycle>RENDER_PHASE</lifecycle>
    </filter>
    
  13. Save the portlet.xml file.

56.2.8.2 Applying a Portlet Filter to a Portlet

After the portlet filter has been defined in the application, you can then apply it to one or more portlets within the application. You can also specify the order in which portlet filters are applied to portlets.

To apply a portlet filter to a portlet:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Filter Mappings tab.

  3. Click the Add icon to add a row to the filter mappings table.

  4. From the Filter Name dropdown list, select the portlet filter that you want to apply to the portlet.

    The dropdown list is populated with all the portlet filters that are defined in the portlet.xml file.

  5. From the Portlet Name dropdown list, select the portlet to which you want to apply the portlet filter.

    The dropdown list is populated with all the portlets that are defined in the portlet.xml file.

    Alternatively, you can use wildcards to apply the portlet filter to more than one portlet. For example, you can enter * to apply the portlet filter to all the portlets in the application.

  6. The filter mapping is added to the application definition section of the portlet.xml file:

    <filter-mapping>
        <filter-name>filter_1</filter-name>
        <portlet-name>jsrportlet4</portlet-name>
    </filter-mapping>
    
  7. Use the Top, Up, Down, and Bottom icons to order the portlet filters in the portlet.xml file. The order of the portlet filters determines the order in which the filters are applied to the portlets.


    Note:

    Remember that filters can be mapped to multiple portlets. If you have multiple portlets mapped to (sharing) a filter, arbitrarily changing the filter order can produce undesired side effects. For example, if you change the order in which filters are applied in one portlet, the reordering will apply to all other portlets that share the filter.

  8. Save the portlet.xml file.

56.2.9 How to Implement Portlet Caching

When you have completed the basic functionality of your portlet, you may want to turn your attention to portlet performance.

Caching is a common technique for enhancing the performance of web sites that include a great deal of dynamic content. The overhead involved in retrieving data and generating the output for dynamic content can be significantly reduced by proxying requests through a local agent backed by a large, low-latency data store known as a cache. The cache agent responds to a request in one of two ways, as follows:

  • If a valid version of the requested content exists in the cache, then the agent simply returns the existing cache copy, thus skipping the costly process of content retrieval and generation. This condition is known as a cache hit.

  • If a valid version of the requested content does not exist in the cache, then the agent forwards the request to its destination and awaits the return of the content. The agent returns the content to the requester and stores a local copy in its cache for reuse if a subsequent request for the same content arises. This condition is known as a cache miss.

Producers generate dynamic content (that is, portlets) and they reside remotely from the WebCenter Portal application instance on which they are deployed. As such, caching might improve their performance. The architecture lends itself well to caching. You can cache the portlets rendered by your producer and reuse the cached copies to handle subsequent requests, minimizing the overhead your producer imposes on page assembly.

For JSR 286 portlets, there are two different caching methods. The methods differ mainly in how they determine whether content is still valid.

  • Expiry-based caching: When a producer receives a render request, it stamps its response with an expiry time. The rendered response remains in the cache and fills all subsequent requests for the same content until its expiry time passes. This caching scheme is perhaps the simplest and most performant because the test for cache validity requires very little overhead and does not involve any network round trips. Expiry-based caching suits applications where the content has a well-defined life span. For content with a less certain life span, however, expiry-based caching is less effective. For more information, see Section 56.2.9.1, "Implementing Expiry-Based Caching.".

  • Validation-based caching: When a producer receives a render request, it stamps a response with a version identifier (or ETag). The response goes into the cache, but before the consumer can reuse the cached response, it must determine whether the cached version is still valid. It sends the producer a render request that includes the version identifier of the cached content. The producer determines whether the version identifier remains valid. If the version identifier is still valid, then the producer immediately sends a lightweight response to the consumer without any content, which indicates that the cached version can be used. Otherwise, the producer generates new content with a new version identifier, which replaces the previously cached version. In this form of caching, the consumer must always confirm with the producer whether the content is up to date. The validity of the cached copy is determined by some logic in the producer. The advantage of this approach is that the producer controls the use of the cached content, rather than relying on a fixed period. For more information, see Section 56.2.9.2, "Implementing Validation-Based Caching."

This section includes the following subsections:

56.2.9.1 Implementing Expiry-Based Caching

You can choose to implement expiry-based caching when you first create a portlet using the Create JSR 286 Portlet Wizard. However, during the initial development of a portlet, you may prefer to turn portlet caching off and implement it later in the development cycle when the portlet content becomes more stable. You may also want to edit the expiration period, or change the cache scope.

To implement expiry-based caching:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. Click the Portlets tab and select the portlet for which you want to implement expiry-based caching.

  3. Click the Advanced tab.

  4. In the Cache Management panel, select Cache Portlet.


    Note:

    To disable portlet caching, deselect Cache Portlet. This sets the cache expiration period to 0, meaning that the cached content is always expired.

  5. Select the Cache Scope:

    • Select Public to share the cached content across users

    • Select Private if the cached content should not be shared across users.

  6. Specify the cache expiration period:

    • Select Cache Content Never Expires to set the cache expiration period to -1. This means that the cached content never expires and the content is always retrieved from the cache. Use this option if you are confident that the portlet contains static content that is unlikely to change. Setting this option results in the following code being added to the portlet.xml file:

      <portlet>
        ...
        <expiration-cache>-1</expiration-cache>
        ...
      </portlet>
      
    • Select Cache Content Expires After to expire the cached portlet content after a specified number of seconds. Enter the expiration period, in seconds, in the adjacent field. Setting this option results in the following code being added to the portlet.xml file:

      <portlet>
        ...
        <expiration-cache>300</expiration-cache>
        ...
      </portlet>
      
  7. Save the portlet.xml file.

56.2.9.2 Implementing Validation-Based Caching

Implementation of validation-based caching takes place after the initial portlet creation and requires hand coding.

Example 56-3 shows how a GenericPortlet would typically implement its doView() method such that the consumer caches the markup using validation-based caching. The example also shows how expiry-based caching can be defined programmatically (using the CacheControl.setExpirationTime() method) and used in conjunction with validation-based caching to further reduce the load on the producer. This would work equally well for serveResource().

Example 56-3 A JSR 286 Portlet Implementing Validation-Based Caching

protected void doView (RenderRequest request, RenderResponse response)
  throws PortletException, IOException 
{
  CacheControl cacheControl = response.getCacheControl();
  String eTag = request.getETag();
  if (isMarkupStillValid(eTag)) 
  { 
    cacheControl.setExpirationTime(30);      // Wait 30 seconds before checking ETag again
    cacheControl.setUseCachedContent(true);  // Tell consumer to use its cached content
    return;
  }
    
  // ETag not valid so set a new one ...
  cacheControl.setETag(generateETag(...));   // Define a new ETag
  cacheControl.setExpirationTime(60);        // Wait 60 seconds before checking ETag again
 
  // ... and generate fresh portlet markup
  createMarkup(request, response);
}
 
private boolean isMarkupStillValid(String eTag)
{
  if (eTag == null)
  {
    return false; // No ETag was supplied
  }
 
  // Perform portlet specific checks for the consumer's cached 
  // copy of the markup still being valid based on the given ETag
  ...
}
 
private String generateETag(...)
{
  // Portlet specific code to generate an ETag, for example, a hash 
  // of the data on which the portlet's markup is based
  ...
  
  return eTag;
}

For more information about validation-based caching in JSR 286 portlets, see the JSR 286 specification at:

http://jcp.org/en/jsr/detail?id=286

56.2.10 How to Implement Export of Customizations (WSRP 2.0)

Another new feature that arrives with WSRP 2.0 is the ability to keep customizations with portlets when moving them from one deployment to another. Customizations are portlet preferences that are set in edit defaults mode. For example, suppose that you create a portlet and then customize its title within your development environment. If you have enabled export for that producer, then the customized title is transported along with the portlet when you deploy it in production environment. If you do not enable export, then all customizations are lost when you transport the portlet from one deployment environment to another.

To implement export of portlet customizations:

  1. Open the Overview Editor for the portlet.xml file. For more information, see Section 56.2.1, "How to Edit the Portlet Deployment Descriptor File."

  2. In the Container Runtime Options section of the Application tab, click the Add icon and choose com.oracle.portlet.allowWsrpExport.

  3. In the row for the newly added container runtime option, double-click the Value field to edit it, and enter true.

  4. Save the portlet.xml file.

56.2.11 How to Implement Rewritten URLs for Resource Proxy

Resource proxying is the standard way to retrieve resources with WSRP. To avoid problems with URLs within your portlet, you can set a flag to rewrite all of the URLs within a specified resource. For example, if have an HTML fragment that contains URLs, then you could set this flag to rewrite its URLs taking into account the WSRP resource proxying.

To indicate that URLs should be rewritten, set the PortletRequest attribute, oracle.portlet.server.resourceRequiresRewriting, to true. For example, you might include code similar to the excerpt in Example 56-4 to use resource proxying for a URL that you are encoding. Encapsulate this code within a method to avoid repeating it for every URL individually.

Example 56-4 Resource Proxy for WSRP

request.setAttribute("oracle.portlet.server.resourceRequiresRewriting", 
     Boolean.TRUE); 
String url = response.encodeURL(pathToResourceForRewriting); 
request.removeAttribute("oracle.portlet.server.resourceRequiresRewriting");

If you do not specifically set oracle.portlet.server.resourceRequiresRewriting, then it defaults to false, meaning that URLs are not rewritten. You must explicitly activate the feature by setting this attribute to true.

56.2.12 How to Implement Stateless Resource Proxying

If you have out of protocol resources that do not require rewriting, you may want to use stateless resource proxying. Stateless resource proxying means that the URLs returned to the browser do not require portlet IDs or any other contextual information. This increases the cache hit ratio for such resources. You might find stateless resource proxying useful for functionality such as static JavaScript files, static images, and so on.

To indicate that stateless proxying is required, set the PortletRequest attribute oracle.portlet.server.useStatelessProxying to true. For example, you might include code similar to the excerpt in Example 56-5 to use stateless proxying for a URL that you are encoding. Encapsulate this code within a method to avoid repeating it for every URL individually.

Example 56-5 Stateless Resource Proxying

request.setAttribute("oracle.portlet.server.useStatelessProxying", Boolean.TRUE);
String url = response.encodeURL(pathToResource);
request.removeAttribute("oracle.portlet.server.useStatelessProxying");

If you do not specifically set oracle.portlet.server.useStatelessProxying, it defaults to false. You must explicitly activate the feature by setting this attribute to true.

56.2.13 How to Enable Java Object Cache for Preference Store Access

To improve preference store performance, you may choose to use Java Object Cache for preference store access. This avoids the need to access the persistent store on each request. You can configure the use of caching by the WSRP preference store with the following JNDI variable:

oracle/portal/wsrp/server/enableJavaObjectCache

By default, this variable is set to false. You can set the variable yourself in the web.xml file for you portlet application as follows:

<env-entry>
 <env-entry-name>oracle/portal/wsrp/server/enableJavaObjectCache</env-entry-name>
 <env-entry-type>java.lang.Boolean</env-entry-type>
 <env-entry-value>true</env-entry-value>
</env-entry>

For more information about setting JNDI variables, see Section 56.3.5.2, "Setting JNDI Variable Values."

56.2.14 How to Implement Security for JSR 286 Portlets

You can secure JSR 286 portlets that are deployed to a WSRP producer by configuring security at the WSRP producer end and the client end. For information about securing a JSR 286 portlet through its WSRP producer, see Section 63.17, "Securing Identity Propagation Through WSRP Producers with WS-Security."

56.3 Enhancing PDK-Java Portlets

When you have built your initial portlet in the Create Oracle PDK-Java Portlet wizard as described in Section 55.2.4, "How to Create a PDK-Java Portlet," the next step is to enhance it. You can find the JavaDoc reference for the PDK-Java in the Oracle Fusion Middleware Java API Reference for Oracle PDK Java:

This section includes the following subsections that describe some enhancements that you might want to perform:

The source code for many of the examples referenced in this section is available as part of the Portlet Developer's Kit (PDK).

When you unzip PDK-Java, find the examples in:

../pdk/jpdk/v2/src/oracle/portal/sample/v2/devguide

56.3.1 Guidelines for PDK-Java Portlets

In Oracle WebCenter Framework, PDK-Java portlets work somewhat differently than they did in Oracle Portal. As a result, you must be aware of the following new design considerations when you build PDK-Java portlets in Oracle WebCenter Framework:

  • Your portlet must not contain any code that relies upon the URL format or parameters in the request that were not explicitly added by your portlet.

  • You should never assume that your portlet is the only one on a page, regardless of the portlet mode. For example, even if your portlet is in Edit mode, you should not assume that it is the only portlet on the page.

  • Never write a portlet mode that simply redirects. A redirect can only be issued while processing a post to your portlet or following a link generated by your portlet.

56.3.2 How to Add Portlet Modes

In the Create Oracle PDK-Java Portlet wizard, you add portlet modes by checking boxes on the wizard pages. For more information about using the wizard, see Section 55.2.4, "How to Create a PDK-Java Portlet." For each portlet mode that you select in the wizard, a basic skeleton is created. If you want to add a portlet mode after creating the portlet, you can do that manually by updating provider.xml and HTML or JSPs in JDeveloper.

The principles of implementing portlet modes using RenderManager are the same for all modes.

For more detailed information about the PDK runtime classes used in this section, see the JavaDoc in the Oracle Fusion Middleware Java API Reference for Oracle PDK Java:

For more information about the syntax of provider.xml, see the provider JavaDoc, also available on OTN.

Before You Begin

The steps that follow assume that you have:

  • Built a portlet using the Create Oracle PDK-Java Portlet wizard

  • Successfully registered the portlet's producer

  • Added the portlet to a page

To add a portlet mode:

  1. In the JDeveloper Application Navigator, open the application that contains the portlet.

  2. Expand the project that contains the portlet.

  3. Expand the Web Content node and then the htdocs node and then the node for the producer.

  4. Right-click the node for the portlet and choose New.

    The node for the portlet is located under Web Content > htdocs > provider.

  5. In the New Gallery, expand Web Tier, select HTML or JSP, and click OK.

    You must create an HTML file or a JSP for each mode to add to your portlet. For example, to implement Help mode, create an HTML file to provide the help content.

  6. In the resulting dialog, enter a file name for the HTML file or JSP and click OK.

  7. In the visual editor, edit the content of the page to implement the desired functionality.

    For example, for Help mode, you could add the following HTML:

    <p>This is the <i>Help</i> mode of your portlet!</p>
    
  8. In the Application Navigator, right-click the provider.xml file for the provider that owns the portlet and choose Open.

    The provider.xml file is located under Web Content > WEB-INF > providers > provider.

  9. Change the value of the appropriate tag for the mode you are adding to true.

    For example, if you are adding Help mode, change the hasHelp tag as follows:

    <hasHelp>true</hasHelp>
    

    This indicates to the PDK Framework that a link or icon to that mode should be rendered.

  10. Add the code to point to the HTML page or JSP that you created earlier for the mode.

    For example, for the Help page, add the following code:

    <helpPage>/htdocs/myprovider/myportlet/myHelpPage.html</helpPage>
    
  11. Save your changes.

  12. Redeploy your portlet. For more information, see Chapter 57, "Testing and Deploying Your Portlets."

    When you redeploy, JDeveloper automatically saves and compiles the code before deploying the portlet.

  13. Copy the HTML file or JSP you created and the updated provider.xml file to the WLS instance where you plan to deploy the portlet.

    This step is not necessary if you have redeployed the producer application to a server instance.

  14. Refresh the producer.

  15. Refresh the page containing your portlet.

    You should now be able to access the new mode. For example, if you added Help mode, you should be able to click the Help link.

56.3.3 How to Implement Public Parameters

PDK-Java and Oracle WebCenter Framework provide public and private portlet parameters to enable portlet developers to easily write reusable, complex portlets. The Create Oracle PDK-Java Portlet wizard in JDeveloper creates portlets that are set up to use parameters. This feature enables you to focus solely on adding business logic to your portlets and does not require any changes to provider.xml.

For an overview of parameters, see Section 53.2.11, "Public Portlet Parameter Support" and Section 53.2.12, "Private Portlet Parameter Support."

Before You Begin

The steps that follow assume that you have:


Note:

Each portlet is limited to 4K of data. The lengths of parameter and event names, display names, and descriptions all contribute toward this 4K limit. Hence, you should not use too many parameters and events for each portlet, or give them lengthy names and descriptions.

Using the Create Oracle PDK-Java Portlet wizard, you can easily create a portlet with public parameters. When you register the producer and drop the portlet on a page, the portlet's parameters are automatically linked to page variables.

To create a portlet with public parameters:

  1. In the JDeveloper Application Navigator, open the application that contains the portlet.

  2. Right-click the project under which you want to create your portlet, and choose New.


    Note:

    To create the portlet in an existing producer, right-click the producer's provider.xml file and choose Add Portlet. This takes you directly to the General Portlet Information page of the Create Oracle PDK-Java Portlet wizard.

  3. In the New Gallery, expand Web Tier, select Portlets and then Oracle PDK-Java Portlet, and click OK.

  4. Proceed through the Create Oracle PDK-Java Portlet wizard until you reach the Public Portlet Parameters page.

    See Section 55.2.4, "How to Create a PDK-Java Portlet" for basic information about going through the wizard.

  5. On the Public Portlet Parameters page (Figure 56-2), click Add.

    This adds a new row to the table of parameters.

    Figure 56-2 Public Portlet Parameters Page of Portlet Wizard

    Description of Figure 56-2 follows
    Description of "Figure 56-2 Public Portlet Parameters Page of Portlet Wizard"

  6. Replace the default values in the Name, Display Name, and Description fields with something more meaningful for your parameter.

  7. Add more parameters as required and then click Finish.

  8. In the Application Navigator, right-click the provider.xml file for the provider that owns the portlet and choose Open.

    The provider.xml file is located under Web Content > WEB-INF > providers > provider.

    You should see entries for the parameters that you added on the Public Portlet Parameters page in the wizard, for example, as shown in Example 56-6.

    Example 56-6 provider.xml Sample, Public Parameters

    <?xml version = '1.0' encoding = 'UTF-8'?><?providerDefinition version="3.1"?>
    <provider class="oracle.portal.provider.v2.DefaultProviderDefinition">
      <session>false</session>
      <passAllUrlParams>false</passAllUrlParams>
      <preferenceStore class=
         "oracle.portal.provider.v2.preference.FilePreferenceStore">
       <name>prefStore1</name>
       <useHashing>true</useHashing>
      </preferenceStore>
      <portlet class="oracle.portal.provider.v2.DefaultPortletDefinition">
          <id>1</id>
          <name>MyPortlet</name>
          <title>My Portlet</title>
          <description>My Portlet Description</description>
          <timeout>40</timeout>
          <showEditToPublic>false</showEditToPublic>
          <hasAbout>false</hasAbout>
          <showEdit>true</showEdit>
          <hasHelp>false</hasHelp>
          <showEditDefault>false</showEditDefault>
          <showDetails>false</showDetails>
          <inputParameter class=
            "oracle.portal.provider.v2.DefaultParameterDefinition">
           <name>Parameter_01</name>
           <displayName>Parameter_01</displayName>
           <description>My first parameter</description>
          </inputParameter>
          <inputParameter class=
            "oracle.portal.provider.v2.DefaultParameterDefinition">
           <name>Parameter_02</name>
           <displayName>Parameter_02</displayName>
           <description>My second parameter</description>
          </inputParameter>
          <inputParameter class=
            "oracle.portal.provider.v2.DefaultParameterDefinition">
           <name>Parameter_03</name>
           <displayName>Parameter_03</displayName>
          </inputParameter>
          <renderer class="oracle.portal.provider.v2.render.RenderManager">
             <renderContainer>true</renderContainer>
             <renderCustomize>true</renderCustomize>
             <autoRedirect>true</autoRedirect>
             <contentType>text/html</contentType>
             <showPage>/htdocs/myportlet/MyPortletShowPage.jsp</showPage>
             <editPage>/htdocs/myportlet/MyPortletEditPage.jsp</editPage>
          </renderer>
          <personalizationManager class=
            "oracle.portal.provider.v2.personalize.PrefStorePersonalizationManager">
           <dataClass>
            oracle.portal.provider.v2.personalize.NameValuePersonalizationObject
           </dataClass>
          </personalizationManager>
       </portlet>
    </provider>
    
  9. In the Application Navigator, right-click the portletnameShowPage.jsp for your portlet and choose Open.

    The file is located under Web Content > htdocs > provider > portlet.

    The portlet includes logic for retrieving the parameters, for example, as shown in Figure 56-2.

    Example 56-7 ShowPage.jsp Sample

    <%@page contentType="text/html; charset=windows-1252"
            import="oracle.portal.provider.v2.render.PortletRenderRequest"
            import="oracle.portal.provider.v2.http.HttpCommonConstants"
            import="oracle.portal.provider.v2.ParameterDefinition"
    %>
    <%
       PortletRenderRequest pReq = (PortletRenderRequest)
          request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST);
    %>
    <P>Hello <%= pReq.getUser().getName() %>.</P>
    <P>This is the <b><i>Show</i></b> render mode!</P>
    <%
       ParameterDefinition[] params =
           pReq.getPortletDefinition().getInputParameters();
    %>
    <p>This portlet's input parameters are...</p>
    <table align="left" width="50%" ><tr><td><span
    class="PortletHeading1">Name</span></td><td><span
    class="PortletHeading1">Value</span></td></tr>
    <%
       String name = null;
       String value = null;
       String[] values = null;
       for (int i = 0; i < params.length; i++)
       {
           name = params[i].getName();
           values = pReq.getParameterValues(name);
           if (values != null)
           {
               StringBuffer temp = new StringBuffer();
               for (int j = 0; j < values.length; j++)
               {
                   temp.append(values[j]);
                   if (j + 1 != values.length)
                   {
                       temp.append(", ");
                   }
               }
               value = temp.toString();
           }
           else
           {
               value = "No values have been submitted yet.";
           }
    %>
    <tr>
      <td><span class="PortletText2"><%= name %></span></td>
      <td><span class="PortletText2"><%= value %></span></td>
    </tr>
    <%
       }
    %>
    </table>
    
  10. Add logic to your portlet that allows it to submit parameter values entered by users.

  11. Create a second portlet using the same steps that simply displays parameter values that it retrieves.

  12. Register the producer with a WebCenter Portal application. For more information, see Section 59.2.3, "How to Register an Oracle PDK-Java Portlet Producer."

  13. Add the two portlets to a page in the application. For more information, see Section 59.3, "Adding Portlets to a Page."

  14. In the Structure window of the Application Navigator, right-click an element of the page and choose Go to Page Definition.

    The page definition should look similar to Example 56-8. Notice the variables at the page level and the parameters at the portlet level (indicated in bold).

    Example 56-8 Page Definition File Sample

    <?xml version="1.0" encoding="UTF-8"?>
    <pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel"
                    version="10.1.3.38.90" id="untitled1PageDef"
                    Package="view.pageDefs">
      <executables>
        <variableIterator id="variables">
          <variable Name="portlet1_Parameter_01" Type="java.lang.Object"/>
          <variable Name="portlet1_Parameter_02" Type="java.lang.Object"/>
          <variable Name="portlet1_Parameter_03" Type="java.lang.Object"/>
        </variableIterator>
        <portlet id="portlet1"       portletInstance="/oracle/adf/portlet/PdkPortletProducer1_1153936627784
              /applicationPortlets/Portlet1_abfc5a10_010c_1000_8003_82235f50d831"
            class="oracle.adf.model.portlet.binding.PortletBinding"
            xmlns="http://xmlns.oracle.com/portlet/bindings">
          <parameters>
            <parameter name="Parameter_01" pageVariable="portlet1_Parameter_01"/>
            <parameter name="Parameter_02" pageVariable="portlet1_Parameter_02"/>
            <parameter name="Parameter_03" pageVariable="portlet1_Parameter_03"/>
          </parameters>
        </portlet>
      </executables>
    </pageDefinition>
    
  15. Run the application.

  16. Enter values in the first portlet and the same values should be displayed in the second portlet.

56.3.4 How to Implement Private Parameters

In some cases, you might need a parameter that is known only to the portlet instance. These parameters are known as private parameters because they have no connection to the page and are known only to the portlet. Private parameters often come in handy when you are building navigation for your portlet. For example, if you have a portlet made up of multiple pages, then you can use these private parameters to jump to another resource of the portlet.

This section includes the following subsections:

56.3.4.1 About Private Parameters

Private parameters are used in classic web applications to pass information from links or forms in the browser back to the server. The server in turn takes actions and returns the appropriate content. For example, if the user of a dictionary web site asks for information about hedgehogs, then the URL submitted to the server might append a private parameter as follows:

http://dictionary.reference.com/search?q=Hedgehog

If the server is responsible for rendering the whole page and the client communicates directly with the server, then this form of URL works well. In a WebCenter Portal application, the client does not communicate directly with portlets. Instead, Oracle WebCenter Framework mediates between the client and the portlet. Moreover, because most pages have multiple portlets, Oracle WebCenter Framework communicates with multiple portlets.

For example, suppose a page contains two portlets, a thesaurus portlet and a dictionary portlet. Both portlets use q as a parameter to record the search queries made by the user. If the user queries the thesaurus portlet, then the URL used to rerequest the page with the updated thesaurus portlet must contain the thesaurus portlet's parameter, q. The thesaurus parameter must also be distinguished from dictionary portlet parameter 1, which performs the same function for that portlet.

You must ensure that the portlet meets the following criteria:

  • It properly qualifies its own parameters when they are built into links and forms.

  • It leaves unchanged any parameters that do not belong to it.

The following API call transforms an unqualified parameter name into a qualified parameter name:

HttpPortletRendererUtil.portletParameter(HttpServletRequest request, String param);

HttpPortletRendererUtil is in the package oracle.portal.provider.v2.render.http.

For example:

qualParamQ = HttpPortletRendererUtil.portletParameter(r, "q");

To fetch the value of a portlet parameter from the incoming request, you can use the following API:


Note:

The API converts the parameter name into the qualified parameter name before fetching the value from the incoming request. Hence, you need not perform this step.

PortletRenderRequest.getQualifiedParameter(String name)

PortletRenderRequest is in the package oracle.portal.provider.v2.render.

For example:

valueQ = r.getQualifiedParameter("q");

The other aspect of a portlet's responsibilities with private parameters is to not disturb the parameters on the URL that it does not own. The utilities you may use to ensure adherence to this rule are discussed in Section 56.3.4.3, "Building Links with the Portlet URL Types" and Section 56.3.4.4, "Building Forms with the Portlet URL Types."

56.3.4.2 About Portlet URL Types

When a portlet renders itself, Oracle WebCenter Framework passes it various URLs, which the portlet can then use to render links. You can fetch and manipulate these URLs to simplify the task of creating links. The following is a list of the URLs provided to portlets:

  • PAGE_LINK is a URL to the page upon which the portlet instance resides. You use this URL as the basis for all intraportlet links. If the portlet renders a link that navigates the user to another section of the same portlet, then this navigation must be encoded as a set of parameters using the PAGE_LINK.

  • DESIGN_LINK is a URL to the portlet's personalization (Edit mode) page. A portlet's Edit and Edit Defaults modes are not rendered on the same page as the portlet. The Edit and Edit Defaults modes take over the entire browser window. The portlet's Edit and Edit Defaults modes are not necessarily accessible to every user. It represents a minimal, static framework in which the portlet is free to render its personalization options. This URL is only of use when rendering Personalize links.

  • BACK_LINK is a URL to a useful return point from the current page where the portlet renders itself. For example, when the portlet is rendering its personalization page (Edit mode), this link refers to the page on which the portlet resides and from which the user navigated to the personalization page. Consequently, it is the link you encode in the buttons that accept or cancel the pending action. This URL is only useful for the desktop rendering of portlets (usually in Edit or Edit Defaults mode).

56.3.4.3 Building Links with the Portlet URL Types

To build links with Portlet URL types, you must access them and use them when writing portlet rendering code. To fetch the URL for a link, you call the following APIs in PDK-Java:

portletRenderRequest.getRenderContext().getPageURL()
portletRenderRequest.getRenderContext().getEventURL()
portletRenderRequest.getRenderContext().getDesignURL()
portletRenderRequest.getRenderContext().getLoginServerURL()
portletRenderRequest.getRenderContext().getBackURL()

In portlet navigation, you must add (or update) your portlet's parameters in the page URL. To perform this task, you can use the following API to build a suitable URL:

UrlUtils.constructLink(
    PortletRenderRequest pr,
    int linkType, -- UrlUtils.PAGE_LINK in this case
    NameValue[] params,
    boolean encodeParams,
    boolean replaceParams)

UrlUtils resides in the package called oracle.portal.provider.v2.url. Notice that you do not actually fetch the page URL yourself. Rather you use the supplied portlet URL type, UrlUtils.PAGE_LINK.

The parameter names in the params argument should be fully qualified. Moreover, if you properly qualify the parameters, UrlUtils.constructLink with the appropriate linkType does not disturb other URL parameters that are not owned by the portlet.

An alternative version of UrlUtils.contructLink accepts a URL as the basis for the returned URL. If you require an HTML link, then you can use UrlUtils.constructHTMLLink to produce a complete anchor element.

The following example portlet, ThesaurusLink.jsp, uses the parameter q to identify the word for which to search the thesaurus. It then creates links on the found, related words that the user may follow to get the thesaurus to operate on that new word. To see the initial submission form that sets the value of q, see the example in Section 56.3.4.4, "Building Forms with the Portlet URL Types."

<%
    String paramNameQ = "q";
    String qualParamNameQ = 
    HttpPortletRendererUtil.portletParameter(paramNameQ);
    PortletRenderRequest pRequest = (PortletRenderRequest)
        request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST);
    String paramValueQ = pRequest.getQualifiedParameter(paramNameQ);
%>
<!-- Output the HTML content -->
<center>
    Words similar to <%= paramValueQ %>
    <br>
    Click the link to search for words related to that word.
    <br>
    <ul>
<%
        String[] relatedWords = Thesaurus.getRelatedWords(paramValueQ);
        NameValue[] linkParams = new NameValue[1]; 
        for (int i=0; i<=relatedWords.length; i++)
        {
            linkParams[0] = new NameValue(
                qualParamNameQ, relatedWords[i]);
%>
            <li>
            <b> <%= relatedWords[i] %> </b>
            <%= UrlUtils.constructHTMLLink(
                pRequest,
                UrlUtils.PAGE_LINK,
                "(words related to " + relatedWords[i] + ")",
                "",
                linkParams,
                true,
                true)%>
           </li>
<%
        }
%>
   </ul>
</center>

56.3.4.4 Building Forms with the Portlet URL Types

The use of portlet parameters in forms is similar to their use in links. The following two fundamental rules continue to apply:

  • Qualify the portlet's parameter names.

  • Do not manipulate or remove the other parameters on the incoming URL.

In terms of markup and behavior, forms and links differ quite considerably. However, just as with links, PDK-Java contains utilities for complying with these two basic rules.

A parameter name is just a string, whether it is a link on a page or the name of a form element. Therefore, the code for properly qualifying the portlet's parameter name is the same as that described in Section 56.3.4.3, "Building Links with the Portlet URL Types."

Forms differ from links in the way you ensure that the other parameters in the URL remain untouched. Once you open the form in the markup, you can make use of the following APIs:

UrlUtils.htmlFormHiddenFields(pRequest,UrlUtils.PAGE_LINK, formName);
UrlUtils.htmlFormHiddenFields(someURL);

where formName = UrlUtils.htmlFormName(pRequest,null).


Note:

Just as parameters in URLs and element names in forms require qualification to avoid clashing with other portlets on the page, form names must be fully qualified because any given page might have several forms on it.

The htmlFormHiddenFields utility writes HTML hidden form elements into the form, one form element for each parameter on the specified URL that is not owned by the portlet.

<INPUT TYPE="hidden" name="paramName" value="paramValue">

Thus, you need only to add their portlet's parameters to the form.

The other item of which you should be aware is how to derive the submission target of your form. In most cases, the submission target is the current page:

formTarget = UrlUtils.htmlFormActionLink(pRequest,UrlUtils.PAGE_LINK)

The value of formTarget can be the action attribute in an HTML form or the target attribute in a SimpleForm. Even though the method name includes HTML, it actually just returns a URL and thus you can use it in mobile portlets, too.

The following example form renders the thesaurus portlet's submission form. For the portlet that results from the submission of this form, see the example in Section 56.3.4.3, "Building Links with the Portlet URL Types."

<%
    String paramNameSubmit = "submit";
    String paramNameQ = "q";
    String qualParamNameQ =
        HttpPortletRendererUtil.portletParameter(paramNameQ);
    String qualParamNameSubmit = 
    HttpPortletRendererUtil.portletParameter(paramNameSubmit);
    PortletRenderRequest pRequest = (PortletRenderRequest)
        request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST);
    String formName = UrlUtils.htmlFormName(pRequest,"query_form");
%>
<!-- Output the HTML content -->
<center>
    <b>Thesaurus</b>
    Enter the word you want to search for
    <form name="<%= formName %>" method="POST" 
        action="<%= UrlUtils.htmlFormActionLink(pRequest,UrlUtils.PAGE_LINK) %>"> 
        <%= UrlUtils.htmlFormHiddenFields(pRequest,UrlUtils.PAGE_LINK, formName)%> 
        <table><tr><td>
            Word of interest:
        </td><td>
            <input
                type="text"
                size="20"
                name="<%= qualParamNameQ %>"
                value="">
        </td></tr></table>
        <input type=submit name="<%= qualParamNameSubmit %>" Value="Search">
    </form>
</center>

56.3.4.5 Implementing Navigation within a Portlet

You can implement navigation within a portlet in one of three ways:

  • Pass navigation information in rendered URLs using private portlet parameters. Branching logic within the portlet code then determines which section of the portlet to render based on the URL. This option represents a small extension to the thesaurus example presented in Section 56.3.4.3, "Building Links with the Portlet URL Types" and Section 56.3.4.4, "Building Forms with the Portlet URL Types." Basically, instead of performing thesaurus search operations using the value of parameter q, the portlet branches based on the parameter value and renders different content accordingly.

  • Pass navigation information as described in the previous item but use PDK-Java to interpret the parameter and thus branch on its value. This option requires some further changes to the thesaurus example and is more fully explained later in this section.

  • Use session storage to record the portlet state and private parameters to represent actions rather than explicit navigation. This method provides the only way that you can restore the portlet to its previous state when the user navigates off the page containing the portlet. Once the user leaves the page, all private portlet parameters are lost and you can only restore the state from session storage, assuming you previously stored it there. This option requires that you understand and implement session storage. For more information about implementing session storage, see Section 56.3.6, "How to Access Session Information."

The following portlet code comes from the multipage example in the sample producer of PDK-Java:

<portlet>
    <id>11</id> 
    <name>Multipage</name> 
    <title>MultiPage Sample</title> 
    <shortTitle>MultiPage</shortTitle> 
    <description>
        This portlet depicts switching between two screens all 
        in an application page.
    </description> 
    <timeout>40</timeout> 
    <timeoutMessage>MultiPage Sample timed out</timeoutMessage> 
    <renderer class="oracle.portal.provider.v2.render.RenderManager">
        <contentType>text/html</contentType> 
        <showPage>/htdocs/multipage/first.jsp</showPage> 
        <pageParameterName>next_page</pageParameterName> 
    </renderer>
</portlet>

Note:

The value of pageParameterName is the name of a portlet parameter, next_page, that the PDK-Java framework intercepts and interprets as an override to the value of the showPage parameter. If the PDK-Java framework encounters the qualified version of the parameter when the multipage portlet is requested, then it renders the resource identified by next_page rather than first.jsp. PDK-Java does not render the parameter within the portlet, that responsibility falls to the portlet.

You can modify the thesaurus example to operate with the use of this parameter. Specifically, you can use the form submission portlet to be the input for the thesaurus (the first page of the portlet), then navigate the user to the results page, which contains links to drill further into the thesaurus. The following examples illustrate these changes.


Note:

The example that follows is most useful for relatively simple cases, such as this thesaurus example. If your requirements are more complex (for example, you want to build a wizard experience), then you should consider using an MVC framework such as Struts. For information about how to build portlets from struts applications, see Section 56.5, "Creating a Struts Portlet."

ThesaurusForm.jsp:

<%
    PortletRenderRequest pRequest = (PortletRenderRequest)
        request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST);
    String paramNameSubmit = "submit";
    String paramNameQ = "q";
    String qualParamNameQ =
        HttpPortletRendererUtil.portletParameter(pRequest, paramNameQ);
    String qualParamNameSubmit = 
    HttpPortletRendererUtil.portletParameter(pRequest, paramNameSubmit);
    String formName = UrlUtils.htmlFormName(pRequest,"query_form");
%>
<!-- Output the HTML content -->
<center>
    <b>Thesaurus</b>
    Enter the word you want to search for
    <form name="<%= formName %>" method="POST" 
        action="<%= UrlUtils.htmlFormActionLink(pRequest,UrlUtils.PAGE_LINK) %>"> 
        <%= UrlUtils.htmlFormHiddenFields(pRequest,UrlUtils.PAGE_LINK, formName)
%> 
        <%= UrlUtils.emitHiddenField(
                HttpPortletRendererUtil.portletParameter(request, "next_page"),
                "htdocs/path/ThesaurusLink.jsp" ) %>
        <table><tr><td>
            Word of interest:
        </td><td>
            <input
                type="text"
                size="20"
                name="<%= qualParamNameQ %>"
                value="">
        </td></tr></table>
        <input type=submit name="<%= qualParamNameSubmit %>" Value="Search">
    </form>
</center>

Notice how next_page must be explicitly set to point to ThesaurusLink.jsp. If you do not explicitly set next_page in this way, then it defaults to the resource registered in provider.xml, which is ThesaurusForm.jsp.

ThesaurusLink.jsp:

<%
    PortletRenderRequest pRequest = (PortletRenderRequest)
        request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST);
    String paramNameQ = "q";
    String paramNameNextPage = "next_page";
    String qualParamNameQ = 
    HttpPortletRendererUtil.portletParameter(pRequest, paramNameQ);
    String qualParamNameNextPage = 
        HttpPortletRendererUtil.portletParameter(pRequest, paramNameNextPage);
    String paramValueQ = pRequest.getQualifiedParameter(paramNameQ);
%>
<!-- Output the HTML content -->
<center>
    Words similar to <%= paramValueQ %>
    <br>
    Click the link to search for words related to that word.
    <br>
    <ul>
<%
        Thesaurus t = new Thesaurus();
        String[] relatedWords = t.getRelatedWords(paramValueQ);
        NameValue[] linkParams = new NameValue[2]; 
        linkParams[0] = new NameValue(
            qualParamNameNextPage, "htdocs/path/ThesaurusLink.jsp");
        for (int i=0; i<relatedWords.length; i++)
        {
            linkParams[1] = new NameValue(
                qualParamNameQ, relatedWords[i]);
%>
            <li>
            <b> <%= relatedWords[i] %> </b>
            <%= UrlUtils.constructHTMLLink(
                pRequest,
                UrlUtils.PAGE_LINK,
                "(words related to " + relatedWords[i] + ")",
                "",
                linkParams,
                true,
                true)%>
           </li>
<%
        }
%>
   </ul>
   <a href="<%=XMLUtil.escapeXMLAttribute
               (pRequest.getRenderContext().getPageURL())%>">
      Reset Portlet
   </a>
</center>

56.3.4.6 Restricting Navigation to Resources

One limitation of implementing navigation with private parameters is that users could potentially navigate to portlet resources that you prefer to restrict. To control navigation to restricted resources, you can create a whitelist of acceptable resources to which a user may navigate. If you do not construct a whitelist to restrict navigation, then your portlet's resources are accessible according to the following default rules:

  • Any path immediately beneath the servlet root context is navigable. For example, /index.jsp is accessible but /WEB-INF/web.xml is not.

  • Any path under the htdocs directory is navigable. For example, both /htdocs/multipage/first.jsp and /htdocs/lottery/lotto.jsp are accessible.

To change this default behavior, you can add allowable path values to the provider definition file, provider.xml. For example, suppose you have a portlet where a JSP is used as a controller to forward requests to other pages depending on the pageParameterName private parameter. The XML excerpt in Example 56-9 allows resources under /htdocs/multiportlet to be shown. All other resources are restricted.

Example 56-9 Whitelist Excerpt from the provider.xml File

<portlet class="oracle.portal.provider.v2.DefaultPortletDefinition">
   <id>1</id>
   <name>Multipage</name>
   <title>A MultiPage Portlet</title>
   ...
   <renderer class="oracle.portal.provider.v2.render.RenderManager">
          <contentType>text/html</contentType>
          <showPage>/htdocs/multiportlet/controller.jsp</showPage>
          <pageParameterName>show_page</pageParameterName>
          <allowedPath>/htdocs/multiportlet/*</allowedPath>
   </renderer>
</portlet>

The pattern matching rules for this feature are similar to URL pattern matching in web.xml files. The rules are as follows:

  • To match the defined patterns, the resource path must exactly match unless wildcards are used.

  • The first wildcard is for path matching and consists of a string beginning with / and ending with /*. Any resource whose path starts with this string is matched. For an <allowedPath> value of /htdocs/sub1/*, valid values of the private parameter include /htdocs/sub1/file.jsp and /htdocs/sub1/sub2/file2.jsp.

  • The second wildcard is for file type matching and consists of a string starting with *. and ending with a file extension. Valid values for the page parameter end with that file extension. For an <allowedPathvalue> of *.jsp, valid values of the private parameter include /htdocs/sub1/file.jsp and /htdocs/sub1/file2.jsp.

56.3.5 How to Use JNDI Variables

When writing Java portlets, you may set deployment-specific properties through the JNDI service such that their values may be retrieved from your producer code. In this way, you can specify any property in a producer deployment and then easily access it anywhere in your producer code.

You can use JNDI variables to change producer property values after the producer has been deployed. The environment entry must be declared in web.xml. It can then be updated on deployment using a deployment plan.

PDK-Java provides utilities to enable the retrieval of both producer and non-producer JNDI variables within a Java EE container.

This section includes the following subsections:

56.3.5.1 Declaring JNDI Variables

You declare JNDI variables in the web.xml file for your producer. The format for declaring a JNDI variable is as follows:

<env-entry>
    <env-entry-name>variableName</env-entry-name>
    <env-entry-type>variableType</env-entry-type>
    <env-entry-value>variableValue</env-entry-value> 
</env-entry>

The env-entry-name element contains the name by which you want identify the variable. env-entry-type contains the fully qualified Java type of the variable. env-entry-value contains the variable's default value.

This section includes the following subsections:

56.3.5.1.1 Variable Types

In the env-entry-type element, you must supply the fully qualified Java type of the variable, which is expected by your Java code. The Java types you may use in your JNDI variables are as follows:

  • java.lang.Boolean

  • java.lang.String

  • java.lang.Integer

  • java.lang.Double

  • java.lang.Float

The Java EE container uses these type declarations to automatically construct an object of the specified type and gives it the specified value when you retrieve that variable in your code.

56.3.5.1.2 Variable Naming Conventions

The PDK-Java defines environment variables that can be set at the individual producer service level or at the web application level. To avoid naming conflicts between different producer services or different application components packaged in the same web application, Oracle recommends you devise some naming convention.


Note:

If you use the EnvLookup method, then you must use oracle/portal/provider/service/property. You cannot substitute your own company name or component in this case.

For example:

  • Producer service-specific names should be of the form:

    company/component name/producer name/variable name
    
  • Shared names must be of the form:

    company/component name/producer name/global
    

where:

  • company is the name of the company owning the application.

  • component name is the name of the application or component with which the producer is associated.

  • producer name is the service name of the producer.

  • variable name is the name of the variable itself.

As you can see, these naming conventions are similar to those used for Java packages. This approach minimizes the chance of name collisions between applications or application components. PDK-Java provides utilities that enable you to retrieve variables in this form without hard coding the service name of the producer into your servlets or JSPs. The service name need only be defined in the producer's WAR file. For more information about retrieving JNDI variables, see Section 56.3.5.3, "Retrieving JNDI Variables."

56.3.5.1.3 Examples

The following examples illustrate producer variable names:

oracle/portal/myProvider/myDeploymentProperty
oracle/portal/myprovider/myProperties/myProperty

The following example illustrates non-producer variable names:

oracle/portal/myOtherProperty

56.3.5.2 Setting JNDI Variable Values

In your producer deployment, you may want to set a new value for some or all of your JNDI variables. You can perform this task by setting the values manually within a WLS deployment plan. Deployment plans can be created for the producer deployment through the WLS console.

To set variable values manually within a deployment plan:

  1. Go to the producer deployment with the WLS console and create a new deployment plan if one does not exist.

  2. Edit the deployment plan XML file. For each deployment property you want to set, add the following variable definition directly under the <deployment-plan> tag:

    <variable-definition>
      <variable>
        <name>jndi_var_def</name>
        <value>false</value>
      </variable>
    </variable-definition>
    
  3. To tie this variable definition to the actual JNDI variable, add the following for each property under the WEB-INF/web.xml module descriptor (oracle/portal/sample/rootDirectory is used as an example):

    <module-descriptor external="false">
      <root-element>web-app</root-element>
      <uri>WEB-INF/web.xml</uri>
      <variable-assignment>
        <name>jndi_var_def</name>
        <xpath>/web-app/env-entry/[env-entry-name="oracle/portal/sample/rootDirectory"]/env-entry-value</xpath>
       </variable-assignment>
    </module-descriptor>
    
  4. Save and close the file.

  5. Select Update on the producer deployment to apply the deployment plan for the new settings to take effect.

56.3.5.3 Retrieving JNDI Variables

JNDI is a standard Java EE technology. As such, you can access JNDI variables through Java EE APIs. For example:

String myVarName = "oracle/portal/myProvider/myVar"
String myVar = null;
try 
{
   InitialContext ic = new InitialContext();
   myVar = (String)ic.lookup("java:env/" + myVarName);
}
catch(NamingException ne)
{
   exception handling logic
}

In addition to the basic Java EE APIs, PDK-Java includes a simple utility class for retrieving the values of variables defined and used by the PDK itself. These variables conform to the naming convention described in Section 56.3.5.1.2, "Variable Naming Conventions" and are of the form:

oracle/portal/provider_service_name/variable_name
oracle/portal/variable_name

To use these APIs, you need only provide the provider_service_name and the variable_name. The utilities construct the full JNDI variable name, based on the information you provide, and look up the variable using code similar to that shown earlier and return the value of the variable.

The EnvLookup class (oracle.portal.utils.EnvLookup) provides two lookup() methods. One retrieves producer variables and the other retrieves non-producer variables. Both methods return a java.lang.Object, which can be cast to the Java type you are expecting.

The following code example illustrates the retrieval of a producer variable:

EnvLookup el = new EnvLookup();
String s = (String)el.lookup(myProviderName, myVariableName);

myProviderName represents the service name for your producer, which makes up part of the variable name. myVariableName represents the portion of the variable name that comes after the producer's service name. The example assumes the variable being retrieved is of type java.lang.String.

To retrieve a non-producer variable, you use the same code, you pass only one parameter, the variable name, to the lookup(), again excluding the oracle/portal prefix.

EnvLookup el = new EnvLookup();Object o = el.lookup(myVariableName);

Table 56-3 shows the JNDI variables provided by default with PDK-Java. If you do not declare these variables, then PDK-Java looks for their values in their original locations (web.xml and the deployment properties file).

Table 56-3 PDK-Java JNDI Variables

Variable Description
oracle/portal/provider/provider_name/autoReload

Boolean auto reload flag. Defaults to true.

oracle/portal/provider/provider_name/definition

Location of producer's definition file.

oracle/portal/provider/global/log/logLevel

Log setting (0 through 8). 0 being no logging and 8 the most possible logging.

oracle/portal/provider/provider_name/maxTimeDifference

Producer's HMAC time difference.

oracle/portal/provider/<service_name>/resourceUrlKey

Authentication key for resource proxying through the Parallel Page Engine. See Oracle Fusion Middleware Administrator's Guide for Oracle Portal for more information.

oracle/portal/provider/provider_name/rootDirectory

Location for producer personalizations. No default value.

oracle/portal/provider/provider_name/sharedKey

HMAC shared key. No default value.

oracle/portal/provider/provider_name/showTestPage

(non-producer) A Boolean flag that determines if a producer's test page is accessible. Defaults to true.

oracle/portal/provider/global/transportEnabled

A Boolean flag that determines whether Edit Defaults personalizations may be exported and imported.


56.3.6 How to Access Session Information

When a user accesses a page, it initiates a public, unauthenticated session and tracks information about the session across requests. If the user logs in, then this session becomes an authenticated session of the logged-in user. This session terminates when any of the following occur:

  • The browser session terminates (that is, the user closes all the browser windows).

  • The user explicitly logs out.

  • The session times out because the user's idle time exceeds the configured limit.

As part of the metadata generation, all of the producers that contribute portlets to the page are contacted, if they specified during registration that they be called for some special processing. This call allows producers to do processing based on the user session, log the user in the producer's application if needed, and establish producer sessions. For producers, this call is referred to as initSession. As most web-enabled applications track sessions using cookies, this API call enables the producer of the application to return cookies.

You can use the session store to save and retrieve information that persists during the portal session. This information is only available, and useful, to you during the life of the session. You should store only temporary information in the session store. Application developers may use the session store to save information related to the current user session. Data in the session store can be shared across portlets.

If the information you want to store must persist across sessions, then you may want to store it in the preference store instead. Some common applications of the session store are as follows:

  • To cache data that is expensive to load or calculate (for example, search results).

  • To cache the current state of a portlet (for example, the current range, or page, of search results displayed in the portlet, or sequence of events performed by user).

Before you implement session storage, you should carefully consider the performance costs. Because portlets and producers are remote, it can be a relatively expensive operation to create and maintain even a small amount of information in the session store. For this reason, you may want to avoid altogether any session storage for public pages that are accessed frequently by many users.

Furthermore, while using the session store with producers, you create a stateful application that tracks state information in memory. Similarly, you create a stateful application if you use the file-system implementation of preference store.

If scalability is an important concern for you, then a stateful application may cause you problems. Stateful applications can affect the load-balancing and failover mechanism for your configuration. Even though you may deploy multiple middle-tiers, you must implement sticky routing (where the same node handles subsequent requests in the same session) to track state. Sticky routing may result in lopsided load-balancing or loss of session data in case a node crashes, affecting failover. This issue is one reason why many developers prefer to build stateless applications. However, if scalability is not a concern, then a stateful application should present no problems for you.

The PDK Framework represents the session with a ProviderSession object, which is established during the call to the Provider Instance's initSession method. This object is associated with the ProviderUser. To make data persistent between requests, you must write data into the session object using the setAttribute method on the ProviderSession object. This method maps a java.lang.Object to a java.lang.String and stores that mapping inside the session object. The String can then be used to retrieve the Object during a subsequent request, provided the session is still valid.

A producer session may become invalid for the following reasons:

  • The session times out.

  • The invalidate method on ProviderSession is called.

  • The JVM process running the servlet container is terminated.

All portlets contained by the same ProviderInstance share the same session for a particular ProviderUser. Therefore, data unique to a particular portlet instance must be mapped to a unique String in the session. This is accomplished using the portletParameter method in the PortletRendererUtil class. This method makes a supplied String parameter or attribute name unique to a PortletInstance, by prefixing it with a generated identifier for that instance. You can use the returned instance-specific name to write portlet instance data into the session.

For more detailed information about the PDK Framework classes, see the JavaDoc in the Oracle Fusion Middleware Java API Reference for Oracle PDK Java.

In the example in this section, session storage is used to count the number of times your portlet has rendered in Shared Screen mode.

Before You Begin

The steps that follow assume that you have:

To implement session storage:

  • Import ProviderSession, PortletRendererUtil, and HttpPortletRendererUtil.

  • Retrieve the producer session.

  • Read and write the session by accessing it from within your Java portlet.

  • Set the session to true in provider.xml.

  • Register the producer for session storage and set the Login Frequency.

The steps that follow describe how to add a session count to your portlet that displays how many times the portlet has been rendered for the current session.

  1. After using the wizard to create a portlet, you can edit the JSP for the Show page in Oracle JDeveloper. You must import the following classes:

    <%@page contentType="text/html; charset=windows-1252"
    import="oracle.portal.provider.v2.render.PortletRenderRequest"
    import="oracle.portal.provider.v2.http.HttpCommonConstants"
    import="oracle.portal.provider.v2.ProviderSession"
    import="oracle.portal.provider.v2.render.PortletRendererUtil"
    import="oracle.portal.provider.v2.render.http.HttpPortletRendererUtil"
    %>
    
  2. Insert code that checks for a valid session first and then increments the count and displays it. If the session is valid and a previously stored value exists, then you display the value, increment the count, and store the new value. If the session is valid but no previously stored value exists, then you initialize a new count starting with 1, and display and store the value. You also want to obtain the unique string key for this portlet and then use an it in an array to count the session. If no session information was received, then you want to provide information to the user indicating they may need to log in again.

    <%
    PortletRenderRequest pReq = (PortletRenderRequest)
    request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST);
    ProviderSession pSession = pReq.getSession();
      if (pSession != null)
      {
        String key = PortletRendererUtil.portletParameter(pReq, "count");
        Integer i = (Integer)pSession.getAttribute(key);
        if (i == null)
        {
          i = new Integer(0);
        }
        i = new Integer(i.intValue()+1);
        pSession.setAttribute(key, i);
    %>
    
    <p>Render count in this session: <%=i%> </p>
    
    <% 
      } 
      else 
      {
    %>
    
    <p>The session has become invalid</p>
    <br>
    Please log out and log in again.
    <%
      } 
    %>
    
  3. By default, the wizard does not set session to true in provider.xml. You must update this flag in order for the producer to receive session information from the portal. You should only set this tag to true if you are using session information in your producer or portlets. By setting this flag to true, extra load is added to the producer calls.

    <provider class="oracle.portal.provider.v2.DefaultProviderDefinition">
    <session>true</session>
    
  4. Register your producer with session support. For a reminder on how to register your portlet, see Section 57.4, "Registering and Viewing Your Portlet."

  5. If you have not added your Java portlet to a page, then do so now. Ensure that you perform the following tasks:

    • Refresh the producer to accept the new changes.

    • Re-login in case your session is no longer valid.

56.3.7 How to Enhance Portlet Performance with Caching

Once you have completed the basic functionality of your portlet, you may want to turn your attention to portlet performance.

Caching is a common technique for enhancing the performance of web sites that include a great deal of dynamic content. The overhead involved in retrieving data and generating the output for dynamic content can be significantly reduced by proxying requests through a local agent backed by a large, low-latency data store known as a cache. The cache agent responds to a request in one of two ways, as follows:

  • If a valid version of the requested content exists in the cache, then the agent simply returns the existing cached copy, thus skipping the costly process of content retrieval and generation. This condition is called a cache hit.

  • If a valid version of the requested content does not exist in the cache, then the agent forwards the request to its destination and awaits the return of the content. The agent returns the content to the requester and stores a local copy in its cache for reuse if a subsequent request for the same content arises. This condition is called a cache miss.

Producers generate dynamic content (that is, portlets) and they reside remotely from the WebCenter Portal application instance on which they are deployed. As such, caching might improve their performance. The architecture lends itself well to caching. You can cache the portlets rendered by your producer and reuse the cached copies to handle subsequent requests, minimizing the overhead your producer imposes on page assembly.

The producer can use any one of three different caching methods, depending upon which one is best suited to the application. The methods differ chiefly in how they determine whether content is still valid. Following are the three caching methods:

  • Expiry-based Caching: When a producer receives a render request, it stamps its response with an expiry time. The rendered response remains in the cache and fills all subsequent requests for the same content until its expiry time passes. This caching scheme is perhaps the simplest and most performant because the test for cache validity requires very little overhead and does not involve any network round trips. Expiry-based caching suits applications where the content has a well-defined life span. For content with a less certain life span, however, expiry-based caching is less effective. For more information, see Section 56.3.7.1, "Activating Caching" and Section 56.3.7.2, "Adding Expiry-Based Caching."

  • Validation-based Caching: When a producer receives a render request, it stamps its response with a version identifier (or E Tag). The response goes into the cache, but, before the consumer can reuse the cached response, it must determine whether the cached version is still valid. It sends the producer a render request that includes the version identifier of the cached content. The producer determines whether the version identifier remains valid. If the version identifier is still valid, then the producer immediately sends a lightweight response to the consumer without any content, which indicates the cached version can be used. Otherwise, the producer generates new content with a new version identifier, which replaces the previously cached version. In this form of caching, the consumer must always confirm with the producer whether the content is up to date. The validity of the cached copy is determined by some logic in the producer. The advantage of this approach is that the producer controls the use of the cached content rather than relying on a fixed period. For more information, see Section 56.3.7.1, "Activating Caching" and Section 56.3.7.3, "Adding Validation-Based Caching."

This section includes the following subsections:

Before You Begin

The steps that follow assume that you have:

56.3.7.1 Activating Caching

To use the caching features in your producers, you must first activate the middle tier cache. This cache is known as the PL/SQL Cache because it is the same cache used by mod_plsql, the Oracle HTTP Server plug-in that calls database procedures, and hence database producers, over HTTP.

Usually, your administrator is responsible for the configuration details of caching.

56.3.7.2 Adding Expiry-Based Caching

Expiry-based caching is a simple caching scheme to implement, and can be activated declaratively in your XML producer definition. You can set an expiry time for the output of any ManagedRenderer you use by setting its pageExpires property to the number of minutes you want the output to be cached for. For example, suppose you want portlet output to be cached for one minute.

To add expiry-based caching:

  1. After you have used the Create Oracle PDK-Java Portlet wizard to build a portlet as described in Section 55.2.4, "How to Create a PDK-Java Portlet," edit the provider.xml file and set the pageExpires property tag of showPage to 1. This sets an expiry entry of one minute for the portlet.

    By default the wizard generates a standard and compressed tag for showPage. Expand the tag to include a subtag of pageExpires:

    <showPage class="oracle.portal.provider.v2.render.http.ResourceRenderer">
       <resourcePath>/htdocs/mycacheportlet/MyCachePortletShowPage.jsp
          </resourcePath>
       <pageExpires>1</pageExpires>
    </showPage>
    
  2. Test that the portlet is cached for 1 minute by adding some JSP code to your show page. You can simply add the current time to your JSP.

    <%@page contentType="text/html; charset=windows-1252"
       import="oracle.portal.provider.v2.render.PortletRenderRequest"
       import="oracle.portal.provider.v2.http.HttpCommonConstants"
       import="java.util.Date"
       import="java.text.DateFormat"
    %>
    
    <%
     PortletRenderRequest pReq = (PortletRenderRequest)
       request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST);
     DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG,
       DateFormat.LONG,pReq.getLocale());
     String time = df.format(new Date());
    %>
    
    <P>Hello <%=pReq.getUser().getName() %>.</P>
    <P>This is the <b><i>Edit</i></b> render mode!</P>
    <P>This information is correct as of <%=time%>.</P>
    

    When viewing the portlet, you see that the time (including seconds) is constant for one minute. After the time has expired, the portlet displays the most current time and a new cache is set.

56.3.7.3 Adding Validation-Based Caching

Adding validation-based caching requires slightly more effort, but gives you explicit control over exactly which requests to your producer are cache hits. As an example, you may want to update the cache only when data within the portlet has changed. To implement this algorithm, you must override the prepareResponse method. The signature of the BaseManagedRenderer.prepareResponse method is:

public boolean prepareResponse(PortletRenderRequest pr)
                        throws PortletException,
                               PortletNotFoundException

In your version of prepareResponse(), do the following:

  • Retrieve the cached version identifier set by the consumer in the render request by calling the HttpPortletRendererUtil.getCachedVersion() method:

    public static java.lang.String getCachedVersion
        (PortletRenderRequest request)
    
  • If the portlet finds the previously cached version valid, then the appropriate header must be set by calling the HttpPortletRendererUtil.useCachedVersion() method. It also instructs the RenderManager that it is not necessary to call renderBody() to render the portlet body.

    public static void useCachedVersion(PortletRenderRequest request)
    

    Otherwise, use HttpPortletRendererUtil.setCachedVersion() to generate a new version of the portlet, which is cached. It also indicates to the consumer that the renderBody() method has to be called to regenerate the portlet content.

    public static void setCachedVersion(PortletRenderRequest request,
                                        java.lang.String version,
                                        int level)
                                 throws java.lang.IllegalArgumentException
    

For validation-based caching, you need not update provider.xml. You can view the portlet by refreshing the page or adding the portlet to a page and updating the content. If the content has changed, then the portlet shows the new content. If the content has not changed, then a cached version of the portlet is displayed.

56.4 Testing Portlet Personalization

If you have implemented personalization for your portlet, then the Personalize link only appears on the portlet for authenticated users. Hence, to test the personalization of a portlet (the Personalize link), you must have some form of security implemented for the application consuming the portlet. For testing purposes, you may prefer to just configure the most basic authentication possible. For more information, see Section 63.12, "Configuring Basic Authentication for Testing Portlet Personalization."

56.5 Creating a Struts Portlet

Oracle PDK contains extensions to integrate Apache Struts applications. This section explains how to build a portlet from an existing struts application. You can also follow these steps to create a portlet that uses the Model View Controller paradigm. The PDK-Java extensions described in this section rely on Apache Struts 1.1.

You can use the Struts framework to enhance portlet behavior. For example, a Struts controller may be used for page flow within a portlet. A portlet renderer is used as a bridge between portlet render requests and Struts servlet requests

The following code shows a portion of the producer definition file (provider.xml):

...
<renderContainer>true</renderContainer>
    <renderCustomize>true</renderCustomize>
    <autoRedirect>true</autoRedirect>
    <contentType>text/html</contentType>
    <showPage class="oracle.portal.provider.v2.render.http.StrutsRenderer">
        <defaultAction>showCustomer.do</defaultAction>
    </showPage>
</renderer>
...

The showPage of the Struts portlet contains two important components:

The PDK-Java enables you to easily develop a view (portlet view) of your Struts application. This view enforces a consistent look and feel of your Struts portlet using portal styles, and enables the end user to use the application within the portal.

To create a Struts portlet, you must use the PDK-Java Struts tags, which are extensions of the default Struts JSP tags. This development process is similar to that of creating a standalone Struts application. For portlets in a producer application to use the Struts framework, the Struts components must be part of the same web application.

To publish a part of an existing Struts application as a portlet, Oracle recommends that you first create a new view to serve as the portlet view of your application. This view uses existing objects (Actions, ActionForm, and so on) with a new mapping and new JSPs.


Note:

Although Oracle recommends that you create a portlet view of your application, you could alternatively replace your application's struts tags with PDK-Java struts tags. This approach enables your application to run both as a standalone struts application and a portlet.

In this example, you create a portlet that enables you to add a new entry to a blog. Figure 56-3 and Figure 56-4 show how you submit a blog and save a blog entry.

Figure 56-3 Submitting a Blog

Shows updating a BLOG.
Description of "Figure 56-3 Submitting a Blog"

Figure 56-4 Saving a Blog Entry

Shows saving a BLOG.
Description of "Figure 56-4 Saving a Blog Entry"

prepareNewBlog is a simple empty action that redirects the request to the enterNewBlog.jsp page. This page shows a form for submitting a new blog.

The corresponding entry in the struts-config.xml is:

<action path="/prepareNewBlog" scope="request"
    type="view.PrepareNewBlogAction" >
    <forward name="success" path="/view/enterNewBlog.jsp"/>
</action>
<action path="/saveNewBlog" name="blogForm" scope="request"
    type="view.SaveNewBlogAction" input"/view/enterNewBlog.jsp"  >
    <forward name="success" path="/view/newBlogConfirmation.jsp"/>
</action>

This section includes the following subsections:

56.5.1 How to Create a New Flow and View to Host the Portlet Actions

To create a new view, first create a new set of ActionMappings (page flow) that redirects the various actions and requests to Portal-specific JSPs.

<action path="/portal/prepareNewBlog" scope="request"
    type="view.PrepareNewBlogAction" >
    <forward name="success" path="/view/portal/enterNewBlog.jsp"/>
</action>
<action path="/portal/saveNewBlog" name="blogForm" scope="request"
    type="view.SaveNewBlogAction" input="/view/enterNewBlog.jsp"  >
    <forward name="success" path="/view/portal/newBlogConfirmation.jsp"/>
</action>

As you can see, only the path attributes are modified. The FormBean Action responsible for the application business logic remains unchanged.

56.5.2 How to Create the New JSPs

As specified in the previous step, the actions forward the request to new JSPs, which are responsible for rendering the portlet content. Your new portlet view JSPs can share the HTML with the standalone view, but ensure the portlet meets the following criteria:

  • Uses styles that enforce a consistent look and feel with the rest of the page.

  • Contains HTML code that is allowed in HTML table cells (that is, no <html>, <body>, and <frame> tags).

  • Uses the PDK-Java version of the Struts HTML tag library. This renders URLs in the correct format to work in a portlet context.

The PDK Struts HTML tag library contains versions of the Struts HTML tags that can be used in portlet markup.


Note:

You can register the Oracle PDK with Oracle JDeveloper so that you can drop the tags from the Oracle JDeveloper Components Palette. For more information, see the Registering a Custom Tag Library in JDeveloper section in the Oracle JDeveloper online Help.

56.5.3 How to Create a Portlet

You can create your Struts portlet either manually or by using the Create Oracle PDK-Java Portlet wizard. Although the wizard does not explicitly offer Struts support, you can use the wizard to build your Struts portlet.

To create a portlet:

  1. In JDeveloper, open the Oracle PDK-Java Portlet wizard.

    For more information, see Section 55.2.4, "How to Create a PDK-Java Portlet."

  2. On the View Modes page of the wizard, for the Show Page mode, select an Implementation Style of Java Class.

  3. For the Package Name, enter oracle.portal.provider.v2.render.http.

  4. For the Class Name, enter StrutsRenderer. This generates the skeleton of the portlet renderer class, StrutsRenderer.

  5. As the StrutsRenderer is part of the PDK, you do not need this generated file. So, when you finish the wizard, you must delete the file generated by the wizard. To do so, click the file in the System Navigator window, then from the File menu, select Erase from Disk in JDeveloper.

  6. Edit the provider.xml and change the following properties:

    At the producer level, perform the following:

    • If the Struts application uses sessions (for example, the form sysnchronizer token mechanism is used or <actionInSession> is set to true), then enable session handling:

      <session>true</session>
      

    At the portlet level, perform the following:

    • If you want users to always return to the same portlet state as when they left the container page, then you can configure the struts renderer to save the struts action in the struts context:

      <actionInSession>true</actionInSession>
      

      If you prefer that users always start from the beginning of the portlet when they return from outside the container page, then you should not save the struts action:

      <actionInSession>false</actionInSession>
      

      Note that this setting is the default behavior.

    • Specify the first action to raise when the portlet is called. Use the following code:

      <showPage class="oracle.portal.provider.v2.render.http.StrutsRenderer">
      <defaultAction>/portal/prepareNewBlog.do</defaultAction>
      </showPage>
      

56.5.4 How to Extend the Portlet to Add Business Logic

In your application, you should add code specific to your environment, such as the user's information, personalization, and localization. To do so, you can create a new Action class that is only called in context, and handles all business logic.

56.5.5 How to Register the Producer

Now that your portlet is ready to be used by consumers, you must make it accessible by registering it. For information about how to register your PDK-Java portlet, see Section 57.4, "Registering and Viewing Your Portlet."