Oracle® Fusion Middleware Developer's Guide for Oracle WebCenter 11g Release 1 (11.1.1.4.0) E10148-12 |
|
![]() Previous |
![]() Next |
A pagelet is a reusable user interface component similar to a portlet, but while portlets were designed specifically for portals, pagelets are designed to run on any web page. Any HTML fragment can be a pagelet, but pagelet developers can also take advantage of many of the features available to portlet developers to 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.
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.
Section 58.1, "Using Pagelets in Web Applications": This section explains how to use pagelets in your WebCenter Portal application.
Section 58.2, "Building Pagelets Using the Oracle WebCenter Pagelet Producer": This section provides detailed information about building pagelets using the Oracle WebCenter Pagelet Producer.
Section 58.2.1, "About Server Communication and the Proxy": This section explains how the Oracle WebCenter Pagelet Producer acts as a proxy server, brokering transactions between client computers and external resources.
Section 58.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. Adaptive pagelet tools include adaptive tags and the adaptive pagelet scripting framework.
Section 58.2.3, "Using REST APIs": Pagelet Producer REST APIs allow remote web services to retrieve information about resources and pagelets from the Oracle WebCenter Pagelet Producer, and inject pagelets into non-proxied pages.
Section 58.2.4, "Using 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.
Section 58.2.5, "Using Pagelet Producer Credential Mapping": Configure security settings for pagelets and resources to manage authentication for users.
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:
Section 58.1.1, "How to Add a Pagelet to a JSF Page in Oracle JDeveloper"
Section 58.1.3, "How to Add a Pagelet to a Page in WebCenter Spaces"
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:
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:
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?"
In the Name field of the New Pagelet Producer dialog, enter a meaningful name for your producer. For example, myPageletProducer
.
In the URL field, enter the URL of your Pagelet Producer in the format: http://
hostname:portnumber
.
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 58-1.
Figure 58-1 Pagelet Producer in the Application Resources Panel
To add a pagelet to a page:
In JDeveloper, open your JSF page in Design View, if it is not open already.
In the Application Resources panel, under Pagelet Producer, expand your producer to display its contents.
From the producer's contents, drop a pagelet onto the JSF page.
In the Add Pagelet to Page dialog, choose Yes in the Use IFrame section if you would like to enable IFRAME for this pagelet.
In the IFrame Height field, specify the required height in pixels or leave it blank and click OK.
In the Edit Task Flow Binding dialog input parameters are specified by default. Change any parameters, if required, and then click OK.
Save the page. In the Structure window, the page looks like Figure 58-2.
Figure 58-2 Pagelet in the Structure Window
In the Application Navigator, right-click your JSF page under Projects, and choose Run.
In the login page, enter user name and password so you can view the pagelet. Figure 58-3 shows a sample pagelet in a browser window.
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.
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 Pagelet Producer adaptive tags. It includes the following subsections:
Section 58.1.2.2, "How to Insert Pagelets Using Pagelet Producer Adaptive Tags"
Section 58.1.2.3, "How to Add a Pagelet Using Web Injectors"
This section includes the following subsections:
You can also 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 editor content. Sample IFRAME options: iframe width=100% height=auto frameborder=0
. If omitted or left blank, the editor content is rendered inline.
payload: Optional. The XML payload to send along with the pagelet request
params: The pagelet parameters in the query string format. For example, 'param1=value1¶m2=value2¶m3=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 injecteditor
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¶m2=value2¶m3=value3'); </script> </div>
<div> <script type="text/javascript"> injectpagelet('library', 'name', 'iframe width=100% height=200', 'payload'); </script> </div>
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.
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 pt:inject
tag; for details, see Section 58.2.2.2.4, "Inserting Pagelets Using Pagelet Producer Adaptive Tags". You can also inject pagelets using REST; for details, see Section 58.2.3, "Using REST APIs".
The pt:ensemble.inject
tag injects the output of the specified pagelet into the page.
The pagelet is referenced by the fully qualified name of the pagelet as defined in the Pagelet Producer, in the form libraryname:pageletname
. Any attributes not prefixed with "pt:" will be passed on to the pagelet. Any HTML content inside the pagelet tag will be passed to the pagelet as an XML payload.
<pt:ensemble.inject pt:name="mylibrary:mypagelet" pagelet-attribute="A pagelet attribute"> <?xml version="1.0" encoding="utf-8"?> <doc>This is an XML payload.</doc> </pt:ensemble.inject>
You can also insert pagelets into non-proxied pages; for details, see Section 58.1.2.1, "How to Insert Pagelets Using Javascript".
You can use the pt:ensemble.inject
tag discussed in Section 58.2.2.2.4, "Inserting Pagelets Using Pagelet Producer Adaptive Tags" to add a pagelet to the target web application without modifying the source code of the web page. For more information, see Section 58.2.3.2, "Pagelet Inject API" and the section "Injectors" in the chapter "Managing the Oracle WebCenter Pagelet Producer" of the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter.
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.
This section provides detailed information on building pagelets using the Oracle WebCenter Pagelet Producer.
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 58.2.1.2, "About HTTP and CSP".
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. In many situations, an adaptive tag provides the functionality required, including navigation and login elements. Custom tags can be created for additional functionality.
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. To manually mark a URL for transformation, use the pt:url tag. To disable transformation, use pt:transformer with a pt:fixurl attribute of 'off.' For details, see Section 58.2.2.2, "Using Adaptive Tags".
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.
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.
In the Pagelet Producer, a consumer page defines the layout and includes specific pagelets in the page using adaptive tags. Header navigation can be added using tags.
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.
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.
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
.
Java and .NET Pagelets: If you are writing Java or .NET pagelets, but do not plan to use ADF or use portlet standards (WSRP or JSR 168/286), the Oracle WebCenter Interaction Development Kit (IDK) provides Java and .NET client APIs for pagelets. These APIs provide the ability to get and set persistent preferences. For information, see the Oracle Fusion Middleware Web Service Developer's Guide for Oracle WebCenter Interaction.
Non-Java/-.NET Pagelets: If you are writing pagelets on a platform other than Java or .NET, and need to perform actions like getting and setting persistent preferences, the CSP allows data like persistent preferences to be communicated via HTTP headers.
The custom headers used by the Pagelet Producer to communicate system and user configuration variables can also be used by pagelets.
Table 58-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. |
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 58.2.2.1, "Adaptive Pagelet Design Patterns".
Adaptive pagelet tools include the following:
Adaptive Tags: The Pagelet Producer provides a collection of useful XML tags that can be included in the markup returned by any proxied page, including pagelets. For details, see Section 58.2.2.2, "Using Adaptive Tags"
Adaptive Pagelet Scripting Framework: The adaptive pagelet scripting framework is a client-side JavaScript library that provides services to pagelets and proxied pages. For details, see Section 58.2.2.3, "Using the Adaptive Pagelet Scripting Framework".
For additional information on adaptive pagelets, see Section 58.2.2.4, "Adaptive Pagelet Development Tips".
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 58.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 58.2.2.3.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 58.2.2.3.4, "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="pt://images/plumtree" style="display:none"></a> <script type="text/javascript" src="pt://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 --> <!-- NOTE: It is standard practice to use namespace tokens (e.g., <pt:nameSpace pt:token="$$TOKEN$$" xmlns:pt="http://www.plumtree.com/xmlschemas/ptui/"/>) <!-- to ensure unique global JavaScript function and object names. For simplicity, we do not do that here. --> <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>
The Pagelet Producer provides a collection of useful XML tags that can be included in the markup returned by any proxied page, including pagelets.
Using the attributes defined in the tag, the proxy transforms the XML and replaces it with standard HTML to be displayed in a browser. For example, when used in a pagelet, the following code is replaced with the date and time in the current user's locale.
<pt:standard.currenttime xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/>
The adaptive tag libraries provide access to a wide range of components.
The core tag library provides two basic tags to support core tag functionality.
pt:core.debugmode
toggles debug mode.
pt:core.html
allows you to use HTML tags within JavaScript, and supports attribute replacement.
The tags in the constants library provide access to useful URLs, including the stylesheet, Image Service, and the correct return URL for the current user.
Table 58-2 Tags in the Constants Library
Tag | Replaced with | Example |
---|---|---|
The stylesheet URL in proxied pages and pagelets |
|
|
The URL to the Image Service |
|
|
The common tag library provides access to useful functionality, including URL transformation and namespace definition. This library also allows you to insert error information in the page, and CSS and JavaScript references in the Head element in a proxied HTML page. For details, see Section 58.2.2.2.7, "Common Adaptive Tag Library (pt:common)".
The tags in the logic library handle basic logic, including creating data objects and collections, setting shared variables, and looping over a data collection. For details, see Section 58.2.2.2.12, "Logic Adaptive Tag Library (pt:logic)".
In addition to the tags above, platform-specific tags are available to access additional information and functionality in the Pagelet Producer. For details, see Section 58.2.2.2.3, "Oracle WebCenter Pagelet Producer Adaptive Tag Library (pt:ensemble)".
For important information about using tags, see the following sections:
For information on how the Pagelet Producer processes tags, see Section 58.2.2.2.16, "About Adaptive Tag Control Flow".
You can also create custom tags; for details, see Section 58.2.2.2.17, "Creating Custom Adaptive Tags".
These syntax rules and tips apply to all adaptive tags.
All tags are XML compliant. For example, only strings are allowed; you cannot use a tag within an attribute of another tag (<legal a=<illegal/>/>
).
All adaptive tags belong to the namespace http://www.plumtree.com/xmlschemas/ptui/. The namespace prefix must be "pt" (xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/). To avoid including the namespace in every tag, enclose all tags in a span that defines the namespace.
All adaptive tag attributes require the "pt:" prefix. If you do not include the pt prefix, the Pagelet Producer will not return an error, but will replace the attribute with the default value when the tag is processed.
The adaptive tag framework displays tag errors as HTML comments. If you suspect that a tag error has occurred, simply view the HTML source for the page. If there was a problem, there should be an HTML comment where the adaptive tag would have been.
Adaptive tags adhere to XHTML specifications. These specifications are not handled correctly by all HTML editors and IDEs. Some editors do not display tags correctly because of the required "pt:" prefix before tags.
Use tag debug mode for additional insight into tag errors. Turning on Debug Mode causes the adaptive tag framework to output HTML comments declaring the start and end of each tag. This can be useful for determining whether a tag ran and did not output the expected result, or did not run at all, for example. Note: Standard HTML tags are not wrapped in HTML comments.
Adaptive tag attribute value replacement allows you to access data stored in memory.
The following simple example uses the variable and value tags from the Logic tag library to store a value in memory and then display it in HTML.
<span xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'> <pt:logic.variable pt:key="test" pt:value="example text"/> <pt:logic.value pt:value="$test"/> </span>
Attribute value replacement can also be used to display more complicated memory structures. Data objects can contain multiple name value pairs. The following example creates a data object with the name and URL of a link, and then displays the name.
<span xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'> <pt:logic.data pt:key="testdata" url="http://www.myco.com" name="My company"/> <pt:logic.value pt:value="$testdata.name"/> </span>
Attribute value replacement cannot be used with tags outside the adaptive tag libraries. However, the pt.core.html tag supports attribute replacement within a tag and allows you to generate any HTML tag. Use the pt:tag attribute to specify the HTML tag and list the necessary HTML attributes as XML attributes. All non-adaptive tag attributes (attributes not prefixed with "pt:") are included automatically in the outputted HTML tag. For example, the following code creates an HTML anchor tag using an in-memory value for the "href" attribute.
<span xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'> <pt:core.html pt:tag="a" href="$myurl" title="My title">My link</pt:core.html> </span>
This code would be transformed to the following HTML: <a href="[data stored in the $myurl attribute]" title="My title">My link</a>
.
The example below combines several different techniques and tags to show how to loop over a data collection and output HTML. This code outputs several HTML links with lines in between them.
<span xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'> <pt:logic.collection pt:key="testcollection"> <pt:logic.data url="http://www.myco.com" name="My company"/> <pt:logic.data url="http://www.otherco.com" name="Other company"/> </pt:logic.collection> <pt:logic.foreach pt:data="testcollection" pt:var="link"> <pt:core.html pt:tag="a" href="$link.url"> <pt:logic.value pt:value="$link.name"/> </pt:core.html> <pt:logic.separator><br><br></pt:logic.separator> </pt:logic.foreach> </span>
For details on Logic tags, see Section 58.2.2.2.12, "Logic Adaptive Tag Library (pt:logic)".
The Pagelet Producer tag library (pt:ensemble) provides tags to insert pagelets in Pagelet Producer consumer pages and access authentication and role information for Pagelet Producer resources.
Table 58-3 Tags in the Pagelet Producer Adaptive Tag Library
Tag | Function | More Information |
---|---|---|
|
Injects the output of the specified pagelet into the page. |
Section 58.2.2.2.4, "Inserting Pagelets Using Pagelet Producer Adaptive Tags" |
|
Stores data for a specific Pagelet Producer resource, if available, in memory as a data object containing information about the resource. |
Section 58.2.2.2.5, "Accessing Resource Data Using Pagelet Producer Adaptive Tags" |
|
Evaluates a role expression and stores the result as a boolean in memory. Designed to work with the |
Section 58.2.2.2.6, "Accessing User Roles Using Pagelet Producer Adaptive Tags" |
The pt:ensemble.inject
tag injects the output of the specified pagelet into the page.
The pagelet is referenced by the fully qualified name of the pagelet as defined in Pagelet Producer, in the form libraryname:pageletname
. Any non-Pagelet Producer attributes (not prefixed with "pt:") will be passed on to the pagelet. Any HTML content inside the pagelet tag will be passed to the pagelet as an XML payload.
<pt:ensemble.inject pt:name="mylibrary:mypagelet" pagelet-attribute="A pagelet attribute"> <?xml version="1.0" encoding="utf-8"?> <doc>This is an XML payload.</doc> </pt:ensemble.inject>
To forward query string parameters from the resource request to the pagelet, set the optional parameter pt:forwardparams to 'true' as shown in the example below.
<pt:ensemble.inject pt:name="lib:pagelet" pt:forwardparams="true"/>
Note: Some internal Pagelet Producer parameters are not forwarded, including SSO cookies and login redirects. Query string parameters that attempt to override any registered pagelet parameters are not forwarded. |
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. To enable this option, set the attribute pt:onhttperror to one of the following values:
comment (default)
inline
fullpage
You can also insert pagelets into non-proxied pages; for details, see Section 58.1.2.1, "How to Insert Pagelets Using Javascript".
The pt:ensemble.resourcedata
tag stores data for a specific Pagelet Producer resource, if available, in memory as a data object.
The data object contains information about the resource (name, description, urlprefix, secureurlprefix) accessible through the data object dot notation ($resource.name
). If the resource does not have a description, urlprefix, or secureurlprefix, the data will not be available.
<pt:ensemble.resourcedata pt:name="Welcome Resource" pt:key="resource"/> <pt:logic.value pt:value="$resource.name"/> <pt:logic.value pt:value="$resource.description"/> <pt:logic.value pt:value="$resource.urlprefix"/> <pt:logic.value pt:value="$resource.secureurlprefix"/>
The role*
tags in the Pagelet Producer tag library allow pagelets to modify content based on the role of the current user.
For details on roles, see Section 58.2.5, "Using Pagelet Producer Credential Mapping".
The pt:ensemble.roleexpr
tag evaluates a role expression and stores the result as a boolean in memory. This tag is designed to work with the pt:logic.if
tag as shown below.
<pt:ensemble.roleexpr pt:expr="hasRole Default Role from Seed State" pt:key="boolvalue"/> <pt:logic.if pt:expr="$boolvalue"> <pt:logic.iftrue> <!-- This is displayed if expr evaluates to true. --> </pt:logic.iftrue> <pt:logic.iffalse> <!-- This is displayed if expr evaluates to false. --> </pt:logic.iffalse> </pt:logic.if>
For details on logic tags, see Section 58.2.2.2.12, "Logic Adaptive Tag Library (pt:logic)".
The Common tag library (pt:common) provides access to useful functionality, including URL transformation and namespace definition. This library also allows you to insert error information in the page, and CSS and JavaScript references in the Head element in a proxied HTML page.
The Common tag library is a cross-platform tag library that can be used in both Oracle WebCenter Interaction and the Pagelet Producer.
Table 58-4 Tags in the Common Adaptive Tag Library
Tag | Function | More Information |
---|---|---|
|
Defines a token for use in JavaScript functions and HTML elements to ensure unique names in an aggregated page. |
Section 58.2.2.2.10, "Defining a Unique Namespace Token Using Adaptive Tags" |
|
Transforms URLs that should be proxied. |
Section 58.2.2.2.11, "Transforming URLs Using Adaptive Tags" |
|
Disables and enables transformation on a proxied page. |
Section 58.2.2.2.11, "Transforming URLs Using Adaptive Tags" |
|
Allows JavaScript and Style Sheet include information to be added to a specific point in the Head element of an HTML page, as required by the XHTML specification. |
Section 58.2.2.2.9, "Adding Header Content Using Adaptive Tags" |
|
Marks JavaScript and CSS information to be included in the Head element of the HTML page by the pt:common.headincludes tag. |
Section 58.2.2.2.9, "Adding Header Content Using Adaptive Tags" |
|
Displays a specific user information setting. |
Section 58.2.2.2.8, "Accessing User Information Using Adaptive Tags" |
You can use the pt:common.userinfo t
ag to access specific user information settings.
The pt:common.userinfo
tag is replaced with the value of the User Information setting specified in the pt:info
attribute. The name attribute is case sensitive.
<pt:common.userinfo pt:info="FullName" xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/>
Note: You must configure the Resource to send the appropriate user information settings to the pagelet. |
The pt:common.includeinhead
and headincludes
tags allow you to include custom JavaScript and CSS information in the Head element of the HTML page.
The pt:common.includeinhead
tag marks the JavaScript and CSS information to be included in the Head element of the HTML page by the pt:common.headincludes
tag. If a .js or .css file is marked for inclusion multiple times, it will only be included once. JavaScript generated by tags will also be included.
Note: This tag will be ignored during automatic in-place refresh requests. Custom in-place refresh solutions must ensure that JavaScript gets included correctly. |
<pt:common.includeinhead> <script type="text/javascript"><!-- JavaScript --></script> <script type="text/javascript" src="http://test.com/test.js"></script> <link type="text/css" rel="stylesheet" href="http://test.com/test.css"></link> </pt:common.includeinhead>
The pt:common.headincludes
tag adds JavaScript and stylesheet include information defined by the pt:common.includeinhead
tag to the Head element of the HTML page, as required by the XHTML specification. If no pt:common.headincludes
tag is present, JavaScript will be included at the bottom of the Head element, and a Head element will be inserted if one does not exist.
<head> <script type="text/javascript" src="http://test.com/main.js"></script> </head>
It is an established best practice to include the pagelet ID in the name of any JavaScript functions and HTML elements to ensure unique names when the code is combined with markup from other pagelets on an aggregated page.
The pt:common.namespace
tag allows you to define your own token, which is replaced with the pagelet ID. The token must follow these specifications:
Valid values for the token must be in the ASCII range 0x21 to 0x7E, excluding "<" (0x3C).
The scope of the token runs from the tag defining it to the end of the file; you cannot use a token prior to defining it.
A second pt:namespace tag with a different token redefines it; two tokens cannot be defined at the same time.
<pt:common.namespace pt:token="$$TOKEN$$" xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/> <a onclick="doStuff$$TOKEN$$();" href="#">do stuff</a> <script> function doStuff$$TOKEN$$() { alert("hello"); } </script>
The pt:common.url
and pt:common.transformer
tags allow you to create and manipulate proxied URLs.
The pt:common.url
tag is used to transform URLs that should be proxied. If the URL in the pt:href
attribute is outside the proxied Resource, it will be transformed to an absolute URL. This feature does not generate a link in HTML; it obtains the URL as a string and passes it to a client-side function, as shown in the following example.
<script> function myFunction() { document.write("<pt:common.url pt:href="myURL" xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/>"); }
The pt:common.transformer
tag allows you to turn off JavaScript URL transformation in a proxied page. Set the pt:fixurl
attribute to "off" as shown below.
<pt:common.transformer pt:fixurl="off" xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/>
The transformer will not insert calls to the JavaScript URL transformation function for the rest of the file, unless you switch the feature back on in a subsequent directive (with a pt:fixurl
attribute of "on").
Logic tags handle basic logic, including creating data objects and collections, setting shared variables, evaluating expressions, and looping over a data collection.
The pt:logic tag library is a cross-platform tag library that can be used in both Oracle WebCenter Interaction and the Pagelet Producer.
Note: Many logic tags have apt:scope attribute. The valid scope values are: tag, portlet request (pagelet request), http request, session, persistent session, and application. The default is portlet request scope. |
Table 58-5 Tags in the Logic Adaptive Tag Library
Tag | Function | More Information |
---|---|---|
|
Creates a data object (collection of name=value pairs) and stores it in a shared variable using the key supplied. |
Section 58.2.2.2.15, "Using Shared Variables in Adaptive Tags" |
|
Concatenates two values into one and sets the new value in a variable with a specified name. |
Section 58.2.2.2.15, "Using Shared Variables in Adaptive Tags" |
|
Stores a shared variable using the key and value supplied. Designed for use with attribute replacement or with the |
Section 58.2.2.2.15, "Using Shared Variables in Adaptive Tags" |
|
Creates a collection of data objects and stores it in a shared variable using the key supplied. |
Section 58.2.2.2.15, "Using Shared Variables in Adaptive Tags" |
|
Evaluates the length of a collection and stores the result in memory. |
Section 58.2.2.2.15, "Using Shared Variables in Adaptive Tags" |
|
Evaluates an attribute and displays the referenced value. Used as singleton only (does not display the contents of the tag). |
Section 58.2.2.2.15, "Using Shared Variables in Adaptive Tags" |
|
Evaluates a boolean expression and stores the result as a boolean in memory. Designed to work with the |
Section 58.2.2.2.13, "Evaluating Expressions Using Adaptive Tags" |
|
Evaluates an integer expression and stores the result as a boolean in memory. Designed to work with the |
Section 58.2.2.2.13, "Evaluating Expressions Using Adaptive Tags" |
|
Evaluates whether or not two strings are equal and stores the result as a boolean in memory. The case must match. Designed to work with the |
Section 58.2.2.2.13, "Evaluating Expressions Using Adaptive Tags" |
|
Checks if a collection contains a specific data element and sets a specified variable to true or false. Designed to work with the |
Section 58.2.2.2.13, "Evaluating Expressions Using Adaptive Tags" |
|
Evaluates an expression and displays either the |
Section 58.2.2.2.13, "Evaluating Expressions Using Adaptive Tags" |
|
Displayed if the surrounding |
Section 58.2.2.2.13, "Evaluating Expressions Using Adaptive Tags" |
|
Displayed if the surrounding |
Section 58.2.2.2.13, "Evaluating Expressions Using Adaptive Tags" |
|
Allows looping over a data collection. Supports tag and portlet request scope only. |
Section 58.2.2.2.14, "Looping Over Data Collections Using Adaptive Tags" |
|
Inserts a separator between the elements of a for each loop. |
Section 58.2.2.2.14, "Looping Over Data Collections Using Adaptive Tags" |
The pt:logic.boolexpr,
intexpr
, stringexpr
and containsexpr
tags work with the pt:logic.if
tag to evaluate a range of expressions.
The sample code below determines whether the current value for the variable "title" is set to "Administrator". Variables can be set using the pt:logic.data
or pt:logic.variable
tags.
<pt:logic.stringexpr pt:expr="($title) == Administrator" pt:key="boolvalue"/> <pt:logic.if pt:expr="$boolvalue"> <pt:logic.iftrue> This is displayed if expr evaluates to true. </pt:logic.iftrue> <pt:logic.iffalse> This is displayed if expr evaluates to false. </pt:logic.iffalse> </pt:logic.if>
For details on using shared variables, see Section 58.2.2.2.15, "Using Shared Variables in Adaptive Tags".
The pt:logic.foreach
tag allows you to loop over collections of data.
The sample code below creates a table to store links for a navigation menu.
<span xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'> <table cellpadding="5" cellspacing="0" width="100%" border="0"> <!-- loop starts here --> <pt:logic.foreach pt:data="directorymenu" pt:var="temp"> <tr> <td height="25" colspan="3" class="navSidebarText"> <pt:core.html pt:tag="img" src="$temp.img" alt="" border="0" align="absmiddle" height="20" width="20" /> <pt:core.html pt:tag="a" href="$temp.url"> <pt:logic.value pt:value="$temp.title" /> </pt:core.html> </td> </tr> </pt:logic.foreach> </table> </span>
This table can then be populated with links.
The pt:logic.data
, variable
, and collection
tags allow you to store editable shared variables, which can be used in attribute value replacement or with the pt:logic.value
tag.
The pt:logic.data
tag stores a data object (a name=value pair) as an editable shared variable using the key passed in. The pt:logic.variable
tag stores an editable shared variable using the key and value passed in. If either tag is used inside the pt:logic.collection
tag, the variables are stored directly in the parent collection. If the tag is used alone, the key attribute is required. The variable is only stored after the tag is finished processing all its contents. A collection can only contain a single type of variable, such as string variables or data objects.
Note: If a variable or collection with the same name already exists, it will be overwritten. If the preexisting variable is not editable, the tag will fail. Variable names cannot contain the reserved character '.'. |
<pt:logic.variable pt:key="title" pt:value="Administrator"/> <pt:logic.data pt:key="myurl" name="Home" url="http://edocs.bea.com"/> <pt:logic.collection pt:key="testcollection"> <pt:logic.data url="http://www.myco.com" name="My company"/> <pt:logic.data url="http://www.otherco.com" name="Other company"/> </pt:logic.collection> <pt:logic.collection pt:key="teststringcollection"> <pt:logic.variable pt:value="my string data"/> <pt:logic.variable pt:value="my other string data"/> </pt:logic.collection>
The pt:logic.value
tag displays the value of the variable referenced by the pt:value
attribute. Variables can be set using the pt:logic.data
or pt:logic.variable
tags as explained in the previous section. This tag can be used to reference localized strings in message files.
<pt:logic.value pt:value="$title"/> <pt:logic.value pt:value="$myurl.Home"/>
This page describes the control flow of a typical request that makes use of adaptive tags.
First, the proxied page requests pagelet data from the transformer.
The transformer retrieves the requested pagelets from the external resources. Native UI tags, such as JSP Tags or .NET Web controls, are processed on the external resource before the HTML is returned to the transformer.
The transformer converts the HTML into markup data including both HTML and adaptive tags. This markup data is passed to the Tag Transformation Engine, which processes the tags and converts them into standard HTML.
Finally, the HTML is returned to the page where it is displayed to the end user.
The Tag Transformation Engine converts markup data from the transformer into a tree of HTML and adaptive tags. The Engine moves through the tree and outputs HTML and processes the tags. When a tag is processed, it can cause all of its child nodes to be processed, or it can skip that entire section of the tree.
The figure below shows an example of a tree. In this example, when the choose
tag is executed, it determines whether or not the current user matches the conditions in the choose clause. If it does, the when
tag will display the HTML inside the tag. If not, the otherwise
tag will display its HTML
Figure 58-5 Tag Transformation Engine Tree
For details on these tags, see Section 58.2.2.2.12, "Logic Adaptive Tag Library (pt:logic)".
The Adaptive Tag Framework allows you to create custom tags for use in pagelets and proxied pages.
The ATag
class is the base class used to write custom tags. To implement a custom tag, follow the steps below.
To implement a new tag, you must have a tag library. A tag library is simply a .jar
or .dll
file with exactly one class that implements ITagLibraryMetaData
.
Java
public static final TagLibraryMetaData LIBRARY = new TagLibraryMetaData ("Sample Tags", "sample", "This library provides sample tags.", 1.0);
.NET
public static readonly TagLibraryMetaData LIBRARY = new TagLibraryMetaData ("Sample Tags", "sample", "This library provides sample tags.", 1.0);
Create one public static final ITagMetaData
member variable that provides the name and description of the tag. Create a public static final RequiredTagAttribute
or OptionalTagAttribute
member variable for every attribute that the tag supports. You can also use standard HTML and XML attributes; see Section 58.2.2.2.2, "Using Variables in Adaptive Tags".
Java
public static final ITagMetaData TAG; public static final RequiredTagAttribute MESSAGEATTRIBUTE; public static final OptionalTagAttribute LOCATIONATTRIBUTE; static { TAG = new TagMetaData("hellolocation", "This tag displays a hello message for the given location."); MESSAGEATTRIBUTE = new RequiredTagAttribute( "message", "The message to display for hellolocation tag", AttributeType.STRING); LOCATIONATTRIBUTE = new OptionalTagAttribute("location", "The sample location attribute for hellolocation tag", AttributeType.STRING, "World"); }
.NET
public static readonly ITagMetaData TAG; public static readonly RequiredTagAttribute MESSAGEATTRIBUTE; public static readonly OptionalTagAttribute LOCATIONATTRIBUTE; static HelloLocationTag() { TAG = new TagMetaData("hellolocation", "This tag displays a hello message for the given location."); MESSAGEATTRIBUTE = new RequiredTagAttribute( "message", "The message to display for hellolocation tag", AttributeType.STRING); LOCATIONATTRIBUTE = new OptionalTagAttribute("location", "The sample location attribute for hellolocation tag", AttributeType.STRING, "World"); }
Type validation is performed by the tag framework automatically. If an optional attribute is not present in the HTML, the tag framework will use the default value. In the same code below, the optional attribute has a default value of "World.".
Implement the DisplayTag
abstract method. Use this method to create and display HTML. To display any HTML and tags defined within the tag, call ProcessTagBody
and return the resulting HTML. The sample code below adds the "Hello" string with a user-specified location to an HTMLElement
and returns it to be displayed.
Java
public HTMLElement DisplayTag() { String strLocation = GetTagAttributeAsString(LOCATIONATTRIBUTE); String strMessage = GetTagAttributeAsString(MESSAGEATTRIBUTE); HTMLElementCollection result = new HTMLElementCollection(); result.AddInnerHTMLString(strMessage + strLocation + "!"); return result; }
.NET
public override HTMLElement DisplayTag() { String strLocation = GetTagAttributeAsString(LOCATIONATTRIBUTE); String strMessage = GetTagAttributeAsString(MESSAGEATTRIBUTE); HTMLElementCollection result = new HTMLElementCollection(); result.ddInnerHTMLString(strMessage + strLocation + "!"); return result; }
If the tag should not display any HTML contained within the tag, use the GetTagType
method to return TagType.NO_BODY.
Java
public TagType GetTagType() { return TagType.NO_BODY; }
.NET
public override TagType GetTagType() { return TagType.NO_BODY; }
Implement the Create
abstract method to return a new instance of the tag.
Java
public ATag Create() { return new HelloLocationTag(); }
.NET
public override ATag Create() { return new HelloLocationTag(); }
The ATag
class allows you to include a wide range of functionality in custom tags. For details on deploying your custom tag, see Section 58.2.2.2.24, "Deploying Custom Adaptive Tags".
To access browser session information from a custom adaptive tag, use the IEnvironment
class.
The IEnvironment
class provides access to information about the current request and user, including the following:
HTTP Request and Response: Retrieve the Request or Response objects, or the Request URL. For example: IXPRequest request = GetEnvironment().GetCurrentHTTPRequest();
User information: Retrieve the user's session, or key information including language, locale, time zone, and access style (standard, 508, or low bandwidth). For example: String strTZ = GetEnvironment().GetTimeZone();
VarPacks: Retrieve any VarPacks associated with the application in which the tag is executed.
To access attributes used in a custom tag, use one of the GetTagAttribute*
methods.
All basic data types are supported as attributes (defined in the AttributeType
class), including boolean, char, double, int, long and string. The "pt:" attributes specify the logic for the tag, while any non-pt attributes specify the behavior of the resulting HTML tag. Non-pt attributes are only applicable in tags that output a simple HTML tag.
To access pt attributes, use the appropriate GetTagAttributeAs*
method using the attribute name. A method is provided for each supported attribute type, for example, GetTagAttributeAsLong
. The GetTagAttribute
method is provided for backwards compatibility and should not be used.
First, define the attribute: MODE = new OptionalTagAttribute("mode", "Turns debug mode on and off.", AttributeType.BOOLEAN, "true");
Then, access the attribute in the DisplayTag
method:boolean bNewDebugMode = GetTagAttributeAsBoolean(MODE);
To access non-pt (XML/HTML) attributes, use the GetXMLTagAttribute
method using the attribute name, or GetXMLTagAttributesAsString
to retrieve all non-pt attributes. result.AddInnerHTMLElement(new HTMLGenericElement("<a href=\"" + GetHREF() + "\" " + GetXMLTagAttributesAsString() + ">"));
The ITagMetaData
, RequiredTagAttribute
, and OptionalTagAttribute
objects pre-process tag attributes (presence, correct type, and default values). If the required attributes are not correct, an error is logged and the tag and its children are skipped. An HTML comment describing the tag and error is displayed instead.
To store custom data as member variables using a custom tag, use the SetStateVariable
or SetStateSharedVariable
methods. To retrieve it, use GetStateVariable
or GetStateSharedVariable
.
Standard variables (stored with SetStateVariable
) can only be accessed by tags in the same library. Shared variables (stored with SetStateSharedVariable
) can be accessed by tags from any library. To prevent tags from other libraries from editing a shared variable, set bOwnerEditOnly
to true when the shared variable is stored (tags in other libraries will still be able to read the variable).The Scope
parameter determines who can see the data and how long it stays in memory. The following options are defined in the Scope
class:
Table 58-6 Options Defined in Scope Class
Option | Description |
---|---|
Application Scope |
Data is visible to all tags and all users, and is only removed when the application is restarted. Therefore, care should be used when storing data on the application to make sure it does not become cluttered with large amounts of data. |
HTTP Request Scope |
Data will be visible to all tags in the same HTTP Request as the current tag, and is removed from memory when the HTTP Request is finished. |
Session Scope |
Data is visible to all tags for the current user, and is cleared from memory when a user logs out and logs in again. |
Persistent Session Scope |
Data is visible to all tags in the same HTTP session, and is only removed from memory when the browser is closed or the browser session times out. Note: Data is not cleared on user logout, so do not cache anything on this scope that could be considered a security risk if it was leaked to another user. Most tags should use Session Scope for HTTP Session data storage (as described above). |
Portlet Request Scope |
Data is visible to all tags in the same pagelet as the current tag, and is removed from memory when the pagelet is finished displaying. Tags in other pagelets on the same page will not be able to see the data. |
Tag Scope |
Data can only be seen by children of the current tag and is removed from memory when the tag is finished. (For example, in the following tags: |
If data is stored directly in the tag in member variables (not recommended), override the ReleaseTag
method to release the data stored on the tag.
/** * @see com.plumtree.portaluiinfrastructure.tags.ATag#ReleaseTag() */ public void ReleaseTag() { // Release all member variables. m_strPreviousRequestURL = null; }
Note: Displaying anHTMLElement in a tag and caching it so another tag can add more HTML is not supported. HTMLElement trees can be generated and stored for later use as long as they are self-contained trees and used in a read-only way. It is safest to clone a cached HTMLElement tree before trying to display it again to make sure there are no threading problems. |
Note: It is a best practice not to use static fields for data storage in tags. Each tag instance is guaranteed to be accessed by only a single thread at a time, but there may be multiple threads accessing different instances of the same tag class at the same time, either from the same user or a different user. This means that any static fields must be accessed using synchronized methods. Since there can be multiple instances of the same tag running at the same time, state variables set in shared scopes (Session, Persistent Session and Application) could change values during the execution of a single tag. |
To include JavaScript in a tag, use the AddJavaScript
method inside the DisplayTag
method.
For example:
HTMLScriptCollection scriptCollection = new HTMLScriptCollection(); HTMLScript script = new HTMLScript("text/javascript"); scriptCollection.AddInnerHTMLElement(script); script.AddInnerHTMLString("function myTest() { alert('test'); }"); AddJavaScript(scriptCollection);
To include common JavaScript that can be shared between multiple instances of a tag (i.e. JavaScript that is displayed once per page, regardless of how many tags of a certain type there are), override the DisplaySharedJavaScript
method. DisplaySharedJavaScript
is called automatically by the framework.
/** * Adds the PTIncluder object to the client. This object is used for * retrieving JSComponent client classes from a page. */ public HTMLScriptCollection DisplaySharedJavaScript() { HTMLScriptCollection result = new HTMLScriptCollection(); HTMLScript script = new HTMLScript("text/javascript"); result.AddInnerHTMLElement(script); script.SetSrc("/myjsfile.js"); return result; }
If there are errors in the tag and the JavaScript cannot be displayed properly, the tag should throw an XPException
with an error message, and the tag framework will log the error and add the message and stack trace to the HTML as an HTML comment. The message contents will be HTML encoded before being added to the comment.
Note: JavaScript is not displayed in 508 mode for either method, since section 508 compliant browsers do not support JavaScript. |
Tags can be used within other tags. To implement nested tags, use the RequiredParentTag
, RequiredChildTag
and RelatedChildTag
member variables.
The outer tag is referred to as the "parent" tag. Any tags within a parent tag are referred to as "child" tags of that tag. If the tag is only intended for use within a particular parent tag, create a public static final RequiredParentTag
member variable. If there are multiple RequiredParentTag
members, at least one of the parent tags must be present for the child tag to function. If the tag must include a particular child tag to function, create a public static final RequiredChildTag
member variable for each tag that is required inside the parent tag. If the child tag is not required for the parent tag to function, but is still related to that tag, create a public static final RelatedChildTag
member variable instead.
public static final RequiredChildTag DATA_OBJECT; static { ... DATA_OBJECT = new RequiredChildTag(DataObjectTag.TAG); }
Note: If required parent or child tags are missing when a tag is displayed, the tag framework will not process the incorrect tag and will add an error message to the HTML as an HTML comment. |
To implement non-standard tag types in custom adaptive tags, including 508-accessible, looping or singleton tags, override the associated method.
To display a custom tag in non-standard access styles (508 or low bandwidth), override the SupportsAccessStyle
method. The default implementation of the SupportsAccessStyle
method will cause the tag to be skipped in 508 and low-bandwidth mode. Make sure that tags that support 508 mode can function without JavaScript, since JavaScript will not be displayed in 508 mode.
If the tag displays the tag body more than once (looping tag), override the GetTagType()
method and return TagType.LOOPING
.
If the tag never displays the tag body (singleton tag), override GetTagType()
and return TagType.NO_BODY
.
To deploy custom adaptive tags, follow these steps.
Navigate to PORTAL_HOME
\settings\portal
and open the CustomTags.xml
file in a text editor (you might need to make the file writable).
Find the <AppLibFiles>
tag and add a new entry using the name of the .jar
/.dll
file used to define the custom tag library (for example, mytags
).
<AppLibFiles> <libfile name="sampletags"/> </AppLibFiles>
Add the custom implementation (.jar
/.dll
) to Oracle WebCenter Pagelet Producer hierarchy:
Java: Copy the custom .jar file to ENSEMBLE_HOME
\lib\java
and add it to the .war file in ENSEMBLE_HOME
\webapp
. (You must stop Oracle WebCenter Pagelet Producer while modifying portal.war because it will be locked while Oracle WebCenter Pagelet Producer is running.)
.NET: Copy the custom .dll file to ENSEMBLE_HOME
\webapp\portal\bin
.
Run a clean build of the Pagelet Producer to refresh all the jar files associated with the Pagelet Producer.
Once you have deployed your code, create a pagelet that contains the tag. Custom adaptive tags must either include the correct XML namespace or be contained within another tag that does. The simplest way is to put the HTML inside a span. Custom adaptive tags must use the pt:libraryname.tagname and pt:attributename format. The sample code below references the custom tag from Section 58.2.2.2.17, "Creating Custom Adaptive Tags".
<span xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'> <pt:sample.hellolocation pt:message="Hello" pt:location="San Francisco"/> </span>
Add the pagelet to a page and view the page. Test all custom tags.
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 58.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 58.2.2.3.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 58.2.2.3.4, "Using In-Place Refresh".
For a full list of classes and methods, see the JSPortlet API documentation.
These tips and best practices apply to all code that utilizes the 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. You can append the pagelet ID using the pt:namespace
and pt:token
tags, as shown in the code below.
<pt:namespace pt:token="$$TOKEN$$" xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/> <a onclick="doStuff$$TOKEN$$();" href="#">do stuffa onclick="doStuff$$TOKEN$$();" href="#">do stuff</a> <script> function doStuff$$TOKEN$$() { alert("hello"); } </script>
Valid values for the token are in the ASCII range 0x21 to 0x7E, excluding "<" (0x3C). The scope of the token runs from the tag defining it to the end of the file; you cannot use a token prior to defining it. A second pt:namespace
tag with a different token redefines it; two tokens cannot be defined at the same time.
Proxy all URLs. You cannot make a request to a URL whose host/port differs from that of the calling page. All URLs requested through JavaScript must be proxied. For details, see Section 58.2, "Building Pagelets Using the Oracle WebCenter Pagelet Producer"
Check for scripting framework 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.
Do not assume that browsers will process script blocks/includes added through the innerHTML property. Add all required JavaScript to the page in advance:
Microsoft Internet Explorer: Add the defer attribute to the script tag.
Netscape: Use RegExp to parse the response and look for the script, then evaluate it.
The 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 58.2.2.3.3, "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.
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.
The second listener pagelet displays the cube root of the number entered in the broadcast pagelet.
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> <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>
The scripting framework automatically has access to the following page-level events.
Table 58-7 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 |
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.
The in-place refresh is executed by calling the refresh()
method on the pagelet object instance. The pagelet reference can be retrieved using an adaptive tag as shown in the example below. 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> <pt:namespace pt:token="$PORTLET_ID$" xmlns:pt='http://www.plumtree.com/xmlschemas/ptui/'/> <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>
These tips apply to most adaptive pagelets.
Proxy all URLs. You cannot make request to a URL whose host/port differs from that of the calling page. All URLs requested through JavaScript must be proxied. For details, seeSection 58.2, "Building Pagelets Using the Oracle WebCenter Pagelet Producer"
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.
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 58.2.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 58.2.3.2, "Pagelet Inject API".
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).
Two REST APIs are available to retrieve data from the Pagelet Producer:
Pagelet API: Allows remote applications to retrieve pagelet data from the Pagelet Producer. (See Example 58-1, Example 58-2, and Example 58-3.)
Resource API: Allows remote applications to retrieve resource data from the Pagelet Producer. (See Example 58-4 and Example 58-5.)
The base URL for all requests is http://
producer base URL
/api/v2/ensemble/
. Here are some examples:
Example 58-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 58-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 58-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
For example, the http://host:7001/api/v2/ensemble/pagelet/libraryname/pageletname/
returns the following:
<ns2:Pagelet> <name>attributepagelet</name> <desc>This pagelet uses attributes.</desc> <id>5</id> <lastModified>2008-03-03T13:12:44.683-08:00</lastModified> <created>2008-03-03T13:12:44.683-08:00</created> <m_strLibraryName>samples</m_strLibraryName> <parent_resource_name>samples resource</parent_resource_name> <parent_resource_desc>This resource contains the standard sample pages.</parent_resource_desc> <parent_resource_id>8</parent_resource_id> <parent_resource_external_url_list>/samples/</parent_resource_external_url_list> - <parent_resource_external_url_list> https://daniilk-w2k3.devnet.plumtree.com:443/samples/ </parent_resource_external_url_list> - <m_strCodeSample> <pt:ensemble.inject pt:name="samples:attributepagelet" param1="0" param2=""> </pt:ensemble.inject> </m_strCodeSample> <m_bPublishDocs>true</m_bPublishDocs> <m_addInlineRefreshToAllUrls>false</m_addInlineRefreshToAllUrls> <m_refreshInterval>0</m_refreshInterval> <url_suffix>attributepagelet.html</url_suffix> <pagelet_external_url>/inject/v2/pagelet/attributepagelet/samples</pagelet_external_url> <parametersTransport>PAGELET_REALM</parametersTransport> <m_bAllowAll>true</m_bAllowAll> </ns2:Pagelet>
If the format is specified as JSON (http://host:7001/api/v2/ensemble/pagelet/libraryname/pageletname/?format=json
), the following response is returned:
{"ns2$Pagelet":{"@xmlns":{"ns2":"http:\/\/social.bea.com\/ensemble"}, "name":{"name":"attributepagelet"}, "desc":{"desc":"This pagelet uses attributes."}, "id":{"id":"5"}, "lastModified":{"lastModified":"2008-03-03T13:12:44.683-08:00"}, "created":{"created":"2008-03-03T13:12:44.683-08:00"}, "m_strLibraryName":{"m_strLibraryName":"samples"}, "parent_resource_name":{"parent_resource_name":"samples resource"}, "parent_resource_desc":{"parent_resource_desc":"This resource contains the standard sample pages."}, "parent_resource_id":{"parent_resource_id":"8"}, "parent_resource_external_url_list":[{"parent_resource_external_url_list":"\/samples\/"},{"parent_resource_external_url_list":"https:\/\/daniilk-w2k3.devnet.plumtree.com:443\/samples\/"}], "m_strCodeSample":{"m_strCodeSample":"<pt:ensemble.inject pt:name=\"samples:attributepagelet\"\nparam1=\"0\"\nparam2=\"\">\n\n<\/pt:ensemble.inject>"}, "m_bPublishDocs":{"m_bPublishDocs":"true"}, "m_addInlineRefreshToAllUrls":{"m_addInlineRefreshToAllUrls":"false"}, "m_refreshInterval":{"m_refreshInterval":"0"},"url_suffix":{"url_suffix":"attributepagelet.html"}, "pagelet_external_url":{"pagelet_external_url":"\/inject\/v2\/pagelet\/attributepagelet\/samples"}, "parametersTransport":{"parametersTransport":"PAGELET_REALM"}, "m_bAllowAll":{"m_bAllowAll":"true"}}}
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:
|
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 58.2.3.2.1, "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 58.2.3.2.1, "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 linkpagelet
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 tohtml . 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¶m=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>
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>
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:
The master pagelet sets the session preference using the current value of the text box.
The master pagelet calls an update method on the detail pagelet.
The detail pagelet retrieves the session preference to get the color value.
The detail pagelet redraws its color swatch area to reflect the new color value.
Pagelets can manipulate session preferences using the scripting framework. Sample code is provided below.
Note: Shared session preferences must be specified by name on the Preferences page of the associated Web Service editor 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. For more information on the scripting framework, see Section 58.2.2.3, "Using the Adaptive Pagelet Scripting Framework".
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> <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> <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>
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.
Create a java class that implements thecom.plumtree.runner.credentialmapper.IVendorCredentialMapper
interface.
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().getCrededentialsForDomain
. 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.
Compile the class into a jar. The build process must link to common.jar
, included with the Pagelet Producer distribution.
Load the custom vault into the Pagelet Producer. For details, see the Oracle Fusion Middleware Administrator's Guide for Oracle WebCenter.
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.