63 Creating Pagelets with Oracle WebCenter Portal's 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. 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.

Oracle WebCenter Portal's 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.

63.1 About Server Communication and the Proxy

The 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 page markup. Any images stored in the Image Service are retrieved and displayed by the browser.

63.1.1 The 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, including the use of policies. The proxy hides the external resource; to the end user, the content appears to come directly from the proxy server.

This architecture makes the 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 or point to other proxied CSP or web resources 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. Parsers and web injectors can be used to implement targeted control over URL rewriting. For details on configuring parsers and web injectors, see the Managing Oracle WebCenter Portal's Pagelet Producer chapter in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal.

  • 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.

63.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 HTML markup that makes up the page. Pagelets from the same back-end application can interact with each other within the page.

63.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 CSP resources.

63.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 logging (as described in Section 63.3.4, "Debugging Pagelets"). HTTP is used in conjunction with SSL to serve up secure content. Single Sign-On (SSO) also uses HTTP headers for basic authentication.

63.1.2.2 CSP

CSP extends HTTP and defines proprietary headers to pass settings between Pagelet Producer and external CSP resources (i.e., Oracle WebCenter Interaction portlets). CSP outlines how these services use HTTP to communicate and modify settings. 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 CSP headers used to communicate system and user configuration variables can also be used by pagelets.

Table 63-1 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.


63.2 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 Portal: Spaces. Before you can add a pagelet to any web application, you must deploy and configure the resource and pagelet in the Pagelet Producer as described in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal.

This section includes the following subsections:

63.2.1 Adding a Pagelet to a JSF Page in Oracle JDeveloper

Oracle JDeveloper allows you to drag and drop pagelets onto a JSF page. In this section, you will register the Pagelet Producer with your WebCenter Portal: Framework application, add a pagelet to a JSF page, and view the page in a browser to test the pagelet.

This section includes the following subsections:

63.2.1.1 Registering the Pagelet Producer with a WebCenter Portal: Framework Application

Before you can add a pagelet to a JSF page, you must register the Pagelet Producer with your application. You can register a Pagelet Producer 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 Framework applications by dropping it on the page. When you add a pagelet from the Resource Palette, its producer gets registered with the application if that producer is not already registered with the application. You can drag and drop a whole producer connection from the Resource Palette into the Application Resources panel of the Application Navigator. This registers the producer with the application. Alternatively, you can right-click a producer in the Resource Palette and choose Add to Application from the context menu to register the producer with the currently open application

To register a Pagelet Producer through Oracle JDeveloper:

  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/pagelets.

  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 63-1.

    Figure 63-1 Pagelet Producer in the Application Resources Panel

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

63.2.1.2 Adding 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. Go to the Application Resources panel or the IDE Resources panel in the Resource Palette. 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. You can also specify the height as "auto" to use automatic resizing. (To use this option, you must add the IFrame resizing page to the project. For details, see Section 63.2.2.3, "Using Automatic Resizing with IFrames.") 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 63-2.

    Figure 63-2 Pagelet in the Structure Window

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

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

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

    Figure 63-3 Sample Pagelet

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

63.2.1.3 Securing 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 Portal.

63.2.2 Adding a Pagelet to a Web Page

Once you have deployed a pagelet, you can insert it into a proxied or non-proxied page using JavaScript or REST.

This section includes the following subsections:

63.2.2.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/pagelets/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, chrome, forward_params)
{
    ...
}

This function injects a pagelet as a widget into the parent page. The method interface uses the following parameters:

  • library: Required. A string representing the library name of the pagelet to inject. Accepts Unicode letters and numbers only; no spaces.

  • name: Required. A string representing the name of the pagelet to inject. Accepts Unicode letters and numbers only; no spaces.

  • iframe_options: 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: 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: The external identifier of the pagelet instance, used to scope preferences on the Pagelet Producer server. Must be an integer.

  • element_id: 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: 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.

  • chrome: Specifies the name of the chrome template to use for WSRP/JPDK pagelets. To suppress chrome, use a value of none.

  • forward_params: Specifies whether to forward query string arguments from the consuming page to the back-end server. To suppress this functionality, use a value of false.

Note:

These arguments are positional; they must be provided in the given order. If you do not want to specify a particular argument, but do want to specify an argument that follows it, you must pass in an empty value ('') for the former. All arguments are optional except for library and name.

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>
63.2.2.1.1 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 Portal.

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

