12 Creating Portlets from JSF Applications Using the Oracle JSF Portlet Bridge

Use the Oracle JSF Portlet Bridge to expose a JSF application as a portlet.

Topics:

Note:

The Oracle JSF Portlet Bridge extends the Apache Reference implementation of JSR 329. JSR 329 is the standards effort to define the functionality for the Portlet 2.0 Bridge for JavaServer Faces. Oracle is the specification lead for this standard. More information is available at:

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

About Creating Portlets from JSF Applications Using the Oracle JSF Portlet Bridge

The Oracle JSF Portlet Bridge enables application developers to quickly and easily expose their existing JSF applications and Oracle ADF applications and task flows as JSR 286 portlets.

Note:

Unless otherwise noted, the term JSF applications encompasses Oracle ADF applications.

The Oracle JSF Portlet Bridge:

  • Simplifies portlet development by enabling you to provide portlet functionality using JSF rather than relying on the JSR 286 portlet APIs.

  • Simplifies exposing your JSF application to JSR 286 portlet consumers, such as WebCenter Portal.

  • Eliminates the requirement to store, maintain, and deploy your portlets separately from your application by enabling the application to run simultaneously as a regular web application and as a portlet from the same installation.

  • Enables you to create portlets at a more granular level by exposing task flows as portlets. Because portletized task flows are JSR 286 portlets, this also enables you to use your task flows in a distributed environment.

Note:

The Oracle JSF Portlet Bridge uses WSRP extensions that may prevent JSF portlets working as intended with third party WSRP consumers.

Creating a Portlet from a JSF Application

The Oracle JSF Portlet Bridge enables you to expose a JSF application or task flow as a portlet. You do this declaratively, using the Create Portlet Entry dialog; no coding is required. Using the Create Portlet Entry dialog, you can configure Oracle JSF Portlet Bridge on a JSF application to expose the application as a JSR 286 portlet. As part of this configuration, you indicate the initial JSF view (or task flow) to invoke when the portlet is rendered. From that point on the Oracle JSF Portlet Bridge works with the JSF application to navigate through the additional views that are reachable from this initial view. So in the typical situation when you are exposing the entire JSF application as the portlet, you configure the Oracle JSF Portlet Bridge to render the application's initial view in the portlet and the rest of the navigation works naturally within that same portlet.

This section includes the following topics:

How to Create a JSF Portlet Based on a Page

The simplest way to create a portlet from a JSF application is to generate a portlet based upon a page. In the JSF application, either Facelets or jsff should be used for the view handler technology.

To create a JSF portlet from an existing application page:

  1. In JDeveloper, open the application that contains the JSF page that you want to portletize.
  2. In the Application Navigator, right-click on the project that contains the JSF page and select Project Properties.

    Note:

    You cannot generate a portlet based on a page that contains a portlet.

  3. In the Project Properties dialog, select the Features node.

    Figure 12-1 Project Properties Dialog

    This image shows the Project Properties.
  4. On the Features page, click the Add Features (Add Features icon.) icon.
  5. In the Add Features dialog, select Portlet Bridge from the Available list.

    Figure 12-2 Add Features

    This image shows the Add features dialog, which has list of Available and Selected features for a project.
  6. Click the shuttle button to transfer your selection to the Selected list.
  7. Click OK.
  8. In the Application Navigator, right-click the JSF page and select Create Portlet Entry.
  9. In the Create Portlet Entry dialog, in the Portlet Name field, enter a name for the portlet.
  10. In the Display Name field, enter a descriptive name for your portlet.
  11. In the Portlet Title field, enter a descriptive title for your portlet.

    The portlet title is displayed in the Resource Palette or Application Resources panel, so make the title something to help users decide whether the portlet is useful to them. The portlet title is also displayed on the portlet header when the portlet appears on a page.

  12. In the Short Title field, enter a shorter title for your portlet. This short title is displayed on the portlet header when the portlet appears on a page on a mobile device.
  13. In the Description field, enter a description for your portlet.
  14. Select Create portlet events for contextual events to create portlet events in the portlet.xml file for any contextual events exposed by the page. This option is selected by default.

    Portlet events enable a portlet to communicate with the page on which it resides and with other portlets on that page.

  15. Click OK.

When you create a JSF portlet based on a page, a portlet.xml file is created (or updated if it already exists) to contain the portlet entry (see example below) for the page. The file is opened ready for viewing or editing. By default, the file is opened in Design view. To view or edit the source code, click the Source tab.

<portlet id="adf_jsf__testPage_jspx">
 <description>PortletBridgeApplication_testPage_jspx</description>
 <portlet-name>PortletBridgeApplication_testPage_jspx</portlet-name>
 <display-name>PortletBridgeApplication_testPage_jspx</display-name>
 <portlet-class>
 oracle.portlet.bridge.adf.application.ADFBridgePortlet
 </portlet-class>
 <init-param>
 <name>javax.portlet.faces.defaultViewId.view</name>
 <value>/myPage.jspx</value>
 </init-param>
 <supports>
 <mime-type>text/html</mime-type>
 <portlet-mode>VIEW</portlet-mode>
 </supports>
 <supported-locale>en</supported-locale>
 <portlet-info>
 <title>PortletBridgeApplication_testPage_jspx</title>
 <short-title>PortletBridgeApplication_testPage_jspx</short-title>
 </portlet-info>
 <supported-processing-event id="DepartmentSelectedEvent">
 <qname xmlns:x="http://xmlns.oracle.com/adfm/contextualEvent">
 x:DepartmentSelectedEvent
 </qname>
 <supported-publishing-event id="DepartmentSelectedEvent">
 <qname xmlns:x="http://xmlns.oracle.com/adfm/contextualEvent">
 x:DepartmentSelectedEvent
 </qname>
 </supported-publishing-event>
 <supported-public-render-parameter>
 _adf_event_DepartmentSelectedEvent
 </supported-public-render-parameter>
 <container-runtime-option>
 <name>com.oracle.portlet.requireIFrame</name>
 <value>true</value>
 </container-runtime-option>
 <container-runtime-option>
 <name>com.oracle.portlet.minimumWsrpVersion</name>
 <value>2</value>
 </container-runtime-option>
</portlet>

The page you selected is used as the entry point for the portlet View mode. This is indicated in the portlet.xml file by the javax.portlet.faces.defaultViewId.view initialization parameter. You can manually edit the portlet.xml file to define the pages for other default and extended portlet modes supported by WebCenter Portal:

  • Edit mode: javax.portlet.faces.defaultViewId.edit

  • Help mode: javax.portlet.faces.defaultViewId.help

  • About mode: javax.portlet.faces.defaultViewId.about

  • Config mode: javax.portlet.faces.defaultViewId.config

  • Edit Defaults mode: javax.portlet.faces.defaultViewId.edit_defaults

  • Preview mode: javax.portlet.faces.defaultViewId.preview

  • Print mode: javax.portlet.faces.defaultViewId.print

Note:

The value for the defaultViewId is relative to the application context root and must always start with a /. In the example above, the value for defaultViewId.view is /myPage.jspx.

