Skip Headers
Oracle® Fusion Middleware Developer's Guide for Oracle WebCenter
11g Release 1 (11.1.1.5.0)

Part Number E10148-15
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

62 Creating Pagelets with the Oracle WebCenter Pagelet Producer

A pagelet is a reusable user interface component. Any HTML fragment can be a pagelet, but pagelet developers can also write pagelets that are parameterized and configurable, to dynamically interact with other pagelets, and respond to user input using Asynchronous Javascript and XML (AJAX) patterns. Pagelets are similar to portlets, but while portlets were designed specifically for portals, pagelets can be run on any web page, including within a portal or other web application. Pagelets can be used to expose platform-specific portlets in other web environments.

The Oracle WebCenter Pagelet Producer (previously known as Oracle WebCenter Ensemble) provides a collection of useful tools and features that facilitate dynamic pagelet development. This chapter includes detailed information about pagelet development and configuration using the Pagelet Producer.

62.1 Using Pagelets in Web Applications

This section describes how to add pagelets to a JSF page in JDeveloper, to any web page, or to a page in WebCenter Spaces.

This section includes the following subsections:

62.1.1 How to Add a Pagelet to a JSF Page in Oracle JDeveloper

In this section, you will register an Oracle WebCenter Pagelet Producer, add a pagelet to a JSF page, and run the page to a browser to view the pagelet.

This section includes the following subsections:

62.1.1.1 How to Register a Pagelet Producer

Before you can add a pagelet to a JSF page, you must register the Pagelet Producer with your WebCenter Portal application. You can register Pagelet Producers in two ways:

  • Register a producer with a specific application. By default, the IDE Connection option is selected in the New Pagelet Producer dialog that creates the connection under the Application Resources panel.

  • Register a producer using the Resource Palette. This option enables you to use the producer's pagelets in multiple applications. A pagelet that is available in the Resource Palette can be added to any of your WebCenter Portal applications by dropping it on the page.

To register a Pagelet Producer:

  1. In the Application Resources panel of the Application Navigator, right-click Connections, choose New Connection and then choose Pagelet Producer.

    For other methods of invoking the wizard, such as from the Resource Palette, see Section 1.6.2, "How Do I Access the Connection Wizards?"

  2. In the Name field of the New Pagelet Producer dialog, enter a meaningful name for your producer. For example, myPageletProducer.

  3. In the URL field, enter the URL of your Pagelet Producer in the format: http://hostname:portnumber.

  4. Click OK. In the Application Resources panel, the Pagelet Producer is created under the Pagelet Producer directory in the Connections directory, as shown in Figure 62-1.

    Figure 62-1 Pagelet Producer in the Application Resources Panel

    Description of Figure 62-1 follows
    Description of "Figure 62-1 Pagelet Producer in the Application Resources Panel"

62.1.1.2 How to Add a Pagelet to a JSF Page

To add a pagelet to a page:

  1. In JDeveloper, open your JSF page in Design View, if it is not open already.

  2. In the Application Resources panel, under Pagelet Producer, expand your producer to display its contents.

  3. From the producer's contents, drop a pagelet onto the JSF page.

  4. In the Add Pagelet to Page dialog, choose Yes in the Use IFrame section if you would like to enable IFRAME for this pagelet.

  5. In the IFrame Height field, specify the required height in pixels or leave it blank and click OK.

  6. In the Edit Task Flow Binding dialog input parameters are specified by default. Change any parameters, if required, and then click OK.

  7. Save the page. In the Structure window, the page looks like Figure 62-2.

    Figure 62-2 Pagelet in the Structure Window

    Description of Figure 62-2 follows
    Description of "Figure 62-2 Pagelet in the Structure Window"

  8. In the Application Navigator, right-click your JSF page under Projects, and choose Run.

  9. In the login page, enter user name and password so you can view the pagelet. Figure 62-3 shows a sample pagelet in a browser window.

    Figure 62-3 Sample Pagelet

    Description of Figure 62-3 follows
    Description of "Figure 62-3 Sample Pagelet"

62.1.1.3 How to Secure a Pagelet

For information about securing pagelets, see the section "Policy" and the section "Configuring Oracle Single Sign-On (OSSO)" in Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter.

62.1.2 How to Add a Pagelet to any Web Page

Once you have deployed a pagelet, you can insert it into a proxied or non-proxied page. To deploy a pagelet in the Pagelet Producer, you must configure Resource and Pagelet objects.

This section describes how to insert pagelets using javascript and REST. It includes the following subsections:

62.1.2.1 Inserting Pagelets Using Javascript

This section includes the following subsections:

62.1.2.1.1 Inserting Pagelets Using Javascript

You can insert pagelets into non-proxied pages using a simple javascript function.

To activate this feature, add the following HTML snippet in the <HEAD> section of the page.

<script type="text/javascript" src="http://proxy:port/inject/v2/csapi">
</script>

This script injects all CSAPI and pagelet inject functions into the page to display the pagelet. One of the sections injected is the following function:

function injectpagelet(library, name, iframe_options, payload, params, context_id, element_id,  is_in_community)
{
    ...
}

This function injects a pagelet as a widget into the parent page. The method interface is as follows:

  • library: The library name of the pagelet to inject. This argument is a string that accepts spaces like 'library name'.

  • name: The name of the pagelet to inject. This argument is a string that accepts spaces like 'pagelet name'.

  • iframe_options: Optional. This parameter specifies whether to use IFRAME around the pagelet content. Sample IFRAME options: iframe width=100% height=auto frameborder=0. If omitted or left blank, the pagelet content is rendered inline.

  • payload: Optional. The XML payload to send with the pagelet request.

  • params: The pagelet parameters in query string format. For example, 'param1=value1&param2=value2&param3=value3'.

  • context_id: Optional. This is the external identifier of the pagelet instance. It must be an integer.

  • element_id: Optional. The HTML element ID in which the pagelet content is injected. If omitted or left blank, the pagelet content is injected using document.write() when the injectpagelet call is evaluated.

  • is_in_community: Optional. This argument specifies whether this pagelet is on a community or group page. If the value is set to true, it sends the context_id in the community ID header to the pagelet. Defaults to false.

The script also creates a new <div> with a unique name that includes a reference to the injectpagelet function. Several examples are shown below:

<div>
    <script type="text/javascript">
        injectpagelet('library', 'name');
    </script>
</div>
<div>
    <script type="text/javascript">
    injectpagelet('library', 'name', 'iframe', 'payload', 'param1=value1&param2=value2&param3=value3');
    </script>
</div>
<div>
    <script type="text/javascript">
    injectpagelet('library', 'name', 'iframe width=100% height=200', 'payload');
    </script>
</div>
62.1.2.1.2 Adding a Preference Editor Using Javascript

The injecteditor function lets you add preference editors that enable users to set personal and shared preferences for pagelets that support this capability. This functionality is analogous to personalization and customization functionality in Oracle WebCenter.

injecteditor(library, name, type, iframe_options, context_id, element_id)