where:

  • library: Required. The library name of the pagelet to inject. Accepts Unicode letters and numbers only; no spaces.

  • name: Required. The name of the pagelet to inject. Accepts Unicode letters and numbers only; no spaces.

  • type: The 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: 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: The external identifier of the pagelet instance, used to scope preferences on the Pagelet Producer server. Must be an integer.

  • element_id: 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.

  • is_in_community: 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.

  • chrome: Specifies the name of the chrome template to use for WSRP/JPDK pagelets. To suppress chrome, use a value of none.

Note:

These arguments are positional; they must be provided in the given order. If you do not want to specify a particular argument, but do want to specify an argument that follows it, you must pass in an empty value ('') for the former. All arguments are optional except for library and name.

63.2.2.2 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 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 returns a full representation of the object retrieved (pagelet or resource).

Pagelet Producer REST APIs provide the following functionality:

  • 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 63.2.2.2.1, "Pagelet Inject API".

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

63.2.2.2.1 Pagelet Inject API

The pagelet inject URL can be used in portals to specify the location of a remote portlet (this is how a pagelet can be used as a portlet). The inject URL can also be used as the src attribute of an IFrame tag in any HTML page.

The URL must use the following format:

http://host:port/pagelets/inject/v2/pagelet/libraryname/pageletname?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/pagelets/inject/v2/portlet/libraryname/pageletname?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, used to uniquely identify the pagelet on the page to facilitate inter-pagelet communication. Must be unique to the page.

  • context: Optional. The external identifier of the pagelet instance, used for scoping preferences on the Pagelet Producer server. Must be an integer.

  • 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 63.2.2.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 63.2.2.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: Optional. 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:: Optional. 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://host:port/pagelets/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>
63.2.2.2.2 Data Retrieval APIs

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

The base URL for all requests is http://host:port/pagelets/restservice/pageletproducer/.

Example 63-1 All Pagelets

http://host:port/pagelets/restservice/pageletproducer/pagelets/
http://host:port/pagelets/restservice/pageletproducer/pagelets/?format=xml

Example 63-2 Pagelets By Library and Name

http://host:port/pagelets/restservice/pageletproducer/pagelet/libraryname/pageletname/
http://host:port/pagelets/restservice/pageletproducer/pagelet/libraryname/pageletname/?format=xml

Example 63-3 All Resources

http://host:port/pagelets/restservice/pageletproducer/resources/
http://host:port/pagelets/restservice/pageletproducer/resources/

Example 63-4 Resource By Name

http://host:port/pagelets/restservice/pageletproducer/resource/name
http://host:port/pagelets/restservice/pageletproducer/resource/name/?format=xml

63.2.2.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.

The example below resizes the pagelet IFrame after it finishes loading. To add dynamic auto-resizing capabilities to user interaction activities after the initial load, simply add more event listeners for mouse and keyboard events.

<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>

63.2.3 Adding a Pagelet to a Page in WebCenter Portal: Spaces

In WebCenter Portal: Spaces, you can add a pagelet to a page using Composer. By default, pagelets appear in the Mash-Ups folder in the Resource Catalog. To add a pagelet to a page, navigate to the pagelet in the Resource Catalog and select it.

For detailed information about how to add resources to pages in Spaces, see the section "Adding Resource Catalog Components to Pages" in Oracle Fusion Middleware User's Guide for Oracle WebCenter Portal: Spaces.

To configure a pagelet within a page, view the page in Edit mode and click the edit button (wrench icon) for the pagelet. The Pagelet Properties tab in the Component Properties dialog allows you to define pagelet parameters and IFrame options.

Figure 63-4 Component Properties Dialog: Pagelet Properties

Description of Figure 63-4 follows
Description of "Figure 63-4 Component Properties Dialog: Pagelet Properties"

63.3 Building Pagelets Using the Pagelet Producer

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

63.3.1 Using the Adaptive Pagelet Scripting Framework

The Adaptive Pagelet Scripting Framework is a client-side JavaScript library that provides services to CSP pagelets and proxied pages. This section explains how to use the scripting framework to implement dynamic functionality in pagelets.

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

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

63.3.1.1 Handling Structured HTTP Responses

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>

63.3.1.2 Using 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 63.3.1.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 63-5 Broadcast Portlet