If you add defaultViewId for other portlet modes, then ensure that you also add the mode to the <supports> tag. For example, <portlet-mode>HELP</portlet-mode>.

For information about portlet modes, see Portlet Modes.

How to Create a JSF Portlet Based on a Task Flow

This section includes the following topics:

About Creating Portlets from Tasks Flows

An advantage of using Oracle ADF is the existence of task flows, which provide a modular approach for defining control flow in an application. Instead of representing an application as a single large JSF page flow, you can break it up into a collection of reusable task flows. In each task flow, you identify application activities, the work units that must be performed in order for the application to complete. An activity represents a piece of work that can be performed when running the task flow.

Task flows can be unbounded or bounded:

  • An unbounded task flow is a set of activities, control flow rules, and managed beans interacting to allow a user to complete a task. An unbounded task flow consists of all activities and control flows in an application that are not included within any bounded task flow.

  • A bounded task flow is a specialized form of task flow, having a single entry point and one or more exit points. It contains its own set of private control flow rules, activities, and managed beans. An Oracle ADF bounded task flow allows reuse, parameters, transaction management, and reentry. It can have zero to many exit points. Bounded task flows can use pages or page fragments, however only those that use page fragments can be portletized.

A typical application is a combination of an unbounded and one or more bounded task flows. The application can then call bounded task flows from activities within the unbounded task flow. For more detailed information about bounded and unbounded task flows, see About ADF Task Flows in Developing Fusion Web Applications with Oracle Application Development Framework.

Creating a Portlet From a Task Flow Using the Create Portlet Entry Dialog

Use the Create Portlet Entry dialog to create a portlet from a single task flow.

To make a portlet from a task flow using the Create Portlet Entry dialog:

  1. In JDeveloper, open the JSF application that contains the task flow from which you want to make a portlet.
  2. In the Application Navigator, right-click the task flow that you want to portletize, and choose Create Portlet Entry.
  3. In the Create Portlet Entry dialog, in the Portlet Name field, enter a name for the portlet.
  4. If the task flow is unbounded, the Entry Point View drop-down list displays all the view activities of the task flow. From this drop-down list, choose the view activity to use as the entry point for the portlet. By default, the first view activity in the task flow is chosen.

    If the task flow is bounded, there is only a single possible entry point, so you do not see the Entry Point View drop-down list.

  5. In the Display Name field, enter a descriptive name for your portlet.
  6. In the Portlet Title field, enter a descriptive title for your portlet.

    The portlet title is displayed in the Resource Palette or Application Resources panel, so make the title something to help users decide whether the portlet is useful to them. The portlet title is also displayed on the portlet header when the portlet appears on a page.

  7. In the Short Title field, enter a shorter title for your portlet. This short title is displayed on the portlet header when the portlet appears on a page on a mobile device.
  8. In the Description field, enter a description for your portlet.
  9. Select Create portlet events for contextual events to create portlet events in the portlet.xml file for any contextual events exposed by the task flow. This option is selected by default.

    Portlet events enable a portlet to communicate with the page on which it resides and with other portlets on that page.

  10. Click OK.

When your portlet, or portlets, have been created, you should receive a message that says:

New portlet has been successfully created

In addition, the portlet.xml file is created. The portlet.xml file contains the portlet entry (see example below) and is opened ready for viewing or editing.

<portlet id="adf_taskflow_WEB_INF_department_xml">
 <description>PortletBridgeApplication department</description>
 <portlet-name>PortletBridgeApplication_department</portlet-name>
 <display-name>PortletBridgeApplication department</display-name>
 <portlet-class>oracle.portlet.bridge.adf.application.ADFBridgePortlet</portlet-class>
 <init-param>
 <name>javax.portlet.faces.defaultViewId.view</name>
 <value>
 /adf.task-flow?adf.tfDoc=/WEB-INF/adfp-portlet-bridge-container.xml
 &amp;adf.tfId=adfp-portlet-bridge-container&amp;_fragmentTaskFlowDoc=/WEB-INF/
 department.xml&amp;_fragmentTaskFlowId=department
 </value>
 </init-param>
 <supports>
 <mime-type>text/html</mime-type>
 <portlet-mode>VIEW</portlet-mode>
 </supports>
 <supported-locale>en</supported-locale>
 <portlet-info>
 <title>PortletBridgeApplication department</title>
 <short-title>PortletBridgeApplication department</short-title>
 </portlet-info>
 <supported-publishing-event id="DepartmentSelectedEvent">
 <qname xmlns:x="http://xmlns.oracle.com/adfm/contextualEvent">
 x:DepartmentSelectedEvent
 </qname>
 </supported-publishing-event>
 <supported-public-render-parameter>
 _adf_event_DepartmentSelectedEvent
 </supported-public-render-parameter>
 <container-runtime-option>
 <name>com.oracle.portlet.requireIFrame</name>
 <value>true</value>
 </container-runtime-option>
 <container-runtime-option>
 <name>com.oracle.portlet.minimumWsrpVersion</name>
 <value>2</value>
 </container-runtime-option>
</portlet>

Note:

The portlet.xml file can include multiple portlets and can have a combination of pages and task flows exposed as portlets. The file can also include standard JSR 286 (non bridge) portlets.

Creating a Portlet From a Task Flow Using the Manage Portlet Entries of Task Flows Dialog

If your project includes a lot of task flows, you may find it easier to select the task flows to create as portlets from a list. You can do this using the Manage Portlet Entries of Task Flows dialog. This dialog also lets you create portlets from multiple task flows at the same time, rather than having to create them individually.

To create a portlet from a task flow using the Manage Portlet Entries of Task Flows dialog:

  1. From the main menu, choose File and then New.
  2. In the New Gallery, expand Web Tier, select Portlets and then Manage Portlet Entries of Task Flows, and click OK.
  3. In the Manage Portlet Entries of Task Flows dialog, use the shuttle buttons to select which task flows you want to create as portlets.
  4. Select Create portlet events for contextual events to create portlet events in the portlet.xml file for any contextual events exposed by the task flows. This option is selected by default.

    Portlet events enable a portlet to communicate with the page on which it resides and with other portlets on that page.

  5. Click OK to create portlets for the selected task flows.

When your portlet, or portlets, have been created, you should receive a message that says:

New portlet has been successfully created

In addition, the portlet.xml file is created. The portlet.xml file contains the portlet entry (see example below) and is opened ready for viewing or editing.

