Oracle® Application Server Portal Developer's Guide
10g Release 2 (10.1.2) B14134-02 |
|
Previous |
Next |
Note: In general, Oracle recommends that you build your portlets using Java rather than PL/SQL. For more information on choosing a technology for building your portlets, refer to Chapter 2, "Portlet Technologies Matrix". For more information on building your portlets using Java, refer to Chapter 6, "Creating Java Portlets". |
The OracleAS Portal PL/SQL APIs are implemented as a set of PL/SQL packages and objects. Database providers and portlets are deployed to a database schema as PL/SQL packages. This chapter explains how to create PL/SQL portlets based on the Oracle Application Server Portal Developer Kit-PL/SQL (PDK-PL/SQL). To make effective use of this chapter, you should already know PL/SQL and have some familiarity with the PL/SQL Web Toolkit.
This chapter contains the following sections:
The source code for many of the examples referenced in this chapter is available as part of PDK-PL/SQL. You can download PDK-PL/SQL from the OracleAS Portal Developer Kit (PDK) page on OTN:
http://www.oracle.com/technology/products/ias/portal/pdk.html
When you unzip PDK-PL/SQL, you will find the examples in:
../pdk/plsql/starter ../pdk/plsql/sample ../pdk/plsql/cache ../pdk/plsql/sso ../pdk/plsql/svcex
You can find the reference for PDK-PL/SQL in:
../pdk/plsql/doc
When you write your portlets in PL/SQL, you should follow the best practices described in this section:
Just like a Java portlet, a PL/SQL portlet has a variety of Show modes available to it. A Show mode is an area of functionality provided by a portlet. The available Show modes are described more fully in Chapter 6, "Creating Java Portlets":
Shared Screen mode is described in Section 6.1.1.1, "Shared Screen Mode (View Mode for JPS)"
Edit mode is described in Section 6.1.1.2, "Edit Mode (JPS and OracleAS Portal)".
Edit Defaults mode is described in Section 6.1.1.3, "Edit Defaults Mode (JPS and OracleAS Portal)".
Preview mode is describe in Section 6.1.1.4, "Preview Mode (JPS and OracleAS Portal)".
Full Screen mode is described in Section 6.1.1.5, "Full Screen Mode (OracleAS Portal)".
Help mode is described in Section 6.1.1.6, "Help Mode (JPS and OracleAS Portal)".
About mode is described in Section 6.1.1.7, "About Mode (JPS and OracleAS Portal)".
Link mode is described in Section 6.1.1.8, "Link Mode (OracleAS Portal)".
To check for the selected Show mode, you can use the constants in the wwpro_api_provider
package. These constants are listed with their corresponding Show mode in Table 8-1.
The primary goal of the portlet's code is to generate the HTML output that displays on a page for all of the Show modes required by OracleAS Portal. Although it is possible to implement the portlet as a set of separate PL/SQL stored program units, organizing the portlet's code into a PL/SQL package is the best way of encapsulating related portlet code and data as a single unit in the database. You also achieve better database performance and ease of portlet maintenance.
As you may recall from Section 2.4, "Deployment Type", requests from OracleAS Portal for a particular portlet go through the portlet's provider. To communicate with its portlets, the provider contains a set of required methods that make calls to the portlet code.
When implementing a portlet as a PL/SQL package, it is a good idea to organize the portlet code in parallel with the provider code. For example, when the provider needs to retrieve information about one of its portlets, it uses its get_portlet
function. Hence, it makes sense for the portlet to contain a get_portlet_info
function that returns the requested information when called by the provider's get_portlet
function. Similarly, it is logical for the provider's show_portlet
procedure to call the portlet's show
procedure, which produces the HTML output for a requested Show mode and returns it to the provider.
Table 8-2 describes the recommended procedures and functions for a PL/SQL portlet to communicate effectively with the database provider.
Table 8-2 Recommended Functions and Procedures for PL/SQL Portlets
Procedure/Function Name | Purpose |
---|---|
get_portlet_info |
Returns the portlet record to the provider. |
show |
Produces HTML output for a requested Show mode and returns it to the provider. |
register |
Initializes the portlet at the instance level. The register procedure should not contain any transaction closing statements, such as COMMIT, ROLLBACK, or SAVEPOINT. OracleAS Portal handles the closing of the transactions itself. |
deregister |
Enables cleanups at the instance level. The deregister procedure should not contain any transaction closing statements, such as COMMIT, ROLLBACK, or SAVEPOINT. OracleAS Portal handles the closing of the transactions itself. |
is_runnable |
Determines whether the portlet can be run. Security checks can be performed in this function. |
copy |
Copies the customized and default values of portlet preferences from one portlet instance to a new portlet instance when OracleAS Portal makes a copy of the page. |
describe_parameters |
Returns a list of public portlet parameters. |
OracleAS Portal is capable of rendering its pages for both HTML and non-HTML (mobile) devices. When designing a portlet for a mobile device, you must consider some additional guidelines. The guidelines for mobile portlets are described fully in Section 6.1.3, "Guidelines for Mobile Portlets".
For information on how to build mobile-enabled portlets, refer to Section 8.12, "Enhancing Portlets for Mobile Devices".
To facilitate the development of database providers and PL/SQL portlets, you can use the PL/SQL Generator, a utility that creates installable PL/SQL code for a database provider and its portlets. The PL/SQL Generator is a standalone Web application that receives the provider and portlet definitions in the form of an XML file (similar in format to the provider.xml
file). The XML tags used for the provider and portlet definition are a subset of the XML tags used for defining Web providers with PDK-Java. The output of the PL/SQL Generator is a SQL script that can be run from SQL*Plus. The script contains SQL commands for installing the provider and portlet packages in the correct order.
You can download the PL/SQL Generator along with its installation instructions from:
http://www.oracle.com/technology/products/ias/portal/files/plsqlgenerator.zip
The general model for working with the PL/SQL Generator is as follows:
Create an XML file that defines the provider and portlets that you want to build, as described in Section 8.2.1, "Creating the Input XML File".
Run the PL/SQL Generator using the XML file as input, as described in Section 8.2.2, "Running the PL/SQL Generator".
Publish the generated PL/SQL portlet, which includes the following steps:
Install the provider generated by the PL/SQL Generator into the database, as described in Section 8.2.3.1, "Installing the Packages in the Database".
Register the database provider with the Oracle Application Server, as described in Section 8.2.3.2, "Registering the Database Provider".
Add the generated portlet to a page, as described in Section 8.2.3.3, "Adding Your Portlet to a Page".
The source XML file starts and ends with the <provider>
and </provider>
tags, and can include one or more portlet definitions. Each portlet definition is bracketed by the <portlet>
and </portlet>
tags. A portlet definition includes the XML tags that specify values for the portlet record attributes and enable the links in the portlet header. For example, the <name>
tag specifies the portlet name in the provider domain and the <title>
tag specifies the portlet display name or title. When set to true, the <showEdit>
tag enables the Edit mode for the portlet and the corresponding link in the portlet header. Table 8-3 lists the available XML tags for PL/SQL Generator input.
Table 8-3 XML Tags for PL/SQL Generator Input
XML Tag | Definition | Value Type |
---|---|---|
provider |
Encloses provider definition tags. |
Not applicable |
portlet |
Encloses portlet definition tags. |
Not applicable |
id |
Specifies the portlet ID in the provider. This value must be unique within the provider. |
string |
name |
Specifies the portlet name. The name should not contain any spaces. The generator uses the information provided in the |
string |
title |
Specifies the portlet display name. |
string |
shortTitle |
Specifies the portlet short display name. This tag is useful for mobile portlets. |
string |
description |
Specifies the portlet description. |
string |
defaultLocale |
Specifies the language the portlet renders by default. The value is the two letter ISO language and country codes expressed as |
string |
timeout |
Specifies the portlet's timeout interval in seconds. |
number |
timeoutMsg |
Specifies the message to display when the portlet times out. |
string |
showEdit |
Indicates whether the portlet supports Edit mode, which enables the user to customize the portlet's properties. |
Boolean |
showEditDefault |
Indicates whether the portlet supports the Edit Defaults mode, which enables page administrators to customize the default values of the portlet's properties. |
Boolean |
showDetails |
Indicates whether the portlet can be viewed in Full Screen mode. In this mode, the entire browser window is dedicated to the portlet. Full screen mode enables the portlet to show more details than when it shares the page with other portlets. |
Boolean |
showPreview |
Indicates whether the portlet supports the Preview mode. |
Boolean |
hasHelp |
Indicates whether the portlet supports the Help mode. |
Boolean |
hasAbout |
Indicates whether the portlet supports the About mode. |
Boolean |
language |
Defines the portlet's default language (for example, |
string |
contentType |
Indicates the default content type supported by the portlet. The tag can take one of the following values: wwpro_api_provider.CONTENT_TYPE_HTML wwpro_api_provider.CONTENT_TYPE_XML wwpro_api_provider.CONTENT_TYPE_MOBILE |
string |
apiVersion |
Specifies the version of the OracleAS Portal PL/SQL API to which the portlet conforms. The value should be |
string |
callIsRunnable |
Indicates whether OracleAS Portal must check for the user's credentials before displaying the portlet. The default value is |
Boolean |
callGetPortlet |
Indicates whether the portal can use the portlet record data stored in the Portlet Metadata Repository (PMR) instead of contacting the provider for the portlet record. If the portlet record (specified by provider |
Boolean |
acceptContentType |
Specifies a comma-delimited list of content types that the portlet can produce. For example, if a portlet can produce content of both HTML and MOBILEXML type, then the tag value is: text/html,text/vnd.oracle.mobilexml |
string |
hasShowLinkMode |
Indicates whether the portlet implements the Link mode. If the value is |
Boolean |
mobileOnly |
Indicates whether the portlet is available only to mobile devices. The default value is |
Boolean |
preferenceStorePath |
Specifies the base preference store path where the provider has stored the portlet customization information. This path is used when exporting portlets. |
string |
createdOn |
Defines the portlet creation date. The default value is |
date |
createdBy |
Identifies the user who created the portlet record. |
string |
lastUpdatedOn |
Defines the most recent date on which the portlet record was changed. The default value is |
date |
lastUpdatedBy |
Identifies the user who most recently changed the portlet record. |
string |
passAllUrlParams |
Indicates parameter passing behavior in the portlet. If the tag value is |
Boolean |
cacheLevel |
Indicates a portlet's cache level. It can take one of the following values: wwpro_api_provider.CACHE_LEVEL_SYSTEM wwpro_api_provider.CACHE_LEVEL_USER wwpro_api_provider.CACHE_LEVEL_PTL_SESSION |
string |
rewriteUrls |
Indicates whether or not URL rewriting will be performed on the output from a portlet render request. The default value is |
Boolean |
Following is a sample of the input XML for the PL/SQL Generator. Mandatory information is shown in bold.
<!-- This is a sample provider.xml file for the PLSQL Generator 1.2 --> <provider> <portlet> <id>1</id> <name>Test_Portlet</name> <title>Test Portlet Title</title> <shortTitle>Short portlet title</shortTitle> <description>This is a Test portlet</description> <timeout>30</timeout> <timeoutMsg>Test Portlet Timed Out</timeoutMsg> <showEdit>true</showEdit> <showEditDefault>true</showEditDefault> <showDetails>true</showDetails> <showPreview>true</showPreview> <hasHelp>true</hasHelp> <hasAbout>true</hasAbout> <language>en</language> <contentType>wwpro_api_provider.CONTENT_TYPE_HTML</contentType> <apiVersion>wwpro_api_provider.API_VERSION_1</apiVersion> <callIsRunnable>true</callIsRunnable> <callGetPortlet>true</callGetPortlet> <acceptContentType>'text/html'</acceptContentType> <hasShowLinkMode>false</hasShowLinkMode> <mobileOnly>false</mobileOnly> <passAllUrlParams>true</passAllUrlParams> <cacheLevel>wwpro_api_provider.CACHE_LEVEL_USER</cacheLevel> <rewriteUrls>true</rewriteUrls> </portlet> </provider>
After you have created a valid XML input file, you can run the PL/SQL Generator to generate the provider and portlet packages in the form of a SQL file:
If you have not already done so, install the PL/SQL Generator according to the instructions that came with the download.
From your browser, go to the URL for the PL/SQL Generator. It should look something like the page shown in Figure 8-1.
Click Browse and select the source XML file for the Source XML File field. Refer to Section 8.2.1, "Creating the Input XML File" for more information on creating the XML file.
In the Provider Name field, enter the name of the provider. The provider name must not contain any spaces. The generator uses the value entered in this field for the provider package name.
Click Generate to generate the SQL file that contains the installable PL/SQL code for the provider and portlet packages. When the browser prompts you to save or open the file, choose Save.
In the Save dialog box, change the file extension to .sql
and revise the file name as you wish.
Save the file.
After you have run the PL/SQL Generator and obtained a SQL file, you still need to perform the following tasks to make the provider and portlets available to OracleAS Portal:
To install the generated provider and portlet packages into the database where you installed OracleAS Portal, perform the following steps:
Start a SQL*Plus session and log in to the PORTAL schema.
Create a new database schema, the provider schema, to store the generated provider and portlet packages by entering the following commands in SQL*Plus:
create user provider_schema identified by provider_schema_password; grant resource, connect to provider_schema;
Grant the EXECUTE privilege for the OracleAS Portal APIs to the provider schema by running the provsyns.sql
script that is located in the MID_TIER_ORACLE_HOME/portal/admin/plsql/wwc
directory as follows:
@provsyns.sql provider_schema
Log in to the provider schema and run the generated SQL file. It will create the provider and portlet packages in the database.
After creating the provider and portlet packages in the database, you must register the provider with OracleAS Portal before adding the PL/SQL portlet to a portal page:
Log in to OracleAS Portal as an administrator.
From the Portal Builder, click the Administer tab then the Portlets tab.
In the Remote Providers portlet, click Register a Provider.
Fill in the Name, Display Name, Timeout, and Timeout Message as desired.
From the Implementation Style, list choose Database.
Click Next and complete the remainder of the wizard.
When you complete the wizard, click Finish.
From the Portlet Repository portlet, click Display Portlet Repository.
Browse the repository and find the provider that you just registered. Typically, new providers appear in the Portlet Staging Area of the repository.
Once you find the provider, confirm that it contains all of the portlets you created in the provider. If the provider or its portlets do not appear, then retrace the steps in this section and the preceding sections (Section 8.2.3.1, "Installing the Packages in the Database", Section 8.2.1, "Creating the Input XML File", and Section 8.2.2, "Running the PL/SQL Generator") to ensure that you correctly created and registered your provider and portlet.
Once your provider and its portlets appear in the repository, you can add it to a page. To add your portlet to a page, follow the instructions in the Oracle Application Server Portal User's Guide.
This section describes how to build a basic PL/SQL portlet using the hello world
sample contained in the starter
provider sample. The starter
provider sample, located in ..\pdkplsql\pdk\plsql\starter
in PDK-PL/SQL (pdkplsql.zip
), consists of the following files:
starter_provider.pks
is the package specification of the starter
provider.
starter_provider.pkb
is the package body of the starter
provider.
helloworld_portlet.pks
is the package specification of the hello world
portlet.
helloworld_portlet.pkb
is the package body of the hello world
portlet.
snoop_portlet.pks
is the package specification of the snoop
portlet.
snoop_portlet.pkb
is the package body of the snoop
portlet.
insintpr.sql
is the installation script for the starter
provider.
The general model for building PL/SQL portlets manually is as follows:
Modify the hello world
portlet package specification and body to create your own portlet package, as described in Section 8.3.1, "Implementing the Portlet Package".
Modify the starter
provider package specification and body to add your new portlet to a provider, as described in Section 8.3.2, "Implementing the Provider Package".
Add your portlet to a page, as described in Section 8.3.3, "Adding Your Portlet to a Page".
To modify helloworld_portlet.pks
and helloworld_portlet.pkb
to create your own portlet package, perform the following steps:
Make copies of the package specification, helloworld_portlet.pks
, and body, helloworld_portlet.pkb
.
Rename the copies to my_first_portlet.pks
and my_first_portlet.pkb
, respectively.
Open my_first_portlet.pks
in an editor and change the name of the package to my_first_portlet
:
CREATE OR REPLACE package my_first_portlet is ... end my_first_portlet;
Open my_first_portlet.pkb
in an editor and repeat the change that you made in the previous step; that is, change the name of the package to my_first_portlet
.
In my_first_portlet.pkb
, find the function named get_portlet_info
and modify it as follows:
function get_portlet_info ( p_provider_id in integer ,p_language in varchar2 ) return wwpro_api_provider.portlet_record is l_portlet wwpro_api_provider.portlet_record; begin l_portlet.id := starter_provider.PORTLET_FIRST; l_portlet.provider_id := p_provider_id; l_portlet.title := 'My First Portlet'; l_portlet.name := 'My_First_Portlet'; ...
In my_first_portlet.pkb
, find the procedure named show
and modify it as follows:
procedure show ( p_portlet_record wwpro_api_provider.portlet_runtime_record ) is l_portlet wwpro_api_provider.portlet_record; l_text_name in varchar2(100); l_text in varchar2(200); begin ... /* Display the content of the portlet in the show mode. Use the wwui_api_portlet.portlet_text() API when generating the content of the portlet so that the output uses the portlet CSS. */ htp.p(wwui_api_portlet.portlet_text( p_string => 'Hello World - Mode Show' ,p_level => 1 )); /* Add the functionality you want here. In this case we are adding a welcome message addressed to the current user. */ l_text_name := 'Welcome to my first portlet ' || wwctx_api.get_user; l_text := wwui_api_portlet.portlet_text( p_string => l_text_name, p_level => 1 ); htp.p(l_text); htp.para; if (p_portlet_record.has_border) then wwui_api_portlet.close_portlet; end if; ...
Save my_first_portlet.pkb
.
After you implement the portlet package, you must add your portlet to a provider. To modify starter_provider.pks
and starter_provider.pkb
to add your new portlet to a provider, perform the following steps:
Make copies of the package specification, starter_provider.pks
, and body, starter_provider.pkb
.
Rename the copies to starter_provider2.pks
and starter_provider2.pkb
, respectively.
Note: If you want to create a new, empty provider, remove all references to thehello world and snoop portlets from starter_provider2.pks and starter_provider2.pkb before performing the steps that follow.
|
Open starter_provider2.pks
in an editor.
Add a constant called PORTLET_FIRST
. This constant is used as the identifier for the portlet within the provider. Hence, the constant's value must be unique within the provider.
CREATE OR REPLACE
package STARTER_PROVIDER
is
/**
* This package is used as an example to show how providers can be created
* in the portal system.
*
* This provider contains the following portlets:
*
* Hello World (PORTLET_HELLOWORLD)
* Snoop (PORTLET_SNOOP)
*
*/
PORTLET_HELLOWORLD constant integer := 1;
PORTLET_SNOOP constant integer := 2;
PORTLET_FIRST constant integer := 3;
Save starter_provider2.pks
.
Open starter_provider2.pkb
in an editor.
In starter_provider2.pkb
, add a call for the new portlet's get_portlet_info
function in the get_portlet
function of the provider package. This step entails adding the call my_first_portlet.get_portlet_info
in the get_portlet
function. The get_portlet
function allows the portal to retrieve information for the portlet when necessary.
function get_portlet p_provider_id in integer ,p_portlet_id in integer ,p_language in varchar2 ) return wwpro_api_provider.portlet_record is begin if (p_portlet_id = PORTLET_HELLOWORLD) then return helloworld_portlet.get_portlet_info( p_provider_id => p_provider_id ,p_language => p_language ); elsif (p_portlet_id = PORTLET_SNOOP) then return snoop_portlet.get_portlet_info( p_provider_id => p_provider_id ,p_language => p_language ); elsif (p_portlet_id = PORTLET_FIRST) then return my_first_portlet.get_portlet_info( p_provider_id => p_provider_id ,p_language => p_language ); else raise wwpro_api_provider.PORTLET_NOT_FOUND_EXCEPTION; end if; end get_portlet;
In starter_provider2.pkb
, add the new portlet to the list of portlets returned by the provider. This step entails adding the new portlet to the get_portlet_list
function of the provider. The get_portlet_list
function tells the portal which portlets the provider implements.
function get_portlet_list ... begin l_cnt := 0; if (p_security_level = false ) then l_cnt := l_cnt + 1; l_portlet_list(l_cnt) := get_portlet( p_provider_id => p_provider_id ,p_portlet_id => PORTLET_HELLOWORLD ,p_language => p_language ); l_cnt := l_cnt + 1; l_portlet_list(l_cnt) := get_portlet( p_provider_id => p_provider_id ,p_portlet_id => PORTLET_SNOOP ,p_language => p_language ); l_cnt := l_cnt + 1; l_portlet_list(l_cnt) := get_portlet( p_provider_id => p_provider_id ,p_portlet_id => PORTLET_FIRST ,p_language => p_language ); else if (helloworld_portlet.is_runnable( p_provider_id => p_provider_id ,p_reference_path => null) ) then l_cnt := l_cnt + 1; l_portlet_list(l_cnt) := get_portlet( p_provider_id => p_provider_id ,p_portlet_id => PORTLET_HELLOWORLD ,p_language => p_language ); end if; if (snoop_portlet.is_runnable p_provider_id => p_provider_id ,p_reference_path => null) ) then l_cnt := l_cnt + 1; l_portlet_list(l_cnt) := get_portlet( p_provider_id => p_provider_id ,p_portlet_id => PORTLET_SNOOP ,p_language => p_language ); end if; if (my_first_portlet.is_runnable( p_provider_id => p_provider_id ,p_reference_path => null) ) then l_cnt := l_cnt + 1; l_portlet_list(l_cnt) := get_portlet( p_provider_id => p_provider_id ,p_portlet_id => PORTLET_FIRST ,p_language => p_language ); end if; end if; return l_portlet_list; end get_portlet_list;
In starter_provider2.pkb
, modify the is_portlet_runnable
function to add a call to the is_runnable
function of the new portlet.
function is_portlet_runnable ( p_portlet_instance in wwpro_api_provider.portlet_instance_record ) return boolean is begin if (p_portlet_instance.portlet_id = PORTLET_HELLOWORLD) then return helloworld_portlet.is_runnable( p_provider_id => p_portlet_instance.provider_id ,p_reference_path => p_portlet_instance.reference_path ); elsif (p_portlet_instance.portlet_id = PORTLET_SNOOP) then return snoop_portlet.is_runnable( p_provider_id => p_portlet_instance.provider_id ,p_reference_path => p_portlet_instance.reference_path ); elsif (p_portlet_instance.portlet_id = PORTLET_FIRST) then return my_first_portlet.is_runnable( p_provider_id => p_portlet_instance.provider_id ,p_reference_path => p_portlet_instance.reference_path ); else raise wwpro_api_provider.PORTLET_NOT_FOUND_EXCEPTION; end if; end is_portlet_runnable;
Repeat step 9 according to the information in Table 8-4.
Table 8-4 Changes to starter_provider2.pkb
Procedure/Function | Addition |
---|---|
procedure register_portlet |
elsif (p_portlet_instance.portlet_id = PORTLET_FIRST) then my_first_portlet.register(p_portlet_instance) |
procedure deregister_portlet |
elsif (p_portlet_instance.portlet_id = PORTLET_FIRST) then my_first_portlet.deregister (p_portlet_instance) |
function describe_portlet_parameters |
elsif (p_portlet_id = PORTLET_FIRST) then return my_first_portlet.describe_parameters (p_provider_id, p_language); |
procedure show_portlet |
elsif (p_portlet_record.portlet_id = PORTLET_FIRST) then my_first_portlet.show(p_portlet_record) |
procedure copy_portlet |
elsif (p_copy_portlet_info.portlet_id = PORTLET_FIRST) then my_first_portlet.copy(p_portlet_record) |
Save and close starter_provider2.pkb
.
Log in to OracleAS Portal as you normally would.
From the Portal Builder, click the Administer tab then the Portlets tab.
From the Portlet Repository portlet, click Display Portlet Repository.
Browse the repository and find the starter provider (typically it will appear in the Portlet Staging Area of the repository). It should contain its two original portlets: hello world
and snoop
.
From a command line prompt, start SQL*Plus and connect as the owner of the starter
provider schema.
Compile the new and modified PL/SQL packages in the following order:
starter_provider2.pks
my_first_portlet.pks
starter_provider2.pkb
my_first_portlet.pkb
If any compilation errors occur, fix and recompile them until all of the packages compile successfully.
From the Portlet Repository portlet, click Display Portlet Repository.
Browse the repository and find the starter
provider again. It should now contain your new portlet, my_first_portlet
, in addition to its original portlets.
Note: If you make changes to an existing provider or the portlet record, you need to refresh your provider before seeing the changes reflected in your OracleAS Portal instance. |
Your portlet should now be available for adding to pages like any other portlet in the Portlet Repository. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
OracleAS Portal provides APIs for storing and retrieving individual portlet preferences, and storing and manipulating temporary data for the current session:
OracleAS Portal provides a set of APIs for storing and retrieving individual preferences for each unique portlet instance in a persistent manner. It provides a unique identifier for each individual, a preference store automatically mapped by user, and access mechanisms for storing and retrieving personalization information in your PL/SQL portlets.
By default, when you enable end-user personalization, Customize appears on the title bar of your portlet. This link displays a form where users can choose settings for that portlet.
End-user personalization options are available through the wwpre_api_name
and wwpre_api_value
packages.
In general, you can set up preference storage as follows:
Create the preference path via wwpre_api_name.create_path
.
Create the preference with wwpre_api_name.create_name
.
Set the preference values by providing the preference name and scoping level for which you want to set the value. Use wwpre_api_value.set_value_as_varchar2
, set_value_as_number
, or set_value_as_date
for this purpose.
Get preference values by providing the preference name and path whenever you want to retrieve the preference value. Use wwpre_api_value.get_value_as_varchar2
, get_value_as_number
, or get_value_as_date
for this purpose.
The services example, located in ..\pdkplsql\pdk\plsql\svcex
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement preference storage. The objective is to achieve the following functionality:
When a user clicks Customize, they can enter text in two fields.
The first field prompts for personalized text. The second prompts for a personalized portlet title.
The values the user enters for these two fields are stored in the preference store.
The personalized text and portlet titles are retrieved whenever that user invokes the portlet instance.
You can browse through this example as follows to see how to create the preference store, store values in it, and retrieve values from it:
Open the services_portlet.pkb
file in an editor.
The portlet path and preference names are provided with aliases in the constants part of your portlet definition.
DOMAIN constant varchar2(30) := 'provider'; SUBDOMAIN constant varchar2(32) := 'services'; PORTLET_PATH constant varchar2(256):= 'oracle.portal.pdk.servicesportlet'; PREFNAME_STRING constant varchar2(30) := 'services_string'; PREFNAME_TITLE constant varchar2(30) := 'services_title';
Find the register
procedure. Your portlet needs to create a path for storing preferences. To do so, it calls wwpre_api_name.create_path
for creating the preference path. It then calls wwpre_api_name.create_name
for creating the preference name, taking the portlet path, name, and description as input parameters. Another input parameter is the p_type_name
that indicates special value types. The NLSID
type indicates that the value stored is an NLS id. The functions for setting and retrieving this type treat it as a number value. Apart from that, when a preference store value of this type is exported or copied, so are its associated strings. The last input parameter, the language, is obtained from a context API.
procedure register ( p_portlet_instance in wwpro_api_provider.portlet_instance_record ) is begin -- -- Create a path for the portlet instance. This is used to create -- the preferences for the portlet instance in the preference store. -- wwpre_api_name.create_path( p_path => PORTLET_PATH || p_portlet_instance.reference_path ); -- -- Create the names to store the portlet preferences. -- wwpre_api_name.create_name( p_path => PORTLET_PATH || p_portlet_instance.reference_path, p_name => PREFNAME_STRING, p_description => 'Single custom row in ' || 'Introductory Example portlet.', p_type_name => 'NLSID', p_language => wwctx_api.get_nls_language); wwpre_api_name.create_name( p_path => PORTLET_PATH || p_portlet_instance.reference_path, p_name => PREFNAME_TITLE, p_description => 'Single custom row in ' || 'Introductory Example portlet.', p_type_name => 'NLSID', p_language => wwctx_api.get_nls_language); exception when others then raise; end register;
The deregister procedure must eliminate the preference store with a call to wwpre_api_name.delete_name
.
procedure deregister
(
p_portlet_instance in wwpro_api_provider.portlet_instance_record
)
is
begin
--
-- Delete the path used by the portlet instance. This will delete
-- all the names and all the values associated with the path.
--
wwpre_api_name.delete_path(
p_path => PORTLET_PATH || p_portlet_instance.reference_path
);
exception
when others then
raise;
end deregister;
The portlet must also get and set the values in the preference store using wwpre_api_value.set_value
and wwpre_api_value.get_value
. Find the get_default_preference
function. Notice how this function loads the system level default values from the preference store. The default preferences are associated with an instance. The language strings are set in the database.
function get_default_preference ... begin -- -- Try to find a previously entered portlet instance string preference, -- if any. -- A portlet instance string preference is stored in the preference -- store and has a level of SYSTEM_LEVEL_TYPE. -- p_path => PORTLET_PATH || p_reference_path, l_prefs.string_id := to_char(wwpre_api_value.get_value_as_number( p_name => PREFNAME_STRING, p_level_type => wwpre_api_value.SYSTEM_LEVEL_TYPE )); -- -- If the value returned above is null it is an indication that there -- is no default string yet. Initialize the string id to 0 to indicate -- this and load the default string value. -- if (l_prefs.string_id is null or to_number(l_prefs.string_id) = 0) then wwpre_api_value.set_value_as_number( p_path => PORTLET_PATH || p_reference_path, p_name => PREFNAME_STRING, p_level_type => wwpre_api_value.SYSTEM_LEVEL_TYPE, p_level_name => null, p_value => 0 ); ... end get_default_preference;
Find the show
procedure. Notice the behavior when the portlet is in Edit Defaults or Edit mode. Note also how p_action
is populated when the user clicks APPLY, CANCEL, or OK. Once the form is submitted, the show
procedure of the portlet is called again and, if the p_action
parameter is not null, then the save_prefs
procedure is called to save the customizations and redirect to the relevant page.
procedure show ( p_portlet_record wwpro_api_provider.portlet_runtime_record ) is l_str varchar2(32000); l_pref_record preference_record; l_action varchar2(10); l_names owa.vc_arr; l_values owa.vc_arr; begin ... elsif (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW_EDIT) or (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW_EDIT_DEFAULTS) then wwpro_api_parameters.retrieve(l_names, l_values); for i in 1..l_names.count loop if (upper(l_names(i)) = upper('p_string')) then l_pref_record.string := l_values(i); elsif l_names(i) = 'p_title' then l_pref_record.title_string := l_values(i); elsif l_names(i) = 'p_action' then l_action := l_values(i); end if; end loop; if (l_action in (ACTION_OK,ACTION_APPLY,ACTION_CANCEL)) then if (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW_EDIT) then save_prefs(p_string => l_pref_record.string, p_title => l_pref_record.title_string, p_action => l_action, p_level => wwpre_api_value.USER_LEVEL_TYPE, p_portlet_record => p_portlet_record); else save_prefs(p_string => l_pref_record.string, p_title => l_pref_record.title_string, p_action => l_action, p_level => wwpre_api_value.SYSTEM_LEVEL_TYPE, p_portlet_record => p_portlet_record); end if; else show_edit(p_portlet_record => p_portlet_record); end if; ... end show;
The show_edit
procedure renders the page for Edit or Edit Defaults mode. It renders two text fields that allow the user to change the customizable values in a form with three buttons (Apply, OK, and Cancel). Note that this function uses the wwpro_api_adapter.open_form
to create the HTML form with the correct action attribute for the <FORM>
tag and with the correct hidden fields. It is important to use this procedure to create the <FORM>
tag if you want to use the portlet with the Federated Portal Adapter from remote OracleAS Portal instances.
procedure show_edit( p_portlet_record in wwpro_api_provider.portlet_runtime_record)is l_prefs preference_record; l_text_prompt_string varchar2(30); l_title_prompt_string varchar2(30);begin
...
htp.centeropen;
htp.tableOpen(cattributes => 'BORDER="1" WIDTH=90%');
htp.tableRowOpen;
htp.p('<TD>');
--
-- This procedure call creates the <FORM> tags with a set of
-- standard parameters. Using this procedure makes the
-- customisation page work through the pl/sql http adapter.
--
wwpro_api_adapter.open_form(p_formattr => 'NAME="services"',
p_prr => p_portlet_record);
htp.p('</TD>'); htp.tableRowClose; htp.tableClose; htp.centerclose; htp.formclose;end show_edit;
Review the following procedures and functions, which are related to the preference storage implementation in this example:
get_user_preference
retrieves the user customized string and title for the portlet.
save_prefs
is invoked to save the preferences to the preference store when the user clicks OK or Apply after making customization changes.
entered_text_is_valid
checks to see if the text entered in the customizable text fields is valid.
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
The services example, located in ..\pdkplsql\pdk\plsql\svcex
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement a session store. The objective is to achieve the following functionality:
When a user invokes this portlet, it displays text that reads: "This portlet has rendered x
times in this session." x
is the number of times the portlet has been rendered.
Every time the user invokes the portlet, the counter increases by 1.
Clicking Details in the portlet enables the user to reset the counter via Clear. After clearing the counter, the counter starts again from zero.
You can browse through this example as follows to see how to create the session store, store values in it, and retrieve values from it:
Open the services_portlet.pkb
file in an editor.
The domain and subdomain definitions for your session object are provided with aliases in the constants part of your portlet definition.
DOMAIN constant varchar2(30) := 'provider'; SUBDOMAIN constant varchar2(32) := 'services'; PORTLET_PATH constant varchar2(256):= 'oracle.portal.pdk.servicesportlet'; PREFNAME_STRING constant varchar2(30) := 'services_string'; PREFNAME_TITLE constant varchar2(30) := 'services_title';
Find the clear_count
procedure. clear_count
is called from the show
procedure when the user clicks Clear to reset the counter. clear_count
calls wwsto_api_session.load_session
to load the session object. Then, it calls wwsto_api_session.set_attribute
to set the counter to zero. Lastly, it saves the session object by calling save_session
.
procedure clear_count ( p_action in varchar2, p_back_url in varchar2, p_reference_path in varchar2 ) is ex_counter integer; session_parms &&1..wwsto_api_session; begin -- -- Clear the display counter. -- if (p_action = ACTION_CLEAR) then -- -- Load the session object that contains the display counter -- session_parms := &&1..wwsto_api_session.load_session (DOMAIN,SUBDOMAIN); ex_counter := session_parms.get_attribute_as_number( 'ex_counter' || p_reference_path); -- -- Reset the display counter. -- ex_counter := 0; session_parms.set_attribute( 'ex_counter' || p_reference_path, ex_counter); -- -- Save the changes to the database immediately to avoid any -- data consistency problems with the data stored in the -- session object. -- session_parms.save_session; end if; owa_util.redirect_url(curl=>p_back_url); end clear_count;
Find the show_contents
procedure. show_contents
is called from the show
procedure to retrieve the counter, increment it by one, and save the value in the session store. Notice how it retrieves the session object to display the number of times the user has rendered the portlet. It also retrieves the counter value with get_attribute_as_number
and increments the counter for every invocation of this procedure.
procedure show_contents ( p_portlet_record wwpro_api_provider.portlet_runtime_record ) is l_prefs preference_record; session_parms &&1..wwsto_api_session; ex_counter integer; l_portlet wwpro_api_provider.portlet_record; l_str varchar2(32000); begin -- -- In this mode a session counter is used to indicate -- the number of invocations of this portlet during the -- current session. The counter is stored in the session -- store. -- session_parms := &&1..wwsto_api_session.load_session(DOMAIN,SUBDOMAIN); ex_counter := session_parms.get_attribute_as_number( 'ex_counter' || p_portlet_record.reference_path); if (ex_counter is null) then -- first invocation session_parms.set_attribute( 'ex_counter' || p_portlet_record.reference_path,1); ex_counter := session_parms.get_attribute_as_number( 'ex_counter' || p_portlet_record.reference_path); else -- on every invocation increase by 1 ex_counter := ex_counter + 1; session_parms.set_attribute( 'ex_counter' || p_portlet_record.reference_path, ex_counter); end if; session_parms.save_session; ... end show_contents;
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
The functionality of portlets can be extended with the help of parameters. The business logic implemented by portlets may produce different HTML output depending on the parameters passed to the page. By using portlet parameters, you can navigate within the portlet in Shared Screen mode without changing the current page. Portlets can also communicate with each other through parameters.
Portlet parameters are structured as name-value pairs. These pairs map directly to the URL parameter passing format by using the GET
submission method or can use the HTTP message body by using the POST
submission method. Portlets can also expose their parameters to OracleAS Portal. When added to a page, these portlets can accept values in the form of page parameters created by the page designer.
Note: Portlet parameter names should not start with an underscore (_) because those parameters are reserved for internal use by OracleAS Portal and are not passed to the portlet. |
Portlets do not have direct access to the URL, the HTTP message body, or the page parameters. To retrieve the parameter values, portlets must call the OracleAS Portal PL/SQL parameter APIs provided in the wwpro_api_parameters
package.
OracleAS Portal offers the following types of parameters:
WARNING: You cannot mix the usage of public and private parameters in a portlet. To enable public parameters for your portlet, you must take steps that preclude the usage of private parameters and vice versa. |
Private portlet parameters enable the implementation of internal navigation in your portlet.
Public portlet parameters let you pass control over the data flow of your portlet to the page designer. The page designer can map the public portlet parameters to their page parameters, provide default values, and allow users to customize those values.
Page parameters are defined in a simple user interface by page designers. These page parameters can be mapped to public portlet parameters in order for the page designer to pass parameter values from the page to the portlets on it.
For more information about parameters, refer to Section 2.12, "Public Portlet Parameters Support" and Section 2.13, "Private Portlet Parameter Support".
You can use either GET
or POST
HTML submission methods when passing private portlet parameters. The GET
method uses the URL to pass the parameters, whereas the POST
method places the parameters in an HTTP message body. For both methods, you must specify the portlet instance on the portal page, how the parameter is called, and the value of the parameter.
There are two types of private portlet parameters:
Qualified parameters ensure that a private portlet parameter is not read by any other portlet on the page. The reference path, which is assigned when the portlet is added to a page, is the unique prefix of the parameter. For example, http://page_url?277_MAP_368673.region=Europe
. The qualified parameter's reference path is 277_MAP_368673
, the name is region
, and the value is Europe
. For private parameters, we strongly recommend that you always use qualified parameters.
Unqualified parameters have no information about the portlet instance and can be read by any portlet on the page. For example, http://page_url?region=Europe
. The unqualified parameter's name is region
and its value is Europe
. For private parameters, we strongly recommend that you avoid unqualified parameters.
Public portlet parameters enhance the flexibility of your portlets by enabling page designers to reuse your portlets on multiple pages. As a result, page designers do not have to ask you to make changes to the portlet code when adding the portlet to different pages. By using public portlet parameters, any portlet on a page can easily receive its value from the mapped page parameter, regardless of the portlet parameter name.
For example, suppose you have a page parameter named dept_id
. Three portlets need this value, but one portlet calls it dept
, another calls it deptno
, and still another department_id
. Mapping the page parameter enables all three portlets to receive the value from the dept_id
parameter and place it in the appropriate portlet parameter. Furthermore, the page designer may set a default value (for example, department 20) that can be customized by users (for example, department 30) and applied to all three portlets.
The general model for passing public and page parameters is as follows:
Enable public parameters in the portlet record by setting pass_all_url_params
to false
. This ensures that the portlet is only passed parameters intended for that portlet.
Declare the public parameters in the provider's describe_portlet_parameters
function. For each of the portlets that belong to the provider, this procedure should return a list of the parameters that the portlet accepts in the form of a PL/SQL table of records of the type:
type portlet_parameter_table is table ofportlet_parameter_record index by binary_integer;
Provide descriptive information for the parameters in the portlet's describe_parameters
function. For example:
function describe_parameters (p_provider_id in integer, p_language in varchar2) return wwpro_api_provider.portlet_parameter_table is l_params wwpro_api_provider.portlet_parameter_table; begin l_params(1).name := 'dept_id'; l_params(1).datatype := wwpro_api_provider.STRING_TYPE; l_params(1).description := 'Defines a department ID'; l_params(1).display_name := 'Department ID'; return l_params; end describe_parameters;
Assign values to the public parameters. Public parameters typically get their values through page parameters. Page parameters are usually assigned default values by the page designer and the user can then customize the value at runtime. Alternatively, page parameter values can be assigned in the calling URL. For more information about how page designers can use page parameters, refer to the Oracle Application Server Portal User's Guide.
Regardless of whether you are using private or public parameters, you use the same APIs to retrieve their values. Portlets obtain their parameters by calling the PL/SQL parameter APIs in the wwpro_api_parameters
package:
wwpro_api_parameters.get_value
returns the parameter value that is specified by a given parameter name. Parameter names are not case sensitive, whereas parameter values are case sensitive. For example:
l_region := wwpro_api_parameters.get_value
(p_name => 'region',
p_reference_path => p_portlet_record.reference_path);
wwpro_api_parameters.get_values
returns an array of parameter values. This function returns all the values that are associated with a single parameter name or an empty list if no matches are found. Some business logic may require multiple selections, when multiple values are passed to the portlet by using the same parameter name. Portlets can take one or more values of the same parameter. For example:
l_region_values owa.vc_arr;
...
l_region_values := wwpro_api_parameters.get_values
(p_name = 'region',
p_reference_path => p_portlet_record.reference_path);
wwpro_api_parameters.get_names
returns the names of the parameters that are passed on to a specified portlet that is identified by the reference path. The returned list is a PL/SQL table of the owa.vc_ar
type that is defined as follows:
type vc_arr is table of varchar2(32000) index by binary_integer;
Note: Portlet parameter names should not start with an underscore (_) because those parameters are reserved for internal use by OracleAS Portal and are not passed to the portlet. |
For example:
l_names owa.vc_arr;
...
l_names := wwpro_api_parameters.get_names
(p_reference_path => p_portlet_record.reference_path);
wwpro_api_parameters.retrieve
returns the names and values of all of the portlet's parameters. For example:
procedure show_portlet ( p_portlet_record in out wwpro_api_provider.portlet_runtime_record ) is l_names owa.vc_arr; l_values owa.vc_arr; ... begin ... wwpro_api_parameters.retrieve (l_names, l_values); for i in 1..l_names.count loop htp.p('Parameter Name: '||l_names(i)); htp.p('Parameter Value: '||l_values(i)); htp.br; end loop; ... end show_portlet;
Whenever a user accesses a page in OracleAS Portal, a public session is established. When the user logs in to OracleAS Portal, the public session becomes an authenticated session. This session contains several pieces of context information about the user, such as user name, current session ID, IP address, and language preference. It also includes supporting information such as the OracleAS Portal schema currently in use.
Session context services return information about a user's session and are available through the wwctx_api
package.
The general model for working with the session context is as follows:
Identify the piece of information you require for your functionality.
Use the appropriate method from wwctx_api
to get and optionally set this value.
Table 8-5 lists the function calls used to obtain the various pieces of session information.
Note: For more information on the context APIs, see the PL/SQL API Reference. The API Reference can be found on Portal Center (http://portalcenter.oracle.com ) or, if you downloaded PDK-PL/SQL (pdkplsql.zip ), in ..\pdkplsql\pdk\plsql\doc .
|
Table 8-5 Context Information Function Calls
Session Information | Function Call |
---|---|
Current user |
|
Login status of user |
|
Login time |
|
Language |
|
Current session id |
|
IP address of user client |
|
User schema |
|
OracleAS Portal schema |
|
OracleAS Portal version |
|
The services example, located in ..\pdkplsql\pdk\plsql\svcex
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can obtain session information using the wwwctx_api
package. You can browse through this example as follows to see how the function calls are implemented in a portlet:
Open the services_portlet.pkb
file in an editor.
Find the get_portlet_info
function.
Notice the usage of wwctx_api.get_user
to derive the user information and set that value in the portlet information record:
... l_portlet.timeout := null; l_portlet.timeout_msg := null; l_portlet.created_on := to_date('10/19/2000', 'MM/DD/YYYY'); l_portlet.created_by := wwctx_api.get_user; l_portlet.last_updated_on := to_date('10/19/2000', 'MM/DD/YYYY'); l_portlet.last_updated_by := wwctx_api.get_user; l_portlet.has_show_edit_defaults := true; l_portlet.has_show_preview := true; l_portlet.preference_store_path := PORTLET_PATH; ...
wwctx_api.get_user
is used similarly in various places throughout services_portlet.pkb
. Search the code for other occurrences of wwctx_api.get_user
.
Another example of getting context information occurs in the is_runnable
function:
function is_runnable
(
p_provider_id in integer
,p_reference_path in varchar2
)
return boolean
is
begin
--
-- Portlet security check. It allows the portlet to be visible
-- if the user is logged on, i.e. the current session is not a
-- public session.
--
return wwctx_api.is_logged_on;
end is_runnable;
In the register
procedure, wwctx_api.get_nls_language
is used to get the language:
-- -- Create the names to store the portlet preferences. -- wwpre_api_name.create_name( p_path => PORTLET_PATH || p_portlet_instance.reference_path, p_name => PREFNAME_STRING, p_description => 'Single custom row in ' || 'Introductory Example portlet.', p_type_name => 'NLSID', p_language => wwctx_api.get_nls_language); wwpre_api_name.create_name( p_path => PORTLET_PATH || p_portlet_instance.reference_path, p_name => PREFNAME_TITLE, p_description => 'Single custom row in ' || 'Introductory Example portlet.', p_type_name => 'NLSID', p_language => wwctx_api.get_nls_language);
Close services_portlet.pkb
. You can implement session context similarly but based upon your own functional requirements.
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
Portlet security refers to the techniques and methods used by portlets to control their access by end users. The portlets leave authentication to OracleAS Portal and trust that the portal will return them to the correct, validated user upon request.
OracleAS Portal strictly controls access to information and applications by assigning specific privileges to users and groups. Portal security services allow you to specify access control programmatically and check for the appropriate privileges at runtime. Security mechanisms used by portlets ensure that only authorized users gain access to these portlets. These security services are available through the wwsec_api
package.
Portlet security is invoked when a portlet is displayed on a portal page and when a portlet is returned in a portlet list by the get_portlet_list
function for database providers. Security services in the Portal framework have the following key features:
Portlet Display: Before a portlet is displayed on a page, the provider checks for the portlet's access privileges. The provider needs to define the is_portlet_runnable
function which calls the portlet's is_runnable
function to check access privileges.
User Group: You can find which default group a user belongs to by using the wwsec_api.get_defaultgroup
function.
Check Privileges: You can find whether a user or group has the required privileges to customize a portlet by using the wwsec_api.has_privilege
function.
Highest Privilege: You can find the highest available privilege of a user across all groups by using the wwsec_api.get_privilege_level
function.
Accessible Objects: You can find all the objects to which a user has access, given a privilege level, by using the wwsec_api.accessible_objects
function. You can find other similar associated functions in the API documentation. The API Reference can be found on Portal Center (http://portalcenter.oracle.com
) or, if you downloaded PDK-PL/SQL (pdkplsql.zip
), in ..\pdkplsql\pdk\plsql\doc
.
To implement PL/SQL portlet security, the portal requires the function is_portlet_runnable
be implemented by database providers. The actual implementation of this function is up to the application; that is, the security scheme that determines whether the current user has enough privileges to access the portlet is defined by the individual portlet implementation. The portal also requires the function get_portlet_list
for database providers to return the set of portlets that are accessible by the current user.
The portlet security mechanism may use the context and security subsystem APIs and infrastructure. The context APIs can be used to retrieve information about the current user. The security subsystem can be used to check the privileges of the current user.
Note: For more information on the context and security subsystem APIs, see the PL/SQL API Reference. The API Reference can be found on Portal Center (http://portalcenter.oracle.com ) or, if you downloaded PDK-PL/SQL (pdkplsql.zip ), in ..\pdkplsql\pdk\plsql\doc .
|
While using these APIs, keep in mind the following:
Only authorized users should be able to see your portlet in the Add Portlet dialog. This objective can be accomplished by implementing the is_portlet_runnable
function in the provider. You can also allow public access to your portlet.
If a portlet does not want to render itself to a user, it should return no HTML or return an exception that the page engine will ignore. It should not return an error message. Doing so adds unnecessarily to the error stack, which has its limits. Refer to Section 8.9, "Implementing Error Handling" for more information.
Portlet security allows the portlet to perform a runtime security check to ensure that the current user has the necessary authorization to access the portlet.
When a portlet is rendered in Show mode, it may call the is_runnable
method for database providers to determine whether the portlet should be displayed for the currently logged on user. The portal does not make the call to this function directly. It is not a requirement, however, for the portlet to make this call. The portlet should make this call in its Show mode only if it implements portlet security.
The result of the call to is_runnable
determines whether the portlet is actually displayed. If the result is true
, the portlet displays; otherwise it does not display. The portlet is rendered in Show mode when it is displayed in a portal page.
When a portlet is returned in a portlet list by a call to the provider function get_portlet_list
, the value of the p_security_level
parameter determines the purpose of the function call. When the call is made from the Portlet Repository refresh operation in order to retrieve the master list of portlets that the provider implements, the parameter p_security_level
has a value of false
. This setting indicates to the provider that no portlet security check should be made and a master list of all the portlets that the provider implements must be returned. The master list of portlets returned in this case is used to populate the Portlet Repository for that provider.
If the value of p_security_level
is true
, then it is up to the provider implementation to decide whether portlet security should be performed. If portlet security is implemented, the provider may return a different list of portlets depending on the current user.
When the Portlet Repository is displayed, OracleAS Portal calls the is_portlet_runnable
function for database providers for each of the portlets that exist in the Portlet Repository. This step is done to display only the portlets that the currently logged on user is authorized to see. One example where the Portlet Repository is displayed is in the Add Portlets dialog.
The services example, located in ..\pdkplsql\pdk\plsql\svcex
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement security. You can browse through this example as follows to see how the security functions are implemented in a portlet:
Open the services_provider.pkb
file in an editor.
Find the is_portlet_runnable
function. This function calls the security implementation through the portlet's is_runnable
function to check portlet access privileges.
function is_portlet_runnable ( p_portlet_instance in wwpro_api_provider.portlet_instance_record ) return boolean is begin if (p_portlet_instance.portlet_id = SERVICES_PORTLET_ID) then return services_portlet.is_runnable( p_provider_id => p_portlet_instance.provider_id ,p_reference_path => p_portlet_instance.reference_path ); else raise wwpro_api_provider.PORTLET_NOT_FOUND_EXCEPTION; end if; end is_portlet_runnable;
Find the get_portlet_list
procedure. get_portlet_list
allows the portlet to be included in the list of portlets implemented by this provider. get_portlet_list
first checks the security flag (p_security_level
) to find out whether security is enabled. If the flag is set to true, get_portlet_list
uses is_runnable
to check whether the portlet is accessible. The value of the p_security_level
parameter indicates whether to perform security checks before returning a portlet in the list. When a portlet repository refresh operation retrieves the master list of portlets implemented by the provider, p_security_level
has a value of false
. A value of false
means the provider does not need to perform a security check and that a master list of all of the portlets implemented by the provider must be returned. The master list of portlets returned is used to populate the portlet repository for that provider. If the value of p_security_level
is true
, then the provider implementation decides whether to perform portlet security checks. If portlet security is implemented, the provider may return a different list of portlets depending on the currently logged on user.
function get_portlet_list ... if (p_security_level = false) then l_cnt := l_cnt + 1; l_portlet_list(l_cnt) := get_portlet( p_provider_id => p_provider_id ,p_portlet_id => SERVICES_PORTLET_ID ,p_language => p_language ); else if (services_portlet.is_runnable( p_provider_id => p_provider_id ,p_reference_path => null) ) then l_cnt := l_cnt + 1; l_portlet_list(l_cnt) := get_portlet( p_provider_id => p_provider_id ,p_portlet_id => SERVICES_PORTLET_ID ,p_language => p_language ); end if; ... end get_portlet_list;
Open the services_portlet.pkb
file in an editor.
Find the show
procedure. Before displaying a portlet, the show
procedure runs a security check to determine whether the current user is allowed to see the portlet.
procedure show
...
-- Perform a security check
if (not is_runnable(
p_provider_id => p_portlet_record.provider_id
,p_reference_path => p_portlet_record.reference_path)
) then
wwerr_api_error.add(
DOMAIN, SUBDOMAIN,
'securityerr', 'services_portlet.show');
raise wwpro_api_provider.PORTLET_SECURITY_EXCEPTION; end if;
...
end show;
Find the is_runnable
function. is_runnable
is the place where you implement your security checks. In this example, the security check is quite simple. If the user is logged on (that is, not in a public session), then the function returns true
and the portlet is displayed to the user. For your own purposes, you could, of course, code much more complex security checks in the is_runnable
function.
function is_runnable ( p_provider_id in integer ,p_reference_path in varchar2 ) return boolean is begin -- -- Portlet security check. It allows the portlet to be visible -- if the user is logged on, i.e. the current session is not a -- public session. -- return wwctx_api.is_logged_on; end is_runnable;
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
OracleAS Portal provides for the caching of PL/SQL portlets. This functionality permits PL/SQL portlets to cache their Web content on the middle tier. Subsequent requests for the content may be retrieved from the cache, with or without validation from the database, decreasing the database workload.
OracleAS Portal provides three types of caching for your PL/SQL portlets:
Validation-based caching compares a key value to check whether the contents of the cache are still valid. If the key value does not change, it uses the cached content. Otherwise, it makes a round trip to the portal node to fetch the portlet content.
Expiry-based caching uses a given expiration period for the contents of the cache when rendering the portlet. This form of caching is useful for content that changes infrequently or at very regular intervals (for example, every day at the close of business).
Invalidation-based caching is the most complex form of caching but also the most flexible. The objects in OracleAS Web Cache are considered valid as long as they are not invalidated explicitly. You can also combine invalidation-based caching with either expiry-based or validation-based caching.
Because OracleAS Portal supports user customization of pages and portlets, the view of a page can vary from one user to another. OracleAS Portal's caching is designed to allow content to vary on a per-user basis, even if the URL is the same across all users. Therefore, portal objects can be cached at either the user level or the system level:
User-level caching is for a specific user. The cache entries are unique for that user and cannot be accessed by other users.
System-level caching is for all users. One cache entry is used for all users. Examples of content that might be suitable for system-level caching are page banners and news portlets.
When a database provider issues a request for a portlet, the request is sent to the portlets's show
procedure. This procedure accepts the portlet_runtime_record
as a parameter. This record structure contains fields that can be examined and set by the portlet to enable caching. The caching control fields of this record are:
caching_key
: This value is communicated in the ETAG
header for this request and returned back to the portlet provider in subsequent requests. Setting this field enables validation-based caching.
caching_period
: This field enables expiry-based caching. The value is the number of minutes the content should be held in the cache. This mode overrides validation-based caching. If a value is set for this field, then the caching_key
field is ignored.
caching_level
: This field defines whether the content is meant for general use or for a specific user. The valid values are SYSTEM
and USER
.
The general model for working with portlet caching varies according to the type of caching you choose. To a great extent, the type of caching you choose depends on the portlet content. If the portlet content changes at fairly regular intervals (for example, at the close of business every day), then it probably makes sense to use expiry-based caching. If the portlet content changes at irregular intervals, then validation- or invalidation-based caching is probably best.
If you choose validation-based caching, the general model is as follows:
Set the caching_key
field of the portlet_runtime_record
parameter. Add a check to compare the value of the current key with the value of the caching_key
field of the portlet_runtime_record
parameter. Note that the first time the show
procedure is called, the key is null and its value must be set.
Determine whether you want to use system or user level caching. Set the caching_level
field of the portlet_runtime_record
parameter accordingly.
If you choose expiry-based caching, the general model is as follows:
Set the caching_period
field of the portlet_runtime_record
parameter to the desired interval for the cache (in minutes).
Determine whether you want to use system or user level caching. Set the caching_level
field of the portlet_runtime_record
parameter accordingly.
If you choose invalidation-based caching, the general model is as follows:
Indicate to OracleAS Portal that it must generate specific headers for OracleAS Web Cache by calling wwpro_api_provider.USE_INVALIDATION
.
Determine whether you want to use system or user level caching. Set the caching_level
field of the portlet_runtime_record
parameter accordingly.
Optionally, set up validation- or expiry-based caching as well.
Add invalidation logic to your portlet where needed (for example, when the portlet is customized) and make appropriate calls to wwpro_api_invalidation
.
The Oracle Application Server Portal Configuration Guide describes how to configure caching as well as how to monitor and tune performance.
The caching example, located in ..\pdkplsql\pdk\plsql\cache
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement validation and expiry-based caching. You can browse through this example as follows to see how the validation-based functions are implemented in a portlet:
Open the validcache_portlet.pkb
file in an editor.
At the very top of the file, notice the aliases for the caching level constants.
CREATE OR REPLACE package body VALIDCACHE_PORTLET is -- Caching Constants CACHE_LEVEL_SYSTEM constant varchar2(10) := 'SYSTEM'; CACHE_LEVEL_USER constant varchar2(10) := 'USER';
Find the show
procedure. Notice first that the p_portlet_record
is an in
and out
parameter for this procedure.
procedure show
(
p_portlet_record in out wwpro_api_provider.portlet_runtime_record
)
In the procedure's security check, the caching fields of p_portlet_record
are set to null if the security check fails.
begin if (not is_runnable( p_provider_id => p_portlet_record.provider_id ,p_reference_path => p_portlet_record.reference_path) ) then -- Set it to null so that cache does not get used even if exists p_portlet_record.caching_level := null; p_portlet_record.caching_key := null; raise wwpro_api_provider.PORTLET_SECURITY_EXCEPTION; end if;
After that, the procedure calls the get_cache_key
function to get the cache key's value and assign it to a temporary value:
--
-- CACHE IS VALID?
--
l_cache_key := get_cache_key();
Find the get_cache_key
function, which is referenced from the show
procedure. This function generates a key for the portlet. You can implement your own logic here based upon your portlet's requirements.
function get_cache_key return varchar2 is l_date date;begin select sysdate into l_date from dual; return trim(substr(to_char(l_date, 'YYYY:MM:DD:HH:MI:SS'),1,18));exception when others then null;end get_cache_key;
Now return to the show
procedure. Notice how the code checks your portlet_runtime_record
parameter for the current values of the caching_key
and the caching_level
. This same piece of code can compare your caching_key
values.
if p_portlet_record.caching_level = CACHE_LEVEL_SYSTEM then if l_cache_key is not null then -- Cache exists for the user, overwrite it p_portlet_record.caching_level := CACHE_LEVEL_USER; p_portlet_record.caching_key := l_cache_key; else return; -- System cache is still valid. end if; elsif p_portlet_record.caching_level = CACHE_LEVEL_USER then if p_portlet_record.caching_key != l_cache_key then -- cache has expired. reset it p_portlet_record.caching_key := l_cache_key; else return; -- User cache is good as gold end if; elsif p_portlet_record.caching_level is null then if p_portlet_record.caching_key is not null then -- Cache does not exists for the user, create it p_portlet_record.caching_level := CACHE_LEVEL_USER; p_portlet_record.caching_key := l_cache_key; else -- Define a sytem cache. This can happen only once! -- the first time the portlet is rendered. p_portlet_record.caching_level := CACHE_LEVEL_SYSTEM; p_portlet_record.caching_key := 'MY_INITIAL_CACHE_KEY'; end if; else p_portlet_record.caching_level := CACHE_LEVEL_SYSTEM; p_portlet_record.caching_key := 'MY_INITIAL_CACHE_KEY'; end if;
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
The caching example, located in ..\pdkplsql\pdk\plsql\cache
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement expiry-based caching. You can browse through this example as follows to see how the expiry-based functions are implemented in a portlet:
Open the expirycache_portlet.pkb
file in an editor.
At the very top of the file, notice the aliases for the caching level constants.
CREATE OR REPLACE package body VALIDCACHE_PORTLET is -- Caching Constants CACHE_LEVEL_SYSTEM constant varchar2(10) := 'SYSTEM'; CACHE_LEVEL_USER constant varchar2(10) := 'USER';
Find the show
procedure. Notice first that the p_portlet_record
is an in
and out
parameter for this procedure.
procedure show
(
p_portlet_record in out wwpro_api_provider.portlet_runtime_record
)
In the procedure's security check, the caching fields of p_portlet_record
are set to null if the security check fails.
begin if (not is_runnable( p_provider_id => p_portlet_record.provider_id ,p_reference_path => p_portlet_record.reference_path) ) then -- Set it to null so that cache does not get used even if exists p_portlet_record.caching_level := null; p_portlet_record.caching_key := null; raise wwpro_api_provider.PORTLET_SECURITY_EXCEPTION; end if;
After that, the procedure sets the value of the caching period in minutes in a temporary variable. The get_cache_key
function to get the cache key's value and assign it to a temporary value:
-- Set the Caching Period to one minute
l_cache_period := 1;
Next, notice how the code checks your portlet_runtime_record
parameter for the current values of the caching_period
and sets the caching_period
accordingly. This same piece of code can compare your caching_period
values.
if p_portlet_record.caching_level = CACHE_LEVEL_SYSTEM then -- Cache does not exists for the user, create it p_portlet_record.caching_level := CACHE_LEVEL_USER; p_portlet_record.caching_period := l_cache_period; elsif p_portlet_record.caching_level = CACHE_LEVEL_USER then -- Cache exists for the user, overwrite it p_portlet_record.caching_period := l_cache_period; elsif p_portlet_record.caching_level is null then if p_portlet_record.caching_period is not null then -- Cache does not exists for the user, create it p_portlet_record.caching_level := CACHE_LEVEL_USER; p_portlet_record.caching_period := l_cache_period; else -- Define a sytem cache. This can happen only once! p_portlet_record.caching_level := CACHE_LEVEL_SYSTEM; p_portlet_record.caching_period := l_cache_period; end if; else -- p_portlet_record.caching_level value is messed up! p_portlet_record.caching_level := CACHE_LEVEL_SYSTEM; p_portlet_record.caching_period := l_cache_period; end if;
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
Suppose you have a portlet that displays a map of the world, map_portlet.pkb
and map_portlet.pks
. You would go about adding invalidation-based functions to it as follows:
In the show
procedure, you need to add a call to wwpro_api_provider.use_invalidation
. This call indicates to OracleAS Portal that the portlet content should be cached by OracleAS Web Cache. Note that we have also specified that the content be cached at the user level and that expiry-based caching be used as well (that is, an expiration interval of one minute has been set).
procedure show ... if (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW) then p_portlet_record.caching_invalidation := wwpro_api_provider.use_invalidation; p_portlet_record.caching_level := 'USER'; p_portlet_record.caching_period := 1; ...
Create a procedure in your map_portlet.pkb
file that invalidates the cache. For example:
procedure map_invalidation
(
p_provider_id in number,
p_portlet_id in number,
p_instance_id in varchar2,
p_page_url in varchar2
)
is
begin
wwpro_api_invalidation.invalidate_by_instance
(p_provider_id => p_provider_id,
p_portlet_id => p_portlet_id,
p_instance_id => p_instance_id,
p_user => wwctx_api.get_user);
owa_util.redirect_url(p_page_url);
end map_invalidation;
In the show
procedure, add a link for refreshing the portlet before the code that draws the map. For example:
/* Draw the Refresh Me link */
htp.anchor(
curl => wwctx_api.get_user||
'.map_invalidation?p_provider_id='||p_portlet_record.provider_id||
'&p_portlet_id='||p_portlet_record.portlet_id||
'&p_instance_id='||p_portlet_record.reference_path||
'&p_page_url='||utl_url.escape(
url => p_portlet_record.page_url,
escape_reserved_chars => TRUE),
ctext => wwui_api_portlet.portlet_text(
p_string =>'Refresh Me',
p_level => 1)
);
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
OracleAS Portal provides the capability for you to trap erroneous input and return meaningful error messages. It manages the internal error stack by tracking the raised exceptions and retaining information about them. OracleAS Portal also includes a set of APIs for presenting errors in a standardized way.
Error handling services are available through the wwerr_api_error
and wwerr_api_error_ui
packages. These error handling services include the following key features:
Error stack. OracleAS Portal uses an error stack to keep track of the error messages. When an error occurs, the error message is pushed onto an error stack. Whenever procedures or function calls are nested, the error stack keeps track of all the error messages. You can choose to retrieve only the top error (or most recent error) by using the wwerr_api_error.get_top
method. Alternatively, you can get all the error messages on the stack using the wwerr_api_error.get_errors
function. The stack can also be checked for the presence of any errors by calling the wwerr_api_error.is_empty
function.
Error messages. Error handling services provide a way to define meaningful error messages. To define your own error messages, you need to define their name space. The name space consists of the following:
Name is the error name.
Domain is the area of the product where the error occurred.
Subdomain is the subsystem where the error occurred.
Context is the name of the function where the error occurred.
The name space uniquely identifies your error message. If it does not do so, a wwc-0000
error message is generated.
The default domains include the portal (WWC
), application (WWV
), and page groups (WWS
). Each domain is further classified into subdomains, which define the object types. The portal domain includes the portlet, page, and document object types. The application domain includes object types such as forms, menus, reports, and charts. The page group domain includes object types such as pages, items, categories, and perspectives. If you need to define an error that does not fall within these classifications, you can define your own domain with subdomains for your errors.
Message parameters. The other language strings that you create for your errors can take substitution parameters for your messages. The p1
, p2
, p3
... parameters can be used to pass substitution parameters to the error messages. For example, for this string:
(domain='yahoo', subdomain='provider', name='generalerror', string='Error: %1')
an error can be added as follows:
wwerr_api_error.add(p_domain=>'yahoo', p_sub_domain=>'provider', p_name=>'generalerror', p_context=>'yahoo.show', p1=> sqlerrm);
Error display. The wwerr_api_error_ui
package provides a means to generate a standard user interface for displaying the errors in OracleAS Portal. The error messages can be displayed in two different ways:
Full screen user interface: These error messages are displayed in a full screen mode. You may want to display full screen errors when the system encounters fatal or show-stopper errors.
Inline user interface: These error messages are displayed within the current page itself. You may use inline errors for minor errors or warnings.
Additionally, you can choose the output format of the display (HTML, XML, or ASCII text).
In general, you set up error handling as follows:
On detecting error conditions, add the error message, with an appropriate domain and sub-domain combination, to the stack using the wwerr_api_error.add
procedure.
When necessary (for example, at the end of a routine), expose the error messages using the wwerr_api_error_ui
procedures. To display full screen messages, use the procedures show_html
, show_xml
, or show_text
depending on your preferred output type. To display inline messages, use the procedures show_inline_html
, show_inline_xml
, or show_inline_text
, depending on the output type you desire.
While implementing error handling, keep in mind the following:
While defining your own error messages, use your own error domain for these messages. Never use the WWC
, WWV
, or WWS
domain for your error messages. You will need to write a small loader script to load these into the other language tables.
Avoid unnecessary error messages. If you do not want to do anything in a function, just return null
rather than an error. For example, suppose you are coding a copy_portlet
procedure for your portlet because the provider calls it for all of its other portlets. If you do not wish the copy_portlet
procedure for this particular portlet to do anything, then simply have it return null
. If you return errors, it will unnecessarily disrupt the portlet functionality.
A maximum of ten error messages is kept on the stack. Beyond ten, messages are ignored when a call to wwerr_api_error.add
is made.
Use the API as a programmatic way of finding the problem. You can use the non-user-interface format for this purpose. For example, when you programmatically register a provider, the exception block can use get_text_stack
to get the error messages and print them. This approach helps when debugging calls to public APIs since all of them add errors to the stack for exceptions.
Remember to seed the other language strings for your error messages. For more information, refer to Section 8.11, "Writing Multilingual Portlets".
The standard user interface for error messages provides a navigation link back to the previous page. It also includes a Help icon for the specified help URL.
The services example, located in ..\pdkplsql\pdk\plsql\svcex
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement error handling. You can browse through the following example to see how the error handling functions are implemented in a portlet:
Open the services_portlet.pkb
file in an editor.
The domain and subdomain definitions for your error messages are provided with aliases in the constants part of your portlet definition.
DOMAIN constant varchar2(30) := 'provider'; SUBDOMAIN constant varchar2(32) := 'services'; PORTLET_PATH constant varchar2(256):= 'oracle.portal.pdk.servicesportlet'; PREFNAME_STRING constant varchar2(30) := 'services_string'; PREFNAME_TITLE constant varchar2(30) := 'services_title';
Find the show
procedure. This procedure performs a security check and, if an error condition arises, it calls wwerr_api_error.add
to push the securityerr
error message onto the stack.
procedure show ( p_portlet_record wwpro_api_provider.portlet_runtime_record ) is ... begin -- Perform a security check if (not is_runnable( p_provider_id => p_portlet_record.provider_id ,p_reference_path => p_portlet_record.reference_path) ) then wwerr_api_error.add( DOMAIN, SUBDOMAIN, 'securityerr', 'services_portlet.show'); raise wwpro_api_provider.PORTLET_SECURITY_EXCEPTION; end if;
The show
procedure also checks for any other kind of execution mode and generates an appropriate error message for an invalid display mode.
if (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW) then ... elsif (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW_EDIT) ... else wwerr_api_error.add(DOMAIN, SUBDOMAIN, 'invaliddispmode', 'services_portlet.show'); raise wwpro_api_provider.PORTLET_EXECUTION_EXCEPTION; end if;
Lastly, the show
procedure implements a general error message in the exception handler to catch any errors not trapped by the preceding conditions.
exception when others then wwerr_api_error.add( DOMAIN, SUBDOMAIN, 'generalerr', 'services_portlet.show'); raise wwpro_api_provider.PORTLET_EXECUTION_EXCEPTION; end show;
Error handling is also implemented in the save_prefs
and save_default_prefs
procedures. They check whether the error stack is empty and, if it is not, the portlet makes a call to wwerr_api_error.show_html
to display the error in full screen mode.
exception when INVALID_TEXT_EXCEPTION then l_information := l_user||'%'||l_time ||'%INVALID_TEXT_EXCEPTION%'||p_string; l_action := LOG_FAILED; wwlog_api.log (p_domain => DOMAIN, p_subdomain => SUBDOMAIN, p_name => l_user, p_action => l_action, p_information => l_information, p_url => l_url, p_row_count => 0, p_elapsed_time=> l_elapsed_time); wwerr_api_error.add(DOMAIN, SUBDOMAIN, 'invalid_text', 'services_portlet.save_prefs'); if (not wwerr_api_error.is_empty) then wwerr_api_error_ui.show_html; end if; end save_prefs;
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
OracleAS Portal can log events that occur during transactions with its objects. It stores these logs in the database, which makes them available through standard SQL calls and reporting tools.
You can choose the events you would like to log and organize them categorically based on user-defined domains and subdomains. For the logged events, you can view information about the event, the time the event started and stopped, the host or IP address of the remote user, the browser type, and the language.
Event logging services are available through the wwlog_api
and wwlog_api_admin
packages. These services include the following key features:
Event logs are useful for tracking specific usage of the portal. To track such information, you create a log event. Log events require a name space that consists of the following:
Name, which is the event name.
Domain, which is the area of the product where the event occurred.
Subdomain, which is the subsystem that generated the event.
The default domains include the portal (WWC
), application (WWV
), and page group (WWS
). Each domain is further classified into subdomains that define the object types. The portal domain includes the portlet, page, and document object types. The application domain includes object types such as forms, menus, reports, and charts. The page group domain includes object types such as folders, items, categories, and perspectives. Events themselves could be of types such as add, delete, customize, hide, copy, execute, and export. If you need to define an event that does not fall within these classifications, you can define your own domain with subdomains for your events.
Logs can track information in two different ways:
Interval logging calculates the elapsed time for the action performed (for example, the time taken to render a portlet).
Event logging logs the occurrence of a single step event you care about (for example, whenever a user customizes a portlet).
Log switching allows you to set a switch interval that defines how long you want to maintain your existing log records. The log information stored in the database uses two different tables. The log records are purged based on the value entered for the Activity Log Interval in the Configuration tab of Global Settings (accessible from the Services portlet in the Portal subtab of the Administer tab). When the log interval (in days) is reached, the logging switches between the two logging tables in the database (for example, A and B). Logs first go into A. When the log interval is reached the first time, the logs are written to B. When the log interval is reached again, the logs go back to A. A is emptied in preparation to store the new log records. If you set your log interval to 14 (the default setting), the logs will switch every 14 days, thus preserving for you, at any point in time, records dated between 14 and 28 days old.
In general, you can set up event logging as follows:
Add the event object, with an appropriate domain and subdomain combination, using wwlog_api_admin.add_log_event
. Adding the event ensures that lists of values and other user interface components invoked when the user is monitoring the events show this new event in their lists.
Register the log event record by using wwlog_api_admin.add_log_registry
. The log registry record represents the events you want to log in the future and provides a means to filter the events that need to be logged.
Use start_log
and stop_log
to mark the events you want to log in your code. Alternatively, for entering single step event log information, just call the log method to mark that event.
While implementing event logging, keep in mind the following:
Log only what you really care about to improve performance. You don't want to flood the system with log messages that are irrelevant to you. If events are logged in Show mode, then multiple instances of these portlets mean additional hits to the database.
Choose your domain, subdomain, and log events carefully. While using the log APIs, do not use the OracleAS Portal domains such as WWC
, WWV
, or WWS
for your log messages. Organize your domains and subdomains hierarchically ensuring that they are unique across portlets. If other portlets happen to use the same domains or subdomains, you will see those log messages interspersed with your own.
Create log events that show up in the pop-up lists of values monitoring the logs. You can simply create log registry records that filter the events that would actually be logged, either by specifying particular events or using the generic filters with wild cards (%
). Apart from creating log registry records, we recommend that you create log events for events that you want to monitor. This way the lists of values in the user interface show these records for additional functions such as monitoring.
Provide required privileges to users or user groups who need to monitor the logs. Any logs created by a user can be viewed by that user, the Portal Administrator, and any user with the Edit privilege on the ANY_LOGS
object type.
The services example, located in ..\pdkplsql\pdk\plsql\svcex
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement event logging. You can browse through this example as follows to see how the event logging functions are implemented in a portlet:
Open the services_portlet.pkb
file in an editor.
The domain and subdomain definitions for your log messages are provided with aliases in the constants part of your portlet definition.
DOMAIN constant varchar2(30) := 'provider'; SUBDOMAIN constant varchar2(32) := 'services'; PORTLET_PATH constant varchar2(256):= 'oracle.portal.pdk.servicesportlet'; PREFNAME_STRING constant varchar2(30) := 'services_string'; PREFNAME_TITLE constant varchar2(30) := 'services_title';
Find the save_prefs
procedure. This procedure provides customizable functionality where you can personalize text and the portlet title in Edit mode. save_prefs
stores these customizations in the database. While saving the changes, you should also log them. Hence, this procedure provides an ideal example of implementing the logging service. A single step event is logged using wwlog_api.log
. The first instance of wwlog_api.log
logs the event of personalizing text. The second instance logs the event of personalizing the portlet title.
procedure save_prefs ... begin ... if (l_prefs.string_id is null or to_number(l_prefs.string_id) = 0) then l_action := LOG_INSERT; ... else -- string exists in at least one language so update it l_action := LOG_UPDATE; ... end if; -- Log this transaction l_information := l_user||'%'||l_time||'%completed%'||p_string; wwlog_api.log (p_domain => DOMAIN, p_subdomain => SUBDOMAIN, p_name => l_user, p_action => l_action, p_information => l_information, p_url => l_url, p_row_count => l_row_count, p_elapsed_time=> l_elapsed_time); ... if (l_prefs.title_id is null or to_number(l_prefs.title_id) = 0) then l_action := LOG_INSERT; ... else l_action := LOG_UPDATE; ... -- Log this transaction l_information := l_user||'%'||l_time||'%completed%'||p_title; wwlog_api.log (p_domain => DOMAIN, p_subdomain => SUBDOMAIN, p_name => l_user, p_action => l_action, p_information => l_information, p_url => l_url, p_row_count => l_row_count, p_elapsed_time=> l_elapsed_time); ... end save_prefs;
The save_prefs
procedure also logs an event with wwlog_api.log
when an exception occurs.
exception when INVALID_TEXT_EXCEPTION then l_information := l_user||'%'||l_time ||'%INVALID_TEXT_EXCEPTION%'||p_string; l_action := LOG_FAILED; wwlog_api.log (p_domain => DOMAIN, p_subdomain => SUBDOMAIN, p_name => l_user, p_action => l_action, p_information => l_information, p_url => l_url, p_row_count => 0, p_elapsed_time=> l_elapsed_time); ...
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
OracleAS Portal has a robust set of APIs for interacting with OracleAS Portal multilingual storage facility. This storage facility provides a mechanism for storing and retrieving strings in different languages. These APIs abstract the native multilingual functionality and provide developers with a powerful storage mechanism for developing providers that support different language environments.
Multilingual services are available through the wwnls_api
package. These services include the following key features:
The multilingual APIs enable the provider to load several translations for the strings displayed in their portlets. Once the strings have been loaded, the provider can call the APIs to retrieve the strings from the multilingual table as needed.
Context APIs retrieve the user's language and the appropriate translation for that language. The Context APIs determine the user's language environment from the language setting in the browser. When a requested translation does not exist, the APIs return the base language translation.
For example, assume that the provider's register
procedure loads US and French translations for the portlet title. When the portlet is rendered, the provider implementation retrieves the portlet title string from the table and displays the following results:
A request for a French string causes the portlet title to appear in French.
A request for a US string causes the portlet title to appear in US English.
A request for a Chinese string causes the portlet title to appear in US English because we did not load a translation for the Chinese language.
In general, you can set up multilingual support as follows:
Load your string definitions into the database using the string equivalents for each language you intend to use. For this purpose, call the wwnls_api.add_string
or wwnls_api.set_string
with an appropriate domain, subdomain, error message name, and error text combination.
Retrieve the strings you require with wwnls_api.get_string
for the language that you desire.
To add multilingual support, you need to perform the following tasks:
Language strings can be loaded by a script that is part of the provider installation. This script calls add_string
and set_string
to create equivalent strings for different languages.
OracleAS Portal uniquely identifies language strings using a combination of domain, subdomain, and name. The domain and subdomain provide a way to categorize the strings. The domain and subdomain should be unique enough to reasonably preclude conflicts with other users of the APIs.
A domain is a particular area of the product. An example of a domain could be provider or page group.
A subdomain is a subsystem of the domain. For example, the subdomain could be the provider name (e.g., HelloProvider) or subpage name (e.g., HelloPage).
The services example, located in ..\pdkplsql\pdk\plsql\svcex
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement multilingual support. You can browse through this example as follows to see how to load strings for multilingual support:
Open the services_seed.sql
file in an editor.
Notice the add_string
call with the parameters for domain name, subdomain name, string name, language, and the actual string text. It returns the String ID for the language string. For setting equivalent strings in other languages, set_string
is called with the same parameters.
set serveroutput on size 1000000 set define off declare l_string_id integer; l_person_id integer; l_group_id integer; begin ... -- strings for portlet record fields l_string_id := wwnls_api.add_string( 'provider','services','ptldefname','us','DatabaseServicesPortlet'); wwnls_api.set_string( 'provider','services','ptldefname','d','DatenbankServicesPortlet-d'); l_string_id := wwnls_api.add_string( 'provider','services','ptldeftitle','us','Database Services Portlet'); wwnls_api.set_string( 'provider','services','ptldeftitle','d','Datenbank Services Portlet - d'); l_string_id := wwnls_api.add_string( 'provider','services','ptldefdesc','us','This is the database services portlet implemented in PL/SQL. It displays 6 show modes.'); wwnls_api.set_string( 'provider','services','ptldefdesc','d','Dies ist das Datenbank Service Portlet, erstellt in PL/SQL. Es stellt 6 Anzeigemodi dar. - d'); l_string_id := wwnls_api.add_string( 'provider','services','ptldevtmmsg','us','Web Services Portlet Timed Out.'); wwnls_api.set_string( 'provider','services','ptldevtmmsg','d','Zeitüeberschreitung aufgetreten in Web Services Portlet. -d');
The services example, located in ..\pdkplsql\pdk\plsql\svcex
in PDK-PL/SQL (pdkplsql.zip
), illustrates how you can implement multilingual support. You can browse through this example as follows to see how to retrieve strings for multilingual support:
Open the services_portlet.pkb
file in an editor.
The domain and subdomain definitions for your language strings are provided with aliases in the constants part of your portlet definition.
DOMAIN constant varchar2(30) := 'provider'; SUBDOMAIN constant varchar2(32) := 'services'; PORTLET_PATH constant varchar2(256):= 'oracle.portal.pdk.servicesportlet'; PREFNAME_STRING constant varchar2(30) := 'services_string'; PREFNAME_TITLE constant varchar2(30) := 'services_title';
Find the get_portlet_info
procedure. Notice the calls to wwnls_api.get_string
to populate the portlet title, name, and description.
function get_portlet_info ( p_provider_id in integer ,p_language in varchar2 ) return wwpro_api_provider.portlet_record is l_portlet wwpro_api_provider.portlet_record; begin l_portlet.id := services_provider.SERVICES_PORTLET_ID; l_portlet.provider_id := p_provider_id; l_portlet.language := p_language; l_portlet.title := wwnls_api.get_string( p_domain => DOMAIN ,p_sub_domain => SUBDOMAIN ,p_name => 'ptldeftitle' ,p_language => p_language ); l_portlet.description := wwnls_api.get_string( p_domain => DOMAIN ,p_sub_domain => SUBDOMAIN ,p_name => 'ptldefdesc' ,p_language => p_language ); l_portlet.name := wwnls_api.get_string( p_domain => DOMAIN ,p_sub_domain => SUBDOMAIN ,p_name => 'ptldefname' ,p_language => p_language ); ...
Browse the rest of the file to examine other usage examples of wwnls_api.get_string
, which is used in several other places in services_portlet.pkb
.
Optionally, if you want to see this portlet on a page and it is not already in the Portlet Repository, refer to the instructions in Section 8.3.2, "Implementing the Provider Package" for information on how to add it.
Once your portlet appears in the repository, you can add it to a page to test it. To add your portlet to a page, follow the instructions in Oracle Application Server Portal User's Guide.
This section explains how to go about enhancing a portlet with PDK-PL/SQL for a mobile device. Before proceeding with this section, you should familiarize yourself with the guidelines for building mobile-enabled portlets, Section 8.1.3, "Guidelines for Mobile Portlets", and the methods of building portlets with PDK-PL/SQL, Section 8.2, "Building PL/SQL Portlets with the PL/SQL Generator" and Section 8.3, "Building PL/SQL Portlets Manually".
To properly build a portlet for a mobile device, do the following:
Set the portlet record attributes to support mobile output. Requests arriving from mobile devices through the mobile gateway need to be answered with OracleAS Wireless XML using the text/vnd.oracle.mobilexml
content type in the header. A mobile-enabled portlet must specify that it can handle these types of requests and produce the mobile content accordingly.
Table 8-6 lists the portlet record attributes pertinent to mobile portlets and explains how you should specify them.
Table 8-6 Portlet Record Attributes
Attribute | Description |
---|---|
accept_content_type |
Specify a comma-delimited list of the content types that the portlet produces. If the portlet can produce both HTML and OracleAS Wireless XML, the string would be: text/html, text/vnd.oracle.mobilexml If the portlet can produce only OracleAS Wireless XML, the string would be: text/vnd.oracle.mobilexml |
mobile_only |
Indicate whether the portlet is available only to mobile pages. TRUE declares the portlet as mobile only, and it will not appear in the Add Portlets page for a standard page. FALSE declares the portlet as mobile and standard, and it will appear in the Add Portlets page for both standard and mobile pages. If the portlet only produces OracleAS Wireless XML and you set this flag to FALSE, the OracleAS Wireless XML is automatically transformed into HTML for desktop devices (such as a normal PC Web browser). This functionality allows you to develop portlets that output only OracleAS Wireless XML but can be viewed on standard pages for desktop access as well as for mobile access. |
short_title |
Enter a shorter version of the portlet title. This title is used on mobile devices because it is more likely to fit the smaller screen. If you do not set a short title, then the portlet title is used instead. |
has_show_link_mode |
Indicate whether you have implemented Link mode for the portlet. We recommend that all mobile portlets enable Link mode. The rationale for using Link mode is more fully explained when you reach step 3 below. |
If the portlet can produce both HTML and OracleAS Wireless XML, then, during execution, it must determine whether the request is for a mobile or a desktop device. If it is a desktop request, then the portlet must product HTML output. If it is a mobile request, then it must produce OracleAS Wireless XML output. You can determine the request type with the wwctx_api.get_http_accept()
. It fetches the HTTP accept header, which indicates the request type. In the portlet response, you must set the MIME header to the appropriate value in the HTTP header before the portlet content is produced. If not, then the portlet response is rejected when the resulting page is built by OracleAS Portal. If the call to get wwctx_api.get_http_accept()
returns a string starting with text/vnd.oracle.mobilexml
, then you can assume it is a mobile request. Otherwise, it is a desktop request. In the case of a mobile request, you should set the MIME header to text/vnd.oracle.mobilexml
. In the case of a desktop request, you can explicitly set the MIME header to text/html
, but it is not required that you do so because it's the default setting.
If you want to produce HTML for desktop requests and OracleAS Wireless XML for mobile requests, the show
procedure for your portlet should look similar to the following:
procedure show ( p_portlet_record in out wwpro_api_provider.portlet_runtime_record ) is begin -- -- Does the portal want us to render the portlet contents? -- if (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW) then -- -- Is this a mobile request? -- if owa_util.get_cgi_env('HTTP_ACCEPT') like wwpro_login.CONTENT_TYPE_MOBILEXML || '%' then -- -- This is a mobile request for the portlet contents -- call the mobile show contents procedure -- render_mobile_show_contents(p_portlet_record); else -- -- This is a desktop request for the portlet contents, -- call the desktop show contents procedure -- render_desktop_show_contents(p_portlet_record); end if; elsif -- check for other show modes, and handle them ... end show;
If you want to produce only OracleAS Wireless XML for all requests, the show
procedure for your portlet should look similar to the following:
procedure show ( p_portlet_record in out wwpro_api_provider.portlet_runtime_record ) is begin -- -- Does the portal want us to render the portlet contents? -- if (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW) then -- -- This is either a desktop or mobile request for the portlet -- contents call the show contents procedure to render the -- OracleAS Wireless XML output -- render_show_contents(p_portlet_record); elsif -- check for other modes ... end show;
In order to generate OracleAS Wireless XML, the render_show_contents
or render_show_mobile_contents
procedure would need to contain something similar to the following:
...
(
p_portlet_record in out wwpro_api_provider.portlet_runtime_record
)
is
begin
--
-- Set the MIME type to be Oracle9iAS Wireless XML
--
owa_util.mime_header('text/vnd.oracle.mobilexml');
--
-- Output the Oracle9iAS Wireless XML markup
--
htp.p('<SimpleText><SimpleTextItem>');
htp.p('Hello World!');
htp.p('</SimpleTextItem></SimpleText>');
...
Note: As this is a mobile request the MIME header is set totext/vnd.oracle.mobilexml . In the OracleAS Wireless XML markup, you only need to render the actual content. OracleAS Portal fits it into the complete OracleAS Wireless XML document. You do not need <SimpleResult> or <SimpleContainer> tags. These tags are rendered by OracleAS Portal along with a back link, which, by default, is assigned to one of the buttons on the mobile device.
|
If you want your portlet to allow personalization of titles for mobile rendering, you need to implement Link mode. Link mode is only called for mobile requests and it renders a link to the portlet content. This link appears in the menu of page contents when the user first navigates to the page. If a Link mode is not present for a portlet, then OracleAS Portal renders a default link mode using the short title from the portlet record. You can also use Link mode to render more than just a title. For example, in a stock portlet, you could render the stock price of a user's favorite stock. Thus, they could see the current stock price without drilling down further.
The link for Link mode rendition is provided by OracleAS Portal and passed to the portlet via the page_url
parameter on the portlet record. The portlet can extend or completely replace this behavior. If this link is rewritten as a URL that takes the user away from OracleAS Portal (it does not point to the OracleAS Portal middle tier server), then the portlet should set the show_behaviour_style
field to wwpro_api_provider.EXTERNAL_PORTLET
on the portlet record.
The following example illustrates how to code your show
procedure to include Link mode:
procedure show ( p_portlet_record in out wwpro_api_provider.portlet_runtime_record ) is begin -- -- Does the portal want us to render the portlet contents? -- if (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW) then -- -- Is this a mobile request? -- if owa_util.get_cgi_env('HTTP_ACCEPT') like wwpro_login.CONTENT_TYPE_MOBILEXML || '%' then -- -- This is a mobile request for the portlet contents, -- call the mobile show contents procedure -- render_mobile_show_contents(p_portlet_record); else -- -- This is a desktop request for the portlet contents, -- call the desktop show contents procedure -- render_desktop_show_contents(p_portlet_record); end if; -- -- Does the portal want us to render the LINK mode? -- elsif (p_portlet_record.exec_mode = wwpro_api_provider.MODE_LINK) then -- -- This is a mobile request for the portlet link mode, -- call the mobile link procedure -- render_mobile_link(p_portlet_record); elsif -- check for other show modes, and handle them ... end show;
The following example illustrates what you must implement in the render_mobile_link
procedure for Link mode. In particular, notice the setting of the MIME type, the usage of get_custom_short_title
, and the OracleAS Wireless XML output.
procedure render_mobile_link ( p_portlet_record in out wwpro_api_provider.portlet_runtime_record ) is l_short_title varchar2(80); begin -- -- Set the MIME type to be Oracle9iAS Wireless XML -- owa_util.mime_header('text/vnd.oracle.mobilexml'); -- -- Get the customized short title for this portlet instance -- using the language and reference path held in the portlet -- record -- l_short_title := get_custom_short_title(p_portlet_record); -- -- Output the OracleAS Wireless XML markup -- if l_short_title is not null then htp.p('<SimpleHref target="' || htf.escape_sc(p_portlet_record.page_url) || '">' || l_short_title || '</SimpleHref>'); else htp.p('<SimpleHref target="' || htf.escape_sc(p_portlet_record.page_url) || '">' || get_custom_title(p_portlet_record) || '</SimpleHref>'); end if; end render_mobile_link;
To further facilitate the creation of mobile-enabled portlets, you can access information in the DeviceClass
header, which is sent to all portlets, via owa_util.get_cgi_env('x-oracle-device.class')
. You can use the values of this header to determine the complexity of the OracleAS Wireless XML rendition of the portlet. For example, the PDA rendition could contain considerably richer content than the microbrowser rendition. The voice rendition could contain extra tags for voice commands and links to sound files, which play instead of the text-to-speech system.
Table 8-7 describes the values available in the header.
Table 8-7 DeviceClass Header Values
Value | Description |
---|---|
voice |
Indicates a voice-only device, such as a normal telephone calling a voice access number. |
microbrowser |
Indicates a small size display device, which supports a markup browser, such as a WAP phone. |
pdabrowser |
Indicates a medium size display device, such as a Palm or PocketPC. |
pcbrowser |
Indicates a large size display device used with desktop browsers |
In most cases, you use the OracleAS Portal user interface to register providers as described in Section 8.2.3.2, "Registering the Database Provider". In some instances, though, you may wish to register a provider programmatically rather than through the user interface. This section describes how to use wwpro_api_provider_registry.register_provider
to register your providers:
In order to register a provider programmatically with wwpro_api_provider_registry.register_provider
, the following requirements must be met:
You must first install the provider as described in Section 8.2.3.1, "Installing the Packages in the Database".
You must have the necessary privileges to execute wwpro_api_provider_registry.register_provider
. As it is a secure API, a security check determines whether the user calling it has the necessary privileges. At a minimum, you must have wwsec_api.ANYPROVIDER_PUBLISH
. If you have the privileges to execute the API, you also have sufficient privileges to set the OracleAS Portal session via wwctx_api.set_context
.
Note: If the database user of the SQL*Plus session is the OracleAS Portal schema owner, then, by default, the user is the OracleAS Portal schema owner (unlesswwctx_api.set_context is called with a different user). The schema owner already has the necessary privileges to execute wwpro_api_provider_registry.register_provider .
|
The wwpro_api_provider_registry.register_provider
API requires the provider_record
as input. When you pass the provider_record
to register_provider
, all of the fields are not required. Table 8-8 indicates which fields are required for Web and database providers. If a field is not applicable for a particular type of provider, it is shown as NA.
Table 8-8 Required provider_record
Fields
Field | Required for database providers | Required for Web providers | Comments |
---|---|---|---|
name |
Yes |
Yes |
None |
implementation_style |
Yes |
Yes |
This field is always the following for PL/SQL portlets: wwpro_api_provider_registry. DATABASE_IMPL; |
implementation_owner |
NA |
Yes |
This field is the schema where the provider/portlet is located. |
implementation_name |
NA |
Yes |
When registering a database provider the implementation package of the provider must be valid for the registration to be successful. |
login_frequency |
Yes |
Yes |
This field specifies how often to grab the session information. |
http_app_type |
Yes |
NA |
For external application Web providers: wwpro_api_provider_registry.HTTP_APP_TYPE_EXTERNAL For regular Web providers: wwpro_api_provider_registry.HTTP_APP_TYPE_PORTAL |
http_url |
Yes |
NA |
None |
require_url |
Yes |
NA |
None |
encryption_key |
If provider_key is not null,yes. If provider_key is null, no. |
If provider_key is not null,yes. If provider_key is null, no. |
None |
The following sample SQL script illustrates the usage of wwpro_api_provider_registry.register_provider
.
set serveroutput on size 1000000
set define on
declare
l_prov_rec wwpro_api_provider_registry.provider_record;
l_prov_id integer;
begin
l_prov_rec.name := 'CacheProvider';
l_prov_rec.display_name := 'Cache Provider';
l_prov_rec.timeout := 10;
l_prov_rec.timeout_msg := 'The provider timed out';
l_prov_rec.implementation_style := wwpro_api_provider_registry.DATABASE_IMPL;
l_prov_rec.implementation_owner := '&&2';
l_prov_rec.implementation_name := 'cache_provider';
l_prov_rec.language := wwctx_api.get_nls_language;
l_prov_rec.enable_distribution := true;
l_prov_rec.login_frequency := wwpro_api_provider_registry.LOGIN_
FREQUENCY_NEVER;
l_prov_rec.created_on := sysdate;
l_prov_rec.created_by := '&&1';
l_prov_rec.last_updated_on := sysdate;
l_prov_rec.last_updated_by := '&&1';
l_prov_id := wwpro_api_provider_registry.register_provider(l_prov_rec);
commit;
dbms_output.put_line('Cache Provider successfully registered');
exception
when others then
dbms_output.put_line('ERROR: Could not register Cache Provider');
dbms_output.put_line('SQLERRM: ' || SQLERRM);
rollback;
end;
/
Note: After you have registered your provider, you may also refresh the Portlet Repository programmatically usingwwpro_api_provider_registry.refresh_portlet_repository or through the OracleAS Portal user interface.
|