Description of Figure 63-5 follows
Description of "Figure 63-5 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 63-6 Listener -1 Portlet

Description of Figure 63-6 follows
Description of "Figure 63-6 Listener -1 Portlet"

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

Figure 63-7 Listener -2 Portlet

Description of Figure 63-7 follows
Description of "Figure 63-7 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>
63.3.1.2.1 Page-Level Events for Use with the Scripting Framework

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

Table 63-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


63.3.1.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 63-8 Refresh Portlet

Description of Figure 63-8 follows
Description of "Figure 63-8 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>

63.3.1.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.

Figure 63-10 Color Swatch

Description of Figure 63-10 follows
Description of "Figure 63-10 Color Swatch"

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 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>

63.3.1.5 Adaptive Pagelet Development Tips

These tips apply to most pagelets that use the adaptive pagelet scripting framework.

  • 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 63.3, "Building Pagelets Using the 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.

63.3.2 Using Pagelet Producer Credential Mapping

The 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 Portal.

  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 {

  /*
  * 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 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(); // assume that the vault stores all usernames in lowercase
    String domain = "oracle.com"; //getDomain(credType); 
    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 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(); // assume that the vault stores all usernames in lowercase
     String domain = "oracle.com"; //getDomain(credType); 
     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 Portal.

63.3.3 Modifying Pagelet Functionality at Runtime

The Pagelet Producer allows you to modify pagelet functionality at runtime using custom injectors and parsers.

63.3.3.1 Creating Web Injectors

A web injector inserts content into a specified location in the proxied resource page. The content may be any text, including HTML, CSS, JavaScript, and pagelet declarations. An empty injector may also be used to remove unwanted content from a page. Injectors cannot be created for OpenSocial resources. While injecting simple HTML content has a limited use case, you can also inject JavaScript that directly modifies the pagelet's HTML markup.

To create a web injector, select the Injectors section under the resource you want to use and click the Create icon in the toolbar.

The injector can be applied to a subset of the resource by typing a URL pattern into the URL Filter field. The injector will be applied only to those URLs within the resource that begin with the text in the URL Filter box. If the box is empty or contains only a '/', the injector will be applied to the entire resource.

To restrict the injector to specific kinds of content, type a comma separated list of MIME types in the MIME Filter box. For example, text/html restricts the injector to HTML content, while text/css only restricts the injector to CSS content.

Define where in the resource's output the injection will be made:

  • Top puts the content first in the page. Do not use this option to inject pagelet declarations.

  • Bottom puts the content last in the page.

  • The Before/After/Replace options put the content into the page relative to the unique string specified in the field provided. You can choose to ignore the case of the string by selecting Ignore case.

    The Enclose tag option identifies the unique string and replaces both the text and the enclosing tag with the content specified on the next page.

Figure 63-11 Pagelet Producer Console: Injectors - General Page

Description of Figure 63-11 follows
Description of "Figure 63-11 Pagelet Producer Console: Injectors - General Page"

Enter the content to be injected on the Content page. This content may be any text, including HTML, CSS, JavaScript, and pagelet declarations.

For example, the following code could be injected at the top of a page. This example registers a handler function with the page load event and then uses the handler to modify the page markup (by finding and hiding the header and footer).

<script type="text/javascript">
if (window.addEventListener) {
  window.addEventListener('load', hideHeaderFooter, false);
} else if (document.attachEvent) {
  window.attachEvent('onload', hideHeaderFooter);
}
function hideHeaderFooter() {
  var header = null;
  // find the header table by class 
  if (document.getElementsByClassName) {
    header = document.getElementsByClassName('page_header')[0];
  } else {
    // for older versions of IE
    var tables = document.getElementsByTagName('table');
    for (var table in tables) {
      if (table.class == 'page_header') {
        header = table;
        break;
      }
    }
  }
  if (header != null) {
    header.style.display = 'none';
  }
  // now find and hide the footer (easier to find, since it has an id)
  var footer = document.getElementById('t23PageFooter');
  if (footer != null) {
    footer.style.display = 'none';
  }
}
</script>

63.3.3.2 Creating Custom Parsers

Custom parsers allow you to supplement or change built-in logic for parsing content and finding URLs. When the built-in parsers fail to identify URLs or identify sections that must not be rewritten as URLs, custom parsers can be used to change the default behavior. Parsers cannot be created for WSRP or Oracle JPDK portlet producers or for OpenSocial gadget producers.

To create a custom parser, select the Parsers section under the resource you want to use and click the Create icon in the toolbar.

  • Enter a Name for the parser.

  • The parser can be applied to a subset of the resource by typing a URL pattern into the URL Filter box. The parser will be applied only to those URLs within the resource that begin with the text in the URL Filter box. If the box is empty or contains only a '/', the parser will be applied to the entire resource.

  • To add a new parsing rule, click Create to add a new row to the Fragment Locations section.

  • In the Regular Expressions column, enter the regular expression for identifying the URL fragment that should be transformed. The first grouping expression (in parentheses) identifies the fragment, and the rest of the expression provides the context for finding it.

  • Choose the Fragment Type to define how the selected location should be parsed:

    • Static URLs are transformed on the server.

    • Dynamic URLs are transformed using JavaScript on the client.

    • HTML Fragment and Javascript Fragment types are used for content that is embedded in another content type, such as XML.

    • No Rewriting specifies a location that should not be searched for URLs. This option is used to prevent rewriting of markup mistakenly identified as URLs.

  • Click the Save icon in the navigator toolbar.

Figure 63-12 Pagelet Producer Console: Parsers - General Page

Description of Figure 63-12 follows
Description of "Figure 63-12 Pagelet Producer Console: Parsers - General Page"

For example, the regular expression XMLFile=(.*?)" would identify URLs to XML files defined within a tag, as in <embed src="/i/flashchart/anychart_5/swf/OracleAnyChart.swf?>XMLFile=http://apex.oracle.com/pls/apex/apex_util.flash?p=53557:1:74175370346201:FLOW_FLASH_CHART5_R45192463162785599619_en".

63.3.4 Debugging Pagelets

The Pagelet Producer provides advanced logging traces for debugging pagelets. Logging is configured in the Settings section of the Pagelet Producer Console, where you can define different levels of logging for each Pagelet Producer component. (For details on Pagelet Producer configuration settings, see Managing the Oracle WebCenter Portal's Pagelet Producer in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal.)

Figure 63-13 Pagelet Producer Console: Settings - Logging

Description of Figure 63-13 follows
Description of "Figure 63-13 Pagelet Producer Console: Settings - Logging"

The Pagelet Producer logs messages to the standard Oracle Diagnostic Logging facility. In Oracle WebLogic Server, the logs are stored at user-projects/domains/ <domain>/servers/<server>/logs/<server>-diagnostic.log.

63.3.4.1 HTTP Tracing

To view the HTTP requests and responses received and sent by the Pagelet Producer, set the HTTP component on the Logging Settings page to Finest. The example traces below were captured from a test environment.

Example 63-5 HTTP Request Received By Pagelet Producer

URL: http://10.148.118.211:7001/pagelets/bidwiki/includes/js/ajax.js
METHOD: GET
SESSION ID: GdYGNJzMhxy1CJBMVTX8xTNq32GmLXYNY9VqFBcdprFnhcyQtzdp!1377086614!1305769149498
HEADERS: 
  Host: 10.148.118.211:7001
  Connection: keep-alive
  Referer: http://example.com:7001/pagelets/bidwiki/dashboard.action
  User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16
  Accept: */*
  Accept-Encoding: gzip,deflate,sdch
  Accept-Language: en-US,en;q=0.8,ru;q=0.6,it;q=0.4
  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
  If-None-Match: W/"736-1124953206000"
  If-Modified-Since: Thu, 25 Aug 2005 07:00:06 GMT
COOKIES: 
  JSESSIONID: GdYGNJzMhxy1CJBMVTX8xTNq32GmLXYNY9VqFBcdprFnhcyQtzdp!1377086614

Example 63-6 HTTP Response Sent By Pagelet Producer

URL: http://example.com:7001/pagelets/bidwiki/styles/main-action.css
Response Code: 200
Reason: 
HEADERS: 
  Date: Thu, 19 May 2011 01:39:14 GMT
  Content-Type: text/css;charset=UTF-8
  Server: Apache-Coyote/1.1
BODY: 
.sidebar {
    /*background-image: url(http://example.com:7001/pagelets/bidwiki/download/ resources/leftnav_bg.jpg);*/
    /*background-repeat: repeat-y;*/
    background-color: #F0F0F0;
    /*border-bottom:1px solid #F0F0F0;*/
} ...

Example 63-7 HTTP Request Sent By Pagelet Producer

URL: http://example.com/includes/js/ajax.js
METHOD: GET
HEADERS: 
  CSP-Ensemble-REST-API: http://example.com:7001/pagelets
  X-Client-IP: 10.148.118.211
  User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16
  CSP-Session-Username: weblogic
  Accept-Language: en-US,en;q=0.8,ru;q=0.6,it;q=0.4
  CSP-Gateway-Type: Proxy
  PT-Proxy-Passes: 1
  If-Modified-Since: Thu, 25 Aug 2005 07:00:06 GMT
  CSP-Protocol-Version: 1.4
  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
  Accept-Encoding: gzip,deflate,sdch
  Referer: http://example.com:7001/pagelets/bidwiki/dashboard.action
  If-None-Match: W/"736-1124953206000"
  Accept: */*
  CSP-Aggregation-Mode: Single
  PT-Proxy-instance0: {DECBB085-D891-72CF-2B75-005E7FE20000}
  CSP-Gateway-Specific-Config: PT-User-Name=weblogic,PT-Guest-User=0,...

Example 63-8 HTTP Response Received By Pagelet Producer

Original URI: http://example.com/styles/main-action.css
Effective URI: http://example.com/styles/main-action.css
Status Code: 200
Reason: OK
Version: HTTP/1.1
HEADERS: 
  Content-Type: text/css;charset=UTF-8
  Content-Length: 29178
  Server: Apache-Coyote/1.1
  Date: Thu, 19 May 2011 01:39:14 GMT
TRAILERS: 
BODY: 
body, p, td, table, tr, .bodytext, .stepfield {
  font-family: Verdana, arial, sans-serif;
  font-size: 11px;
  line-height: 16px;
  color: #000000;
  font-weight: normal;
}

63.3.4.2 Transformation Tracing

To view the content proxied by the Pagelet Producer before and after transformation, set the Transform component on the Logging Settings page to Finest. The purpose of these traces is to log response content at different stages of transformation, allowing you to compare them and view the result of different transformers.The example traces below were captured from a test environment.

Example 63-9 Untransformed Markup

Original request: URL: http://10.148.118.211:7001/pagelets/bidwiki/styles/main-action.css
METHOD: GET
SESSION ID: GdYGNJzMhxy1CJBMVTX8xTNq32GmLXYNY9VqFBcdprFnhcyQtzdp!1377086614!1305769149498
HEADERS: 
  Host: example.com:7001
  Connection: keep-alive
  Referer: http://example.com:7001/pagelets/bidwiki/dashboard.action
  User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16
  Accept: text/css,*/*;q=0.1
  Accept-Encoding: gzip,deflate,sdch
  Accept-Language: en-US,en;q=0.8,ru;q=0.6,it;q=0.4
  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
COOKIES: 
  JSESSIONID: GdYGNJzMhxy1CJBMVTX8xTNq32GmLXYNY9VqFBcdprFnhcyQtzdp!1377086614
 
Untransformed content: 
body, p, td, table, tr, .bodytext, .stepfield {
  font-family: Verdana, arial, sans-serif;
  font-size: 11px;
  line-height: 16px;
  color: #000000;
  font-weight: normal;
}

Example 63-10 Transformed Markup (Transformed by Transformer Class)

Transformed by: class com.plumtree.server.impl.portlet.transformers.CSSTurboParser
  Original request: URL: http://example.com:7001/pagelets/bidwiki/styles/main-action.css
METHOD: GET
SESSION ID: GdYGNJzMhxy1CJBMVTX8xTNq32GmLXYNY9VqFBcdprFnhcyQtzdp!1377086614!1305769149498
HEADERS: 
  Host: example.com:7001
  Connection: keep-alive
  Referer: http://example.com:7001/pagelets/bidwiki/dashboard.action
  User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/534.16 (KHTML, like Gecko) Chrome/10.0.648.205 Safari/534.16
  Accept: text/css,*/*;q=0.1
  Accept-Encoding: gzip,deflate,sdch
  Accept-Language: en-US,en;q=0.8,ru;q=0.6,it;q=0.4
  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
COOKIES: 
  JSESSIONID: GdYGNJzMhxy1CJBMVTX8xTNq32GmLXYNY9VqFBcdprFnhcyQtzdp!1377086614
 
Transformed content: 
body, p, td, table, tr, .bodytext, .stepfield {
  font-family: Verdana, arial, sans-serif;
  font-size: 11px;
  line-height: 16px;
  color: #000000;
  font-weight: normal;
}

63.4 Working with WSRP and Oracle JPDK Portlets

The Pagelet Producer can be used to present WSRP and Oracle JPDK portlets for use in any web application. For details on configuring the Pagelet Producer to connect to a WSRP or Oracle JPDK portlet producer, see Managing the Oracle WebCenter Portal's Pagelet Producer in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal. The Pagelet Producer can also modify portlet markup at runtime as explained in the next section, Section 63.4.1, "Using Pagelet Chrome."

63.4.1 Using Pagelet Chrome

Pagelet chrome allows you to modify markup at runtime in pagelets created from portlets imported from a WSRP or JPDK portlet producer.

A pagelet chrome template is an HTML file that specifies:

  • How portlet markup should be rendered stylistically

  • How to display the portlet title

  • How to render mode switching options

The default chrome template displays the portlet name and a dropdown menu that allows the user to switch into different modes. The dropdown menu is dynamically populated with all the standard modes supported by the underlying portlet. Templates uses the following reserved tokens to identify key portlet elements, which the Pagelet Producer substitutes at runtime.

Table 63-3 Pagelet Chrome Template Tokens

Token Description
$$PORTLET TITLE$$

Portlet title

$$REPEAT MENU ITEM$$

Used to indicate the beginning of a repeating section for navigational items

$$END REPEAT MENU ITEM$$

Used to indicate the end of a repeating section for navigational items

$$MENU ITEM URL$$

Navigation URL (to switch portlet modes or window states)

$$MENU ITEM$$ 

Display name of navigational item (for example, Customize)

$$TOKEN$$

Unique identifier for pagelet instance on the page

$$PORTLET CONTENT$$

Portlet content

pt://images

Tag used to indicate the imageserver URL


The example below is a very simple pagelet chrome template:

<script type="text/javascript">
function goto(url)
{
  document.location = url;
  return false;
}
</script>
<div style="border: 1px solid">
<span><b><!-- $$PORTLET TITLE$$ --></b></span>
<span style="align: right">
  Switch Mode:
  <select size="1" name="mode">
    <!-- $$REPEAT MENU ITEM$$ -->
    <option onclick="goto('$$MENU ITEM URL$$')"><!-- $$MENU ITEM$$ --></option>
    <!-- $$END REPEAT MENU ITEM$$ -->
  </select>
 
</span>
</div>
<!-- $$PORTLET CONTENT$$ -->

Note:

The pagelet chrome template file must be hosted on the classpath of the Pagelet Producer web application.

If you configured Pagelet Producer to use an external image server, copy the files from ensemblestatic.war/imageserver/yahoo to your image server to properly render the default chrome template.

To implement the chrome template, add it as a parameter to the pagelet inject URL (REST or JavaScript). For details on pagelet inject URLs, see Section 63.2.2, "Adding a Pagelet to a Web Page." For example:

  • REST: /inject/v2/pagelet/pagelet_lib/pagelet_name?chrome=mychrome.html

  • JavaScript: injectpagelet(library, name, iframe_options, payload, params, context_id, element_id, is_in_community, chrome)

The value of the chrome parameter can be the name of the file containing the chrome template or the special reserved value "none", which suppresses all chrome and sends back portlet markup only. If the chrome parameter is omitted, the default chrome is returned with the portlet markup. The default chrome template uses YUI menu control to display a gradient title bar and a DHTML dropdown menu for switching modes. (When ADF content is detected, a different chrome template is used by default. This template can be overridden with a custom template or with the standard default template by setting chrome=chrometemplate.html.)

63.5 Working with OpenSocial Gadgets

Any OpenSocial gadget reachable by the Pagelet Producer server can be registered as a pagelet and used in any web application, including a portal. For details on registering OpenSocial pagelets with the Pagelet Producer, see Managing the Oracle WebCenter Portal's Pagelet Producer in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal.

The Pagelet Producer supports most of the standard OpenSocial APIs excluding OAuth. The complete OpenSocial API reference documentation can be found here: http://shindig.apache.org/shindig-1.1.x/shindig-features/jsdoc/index.html.

The Pagelet Producer also allows gadgets to store preferences, retrieve WebCenter Portal profile and connection information, and access a user's activity stream using OpenSocial APIs. For more details on using these features, see the sections that follow.

63.5.1 Configuring Authentication

In order for gadgets to request user-level data (preferences or people connections), the end user's identity must be established. If any OpenSocial gadgets need to access user-level data from the server, you must configure a security policy for the parent OpenSocial resource in the Pagelet Producer Console. The first time a user accesses an OpenSocial gadget, a login page will be presented. After the initial login, subsequent requests for OpenSocial gadgets will use the established user identity.

For details on configuring a security policy for a Pagelet Producer resource, see the Managing Pagelets chapter in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal

63.5.2 Storing User Preferences

OpenSocial gadgets may use user preferences to store data at the container. User preferences are scoped to a particular user and may optionally be scoped to an appId (the gadget appId is the pagelet context ID). If you choose to use the OpenSocial gadget.Prefs API, the user preferences will be scoped to the user and pagelet instance. Alternatively, you may use the opensocial.DataRequest API to manage preferences at the user level that can be shared with other pagelets.

When registered as a pagelet, a gadget's user preferences are treated as pagelet preferences. In WebCenter Portal, for example, non-hidden user preferences can be edited by the end user using the Personalize button. Additionally, to simulate preferences shared between users, you may pass in user preferences via pagelet parameters. Note that a pagelet preference, if set, will always override the corresponding pagelet parameter (in other words, personalization takes precedence over customization).

Outside of WebCenter Portal, gadget-backed pagelets are provided with a simple chrome that displays the gadget title and buttons for accessing the preference editor and minimizing/maximizing the gadget. The chrome may be suppressed by passing in the value of 'none' to the chrome parameter in the Pagelet Inject API. The preference editor UI supports all four types of user preferences:

  • string: rendered as a text field

  • bool: rendered as a checkbox

  • enum: rendered as a dropdown list

  • list: rendered as a text field (values must be separated with a pipe "|" character)

63.5.3 Accessing WebCenter Portal Profile Information

OpenSocial gadgets can query the current user's profile data and people connections via the standard OpenSocial APIs. To use this feature, you must manually target the WebCenterDS data source to the WC_Portlet server as described in Managing the Oracle WebCenter Portal's Pagelet Producer in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal.

Note:

The OpenSocial API cannot be used to update profile or connection information.

The supported user profile fields are listed in the table below.

Table 63-4 User Profile Fields

OpenSocial Field Type Description

aboutme

string

A general statement about the person.

addresses

Plural-Field <Address>

A physical mailing address for the person.

appData

Plural-Field <AppData>

A collection of AppData keys and values, used for preferences.

birthday

Date

The birthday of the person. The value MUST be a valid Date. The year may be set to 0000 when the age of the person is private or the year is not available.

emails

Plural-Field <string>

E-mail address for the person.

location

string

Physical address for the person.

name

Name

The broken-out components and formatted version of the person's real name.

organizations

Plural-Field <Organization>

Current or past organizational affiliation of the person.

phoneNumbers

Plural-Field <string>

Phone number for the person. In addition to the standard canonical values for type, this field defines the additional values mobile, fax, and pager.

photos

Plural-Field <string>

URL to a photo of the person. The value MUST point to an actual image file (e.g. a GIF, JPEG, or PNG image file) rather than to a web page containing an image. Note that this field SHOULD NOT be used to send down arbitrary photos taken by this user, but specifically profile photos of the contact suitable for display when describing the contact.

preferredUsername

string

The preferred username of this person on sites that ask for a username (e.g. jsmarr or daveman692).

status

string

The person's status, headline or shoutout.

thumbnailUrl

string

The person's photo thumbnail URL, specified as a string. This URL MUST be fully qualified.


63.5.4 Accessing a User's Activity Stream

OpenSocial gadgets can operate on a user's activity stream using OpenSocial APIs. The following operations are supported:

  • get activities

  • create activity

The following operations are not supported:

  • update activity

  • delete activity

The supported activity stream fields are listed in the table below.

Table 63-5 Activity Stream Fields

OpenSocial Field Type Description

appId

Object-Id

The application with which the activity is associated.

body

string

An optional expanded version of the activity. Bodies may only have the following HTML tags: <b> <i>, <a>, <span>, but this formatting may be ignored.

externalId

Object-Id

An optional ID generated by the posting application.

id

Object-Id

An ID that is permanently associated with the activity.

postedTime

string

The time at which the activity took place in milliseconds since the epoch.

priority

number

A number between 0 and 1 representing the relative priority of the activity in relation to other activities from the same source.

title

string

The primary text of the activity. Titles may only have the following HTML tags: <b> <i>, <a>, <span>, but this formatting may be ignored.

userId

Object-Id

ID of the user for whom the activity is defined.


63.5.5 Using Gadget Eventing

The Pagelet Producer supports the OpenSocial pubsub inter-gadget eventing model. A gadget may publish events over any number of arbitrary channels (defined by simple string names) in JavaScript. On the receiving end, a gadget may subscribe to receive events over any number of channels, again in JavaScript, and take appropriate actions based on the events.

function connSelected(element) {
  var connId = element.id;
  var connName = element.lastChild.textContent;
  gadgets.pubsub.publish(channel, {id: connId, name: connName});

For a complete JavaScript reference to the supported eventing API, see http://shindig.apache.org/shindig-1.1.x/shindig-features/jsdoc/symbols/gadgets.pubsub.html.

63.5.6 Example: Consuming an External OpenSocial Gadget

The example that follows is simplified for illustration. For details on Pagelet Producer Console settings, see the Managing Oracle WebCenter Portal's Pagelet Producer chapter in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal.

  1. Using the Pagelet Producer Console, create a new Resource and choose OpenSocial as the type. Define URLs and policies as necessary. Save the new Resource.

  2. Using the Pagelet Producer Console, create a new pagelet and enter the location of the gadget XML schema in the Gadget URL field.

    • To import the gadget name and any user preferences defined for the gadget, click the Import Gadget Metadata button. If any of the preferences are editable, the Pagelet Producer will create a preference editor using the imported preferences.

    • To configure or customize the generated preference editor, go to the Pagelet Parameters page.

  3. Go to the Documentation page to view sample code to access the pagelet and preference editor using either the JavaScript or REST API.

  4. Save the new pagelet.

63.5.7 Example: Consuming a Local OpenSocial Gadget

The example that follows is simplified for illustration. For details on Pagelet Producer Console settings, see the Managing Oracle WebCenter Portal's Pagelet Producer chapter in the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter Portal.

  1. Using the Pagelet Producer Console, create a new Resource and choose OpenSocial as the type. Define URLs and policies as necessary. Save the new Resource.

  2. Create or upload the gadget file.

    Note:

    If you choose to host OpenSocial gadget XML files, the files must be placed under an anonymous resource (with no security policy) or gadget functionality will not work correctly.

    1. Select the Files section under the resource and click the Create icon in the toolbar.

    2. On the General page, enter the relative path to the file in the Name field. Do not use a leading forward-slash ("/"). For example, "gadgets/activities.xml". Any path and name can be used; the path is a 'virtual' URL that the Pagelet Producer will use to serve the file. The visual directory structure of the Files collection in the navigator is updated to match the path to the file.

    3. Go to the Content page to upload or create the gadget file.

      To upload a gadget file, enter the path to the file or click the Browse button to navigate to the file, then click the Upload button to upload the file to the Pagelet Producer server.

      To create a gadget file, use the editor on the Content page to enter and edit content.

    4. Click the Save icon in the navigator toolbar.

  3. Create or upload any other files required by the gadget (JavaScript, images, etc.) in the Files section of the resource. Define paths for the files that match the paths in the gadget code. For example, if the gadget uses JavaScript files in a subfolder called "js", include that directory in the Name field when you upload the files, e.g., "gadgets/js/activities.js".)

  4. Using the Pagelet Producer Console, create a new pagelet and enter the relative path to the gadget XML schema (created or uploaded in step 2) in the Gadget URL field. For local files, this is the same path defined in the Name field for the file object; for example, "gadgets/activities.xml".

    • To import the gadget name and any user preferences defined for the gadget, click the Import Gadget Metadata button. If any of the preferences are editable, the Pagelet Producer will create a preference editor using the imported preferences.

    • To configure or customize the generated preference editor, go to the Pagelet Parameters page.

  5. Go to the Documentation page to view sample code to access the pagelet and preference editor using either the JavaScript or REST API.

  6. Save the new pagelet.