<portlet id="adf_taskflow_WEB_INF_department_xml">
 <description>PortletBridgeApplication department</description>
 <portlet-name>PortletBridgeApplication_department</portlet-name>
 <display-name>PortletBridgeApplication department</display-name>
 <portlet-class>oracle.portlet.bridge.adf.application.ADFBridgePortlet</portlet-class>
 <init-param>
 <name>javax.portlet.faces.defaultViewId.view</name>
 <value>
 /adf.task-flow?adf.tfDoc=/WEB-INF/adfp-portlet-bridge-container.xml
 &amp;adf.tfId=adfp-portlet-bridge-container&amp;_fragmentTaskFlowDoc=/WEB-INF/
 department.xml&amp;_fragmentTaskFlowId=department
 </value>
 </init-param>
 <supports>
 <mime-type>text/html</mime-type>
 <portlet-mode>VIEW</portlet-mode>
 </supports>
 <supported-locale>en</supported-locale>
 <portlet-info>
 <title>PortletBridgeApplication department</title>
 <short-title>PortletBridgeApplication department</short-title>
 </portlet-info>
 <supported-publishing-event id="DepartmentSelectedEvent">
 <qname xmlns:x="http://xmlns.oracle.com/adfm/contextualEvent">
 x:DepartmentSelectedEvent
 </qname>
 </supported-publishing-event>
 <supported-public-render-parameter>
 _adf_event_DepartmentSelectedEvent
 </supported-public-render-parameter>
 <container-runtime-option>
 <name>com.oracle.portlet.requireIFrame</name>
 <value>true</value>
 </container-runtime-option>
 <container-runtime-option>
 <name>com.oracle.portlet.minimumWsrpVersion</name>
 <value>2</value>
 </container-runtime-option>
</portlet>

Note:

The portlet.xml file can include multiple portlets and can have a combination of pages and task flows exposed as portlets. The file can also include standard JSR 286 (non bridge) portlets.

What You May Need to Know When Creating a JSF Portlet

You must code your JSF pages such that they produce markup that conforms with JSR 286 portlet markup fragment rules. If you have chosen to use Oracle ADF, the markup in your page comes mainly from the Oracle ADF Faces components, which naturally render markup in a style that is either compatible with JSF portlets or can be automatically interpreted by the Oracle JSF Portlet Bridge into a compatible style (for example, by rendering the portlet in an inline frame).

The sections that follow provide some guidance on how to avoid common issues that you may encounter as you code Oracle ADF pages that you later choose to publish as portlets.

This section includes the following topics:

General Guidelines for Creating a JSF Portlet

Consider the following general guidelines when creating a JSF portlet:

  • Application Must Run as a Web Application. Prior to creating a portlet from your JSF application, the application, including all of its pages and task flows, must run properly after you deploy it to Integrated WLS. If it cannot run as a regular web application, it cannot run as a portlet producer either.

  • The Portlet Is Contained by a Different Page. One area that you should consider when creating task flows that will be exposed as portlets is that the page on which you render the task flow as a portlet is different to the one in the original producer application.

    Some common errors that occur include:

    • Expecting to access JavaScript in the consuming page.

    • Expecting to find managed beans or objects added to scopes as part of the consuming page.

    • Expecting components in the JSF component tree from the consumer to be present.

  • Servlet Dependencies. When writing an application that is supposed to run in both servlet and portlet environments, avoid casting to HttpServlet objects (or you get a ClassCastException when running as a portlet). Instead, use the abstraction provided by the Faces ExternalContext object. For example, instead of:

    HttpServletRequest request =getRequestFromFacesContext();
    String localContextPath =request.getContextPath();
    

    Use the following:

    String localContextPath=
    FacesContext().getCurrentInstance().getExternalContext().getRequestContextPath();
    

    To the extent that ExternalContext does not provide that abstraction for you, you can write servlet or portlet specific code. You can use the method shown in the example below to check if the application runs as portlet:

    public static boolean isPortletRequest()
     {
    Map<String, Object> m =
    FacesContext.getCurrentInstance().getExternalContext().getRequestMap();
     Object phase =m.get("javax.portlet.faces.phase");
     if (phase != null)
     {
    return true;
     }
    else
     {
    return false;
     }
    }
    
  • Secured Applications. If your application is secured, ensure that you have secured identity propagation.

  • Deep Links. For normal interactions with a portlet, there is a session maintained between the consumer and the producer. This is done by storing a session cookie in the consumer and sending it to the producer on each request. On the original request, the session is established and on subsequent requests, the portlet sends the session cookie to the producer and the session is reused.

    For deep links, that is, links from the portlet to the producer application, the request is from the browser direct to the producer application. In this case, the session cookie cannot be sent so a new session is established. If a shared session is required for deep links, then this must be implemented by the developer. A common implementation is to write this state to a common location, accessible from the producer and the application, and pass a reference to this state in the deep link.

  • Java EE Authentication. Java EE login is not supported. Java EE applications can be configured with different authentication techniques, such as Basic and Digest. As portlets are fragments incorporated into a consumer's page, it is generally expected that direct authentication occurs between the client and the consumer, not the client and the portlet producer. As a result, these authentication techniques are not supported in JSR 286. In the JSR 286 case, Java EE authentication occurs through WS-Security mechanisms that allow the Web service consumer to be authenticated and verified by the producer, and propagate the user identity for user authentication and authorization. Published Oracle ADF artifacts must not contain login links that trigger Java EE authentication.

  • Timeout Period. For applications that take a long time to render, consider increasing the time out period when you register a producer that was created by the Oracle JSF Portlet Bridge. Note however that the time out period specified during producer registration is limited by the maximum time out period (maximumTimeout element) specified in adf-config-xml.

Portlet Guidelines

Consider the following portlet guidelines when creating a JSF portlet:

  • Portlet Sizing. When consuming a JSF portlet, the consumer application automatically renders the portlet content within an inline frame. This means that any inline popup is then confined within the inline frame. You should take this into consideration when specifying the size of the portlet.

    If the JSF portlet is a portletized page, then you have full control of the content and can decide how that content fills the inline frame window, utilizing exactly the same techniques as you would to determine how the content would fill the browser window.

    If the portlet is being stretched by its ancestor in the consumer application, then the maximized attribute is set to true on the af:document component in the document produced by the Oracle JSF Portlet Bridge. This means that components that support it, such as panelStretchLayout, will fill the entire inline frame.

  • Resources and Links. For resources and links, you must specify the location relative to the web-app-context-root. Otherwise, your images and other resources cannot be found by the portlet. Do not use relative (../) path notation. Portlets in Oracle WebCenter Portal run remotely and are accessed using a SOAP protocol (WSRP). The latter means that the regular web application concept of request path does not apply in a JSR 286 container. The JSR 286 specification reflects this by mandating that all resource URLs either be absolute or context path relative.

  • Redirecting Requests. Do not redirect or forward a request within your JSP. JSR 286 only supports requestDispatcher.include(). The use of httpServletResponse.sendRedirect() or requestDispatcher.forward() results in exceptions and errors. To work properly in a portlet environment, you must implement JSF navigation rules in faces-config.xml or Oracle ADF task flow control flow rules.

  • Memory Consumption. The Oracle JSF Portlet Bridge stores the content of the request scope between requests so that the request scope is preserved between a portlet Action and a portlet Render (which are two separate requests). Because of this, to minimize overall memory consumption, you must especially avoid storing too much data in the request scope when the application contains JSF portlets.

  • WSRP Version. The Oracle JSF Portlet Bridge makes use of Portlet 2.0 features. Consequently, it should be used only with WSRP V2. The portlet's minimumWsrpVersion container runtime option should be set to 2. For more information, see How to Customize the Runtime Environment for JSR 286 Portlets.

  • If your portlet does not display as expected, check the HTML tagging. For example, in a portlet container, the <head> tag may conflict with the WebCenter Portal page <html> tags. Consider using an iframe or removing conflicting <html> tags in the portlet container.