where:

  • library: The library name of the pagelet to inject. This argument is a string that accepts spaces like 'library name'.

  • name: The name of the pagelet to inject. This argument is a string that accepts spaces like 'pagelet name'.

  • type: The type of the editor. editor type. This argument supports these values: 'admin', 'pagelet', 'community'. In case of the 'community' argument, context_id is sent to pagelet in the community ID CSP header.

  • iframe_options: Optional. This parameter specifies whether to use IFRAME around the pagelet editor content. Sample IFRAME options: iframe width=100% height=auto frameborder=0. If omitted or left blank, the editor content is rendered inline.

  • context_id: Optional. This is the external identifier of the pagelet instance. It must be an integer.

  • element_id: Optional. The HTML element ID in which the pagelet content is injected. If omitted or left blank, the pagelet content is injected using document.write() when the injecteditor call is evaluated.

62.1.2.1.3 Using Automatic Resizing with IFrames

The pagelet inject function can automatically resize the IFrame that encapsulates pagelet content. The resizing is done so that the IFrame stretches to fit the content within. To use this feature, the ifwidth and ifheight parameters must be set to 'auto' as shown in the example below:

<script type="text/javascript">
injectpagelet('library', 'pagelet', 'iframe ifheight=auto ifwidth=auto');
</script>

In addition, this feature relies on an external page on the same domain as the consumer page. This page is included into the pagelet IFrame as an internal hidden IFrame. This page collects the sizing information and passes it on to the parent consumer page. This page must be deployed in the same directory as the consumer page. An example is shown below.

<html>
  <head>
    <title>Resizing Page</title>
    <script type="text/javascript">
                function onLoad() {
                        var params = window.location.search.substring( 1 ).split( '&' );
                        var height;
                        var width;
                        var iframe;
 
                        for( var i = 0, l = params.length; i < l; ++i ) {
                                var parts = params[i].split( '=' );
                                switch( parts[0] ) {
                                        case 'height':
                                                height = parseInt( parts[1] );
                                                break;
                                        case 'width':
                                                width = parseInt( parts[1] );
                                                break;
                                        case 'iframe':
                                                iframe = parts[1];
                                                break;
                                }
                        }
                        window.top.updateIFrame( iframe, height, width );
                }
 
                if (window.addEventListener) {
                        window.addEventListener("load", onLoad, false)
                } else if (window.attachEvent) {
                        window.detachEvent("onload", onLoad)
                        window.attachEvent("onload", onLoad)
                } else {
                        window.onload=onLoad
                }
    </script>
  </head>
  <body>
  </body>
</html>

To insert a pagelet into a proxied page, use the REST API; for details, see Section 62.1.3.2, "Pagelet Inject API".

62.1.3 Accessing Pagelets Using REST

REST stands for Representational State Transfer and is a simple way of providing APIs over HTTP. The basic principles of REST are:

  • API URLs point to the resource being used, rather than a generic method endpoint.

  • Requests use standard HTTP verbs for simplified CRUD methods. This is a read-only API and allows GET requests only.

  • Every request should return a full representation of the object retrieved (pagelet or resource).

Oracle WebCenter Pagelet Producer REST APIs provide the following functionality:

  • Allow remote web services to retrieve information about resources and pagelets from the Pagelet Producer. For details, see Section 62.1.3.1, "Data Retrieval APIs".

  • Inject pagelets into non-proxied pages, allowing the Pagelet Producer to act as a portlet provider for Oracle WebCenter Interaction, Oracle WebLogic Portal, or other third-party portals. For details, see Section 62.1.3.2, "Pagelet Inject API".

62.1.3.1 Data Retrieval APIs

Two REST APIs are available to retrieve data from the Pagelet Producer:

The base URL for all requests is http://producer base URL/api/v2/ensemble/. Here are some examples:

Example 62-1 Pagelets

http://host/api/v2/ensemble/pagelets/
http://host/api/v2/ensemble/pagelets/?format=xml
http://host/api/v2/ensemble/pagelets/?format=json

Example 62-2 Pagelets By Library

http://host:7001/api/v2/ensemble/pagelet/libraryname/
http://host:7001/api/v2/ensemble/pagelet/libraryname/?format=xml
http://host:7001/api/v2/ensemble/pagelet/libraryname/?format=json

Example 62-3 Pagelets By Library and Name

http://host:7001/api/v2/ensemble/pagelet/libraryname/pageletname/
http://host:7001/api/v2/ensemble/pagelet/libraryname/pageletname/?format=xml
http://host:7001/api/v2/ensemble/pagelet/libraryname/pageletname/?format=json

Example 62-4 Resource By Name

http://host/api/v2/ensemble/resource/resourcename
http://host/api/v2/ensemble/resource/resourcename/?format=xml
http://host/api/v2/ensemble/resource/resourcename/?format=json

Example 62-5 Resources By URL Prefix

http://host/api/v2/ensemble/resources?externalurlprefix=/url/
http://host/api/v2/ensemble/resources?externalurlprefix=/url/&format=xml
http://host/api/v2/ensemble/resources?externalurlprefix=/url/&format=json

62.1.3.2 Pagelet Inject API

By entering a proxy URL into the portal portlet source code, the Pagelet Producer will load up the pagelet as a portlet. The proxy URL must use the following format:

http://host:port/inject/v2/pagelet/libraryname/pageletname?instanceid=55&content-type=html

where libraryname and pageletname refer to the library and pagelet configured in the Pagelet Producer.

Note:

When using the pagelet inject API as the URL for a Portlet Web Service in Oracle WebCenter Interaction, you must switch "pagelet" to "portlet" in the URL. For example, the above URL would become:

http://host:port/inject/v2/portlet/libraryname/pageletnameinstanceid=55&content-type=html

The query string arguments to the above call define how the pagelet is to be returned. The following parameters are defined:

  • instanceid: Optional. The instance ID of the pagelet.

  • content-type: The return type. Three types are supported:

    • javascript: Returns injectable code.

    • html: Returns the pagelet markup with its associated PTPortlet object.

    • iframe: Returns an IFrame that points back to the inject api, filling the IFrame with the pagelet content, instead of directly inline with the page. The IFrame can be styled by providing a set of query string parameters.

      Parameter Description Default
      ifwidth Sets the width of the IFrame; can be specified in percent '%' or pixels 'px', for example: ifwidth=500px. Can be set to 'auto' to automatically resize the IFrame to fit the content within. For details, see Section 62.1.3.3, "Using Automatic Resizing with IFrames". 100%
      ifheight Sets the height of the IFrame; can be specified in percent '%' or pixels 'px', for example: ifheight=500px. Can be set to 'auto' to automatically resize the IFrame to fit the content within. For details, see Section 62.1.3.3, "Using Automatic Resizing with IFrames". No default
      ifborder Sets the border of the IFrame. 'none'
      ifalign Sets the align rule within the IFrame, for example: ifalign=center. No default
      ifdesc Sets the description of the IFrame. No default
      ifmarginheight Sets the margin height; can be specified in percent '%' or pixels 'px', for example: ifmarginheight=500px. No default
      ifmarginwidth Sets the margin width; can be specified in percent '%' or pixels 'px', for example: ifmarginwidth=500px. No default
      ifscrolling Sets the scrollbars of the IFrame. Accepted values: yes/no/auto. auto
      ifstyle Sets the CSS style of the IFrame No default
      ifclass Sets the CSS class of the IFrame. No default

  • csapi: Sets whether the CSAPI will be included with the pagelet response (true or false). Including the CSAPI is optional, but the pagelet included in the response relies on the CSAPI libraries being present on the page where the pagelet is to be rendered. If csapi=false, then the CSAPI libraries must be included with the parent page (usually in the HEAD section).

  • onhtttperror:: When a pagelet request results in a 403, 404 or any other error code, the Pagelet Producer can forward the error code and the error page itself to the browser for display to the user. The onhttperror parameter accepts the following values:

    • comment (default): The Pagelet Producer will create an HTML comment in place of the failing pagelet (the failing pagelet will simply not be displayed).

    • inline: The pagelet error along with the server error page will be displayed inline where the pagelet would normally be shown on the page.

    • fullpage: The http error will consume the whole page. This mode is only available if the Pagelet Producer controls the parent page.