Security Guidelines

Consider the following security guidelines when creating a JSF portlet:

  • Oracle ADF Secured Applications. When you use the Create Portlet Entry or Manage Portlet Entries of Task Flows dialog to portletize a task flow in an Oracle ADF secured application (the security scheme being Authentication and Authorization), you must manually grant permission to the following wrapper task flow in the jazn-data.xml file of the producer application:

    /WEB-INF/adfp-portlet-bridge-container.xml#adfp-portlet-bridge-container
    

    If you do not grant the permissions, the portlet does not render.

    For example, if you have an application with two roles: authenticated-role, with view permission; and testrole, with customize, edit, grant, personalize, and view permissions, you must add the following entries inside the <permissions> tag of each role:

    • For authenticated-role:

      <permission>
       <class>oracle.adf.controller.security.TaskFlowPermission</class>
       <name>
       /WEB-INF/adfp-portlet-bridge-container.xml#adfp-portlet-bridge-container
       </name>
       <actions>view</actions>
      </permission>
      
    • For testrole:

      <permission>
       <class>oracle.adf.controller.security.TaskFlowPermission</class>
       <name>
       /WEB-INF/adfp-portlet-bridge-container.xml#adfp-portlet-bridge-container
       </name>
       <actions>customize,edit,grant,personalize,view</actions>
      </permission>
      
  • Role Based Authorization. If you are portletizing a task flow or page that has role based authorization (that is, the task flow or page has been granted certain roles), WS-Security is required to propagate the user correctly. If you set up WS-Security, the JSF portlet does not render the content if the propagated user does not have permission to view the task flow.

JSF Guidelines

Consider the following JSF guidelines when creating a JSF portlet:

  • Using h:commandLink. When using the h:commandLink JSF standard HTML component ensure that you set the externalizeJavaScript parameter in web.xml so that the JSF Reference Implementation does not generate any external JavaScript resource (see example below). This is to work around an issue in the JSF Reference Implementation where the reference to the JavaScript resource is not properly encoded.

    <context-param>
     <param-name>com.sun.faces.externalizeJavaScript</param-name>
     <param-value>false</param-value>
    </context-param>
Oracle ADF Guidelines

Consider the following ADF guidelines when creating a JSF portlet:

  • Task Flow Returns. When an ADF bounded task flow completes it may use a task flow return to send control back to the calling task flow. In a portletized task flow, there is no calling task flow, so the task flow return does not make any sense in this context. This may cause what appears to be an empty portlet to display as the task flow navigates to a state where there is no view selected. The task flow will stay in this state until it is refreshed either when the input parameters change or the session on the producer is reset.

    If you plan to portletize your task flow, you should avoid using task flow returns. If you must use a task flow return, you can provide a dummy task flow with a default activity of the task flow that you want to portletize. When the task flow return is executed, it returns to the dummy task flow. The dummy task flow then executes its default activity, which is to call back to the original task flow and thus restart the task flow when the portlet is next called.

  • Mismatched Style Sheets. In general, when you consume a task flow using the Oracle JSF Portlet Bridge, the portlet producer tries to use the skin of the consumer page. When the producer cannot match the consumer skin, the portlet generates and references its own style sheet. This is known as a mismatched skin. A mismatched skin can occur when:

    • The consumer and producer use different versions of ADF Faces. In this case, the producer still uses the consumer skin.

    • The consumer has additional skin-additions that the producer does not have, or vice versa. In this case, the producer still uses the consumer skin.

    • The producer does not have the consumer skin. In this case, the producer uses the portlet skin.

    Mismatched skins can cause performance problems because the browser has to fetch an extra style sheet and the generated portlet markup uses uncompressed styles resulting in larger markup.

    If a mismatched skin occurs, the producer log includes the following:

    The skin skinName specified on the requestMap will not be used because the
    styleSheetDocument id on the requestMap does not match the local skin's
    styleSheetDocument's id. It could mean the jars are not identical. For example,
    one might have trinidad-skins.xml skin-additions in a jar file on the class path
    that the other does not have.
    

    The portlet markup inside the inline frame also includes a link tag to the portlet style sheet resource, for example:

    <link rel=\"stylesheet\" charset=\"UTF-8\" type=\"text/css\" href=\"http:.../resourceproxy/portletId...252525252Fadf%252525252Fstyles%252525252Fcache%252525252Fblafplus-rich-portlet-d1062g-en-ltr-gecko.css...
    

    You can use an HTTP monitoring tool to see that a request is made to the portlet style sheet resource.

    There are a number of reasons for mismatched skins. For a skin to match, the producer and consumer must be the same for all the following conditions:

    • The ADF Faces version; a different version of ADF Faces may have different style selectors.

    • The style compression, defined in web.xml, for example:

      <context-param>
       <param-name>
       org.apache.myfaces.trinidad.DISABLE_CONTENT_COMPRESSION
       </param-name>
       <param-value>false</param-name>
      </context=param>
      
    • Tonal style or themes, defined in web.xml, for example:

      <context-param>
       <param-name>xyz</param-name>
       <param-value>xyz</param-value>
      </context-param>
      
    • Availability of skin additions. Skin additions are defined in META-INF/trinidad-skins.xml in a JAR file. These are then aggregated from all the JAR files in the class path. If there are any JAR files that exist on the producer but not on the consumer, or vice versa, you get a mismatch.

      <skin-addition>
       <skin-id>blafplus-rich.desktop</skin-id>
       <style-sheet-name>
       adf/styles/flexComponents-blafplus-rich-desktop.css
       </style-sheet-name>
      </skin-addition>
      

      To determine if the JAR files match, turn on Trinidad logging to show which skin-addition it is processing. To do this, update the logging.xml log level of both the producer and consumer WebLogic Servers to FINEST then restart the servers:

      <logger name="org.apache.myfaces.trinidad.skin.SkinUtils" level=FINEST"/>
      

      When you run the consumer page, any skin entries that do not match in the consumer and producer log files are the cause of the skin mismatch.

  • ADF Faces Dialog Framework. ADF Faces Dialog Framework is not supported. If your application includes any buttons or icons that launch secondary browser windows, then the contents of the new windows are not displayed properly when the application is run as a portlet. As such, you should avoid using these components if you plan to portletize your application. Examples of components that launch secondary windows are:

    • <tr:inputDate>

    • <tr:inputColor>

    • <tr:popup>

    • the useWindow attribute of <af:commandButton>

  • Composer Components. Portletization of pages that contain Composer components is not supported.

  • The fileDownloadActionListener Component. The <af.fileDownloadActionListener> component is not supported.

  • The prepareModel Phase. Oracle ADF components/code that handle prepareModel must be idempotent. Any code running during the prepareModel phase must be rerunnable without effect to the underlying data/business logic. When running in the portlet environment, prepareModel is called twice during the complete JSF lifecycle as opposed to being called once when running within a regular web application.

    The reason for this difference is that the Oracle JSF Portlet Bridge runs JSF in two requests not one. It is implemented as if every JSF request redirected before the render phase. The consequence of this approach is that the JSF restoreView phase is called both when the request is first submitted and then again when request to render is received.

  • Accessing Request Parameters. Do not access or reference request parameters from model code except in page parameters. Besides being a cleaner MVC2 implementation, following this guideline avoids problems when such artifacts are published as portlets. Where regular JSF artifacts run their entire lifecyle in a single request, the Oracle JSF Portlet Bridge runs these artifacts in two requests, as if every JSF request redirected before the render phase.

    This two phase model enables the clearing of submitted parameters before rendering in a manner that allows such clearing to be communicated all the way back to the client, which makes this request something you could bookmark. As a result, request parameters do not exist during the render phase. As described previously, prepareModel is invoked again in this rendering phase. Therefore, any references to request parameters in this phase handler fail. You should avoid code like either of the following fragments:

    <invokeAction id="doExecuteWithParams" 
    Binds="ExecuteWithParams" 
    Refresh="prepareModel" 
    RefreshCondition="${param.id != null}"
    />
    
    <invokeAction id="doExecuteWithParams" 
    Binds="ExecuteWithParams" 
    Refresh="renderModel" 
    RefreshCondition="${param.id != null}"
    />
    
  • Referencing Page Parameters. Do not reference page parameters in the prepareModel phase. This issue relates to the same problem described for request parameters in the previous guideline. Generally, page parameters depend on request parameters and are evaluated during the restoreView phase. As this phase is called a second time during portlet rendering and request parameters are not available, such use fails. Instead, move any dependency on a page parameter value into the model before JSF transitions from its execute phases to its render phase.

  • Using ADF Faces Client-Side APIs to Find Components. Because a portlet is a naming container, special consideration should be taken when using ADF Faces client-side APIs to find components. An example component ID:

    • When run as a regular web application: id="demoTemplate:popup"

    • When run as a Portlet Producer application: id="__ns12345678:demoTemplate:popup"

    Things to watch out for specifically are:

    • Avoid using the AdfPage.PAGE.findComponentByAbsoluteId() API. Use getSource() and findComponent() methods instead. For example:

      <trh:script text="
      function showPopup(event) {
      event.cancel();
       //var popup =
      //AdfPage.PAGE.findComponentByAbsoluteId("demoTemplate:popup");
       var source =event.getSource();
       var popup =source.findComponent("popup");
       popup.show({align:"after_end", alignId:"button"});
      }
      "/>
      
    • Use a relative path for clientId instead of an absolute path (starting with a ':'). For example, use:

      <af:showPopupBehavior popupId="demoTemplate:iteratorpop"
       triggerType="mouseHover"/>
      

      Instead of:

      <af:showPopupBehavior popupId=":demoTemplate:iteratorpop"
       triggerType="mouseHover"/>
      
    • For more information, see What You May Need to Know About Using Naming Containers in the Developing Web User Interfaces with Oracle ADF Faces.

  • Encoded URLs. By default, URLs in the portletized page or task flow are encoded such that they are proxied by the consumer application. In some circumstances, you may not want to encode these URLs, for example, when requesting JavaScript libraries from content delivery networks or accessing resources directly from the user's browser to make use of a locally configured HTTP proxy.

    Another example is if your task flow includes an inline frame (for example, using an af:inlineFrame tag). In this case you need to ensure that the inline frame URL does not get encoded to go via the portlet resource proxy in the consumer. If you do not do this, any relative URLs in the content inside the inline frame will not work because they will be relative to the URL to the resource proxy rather than their correct location relative to the original URL for the inline frame.

    To bypass the URL encoding, set the _xEncodeUrl parameter to false on URLs that are passed to the Oracle JSF Portlet Bridge for encoding. This parameter is picked up by the Oracle JSF Portlet Bridge, which ensures that the URL does not get encoded via the resource proxy. The parameter is ignored if the task flow is not running as a portlet.

    For example, replace:

    <af:inlineFrame source="http://myiframe.example.com">
    

    with:

    <af:inlineFrame source="http://myiframe.example.com?_xEncodeUrl=false">

    Note:

    Do not use this parameter to access resources that reside on the producer server. These resources must be accessed using the portlet client's proxy.

  • Issues with goLink. The adf:goLink component encodes the link URL as an action for the current JSF application. In other words, it encodes the link using ExternalContext.encodeActionURL(...). This is different to the JSF h:outputLink component, which encodes the URL as a resource URL using ExternalContext.encodeResourceURL(...). If you are using goLink to link to a resource that is not a Faces View, then the URL must be encoded as a Resource URL. To do this, you must tell the Oracle JSF Portlet Bridge the link is not a Faces View by adding the following parameter to the URL:

    javax.portlet.faces.ViewLink=false
    

    For example:

    <af:goLink text="goLink 1" id="gl1" destination="/mynonfaceslink?javax.portlet.faces.ViewLink=false"/>
    
  • In-Protocol Resource Requests. Within a JSF application running under the Oracle JSF Portlet Bridge, when a resource URL is created using ExternalContext.encodeResourceURL(...), that resource URL is encoded in such a way that it is executed as an out-of-protocol resource request. This means that when the portlet consumer accesses that resource it does so by making a direct call to the target URL. It is also possible for resource URLs to be in-protocol. This means that the portlet consumer accesses the resource by making a WSRP web service call to the producer application, which in turn ultimately leads to the serverResource method being called on the portlet. It is then the portlet's responsibility to provide the resource which is sent back in the WSRP response. When that portlet is the Oracle JSF Portlet Bridge, it serves the resource by using a request dispatcher to forward to the target URL.

    Generally out-of-protocol resource requests are to be preferred as they do not incur the additional overhead of the web service call. In-protocol requests can also cause large amounts of memory to be allocated as the WSRP SOAP response is constructed, if the resource being served is large. In the case of the Oracle JSF Portlet Bridge, the only time that you would want to use in-protocol resources is when you need to share the portlet scoped HTTP session between the resource requests and the other portlet requests, such as portlet action or render requests.

    To cause the Oracle JSF Portlet Bridge to encode resource URLs as in-protocol resource requests, add the following parameter to the URL, before ExternalContext.encodeResourceURL(...) is called:

    javax.portlet.faces.InProtocolResourceLink=true
    

    For example:

    <af:goLink text="goLink 1" id="gl1" destination="/mynonfaceslink?javax.portlet.faces.ViewLink=false&javax.portlet.faces.InProtocolResourceLink=true"/>

Updating the Portlet Entry for a Portletized Page or Task Flow

If you edit a page or task flow that has been previously portletized, if those edits include updates to the task flow or page's parameters or events, then you must update the portlet entry for the page or task flow to keep the portlet in sync with the underlying page or task flow.

Note:

If you delete a page that has been portletized, you must manually remove the portlet entry for that page from the portlet.xml file.

To update the portlet entry for a portletized page or task flow:

  1. In the Application Navigator, open the JSF application that contains the portletized page or task flow that you want to update.

  2. Right-click the page or task flow, and choose Update Portlet Entry.

  3. If the portlet entry is for an unbounded task flow, then a dialog prompts you to select the view activity that was used to create the portlet.