For example, the following URL points to the linkspagelet in the samples library:

http://proxy:port/inject/v2/pagelet/samples/linkspagelet?content-type=iframe&csapi=true&ifheight=123px&ifclass=myclass

This URL should result in markup similar to the code below.

Note:

The IFrame source points back to the inject API, but this time the content-type parameter is set to html. This feature adds an additional step in the pagelet retrieval. The csapi parameter is set to true on the subsequent call to get the IFrame contents so that the required CSAPI content is included in the IFrame (if this was not the case, javascript resolve errors would be returned because the pagelet code cannot access any CSAPI script included outside the IFrame).
<html>
 <head>
 </head>
 <body>
  <iframe frameborder="none" class="myclass" width="100%" height="123px" scrolling="auto" src="http://proxy:port/inject/v2/pagelet/samples/linkspagelet?asdg=asdfgas&param=true&content-type=html&jswrap=false&csapi=true">
   <html>
    <head>
     <script src="http://proxy:loginserverport/loginserver/ensemblestatic/imageserver/plumtree/common/private/js/jsutil/LATEST/PTUtil.js" type="text/javascript"> </script>
     <script src="http://proxy:loginserverport/loginserver/ensemblestatic/imageserver/plumtree/common/private/js/jsutil/LATEST/PTDateFormats.js" type="text/javascript"></script>
     <script src="http://proxy:loginserverport/loginserver/ensemblestatic/imageserver/plumtree/common/private/js/jsxml/LATEST/PTXML.js" type="text/javascript"></script>
     <script src="http://proxy:loginserverport/loginserver/ensemblestatic/imageserver/plumtree/common/private/js/jsportlet/LATEST/PTPortletServices.js" type="text/javascript"></script>
    </head>
 
    <body>
     <div id="pt-pagelet-content-1" class="pagelet-container" style="display: inline;">
      <span xmlns:pt="http://www.plumtree.com/xmlschemas/ptui/">
      Pagelet links:
      <br/>
      <a href="http://proxy:port/inject/RP_PID393219_I1/headpagelet1.html">The first pagelet</a>
      <br/>
      <a href="http://proxy:port/inject/RP_PID393219_I1/headpagelet2.html">The second pagelet</a>
      <br/>
      <a href="http://proxy:port/inject/RP_PID393219_I1/csapipagelet.html">The csapi pagelet</a>
      <br/>
      <a href="http://proxy:port/inject/RP_PID393219_I1/linkspagelet.html">This pagelet</a>
      <br/>
      </span>
     </div>
    </body>
   </html>
  </iframe>
 </body>
</html>

62.1.3.3 Using Automatic Resizing with IFrames

The Pagelet Producer pagelet inject API can automatically resize the IFrame that encapsulates pagelet content. The resizing is done so that the IFrame stretches to fit the content within. To use this feature, the ifwidth and ifheight parameters must be set to 'auto' as shown in the example below:

http://proxy:port/inject/v2/pagelet/samples/linkspagelet?content-type=iframe&csapi=true&ifheight=auto&ifwidth=auto&ifclass=myclass

In addition, this feature relies on an external page on the same domain as the consumer page. This page is included into the pagelet IFrame as an internal hidden IFrame. This page collects the sizing information and passes it on to the parent consumer page. This page must be deployed in the same directory as the consumer page. An example is shown below.

<html>
  <head>
    <title>Resizing Page</title>
    <script type="text/javascript">
                function onLoad() {
                        var params = window.location.search.substring( 1 ).split( '&' );
                        var height;
                        var width;
                        var iframe;
 
                        for( var i = 0, l = params.length; i < l; ++i ) {
                                var parts = params[i].split( '=' );
                                switch( parts[0] ) {
                                        case 'height':
                                                height = parseInt( parts[1] );
                                                break;
                                        case 'width':
                                                width = parseInt( parts[1] );
                                                break;
                                        case 'iframe':
                                                iframe = parts[1];
                                                break;
                                }
                        }
                        window.top.updateIFrame( iframe, height, width );
                }
 
                if (window.addEventListener) {
                        window.addEventListener("load", onLoad, false)
                } else if (window.attachEvent) {
                        window.detachEvent("onload", onLoad)
                        window.attachEvent("onload", onLoad)
                } else {
                        window.onload=onLoad
                }
    </script>
  </head>
  <body>
  </body>
</html>

62.1.4 How to Add a Pagelet to a Page in WebCenter Spaces

In WebCenter Spaces, you can add a pagelet to a page using Oracle Composer. For information about how to add a pagelet in WebCenter Spaces, see the section "Adding Resource Catalog Components to Pages" in Oracle Fusion Middleware User's Guide for Oracle WebCenter Spaces.

62.2 Building Pagelets Using the Oracle WebCenter Pagelet Producer

This section provides detailed information on building pagelets using the Oracle WebCenter Pagelet Producer.

62.2.1 About Server Communication and the Proxy

The Oracle WebCenter Pagelet Producer acts as a proxy server, brokering transactions between client computers and external resources.

Services on external resources communicate with the Pagelet Producer via HTTP. For example, when a browser requests a page, the Pagelet Producer makes simultaneous requests to each external resource to retrieve the pagelet content for the page. The external resource reads the current user's preferences from the HTTP headers sent by the Pagelet Producer and sends back the appropriate HTML. The Pagelet Producer inserts the HTML into the table that makes up the page. Any images stored in the Image Service are retrieved and displayed by the browser.

The syntax of communication between the Pagelet Producer and external resources is defined by CSP. CSP is a platform-independent protocol based on the open standard of HTTP 1.1 that defines custom headers and outlines how services use HTTP to communicate and modify settings. For details on CSP, see Section 62.2.1.2, "About HTTP and CSP".

62.2.1.1 The Oracle WebCenter Pagelet Producer Proxy

A proxy server acts as a middleman, brokering transactions between a client computer and another server. This configuration is typically used to serve content to clients that would otherwise be unable to access the external resource, but it can be used to impose additional security restrictions on the client. The proxy hides the external resource; to the end user, the content appears to come directly from the proxy server.

This architecture makes the Oracle WebCenter Pagelet Producer the single point of access for content, and allows external resources to reside on a private network or behind a firewall. As long as the Pagelet Producer can connect to the external resource, users can view the content, even if they cannot access it directly. To the browser, the Pagelet Producer appears to be the source of content on the external resource.

When a user interacts with a service, any request made to a URL in the proxy is automatically rerouted through the Pagelet Producer. To the user, the content appears to come from the Pagelet Producer; the external resource is an unknown back-end system.