When you update the portlet entry for a portletized page or task flow, the portlet entry is updated as follows:

  • The Create portlet events for contextual events option is set to true.

  • No updates are made to the portlet name, display name, title, short title, or description.

  • Any event-definition elements (at the portlet application level) are created as necessary.

  • None of the existing event-definition elements are deleted or updated.

  • Any public-render-parameter elements (at the portlet application level) are created as necessary.

  • None of the existing public-render-parameter elements are deleted or updated.

  • The list of supported-processing-event, supported-publishing-event, and supported-public-render-parameter elements in the portlet entry are re-created to reflect the current events and input parameters of the page or task flow. This means that some existing portlet events and public parameters may be deleted and new ones added.

Testing a Portletized Page or Task Flow in JDeveloper

After you have portletized a page or task flow, you must test it to ensure that it is working correctly. Testing a portletized page or task flow requires the following steps:

  1. Portletize the page or task flow to create a portlet entry in the portlet.xml file.
  2. Deploy the portletized application to a portlet server.
  3. Create an application to consume the portletized page or task flow.
  4. Register the portletized application with the consumer application.
  5. Create a page in the consumer application and add the portletized page or task flow to it.
  6. Deploy the consumer application and display the page that contains the portletized page or task flow.

Testing a JSF Portlet Using the Integrated WebLogic Server

When you have created your JSF portlet you can test it using the Integrated WebLogic Server that comes packaged with JDeveloper.

Before You Begin

Before you test your portletized page or task flow, it is a good idea to first test that the page or task flow works correctly in the running ADF application. You can do this, using the Integrated WebLogic Server, by running the page or, for task flows, adding the task flow to a page and running that page.

For more information, see Running an ADF application in Integrated WebLogic Server in the Developing Fusion Web Applications with Oracle Application Development Framework.

To test a JSF portlet:

  1. From the main menu, choose Run and then Start Server Instance.

    It may take a few moments for the Integrated WLS to start. When the instance has started, you should see a message similar to the following in your Log panel:

    IntegratedWebLogicServer started.
    

    For more information, see Managing the Integrated WebLogic Server.

  2. You are now ready to run your Portlet Producer application on the Integrated WLS. Because your web application and Portlet Producer application are one and the same (the Portlet Producer application is your existing web application with additional portlet artifacts), you can run your web application as you normally would (see Running an ADF application in Integrated WebLogic Server in Developing Fusion Web Applications with Oracle Application Development Framework) or you can run your portlet following the instructions in How to Run a WSRP Portlet Producer on Integrated WebLogic Server.
  3. When the application is deployed, you can view the WSRP Producer Test Page by going to:
    http://host:port/context-root/info
    

    where:

    • host is the server to which the application has been deployed.

    • port is the HTTP Listener port. Typically it is 7101. When the server is started, the port is displayed in the console.

    • context-root is the web application's context root.

  4. Once you have successfully deployed the application containing the portlet, you can register it as a portlet producer with any other application.

    Note:

    Because the Oracle JSF Portlet Bridge uses WSRP 2.0 features, you should register the producer using the WSRP v2 WSDL URL listed in the WSRP Producer Test Page.

    You can continue to access the application as a regular web application or consume it as a portlet producer.

  5. Now that your portlet producer is deployed and registered, you can consume your JSF portlet as you would any other portlet.

Deploying JSF Portlets to a WebLogic Managed Server

When you are satisfied that the application works correctly both as a web application and a portlet application, you can deploy it to your production Oracle WebLogic Managed Server.

Because your web application and portlet application are one and the same (the portlet application is your existing web application with additional portlet artifacts), deploying the web application also deploys the portlet producer application.

For information about how to deploy an application to a WebLogic Managed Server, see Deploying Fusion Web Applications in the Developing Fusion Web Applications with Oracle Application Development Framework.

Note:

Ensure that you deploy your application to a Java EE container with the Oracle Portlet Container installed. The Integrated WLS has the container installed, which is why it is recommended for testing.

After successful deployment, you can access both the application and the portlet producer test page. For example, the application URL would be similar to:

http://host:port/appcontextroot/faces/pagename.jspx

And the portlet producer test URL would be similar to:

http://host:port/appcontextroot/info

Using Events to Link JSF Portlets with Other Portlets

This section includes the following topics:

About Linking JSF Portlets with Other Portlets

If you portletize an Oracle ADF task flow that triggers a contextual event, the Oracle JSF Portlet Bridge creates a JSR 286 portlet event to wrap the contextual event. This means that when the portletized task flow is consumed on a page, it can be linked to other JSF portlets or to JSR 286 portlets.

The examples in this section use the following portlets:

  • Departments portlet, a portletized ADF task flow that displays a list of departments. The list of departments can be restricted by location ID. This portlet raises a contextual event, departmentSelected, when a department row is selected in the portlet. The payload of the departmentSelected event is an object of type hr.Department (a Java object representing one row of the Departments table).

  • Employees portlet, a portletized ADF task flow that displays a list of employees. The list of employes can be restricted by department ID.

  • Department Address portlet, a JSR 286 portlet that displays the address of a specified department.

  • Department Locations portlet, a JSR 286 portlet that displays a list of locations. This portlet raises a portlet event, named locationId with the namespace http://xmlns.oracle.com/adfm/contextualevent, when one of the listed locations is selected.

How to Link a JSF Portlet to Another JSF Portlet

The Departments task flow raises a contextual event, departmentSelected, when a department row is selected within the task flow. The event is ultimately raised by an eventBinding which is triggered from a row selection listener (see example below).

The payload of the event (an object of type hr.Department, a Java object representing one row of the departments table) is generated by using the customPayload attribute which points to the current row from the departments table iterator.

For more information about standard ADF contextual event techniques, like the ones used in this example, see About Creating Contextual Events in the Developing Fusion Web Applications with Oracle Application Development Framework.

<eventBinding Listener="org.apache.myfaces.trinidad.event.SelectionListener"
 id="DepartmentSelectedEvent">
 <events xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
 <event name="departmentSelected"
 customPayLoad="#{bindings.departments.currentRow.dataProvider}"/>
 </events>
</eventBinding>

When the Departments task flow is portletized, using the steps described in How to Create a JSF Portlet Based on a Task Flow, a portlet.xml file is created containing a definition for a portlet event that is used to transfer the corresponding contextual event during portlet communication with the portlet over WSRP:

<portlet id="adf_taskflow_WEB_INF_departments_xml">
 ...
 <supported-publishing-event id="departmentSelected">
 <qname xmlns:x="http://xmlns.oracle.com/adfm/contextualEvent">
 x:departmentSelected
 </qname>
 </supported-publishing-event>
 ...
</portlet>

There is also a corresponding event definition in portlet.xml for the Departments portlet's departmentSelected event:

<event-definition id="departmentSelected">
 <qname xmlns:x="http://xmlns.oracle.com/adfm/contextualEvent">
 x:departmentSelected
 </qname>
 <value-type>
 oracle.portlet.bridge.adf.lifecycle.ADFmPayloadWrapper
 </value-type>
</event-definition>

Note:

The namespace for contextual events that are converted into portlet events is always:

http://xmlns.oracle.com/adfm/contextualEvent

The payload type is always:

oracle.portlet.bridge.adf.lifecycle.ADFmPayloadWrapper

The ADFmPayloadWrapper is used to ensure that any serializable contextual event payload is wrapped in a JAXB marshallable wrapper. It also ensures that a fixed type can be declared for the portlet event, even though it is not possible to know the payload type until the event is raised. The payload is unwrapped when extracting the contextual event from the portlet event.

The Employees task flow uses standard ADF techniques to handle a departmentSelected event. This is in the form of a methodAction binding that invokes a method on a data control, delivering the event payload from the departmentSelected event as a parameter to that method. The example below shows the definition of the methodAction binding.

<methodAction id="updateTableForDepartmentId" RequiresUpdateModel="true"
 Action="invokeMethod" MethodName="updateTableForDepartmentId"
 IsViewObjectMethod="false" DataControl="EmployeesDataControl"
 InstanceName="EmployeesDataControl.dataProvider">
 <NamedData NDName="departmentIdPayLoad" NDType="hr.Department"/>
</methodAction>

The updateTableForDepartmentId method takes the hr.Department object, passed as the payload of the departmentSelected event, and filters the data queried from the EmployeesDataControl so that it shows only employees who are in the selected department. It also takes steps to ensure that the iterator is re-executed and that the table view component is marked as needing to be re-rendered in this request.

The Employees task flow includes an event map to specifically map the incoming event onto the appropriate methodAction when the task flow is portletized:

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
 <event name="departmentSelected">
 <producer region="*">
 <consumer region="" handler="updateTableForDepartmentId"
 handleCondition="${ADFPortletBridge.bridgeRequest}">
 <parameters>
 <parameter name="p1" value="#{payLoad}"/>
 </parameters>
 </consumer>
 </producer>
 </event>
</eventMap>

Note:

The <producer region="*"> attribute accepts events from any region. This is because when the task flow is running as a portlet, with the event coming into the portlet from a remote application, the remote application does not have any knowledge of the producer region.

The EL expression within handleCondition="${ADFPortletBridge.bridgeRequest}" evaluates to true if the current request is running under the Oracle JSF Portlet Bridge. This ensures that this event map is used only when the task flow is running as a portlet. It is not essential to have this handleCondition. However it can be useful to be able to define a separate eventMap which is used only when the task flow is running as a portlet.

When the two portletized task flows are added to a page, as long as the name of the event triggered by the Departments portlet is the same as that expected by the Employees portlet, no further coding is required; the portlets are automatically linked and when a department is selected in the Departments portlet, the Employees portlet is updated to display employees belong to the selected department.

Figure 12-3 Linked JSF Portlets

Description of Figure 12-3 follows
Description of "Figure 12-3 Linked JSF Portlets"

You may choose to not use automatic event listening, for example, if you have multiple portlets on the same page that use the same events and you wish to control the flow of events between them. Or perhaps the names of the contextual events used by the JSF portlets that you want to link do not match. In this case you must explicitly create an event map in the page definition of the page containing the portletized task flows. This event map links the portlet events of the portlets that you want to wire together. The example below shows how this would work in our example if the Employees task flow was expecting an event named departmentId instead of departmentSelected.

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
 <event name="departmentSelected">
 <producer region="EventSampleProducerdepartments1_1">
 <consumer handler="EventSampleProduceremployees1_1.
 {http://xmlns.oracle.com/adfm/contextualEvent}departmentId"/>
 </producer>
 </event>
</eventMap>

Note:

In the case of portletized task flows, the handler attribute must specify not only the specific binding object that is to handle the event, it must also specify the full QName of the portlet event, using the format <portletBindingId>.<eventQName>. The namespace does not have to be the ADFm namespace; it can be any portlet event, provided the payload is compatible.

How to Link a JSF Portlet to a JSR 286 Portlet

As well as linking JSF portlets to other JSF portlets, you can also link a JSF portlet to a regular JSR 286 portlet. To do this, you must ensure that the JSR 286 portlet explicitly declares that it can to receive contextual events.

For example, we can link the Departments task flow from our previous example to a Department Address portlet, a JSR 286 portlet, to display the address of a selected department.

For automatic event wiring to work, the Department Address portlet must declare that it can receive the contextual event from the Department portlet. It can do this in two ways:

  • The Department Address portlet directly supports the departmentSelected contextual event:

    <supported-processing-event id="departmentSelected">
     <qname xmlns:x="http://xmlns.oracle.com/adfm/contextualEvent">
     x:departmentSelected
     </qname>
    </supported-processing-event>
    
  • The event definition for the Department Address portlet's event, department, provides an alias to associate it with the departmentSelected contextual event:

    <event-definition id="department">
     <qname xmlns:x="http://xmlns.oracle.com/portlet/EventSample">
     x:department
     </qname>
     <alias xmlns:x="http://xmlns.oracle.com/adfm/contextualEvent">
     x:departmentSelected
     </alias>
     <value-type>hr.Department</value-type>
    </event-definition>

Note:

The namespace for portlet events used to carry contextual event is always:

http://xmlns.oracle.com/adfm/contextualEvent

The namespace is used in the event declarations or alias given above. This namespace indicates to the consumer that the portlet wishes to receive a contextual event with the given name as a portlet event. This is essential for automatic event wiring to work.

The Department Address portlet includes code in its processEvent implementation to handle the event. This method looks for either the departmentSelected or the department event with the alias as defined above. The payload type for both of these events is hr.Department. However, the method shown in the example below illustrates how to use the ADFmPayloadWrapper to unwrap the payload. ADFmPayloadWrapper is the event type that the Oracle JSF Portlet Bridge uses by default when raising events.

public void processEvent(EventRequest request, EventResponse response)
 throws PortletException, IOException
 {
response.setRenderParameters(request);
 
Event event =request.getEvent();
 String eventName =event.getName();
 if ("departmentSelected".equals(eventName) ││
"department".equals(eventName))
 {
Object payload =event.getValue();
 if (payload instanceof ADFmPayloadWrapper)
 {
payload =((ADFmPayloadWrapper)payload).getPayload();
 }
if (payload instanceof Department)
 {
Department department =(Department)payload;
 int locationId =department.getLocation();
 response.setRenderParameter("locationId", Integer.toString(locationId));
 }
}
}

When these two portlets are displayed together on a page, selecting a department in the Departments portlet automatically updates the Department Address portlet to display the address of the selected department.

Figure 12-4 JSF Portlet Linked to a JSR 286 Portlet

Description of Figure 12-4 follows
Description of "Figure 12-4 JSF Portlet Linked to a JSR 286 Portlet"

If the Department Address portlet does not explicitly support the departmentSelected event or define an appropriate alias, you can still link the two portlets by creating an event map in the page definition:

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
 <event name="departmentSelected">
 <producer region="EventSampleProducerdepartments1_1">
 <consumer handler="DepartmentAddress1_1.
 {http://xmlns.oracle.com/portlet/EventSample}department"/>
 </producer>
 </event>
</eventMap>

The result of this event mapping is that when the departmentSelected contextual event is raised by the EventSampleProducerdepartments1_1 portlet binding, the event is delivered to the DepartmentAddress1_1 portlet binding, which in turn sends the event on to the portlet using the portlet event, department.

Note:

The payload of the departmentSelected contextual event is a hr.Departments object. This is the same payload type that the portlet's department portal event is expecting, so that matches and everything works correctly. It is also possible for the portlet to declare that it expects a payload of type ADFmPayloadWrapper. In this case, the portlet consumer detects this and automatically wraps the contextual event payload in an ADFmPayloadWrapper object.

How to Link a JSR 286 Portlet to a JSF Portlet

You can also send portlet events from a JSR 286 portlet to a JSF portlet. The portlet event is converted into a contextual event by the Oracle JSF Portlet Bridge and is then delivered into the producer ADF application to be consumed using standard contextual event techniques.

The Departments task flow contains a methodAction binding that binds to a method on the DepartmentsDataControl:

<methodAction id="updateTableForLocationId" RequiresUpdateModel="true"
 Action="invokeMethod" MethodName="updateTableForLocationId"
 IsViewObjectMethod="false"
 DataControl="DepartmentsDataControl"
 InstanceName="DepartmentsDataControl.dataProvider">
 <NamedData NDName="locationId" NDType="int"/>
</methodAction>

The updateTableForLocationId method receives, as a parameter, a location ID that causes the list of departments returned by the data control to be filtered by that location ID.

The task flow contains an event map to map the contextual event onto the appropriate methodAction:

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
 <event name="locationId">
 <producer region="*">
 <consumer region="" handler="updateTableForLocationId"
 handleCondition="${ADFPortletBridge.bridgeRequest}">
 <parameters>
 <parameter name="p1" value="#{payLoad}"/>
 </parameters>
 </consumer>
 </producer>
 </event>
</eventMap>

Note:

The event map cannot reference the region where the event originates because it is not present when the task flow is running as a portlet, so we use a wildcard as the event source in the event map

In the Department Locations portlet, when a location is selected, the processAction method raises a portlet event, locationId, giving the location ID of the selected location:

public void processAction(ActionRequest request, ActionResponse response)
 throws PortletException
 {
String locationId =request.getParameter("locationId");
 Location location =getLocation(Integer.parseInt(locationId));
 
if (location != null)
 {
//QName matches the event declared as a supported-publishing-event in
 //portlet.xml for this portlet.
 
//LocationId event. Raised in the ContextualEvent namespace makes it readily
 //consumable by ADF Bridge portlets. Likewise we wrap with the
 //ADFmPayloadWrapper payload object that the ADF Bridge expects.
 response.setEvent(new QName("http://xmlns.oracle.com/adfm/contextualEvent",
 "locationId"),
 new ADFmPayloadWrapper(Integer.valueOf(location.getLocationId())));
 }
}

Note:

The locationId event raised in the processAction method has a payload of type of Integer. However, because JSF portlets always expect portlet events with the contextual event payloads wrapped with ADFmPayloadWrapper, we must wrap the payload to suit the receiving portlet's requirements if we want automatic delivery of events to work.

Likewise, the QName for the event we raise must be:

{http://xmlns.oracle.com/adfm/contextualEvent}locationId

When you drop the portlets on a page, selecting a location in the Department Location portlet automatically updates the Departments portlet to display the departments at the selected location.

Figure 12-5 JSR 286 Portlet Linked to a JSF Portlet

Description of Figure 12-5 follows
Description of "Figure 12-5 JSR 286 Portlet Linked to a JSF Portlet"

If the two portlets do not declare events with matching names (for example the contextual event from the Departments portlet is called locId), or if automatic event listening is disabled, you can still link the two portlets by creating an event map in the page definition to map the contextual event from the Departments portlet to the portlet event from the Department Location portlet:

<eventMap xmlns="http://xmlns.oracle.com/adfm/contextualEvent">
 <event name="locationId">
 <producer region="DepartmentLocations1_1">
 <consumer handler="DepartmentsADFBridgePortlet1_1.
 {http://xmlns.oracle.com/adfm/contextualEvent}locId">
 </consumer>
 </producer>
 </event>
</eventMap>

What You May Need to Know About Portlet Events in the Oracle JSF Portlet Bridge

This section includes the following topics:

What You May Need to Know About Using a Serialized Type for the Contextual Event Payload

Part of the JSR 286 event's payload is the wrapped contextual event payload, which is serialized. Therefore, while contextual event payloads can be any object type, when you are sending contextual events via WSRP, only serialized types are supported.

When this wrapped contextual event is delivered, the contextual event payload must be deserialized on the consumer before the contextual event can be forwarded into the consumer application. To deserialize the event, the payload class must be available on the consumer as well as on the producer. This condition is automatically met when the original payload is a Java Runtime Environment class, such as java.lang.String.

What You May Need to Know About Raising Undeclared Events

If your Oracle ADF task flow includes ADFm events that do not have corresponding portlet events declared in the portlet.xml file, you can enable the Oracle JSF Portlet Bridge to raise these undeclared events.

To raise undeclared events, set the following container runtime option for the portletized task flow:

<portlet id="Application5untitled1jspx1_1">
 ...
 <container-runtime-option>
 <name>oracle.portlet.bridge.adf.raiseUndeclaredContextualEvents</name>
 <value>true</value>
 </container-runtime-option>
 ...
</portlet>

Setting this option to true means that any ADFm event raised is forwarded on as a portlet event. If this option is not provided or is set to false, then only events with corresponding portlet event declarations are forwarded. For information about setting container runtime options, see Setting Container Runtime Options for Individual Portlets.

You can also enable undeclared portlet events to automatically be forwarded on from the portlet binding in the consumer application as ADFm events.

In the portlet binding, set the raiseUndeclaredContextualEvent attribute to true, for example:

<portlet id="Application5untitled1jspx1_1"
 portletInstance="/oracle/adf/portlet/WsrpPortletProducer4/ap/
 Application5untitled1jspx_2943bd23_012e_1000_8004_0aa7c0849010"
 class="oracle.adf.model.portlet.binding.PortletBinding"
 retainPortletHeader="false"
 listenForAutoDeliveredPortletEvents="true"
 listenForAutoDeliveredParameterChanges="true"
 raiseUndeclaredContextualEvents="true"
 xmlns="http://xmlns.oracle.com/portlet/bindings"/>

Setting this option to true means that if a portlet event is received, a corresponding ADFm event is raised, even if there is no event declaration in the portlet binding. The name of the ADFm event is directly taken from the QName of the portlet event. This is so that ADFm events raised from the Oracle JSF Portlet Bridge have the same name as that used when the event was raised on the remote application.

What You May Need to Know About Partial Page Rendering

The Oracle JSF Portlet Bridge uses portlet events to transport contextual events to and from the consumer application. However, partial page rendering (PPR) requests are implemented using Portlet 2.0 resource requests. It is not possible to send or receive portlet events in resource requests. Therefore proprietary mechanisms are used to transport the contextual events from the JSF Portlet to the consumer application in the case of PPR requests.