There are many benefits to this configuration. The most useful to services are:

  • Dynamic functionality and personalization: The Pagelet Producer intercepts requests from pagelets, which allows it to include information stored in the MDS in HTTP requests and responses.

  • Security: Services can allow users to access content that is not publicly available. Files stored on a secure server can be made available by including specific URLs in the configuration of the proxy. Note: The proxy is a powerful feature, and can compromise security if incorrectly configured. Allowing direct access to a external resource that hosts unprotected private content could create a dangerous security hole.

  • Performance: The Pagelet Producer caches proxied content, decreasing response time for end users and improving performance on the external resource. While proxying works efficiently for content like HTML, it is generally not appropriate for binary data like static images. Images do not need to be transformed, and proxying large images can adversely affect performance. This is one reason the Image Service should be used to prevent routing static images through the proxy.

The collection of URLs that should be proxied for a service is configured in the Resource editor. All URLs that use the Internal URL prefix configured for the resource will be proxied unless Enable URL Rewriting is deselected.

Keep the following warnings and best practices in mind when implementing services that use the proxy:

  • URL transformation: The Pagelet Producer must transform code so that proxied URLs open correctly. Before the Pagelet Producer sends a response, it parses the HTML and looks for any URLs that use the Internal URL prefix configured for the associated producer resource. The Pagelet Producer transforms any URLs that should be proxied before returning the response to the client. Relative URLs are transformed to point to the correct location.

  • Scripting limitations: JavaScript constructs that dynamically create URLs can cause problems, because they are run after content is already transformed. VBScript is not transformed by the proxy; you can continue to use dynamic scripts and VBScript as long as your code is proxy-aware.

  • URL encoding: It is a best practice to encode all headers that are URLs to prevent unexpected transformation. In JSP, encode all URLs that are written. If the code writes URLs in the body of a page (for example, a link to a preferences page) it should be encoded. The standard Java servlet command response.encodeURL() is the preferred method, but you can also use URLEncoder.encode(url). In the .NET Framework, the HttpUtility.URLEncode class provides the necessary functionality. Note: In .NET, there is no need to encode the redirect URL; this is handled automatically on the back end.

62.2.1.1.1 About Pagelets and the Proxy

All pagelets are designed to be displayed with other pagelets. As explained in the previous section, the Pagelet Producer acts as a proxy, processing and combining pagelets from multiple applications to create a single, unified page with a range of functionality.

The code returned by a pagelet is parsed by the Pagelet Producer server and inserted into the appropriate cell in the HTML table that makes up the page. Pagelets from the same back-end application can interact with each other within the page.

62.2.1.2 About HTTP and CSP

HTTP is a protocol used mostly for transferring web page content and XML between a server and a client. CSP is a platform-independent protocol based on the open standard of HTTP 1.1 that defines the syntax of communication between the Pagelet Producer and external resources.

62.2.1.2.1 HTTP

HTTP communication is made up of Requests and Responses. Requests and Responses are essentially lists of name-value pairs of metadata in headers, along with an optional body. The body is the data that is being transferred (an HTML page or XML file). The metadata in the headers is information about the Request or Response itself (what language the content is in, or how long the browser should cache it). The Request and Response each contain specific information, outlined next. For more detailed information on HTTP, see RFC 2616 (http://www.faqs.org/rfcs/rfc2616.html).

The client sends the server an HTTP Request, asking for content. The Request body is used only for requests that transfer data to the server, such as POST and PUT.

HTTP Request Format:

[METHOD] [REQUEST-URI] HTTP/[VERSION]
[fieldname1]: [field-value1]
[fieldname2]: [field-value2]
[request body, if any]

HTTP Request Example:

GET /index.html HTTP/1.1 
Host: www.plumtree.com 
User-Agent: Mozilla/3.0 (compatible; Opera/3.0; Windows 95/NT4) 
Accept: */* 
Cookie: username=JoeSmith

The server sends back an HTTP Response that contains page content and important details, such as the content type, when the document was last modified, and the server type. The Response contains an error message if the requested content is not found.

HTTP Response Format:

HTTP/[VERSION] [CODE] [TEXT] 
[fieldname1]: [field-value1] 
[fieldname2]: [field-value2] 
[response body, if any (document content here)]

HTTP Response Example:

HTTP/1.0 200 Found 
Last-modified: Thursday, 20-Nov-97 10:44:53 
Content-length: 6372 
Content-type: text/html 
<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 3.2 Final// EN'><HTML> 
...followed by document content...

Custom HTTP headers can be configured to include specialized information.

Note:

Header size limits are controlled by the server that hosts the code. The standard limit for IIS/ASP is 60K. Java Application Servers range from 2K to 10K. These limits are generally configurable; see your server documentation for details.

Services can also access standard HTTP headers, such as the Set-Cookie header or HTTP 1.1 basic authentication header. If you want to investigate HTTP further, you can view all the headers being passed back and forth between your browser and Web server using a tunnel tool. HTTP is used in conjunction with SSL to serve up secure content. Single Sign-On (SSO) also uses HTTP headers for basic authentication.

62.2.1.2.2 CSP

CSP extends HTTP and defines proprietary headers to pass settings between Pagelet Producer and external resources. CSP outlines how Pagelet Producer services use HTTP to communicate and modify settings. (CSP is also used by Oracle WebCenter Interaction.) The latest version is 1.4, and is available here: http://download.oracle.com/docs/cd/E13158_01/alui/wci/docs103/devguide/references/CSP1.4.pdf.

The custom headers used by the Pagelet Producer to communicate system and user configuration variables can also be used by pagelets.

Table 62-1 Oracle WebCenter Pagelet Producer Headers

Header Name Description

User ID

The User ID of the currently logged in user. This value can be used to determine if the session has expired. If UserID=2, the default 'Guest' user is logged in; any other user's session has ended.

User Name

The name of the logged in user. The user's name can be used to personalize display or pre-fill form fields.

Image Service URL

The URL to the root virtual directory of the Image Service in the user's implementation of the Pagelet Producer. This location should be used for all static images used in services.

Stylesheet URL

The URL to the current user's style sheet. In each implementation of the Pagelet Producer, the UI is customized. In some portals, users can choose between a selection of stylesheets. Using these styles ensures that pagelets appear in the style of the current user's implementation of the Pagelet Producer.

Pagelet ID

The ID for the current resource (pagelet), and the instance ID for the current pagelet. This value is useful for appending to the names of HTML forms and client-side JavaScript functions to ensure unique form and function names on the page to avoid name conflicts.

Host Page URL

The URL to the page that hosts the pagelet. Preference pages need this URL to return the user to the correct page after settings are configured. This value can also be used to allow a single pagelet to display different content on different pages.


62.2.2 Building Adaptive Pagelets

Adaptive pagelets allow you to create a coordinated page with dynamic, interactive functionality comprised of cross-platform services that talk to multiple back-ends. For detailed examples, see Section 62.2.2.1, "Adaptive Pagelet Design Patterns".

The Adaptive Pagelet Scripting Framework is a client-side JavaScript library that provides services to pagelets and proxied pages. The scripting framework allows pagelets to:

  • Store and share session state through browser level variables. Browser-level variables can be stored and shared among pagelets, even if they are not on the same page. For example, a value entered by the user in one pagelet can be retrieved by another. The scripting framework acts as an intermediary, allowing all pagelets access to all values stored in a common session. For details, see Section 62.2.2.4, "Using Session Preferences".

  • Leverage page-level events. A pagelet can respond when specific events happen, such as when the page loads or when the browser focus changes. For details, see Section 62.2.2.2, "Using Scripting Framework Event Notification".

  • Refresh pagelet content without reloading the page. Pagelets can reload their internal content without refreshing the page. For details, see Section 62.2.2.3, "Using In-Place Refresh".

For a full list of classes and methods, see the JSPortlet API documentation.

For additional information on adaptive pagelets, see Section 62.2.2.5, "Adaptive Pagelet Development Tips".

62.2.2.1 Adaptive Pagelet Design Patterns

Adaptive pagelet design patterns provide solutions for broad classes of problems, and provide the base for a range of cross-platform services.

The Master-Detail design pattern uses two pagelets; users select an item from a list in one, and the details for that item are retrieved from the external resource and displayed in another. For example, a set of customers could be listed by name in the "master" pagelet. When the user clicks a name in this pagelet, the "detail" pagelet presents details about the item. The detail pagelet for a customer list could list all the important information about that customer, such as name, address, and phone number. This pattern assumes a tight coupling between the two pagelets; both the master pagelet and detail pagelet must be displayed on the same page. For details and sample code, see Section 62.2.2.4, "Using Session Preferences". For a looser coupling, use the Broadcast-Listener pattern.

The Broadcast-Listener design pattern is similar to the Master-Detail pattern, but assumes a loose coupling between pagelets. Users can select an item or perform some other action in a "broadcast" pagelet, which causes the content in other related "listener" pagelets to be redrawn. The major difference is that the Broadcast-Listener pattern relies on the scripting framework to raise an event when an action is performed in the "broadcast" pagelet. One or more "listener" pagelets can respond to this event and update their content accordingly. For details and sample code, see Section 62.2.2.2, "Using Scripting Framework Event Notification".

In Place Refresh allows you to refresh the content in a pagelet without refreshing the page. For details and sample code, see Section 62.2.2.3, "Using In-Place Refresh".

The Structured Response design pattern handles structured HTTP responses, typically encoded as XML. In many cases it can be expensive and inefficient to send large amounts of HTML back in response to some HTTP request, if only a small part of the user interface needs to be changed. This is especially true with more complex user interfaces. In these cases, the response can be encoded in XML. The client-side response handler can then parse the XML, and update the user interface (or perform some other action) based on that response. Use the Structured Response design pattern to redraw a small area of the user interface after making an HTTP request, or to access a simple HTTP/URI type web service from a pagelet. The example code below (structuredresponse_portlet.html) accesses an RSS feed from a selection of news sites.

<!-- jsxml includes -->
<a id="imgServerHref" href="/images/plumtree" style="display:none"></a>
<script type="text/javascript"
src="/images/plumtree/common/private/js/PTLoader.js"></script>
<script type="text/javascript">
var oImgServer = new Object();
oImgServer.location = document.getElementById('imgServerHref').href;
var imageServerURL = document.getElementById('imgServerHref').href;
var imageServerConnectionURL = oImgServer.location;
new PTLoader(imageServerURL, imageServerConnectionURL).include('jsxml','en');
</script>

<!-- jscontrols includes -->
<link rel="stylesheet" type="text/css" href="/portal-remote-server/js/jscontrols/styles/css/PTMenu.css"/>
<link rel="stylesheet" type="text/css" href="/portal-remote-server/js/jscontrols/styles/css/PTRichTextEditor.css"/>
<script type="text/javascript" src="/portal-remote-server/js/jscontrols/strings/PTControls-en.js"></script>
<script type="text/javascript" src="/portal-remote-server/js/jscontrols/PTControls.js"></script>

<!-- Inline JS helper functions -->
-->

<script defer type="text/javascript" id="structured-response-portlet-A-script">
// Function that gets the RSS XML feed found at the specified url
getRSSFeed = function(url)
  {
  // First clear out any existing rows in the table
  channelTable.clearRows();

  // Force the transformer to fix up the url
  var oURL = new Object();
  oURL.location = url;

  // Do the http get
  var get = new PTHTTPGETRequest(oURL.location, handleRSSResponse);
  get.invoke();
  }

// Function that handles the RSS XML response and updates the table based on the RSS items
handleRSSResponse = function(response)
  {
  // Get the rss xml
  var xml = response.responseText;
  if (!xml || xml.indexOf('<?xml') == -1) { return; }

  // Parse into a dom, and get the channel node
  var xmlDOM = new PTXMLParser(xml);
  var rssNode = xmlDOM.selectSingleNode('rss');
  var channelNode = rssNode.selectSingleNode('channel');

  // Get the channel title and set the status bar text in the table
  var channelTitle = channelNode.selectSingleNode('title').getNodeValue();
  channelTable.statusBarText = '<b>Loaded Channel</b>: ' + channelTitle;

  // Get channel item nodes
  var itemNodes = channelNode.selectNodes('item');
  
  // Build table rows
  channelTable.rows = new Array();
  for (var i=0; i<itemNodes.length; i++)

    {
    var itemNode = itemNodes[i];

    // Get channel item properties
    var itemTitle = itemNode.selectSingleNode('title').getNodeValue();
    var itemLink = itemNode.selectSingleNode('link').getNodeValue();
    var itemDescription = itemNode.selectSingleNode('description').getNodeValue();
    if (itemNode.selectSingleNode('author'))
      var itemAuthor = itemNode.selectSingleNode('author').getNodeValue();
    if (itemNode.selectSingleNode('category'))
      var itemCategory = itemNode.selectSingleNode('category').getNodeValue();
    if (itemNode.selectSingleNode('pubDate'))
      var itemPubDate = itemNode.selectSingleNode('pubDate').getNodeValue();

    // Create a row and add it to the table
    var row = new PTRow();
    row.parent = channelTable;
    row.id = i;
    row.uid = i;
    row.previewText = itemDescription;
    row.link = itemLink;
    row.columnValues[0] = new PTTextColumnValue(itemTitle);
    row.columnValues[1] = new PTTextColumnValue(itemCategory);
    row.columnValues[2] = new PTTextColumnValue(itemAuthor);
    row.columnValues[3] = new PTTextColumnValue(itemPubDate);
    channelTable.rows[channelTable.rows.length] = row;
    }

  // Redraw the table
  channelTable.draw();
  }
</script>

<b>Select RSS Feed:</b>
<a href="#" onclick="getRSSFeed('http://www.wired.com/news/feeds/rss2/0,2610,,00.xml'); return false;">Wired News</a>
<a href="#" onclick="getRSSFeed('http://news.com.com/2547-1_3-0-5.xml'); return false;">CNET News.com</a>
<a href="#" onclick="getRSSFeed('http://partners.userland.com/nytRss/nytHomepage.xml'); return false;">NY Times</a>
<br><br>

<!-- Set up a table control to display channel items -->
<div id="channelTableContainer"></div>
<script defer type="text/javascript">
  var channelTable = new PTTableControl();
  channelTable.locale = 'en_US';
  channelTable.objName = 'channelTable';
  channelTable.container = 'channelTableContainer';
  channelTable.baseURL = '/imageserver/plumtree/common/private/portal-remote-server/js/jscontrols/1/';
  channelTable.statusBarText = 'No RSS Feed Selected';
  channelTable.rowDetailAction = new PTJavaScriptAction('window.open(\'${ROW.link}\');');
  channelTable.columns[0] = new PTColumn();
  channelTable.columns[0].name = 'Title';
  channelTable.columns[0].width = '40%';
  channelTable.columns[1] = new PTColumn();
  channelTable.columns[1].name = 'Category';
  channelTable.columns[1].width = '20%';
  channelTable.columns[2] = new PTColumn();
  channelTable.columns[2].name = 'Author';
  channelTable.columns[2].width = '20%';
  channelTable.columns[3] = new PTColumn();
  channelTable.columns[3].name = 'Publication Date';
  channelTable.columns[3].width = '20%';
  channelTable.areColumnsResizable = true;
  channelTable.clientSortEnabled = true;
  channelTable.scrollHeight = 250;

  channelTable.init();
  channelTable.draw();
</script>
</div>

62.2.2.2 Using Scripting Framework Event Notification

The adaptive pagelet scripting framework allows pagelets to respond to both page-level events and custom events raised by other pagelets.

The registerForWindowEvent and registerOnceForWindowEvent methods in the scripting framework provide pagelets with access to page-level events. For a complete list, see Section 62.2.2.2.1, "Page-Level Events for Use with the Scripting Framework". To register for notification of these events, pass in the name of the event and the name of the method that should be called when it occurs. When a page-level event is raised, the JavaScript event object is passed to the event handler as an argument. The scripting framework also allows pagelets to raise and respond to custom events using raiseEvent and registerForEvent. The Broadcast-Listener design pattern illustrates an important example of using notification services with session preferences. Users can select an item or perform some other action in a "broadcast" pagelet, which causes the content in other related "listener" pagelets to be redrawn. In the following example, the broadcast pagelet displays a form that allows you to enter a number in a text box.

Figure 62-4 Broadcast Portlet

Description of Figure 62-4 follows
Description of "Figure 62-4 Broadcast Portlet"

When the user enters a number in the text box, the values in the listener pagelets change. The first listener pagelet displays the square root of the number entered in the broadcast pagelet.

Figure 62-5 Listener -1 Portlet

Description of Figure 62-5 follows
Description of "Figure 62-5 Listener -1 Portlet"

The second listener pagelet displays the cube root of the number entered in the broadcast pagelet.

Figure 62-6 Listener -2 Portlet

Description of Figure 62-6 follows
Description of "Figure 62-6 Listener -2 Portlet"

The following steps summarize how the pagelets work:

  • On load, each listener pagelet calls its own instance method (registerForEvent) to register for events of type 'onBroadcastUpdate'.

  • On each onkeyup event that occurs in the "Enter number" text box, the broadcast pagelet sets a session preference to the value entered in the text box, and calls its own instance method (raiseEvent) to raise an event of type 'onBroadcastUpdate'.

  • When the onBroadcastUpdate event is raised or the page is reloaded, each listener pagelet retrieves the session preference set by the broadcast pagelet and computes a new value to display based on the value of the preference.

Broadcast Pagelet

<div style="padding:10px;" align="center">
<p><b>Enter number:</b>
&nbsp;<input type="text" style="font-size:22px;font-weight:bold;text-align:center;"
id="broadcast_prefName" value="4" size="7" onkeyup="broadcast_setPrefs(this.value)"></p>
<br>
</div>

<script type="text/javascript">

function broadcast_setPrefs(val)
{
    var prefName = 'broadcastNumber';
    var prefValue = val;
    PTPortlet.setSessionPref(prefName,prefValue);

    var broadcastPortlet = PTPortlet.getPortletByGUID('{D9DFF3F4-EAE7-5478-0F4C-2DBD94444000}');

      if (!broadcastPortlet)
    {
        broadcast_debug('Could not locate PTPortlet object which corresponds to <b>Broadcast Portlet</b> on page.');
        return;
        }

      broadcast_debug('<b>Broadcast Portlet</b> raising onBroadcastUpdate event.');
    broadcastPortlet.raiseEvent('onBroadcastUpdate',false);

}

function broadcast_debug(str)
{
    if (window.PTDebugUtil) 
    { 
        PTDebugUtil.debug(str); 
    }
}
</script>

Listener Pagelet #1

<div style="padding:10px;" align="center">
<p><b>Square root:</b>
<div style="height:21px;border:2px solid black;padding:2px;overflow:visible;font-size:14px;"id="listener1-swatch">
</div>
</div>

<script>

function listener1_update()
{
    var broadcastNumber = parseFloat(PTPortlet.getSessionPref('broadcastNumber'));
    if (isNaN(broadcastNumber))
    {
        listener1_error('<b>Listener-1 Portlet</b> cannot parse number from session pref broadcastNumber');
        return;
    }

      listener1_debug('<b>Listener-1 Portlet</b> computing square root of ' + broadcastNumber);
      var swatch = document.getElementById('listener1-swatch');
    swatch.innerHTML = Math.sqrt(broadcastNumber);
}

function listener1_debug(str)
{
    if (window.PTDebugUtil) 
    { 
        PTDebugUtil.debug(str); 
    }
}

function listener1_error(str)
{
    if (window.PTDebugUtil) 
    { 
        PTDebugUtil.error(str); 
    }
}

function listener1_getPortlet()
{
    var portletGUID = '{D9DFF3F4-EAE7-5478-0F4C-2DBDB4F4A000}';
    var listener1Portlet = PTPortlet.getPortletByGUID(portletGUID);
    return listener1Portlet;
}

var listener1Portlet = listener1_getPortlet();
if (listener1Portlet)
{
    listener1Portlet.registerForEvent('onBroadcastUpdate','listener1_update');
    listener1_debug('<b>Listener-1 Portlet</b> registered refreshOnEvent for event onBroadcastUpdate');
    listener1Portlet.registerForEvent('onload','listener1_update');
}

</script>

Listener Pagelet #2

<div style="padding:10px;" align="center">
<p><b>Cube root:</b>
<div style="height:21px;border:2px solid black;padding:2px;overflow:visible;font-size:14px;"id="listener2-swatch">
</div>
</div>

<script>
var listener2_oneThird = (1/3);

function listener2_update()
{
    var broadcastNumber = parseFloat(PTPortlet.getSessionPref('broadcastNumber'));
    if (isNaN(broadcastNumber))
    {
        listener2_error('<b>Listener-2 Portlet</b> cannot parse number from session pref broadcastNumber');
        return;
    }

    listener2_debug('<b>Listener-2 Portlet</b> computing square root of ' + broadcastNumber);

    var swatch = document.getElementById('listener2-swatch');
    swatch.innerHTML = Math.pow(broadcastNumber,listener2_oneThird);
}

function listener2_debug(str)
{
    if (window.PTDebugUtil) 
    { 
        PTDebugUtil.debug(str); 
    }
}

function listener2_error(str)
{
    if (window.PTDebugUtil) 
    { 
        PTDebugUtil.error(str); 
    }
}

function listener2_getPortlet()
{
    var portletGUID = '{D9DFF3F4-EAE7-5478-0F4C-2DBDCA1C7000}';
    var listener2Portlet = PTPortlet.getPortletByGUID(portletGUID);
    return listener2Portlet;
}

var listener2Portlet = listener2_getPortlet();
if (listener2Portlet)
{
    listener2Portlet.registerForEvent('onBroadcastUpdate','listener2_update');
    listener2_debug('<b>Listener-2 Portlet</b> registered refreshOnEvent for event onBroadcastUpdate');
    listener2Portlet.registerForEvent('onload','listener2_update');
}

</script>
62.2.2.2.1 Page-Level Events for Use with the Scripting Framework

The scripting framework automatically has access to the following page-level events.

Table 62-2 Page-Level Events

Event Triggered:

onload

immediately after the browser loads the page

onbeforeunload

prior to a page being unloaded (browser window closes or navigates to different location)

onunload

immediately before the page is unloaded (browser window closes or navigates to different location)

onactivate

the page is set as the active element (receives focus)

onbeforeactivate

immediately before the page is set as the active element (receives focus)

ondeactivate

when the active element is changed from the current page to another page in the parent document

onfocus

when the page receives focus

onblur

when the page loses focus

oncontrolselect

when the user is about to make a control selection of the page

onresize

when the size of the page is about to change

onresizestart

when the user begins to change the dimensions of the page in a control selection

onresizeend

when the user finishes changing the dimensions of the page in a control selection

onhelp

when the user presses the F1 key while the browser is the active window

onerror

when an error occurs during page loading

onafterprint

immediately after an associated document prints or previews for printing


62.2.2.3 Using In-Place Refresh

To refresh pagelet content in place, without affecting other content on the page, use the scripting framework to implement in-place refresh.

Many pagelets display data that is time sensitive. In some cases, users should be able to navigate across links within a pagelet without changing or refreshing the rest of the page. You can refresh pagelet content on command, associate the refresh action with an event (refreshOnEvent), or program the pagelet to refresh at a set interval (setRefreshInterval). The scripting framework also contains methods for expanding and collapsing pagelets. In the simplified example below, the refresh pagelet displays a "Refresh Portlet" button. Clicking the button updates the date and time displayed in the pagelet.

Figure 62-7 Refresh Portlet

Description of Figure 62-7 follows
Description of "Figure 62-7 Refresh Portlet"

The in-place refresh is executed by calling the refresh() method on the pagelet object instance. You can also set a new URL to be displayed within the pagelet upon refresh. (The title bar cannot be altered on refresh.)

<div style="padding:10px;" align="center">
<p><button onclick="refresh_portlet()">Refresh Portlet</button></p>
<p><b>Current time is:</b><br> <span id="refreshTimeSpan"></span></p>
</div>

<script type="text/javascript"> 
function refresh_portlet()
{
var refreshPortlet = PTPortlet.getPortletByID($PORTLET_ID$);
if (!refreshPortlet)
  {
  refresh_debug('Could not locate PTPortlet object which corresponds to <b>Refresh Portlet</b> on page.');
  return;
  }
refresh_debug('<b>Refresh Portlet</b> calling refresh() method.');
refreshPortlet.refresh();
}

function refresh_debug(str)
{
if (window.PTDebugUtil) 
  { 
  PTDebugUtil.debug(str); 
  }
}

var t = new Date();
document.getElementById('refreshTimeSpan').innerHTML = t;
</script>

62.2.2.4 Using Session Preferences

To store and share settings within the client browser, use session preferences.

Pagelets can use preferences to communicate with each other, but accessing preferences usually requires a round trip to a database. Session preferences provide a way to store and share settings in the user's session within the client browser. The Master-Detail design pattern illustrates the most basic usage of session preferences. This design pattern splits control and display between two pagelets. For example, the "master" pagelet could summarize data in list form, and the "detail" pagelet could display details on each data item in response to user selection. In the example below, the master pagelet displays a form that allows you to enter a color code in a text box.

When the user enters a color code in the text box, the color in the detail pagelet changes.

For each onkeyup event that occurs in the "Enter color" text box in the master pagelet, the following steps are executed:

  1. The master pagelet sets the session preference using the current value of the text box.

  2. The master pagelet calls an update method on the detail pagelet.

  3. The detail pagelet retrieves the session preference to get the color value.

  4. The detail pagelet redraws its color swatch area to reflect the new color value.

Note:

Shared session preferences must be specified by name on the Preferences page for the pagelet in the Oracle WebCenter Pagelet Producer Console or they will not be sent to the pagelet.

The adaptive pagelet scripting framework provides an easy way to detach the relationship between pagelets and use a common event interface for communication.

Note:

The example below is oversimplified; the master pagelet makes a direct call to a JavaScript method of the detail pagelet. Unless the master pagelet takes extra measures to ensure that the detail pagelet is actually present on the same page, calls from master to detail could generate errors.

Master Pagelet

<div style="padding:10px;" align="center">
<p><b>Enter color:</b> &nbsp;
<input type="text" style="font-size:22px;font-weight:bold;text-align:center;" id="master_prefName"
value="#FFFFFF" size="8" onkeyup="master_setPrefs(this.value)"></p><br>
</div>

<script type="text/javascript">
function master_setPrefs(val)
{
var prefName = 'masterColor';
var prefValue = val;
PTPortlet.setSessionPref(prefName,prefValue);

master_debug('<b>Master Portlet</b> called PTPortlet.setSessionPref(\'masterColor\',\'' + prefValue + '\').');

if (window.detail_update)
  {
  master_debug('<b>Master Portlet</b> calling detail_update().');
  detail_update();
  }
else
  {
  master_debug('Could not locate portlet <b>Detail Portlet</b> on page.');
  }
}
function master_debug(str)
{
if (window.PTDebugUtil) 
  { 
  PTDebugUtil.debug(str); 
  }
}
</script>

Detail Pagelet

<div style="padding:10px;" align="center">
<p><b>Color swatch</b> &nbsp;
<div style="width:100px;height:100px;border:2px solid black;padding:2px;"id="detail-swatch"></div>
<script>
function detail_update()
{
var color = PTPortlet.getSessionPref('masterColor');
detail_debug('<b>Detail Portlet</b> received value="' + color + '" for PTPortlet.getSessionPref(\'masterColor\')');

var swatch = document.getElementById('detail-swatch');
if (swatch)
  {
  swatch.innerHTML = '<div style="background-color:' + color + ';width:100%;height:100%;"></div>';
  }
else
  {
  detail_debug('<b>Detail Portlet</b> cannot find \'detail-swatch\' DIV element.');
  }
}

function detail_debug(str)
{
if (window.PTDebugUtil) 
  { 
  PTDebugUtil.debug(str); 
  }
}
</script>

62.2.2.5 Adaptive Pagelet Development Tips

These tips apply to most adaptive pagelets.

  • Use unique names for all forms and functions. Use the GUID of a pagelet to form unique names and values to avoid name collisions with other code on the page.

  • Proxy all URLs. You cannot make a request to a URL with a host/port that is different from that of the calling page. All URLs requested through JavaScript must be proxied. For details, see Section 62.2, "Building Pagelets Using the Oracle WebCenter Pagelet Producer"

  • If you are using the adaptive pagelet scripting framework, check for support. It is good practice to include code that determines whether or not the component is present. Ideally, your pagelet should be able to handle either situation. The simplest solution is to precede your code with an If statement that alerts the user if the scripting framework is not supported.

    <script>
    if (PTPortlet == null) 
      {
      if (document.PCC == null) 
        {
        alert("This pagelet only works in portals that support the JSPortlet API .
    The pagelet will be displayed with severely reduced
        functionality. Contact your Administrator.");
        }
      }
    else 
      {
      [scripting code here]
      }
    </script>
    
    
  • Close all popup windows opened by a pagelet when the window closes. The scripting framework can be used to close popup windows using the onunload event.

  • Add all required JavaScript to the page in advance. Browsers might not process script blocks/includes added to the page through the innerHTML property.

    • Microsoft Internet Explorer: Add the defer attribute to the script tag.

    • Netscape: Use RegExp to parse the response and look for the script, then eval it.

  • JavaScript HTTP and proxied HTTP must use the same authentication credentials. JavaScript brokered HTTP requests send the same authentication token (cookie) as when you make a normal gatewayed HTTP request.

62.2.3 Using Pagelet Producer Credential Mapping

The Oracle WebCenter Pagelet Producer manages authentication with each proxied application based on the settings defined for the associated resource.

The Pagelet Producer provides an API for creating custom mappings to external credential stores, allowing you to authenticate users against a custom credential source.

The IVendorCredentialMapper interface defines the Pagelet Producer interface for objects capable of obtaining an appropriate set of credentials needed for secondary authentication for a particular user in an application. To implement this interface, follow the directions below.

  1. Create a java class that implements the com.plumtree.runner.credentialmapper.IVendorCredentialMapper interface.

  2. Map the getCredential and setCredential methods of this interface to your credential vault. The simplified example below uses an internal class called VConnector and calls VConnector.getInstance().getCredentialsForDomain. Note: This step is vendor-specific. It will probably include a network hop, since the credential store will most likely reside on another server. You must give the mapper a unique name, and localized ones if necessary. See the IVendorCredentialMapper API documentation for all required names.

  3. Compile the class into a jar. The build process must link to common.jar, included with the Pagelet Producer distribution.

  4. Load the custom vault into the Pagelet Producer. For details, see the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter.

  5. Restart the Pagelet Producer server (both proxy and adminui if they are on separate servers). The custom credential vault should show up in the list of credential sources on the Credential Mapping page of the Resource editor.

The example below is simplified for illustration purposes.

package com.oracle.credentialvault;

import com.oracle.connector.CredentialsSet;
import com.oracle.connector.VConnector;
import com.plumtree.runner.credentialmapper.Credential;
import com.plumtree.runner.credentialmapper.IVendorCredentialMapper;

public class OracleCredentialVault implements IVendorCredentialMapper {

    /*
     * Oracle WebCenter Pagelet Producer will pass credential types as following:
     * Runner_*, where * is what the credential value type associated with this login form in the adminui.
     * For example, if the credential value type is 'username' then "Runner_username" will be passed to the mapper.
     */
    public Credential getCredential(String initiator, String credType) {
        System.out.println("OracleCredentialVault::getCredential, initiator: " + initiator + ", credType: " + credType);
        
        /*
         * Since this vault stores credentials per user and domain, we need to devise a scheme to
         * map Oracle WebCenter Pagelet Producer's credential type to a domain. One way to do this is to specify the credential 
         * type as something like: "domain_type", which would translate to credTypes like:
         * Runner_domain.com_username and Runner_domain.com_password
         */
        
        String username = initiator.toLowerCase(); // lets assume that the vault stores all usernames in lowercase
        String domain = "oracle.com"; //getDomain(credType); // lets assume that the vault stores all domains in lowercase
        String type = credType; //getType(credType);
        
        CredentialsSet credSet = VConnector.getInstance().getCrededentialsForDomain(username, domain);
        if( credSet != null ) {
            System.out.println("OracleCredentialVault::getCredential, found vault set: " + credSet.toString() + ", returning type = " + type);
            return new Credential(credSet.getCredential(type));
        } else {
            System.out.println("OracleCredentialVault::getCredential, found null vault set");
            return null;
        }
        
    }

    public String getDescription(String userLocale) {
        return "Test mapper that mimics a mapper between Oracle WebCenter Pagelet Producer and a credential vault that associates credentials with a username/domain relationship";
    }

    public String getName() {
        return "OracleCredentialVault";
    }

    public String getName(String userLocale) {
        return "OracleCredentialVault";
    }

    public String getVendorName(String userLocale) {
        return "Oracle";
    }

  
    public boolean setCredential(String initiator, Credential credential, String credType) {
        System.out.println("OracleCredentialVault::setCredential, initiator: " + initiator + ", credType: " + credType + ", Credential: " + credential.getCredentialValue());
              
        String username = initiator.toLowerCase(); // lets assume that the vault stores all usernames in lowercase
        String domain = "oracle.com"; //getDomain(credType); // lets assume that the vault stores all domains in lowercase
        String type = credType; //getType(credType);
        
        System.out.println("OracleCredentialVault::setCredential setting username: " + credential.getCredentialValue());
        CredentialsSet userCredSet = VConnector.getInstance().getCrededentialsForDomain(username, domain);
        userCredSet.setCrededential(type, credential.getCredentialValue());
        VConnector.getInstance().setCrededentialsForDomain(username, domain, userCredSet);
        return true;
        
    }

    public boolean supportsCredentialsEditing() {
        // We can set new credentials using this vault
        return true;
    }

    /*
    private String getDomain(String credType) {
        int dstart = credType.indexOf("_");
        int dend = credType.indexOf("_", dstart+1);
        String domain = credType.substring(dstart+1, dend);
        System.out.println("TestMapper::getDomain, reading domain as: " + domain);
        return domain;
    }
    */
    
    /*
    private String getType(String credType) {
        int dstart = credType.indexOf("_");
        dstart = credType.indexOf("_", dstart+1);
        String type = credType.substring(dstart+1, credType.length());
        System.out.println("TestMapper::getType, reading type as: " + type);
        return type;
    }
    */
    
    /*
    private String doGetPropertyValue(String principal, String property) { 
        return doGetPropertyValue(principal, property, ",", "=");
    }
    */
    
    /*
    private String doGetPropertyValue(String principal, String property, String propDelim, String valueDelim) {
        int propertyindex = principal.toLowerCase().indexOf(property.toLowerCase());
        String uname = null;
        if( propertyindex != -1) {
            // found a property occurence
            int beginIndex = propertyindex;
            int endIndex = principal.toLowerCase().indexOf(propDelim.toLowerCase(), beginIndex);

            String prop = null;
            if(endIndex != -1) {
                prop = principal.subSequence(beginIndex, endIndex).toString().trim();
            } else {
                prop = principal.subSequence(beginIndex, principal.length()).toString().trim();
            }

            if( prop != null ) {
                int valueIndex = prop.toLowerCase().indexOf(valueDelim);
                if(valueIndex != -1) {
                    uname = prop.subSequence(valueIndex + valueDelim.length(), prop.length()).toString().trim();
                }
            }

        }
        return uname;
    }
    */
    
}

For details on configuring resources to use credential mappings, see the section "Creating Pagelet Producer Resources and Pagelets" in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter.