Skip Headers
Oracle® Application Server Portal Developer's Guide
10g Release 2 (10.1.4)
B14135-03
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
 
Next
Next
 

8 Creating PL/SQL Portlets


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:

More on OTN

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

8.1 Guidelines for Creating PL/SQL Portlets

When you write your portlets in PL/SQL, you should follow the best practices described in this section:

8.1.1 Portlet Show Modes

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 fully in Chapter 6, "Creating Java Portlets":

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.

Table 8-1 Show Mode Constants in wwpro_api_provider

Show mode Constant

Shared Screen

MODE_SHOW

Edit

MODE_SHOW_EDIT

Edit Defaults

MODE_SHOW_EDIT_DEFAULTS

Preview

MODE_SHOW_PREVIEW

Full Screen

MODE_SHOW_DETAILS

Help

MODE_SHOW_HELP

About

MODE_SHOW_ABOUT

Link

MODE_SHOW_LINK

8.1.2 Recommended Portlet Procedures and Functions

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


8.1.3 Guidelines for Mobile Portlets

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

8.2 Building PL/SQL Portlets with the PL/SQL Generator

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:

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

  2. Run the PL/SQL Generator using the XML file as input, as described in Section 8.2.2, "Running the PL/SQL Generator".

  3. Publish the generated PL/SQL portlet, which includes the following steps:

8.2.1 Creating the Input XML File

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 name tag for the portlet package name.

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 language.country.

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 personalize the portlet's properties.

Boolean

showEditDefault

Indicates whether the portlet supports the Edit Defaults mode, which enables page administrators to personalize 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, en).

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 wwpro_api_provider.API_VERSION_1.

string

callIsRunnable

Indicates whether OracleAS Portal must check for the user's credentials before displaying the portlet. The default value is true.

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 id, portlet id, and language) returned by a provider does not change, then the provider should set the value for call_get_portlet to false. This tells the portal to use the PMR instead of making calls to the provider's get_portlet and get_portlet_list functions. An example of when a provider would not want the portal to use portlet metadata from the PMR is when the value of the portlet records is different for logged on users. The default value is true.

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 false, the portlet uses its short or full title to display a link label that references the portlet content in a mobile device. Otherwise, a personalized link can be generated in the portlet code. The default value is false.

Boolean

mobileOnly

Indicates whether the portlet is available only to mobile devices. The default value is false.

Boolean

preferenceStorePath

Specifies the base preference store path where the provider has stored the portlet personalization information. This path is used when exporting portlets.

string

createdOn

Defines the portlet creation date. The default value is sysdate.

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

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 true, then OracleAS Portal passes all parameters in the URL to the portlet. If the tag value is false, then the portlet receives only those parameters that are intended for the portlet. The default value is true.

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

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>

8.2.2 Running the PL/SQL Generator

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:

  1. If you have not already done so, install the PL/SQL Generator according to the instructions that came with the download.

  2. From your browser, go to the URL for the PL/SQL Generator. It should look something like the page shown in Figure 8-1.

    Figure 8-1 PL/SQL Generator Page

    Description of Figure 8-1 follows
    Description of "Figure 8-1 PL/SQL Generator Page"

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

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

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

  6. In the Save dialog box, change the file extension to .sql and revise the file name as you wish.

  7. Save the file.

8.2.3 Publishing the Generated PL/SQL Portlet

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:

8.2.3.1 Installing the Packages in the Database

To install the generated provider and portlet packages into the database where you installed OracleAS Portal, perform the following steps:

  1. Start a SQL*Plus session and log in to the PORTAL schema.

  2. 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;
    
    
  3. 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
    
    
  4. Log in to the provider schema and run the generated SQL file. It will create the provider and portlet packages in the database.

8.2.3.2 Registering the Database Provider

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:

  1. Log in to OracleAS Portal as an administrator.

  2. From the Portal Builder, click the Administer tab then the Portlets tab.

  3. In the Remote Providers portlet, click Register a Provider.

  4. Fill in the Name, Display Name, Timeout, and Timeout Message as desired.

  5. From the Implementation Style, list choose Database.

  6. Click Next and complete the remainder of the wizard.

  7. When you complete the wizard, click Finish.

  8. From the Portlet Repository portlet, click Display Portlet Repository.

  9. Browse the repository and find the provider that you just registered. Typically, new providers appear in the Portlet Staging Area of the repository.

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

8.2.3.3 Adding Your Portlet to a Page

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.

8.3 Building PL/SQL Portlets Manually

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:

The general model for building PL/SQL portlets manually is as follows:

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

  2. 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".

  3. Add your portlet to a page, as described in Section 8.3.3, "Adding Your Portlet to a Page".

8.3.1 Implementing the Portlet Package

To modify helloworld_portlet.pks and helloworld_portlet.pkb to create your own portlet package, perform the following steps:

  1. Make copies of the package specification, helloworld_portlet.pks, and body, helloworld_portlet.pkb.

  2. Rename the copies to my_first_portlet.pks and my_first_portlet.pkb, respectively.

  3. 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;
    
    
  4. 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.

  5. 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';
        ...
    
    
  6. 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;
    ...
    
    
  7. Save my_first_portlet.pkb.

8.3.2 Implementing the Provider Package

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:

  1. Make copies of the package specification, starter_provider.pks, and body, starter_provider.pkb.

  2. 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 the hello world and snoop portlets from starter_provider2.pks and starter_provider2.pkb before performing the steps that follow.

  3. Open starter_provider2.pks in an editor.

  4. 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;
    
    
  5. Save starter_provider2.pks.

  6. Open starter_provider2.pkb in an editor.

  7. 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;
    
    
  8. 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;
    
    
  9. 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;
    
    
  10. 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)
    

  11. Save and close starter_provider2.pkb.

  12. Log in to OracleAS Portal as you normally would.

  13. From the Portal Builder, click the Administer tab then the Portlets tab.

  14. From the Portlet Repository portlet, click Display Portlet Repository.

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

  16. From a command line prompt, start SQL*Plus and connect as the owner of the starter provider schema.

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

  18. If any compilation errors occur, fix and recompile them until all of the packages compile successfully.

  19. From the Portlet Repository portlet, click Display Portlet Repository.

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

8.3.3 Adding Your Portlet to a Page

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.

8.4 Implementing Information Storage

OracleAS Portal provides APIs for storing and retrieving individual portlet preferences, and storing and manipulating temporary data for the current session:

8.4.1 Implementing a Preference Store

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, Personalize 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.

8.4.1.1 Using a Preference Store

In general, you can set up preference storage as follows:

  1. Create the preference path with wwpre_api_name.create_path.

  2. Create the preference with wwpre_api_name.create_name.

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

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

8.4.1.2 Creating and Accessing a Preference Store

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 Personalize, 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:

  1. 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';
    
    
  2. 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;
    
    
  3. 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;
    
    
  4. 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 here 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;
    
    
  5. 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 personalizations 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;
    
    
  6. 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 personalizable 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 
        --  personalization 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;
    
    
  7. Review the following procedures and functions, which are related to the preference storage implementation in this example:

    • get_user_preference retrieves the user personalized 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 personalization changes.

    • entered_text_is_valid checks to see if the text entered in the personalizable text fields is valid.

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

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

8.4.2 Implementing a Session Store

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 using Clear. After clearing the counter, the counter starts again from zero.

Creating and Accessing a Session Store

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:

  1. 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';
    
    
  2. 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;
    
    
  3. 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;
    
    
  4. 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.

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

8.5 Using Parameters

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:


Caution:

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.


For more information about parameters, refer to Section 2.12, "Public Portlet Parameters Support" and Section 2.13, "Private Portlet Parameter Support".

8.5.1 Passing Private Parameters

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 the following 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.

8.5.2 Passing Page Parameters and Mapping Public Portlet 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 personalized by users (for example, department 30) and applied to all three portlets.

The general model for passing public and page parameters is as follows:

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

  2. 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;
    
    
  3. 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;
    
    
  4. 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 personalize 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.

8.5.3 Retrieving Parameter Values

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;
    

8.6 Accessing Context Information

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.

8.6.1 Using Context Information

The general model for working with the session context is as follows:

  1. Identify the piece of information you require for your functionality.

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

wwctx_api.get_user

Login status of user

wwctx_api.is_logged_on

Login time

wwctx_api.get_login_time

Language

wwctx_api.get_nls_language

Current session id

wwctx_api.get_sessionid

IP address of user client

wwctx_api.get_ip_address

User schema

wwctx_api.get_db_user

OracleAS Portal schema

wwctx_api.get_product_schema

OracleAS Portal version

wwctx_api.get_product_version


8.6.2 Using wwctx_api to Obtain Context Information

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:

  1. Open the services_portlet.pkb file in an editor.

  2. Find the get_portlet_info function.

  3. 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;
    ...
    
    
  4. 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.

  5. 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, that is, the current session is not a
        -- public session.
        --
        return wwctx_api.is_logged_on;
    end is_runnable;
    
    
  6. 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);
    
    
  7. Close services_portlet.pkb. You can implement session context similarly but based upon your own functional requirements.

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

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

8.7 Implementing Portlet Security

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:

8.7.1 Using Security

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.

Guidelines for Using the Security APIs

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

8.7.2 Coding Security

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:

  1. Open the services_provider.pkb file in an editor.

  2. 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;
    
    
  3. 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;
    
    
  4. Open the services_portlet.pkb file in an editor.

  5. 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;
    
    
  6. 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, that is, the current session is not a
        -- public session.
        --
        return wwctx_api.is_logged_on;
    end is_runnable;
    
    
  7. 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.

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

8.8 Improving Portlet Performance with Caching

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 the following three types of caching for your PL/SQL portlets:

Because OracleAS Portal supports user personalization 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 for each user, 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, as follows:

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 as follows:

8.8.1 Using Caching

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.

8.8.1.1 Validation-Based Caching

If you choose validation-based caching, the general model is as follows:

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

  2. Determine whether you want to use system or user level caching. Set the caching_level field of the portlet_runtime_record parameter accordingly.

8.8.1.2 Expiry-Based Caching

If you choose expiry-based caching, the general model is as follows:

  1. Set the caching_period field of the portlet_runtime_record parameter to the desired interval for the cache (in minutes).

  2. Determine whether you want to use system or user level caching. Set the caching_level field of the portlet_runtime_record parameter accordingly.

8.8.1.3 Invalidation-Based Caching

If you choose invalidation-based caching, the general model is as follows:

  1. Indicate to OracleAS Portal that it must generate specific headers for OracleAS Web Cache by calling wwpro_api_provider.USE_INVALIDATION.

  2. Determine whether you want to use system or user level caching. Set the caching_level field of the portlet_runtime_record parameter accordingly.

  3. Optionally, set up validation- or expiry-based caching as well.

  4. Add invalidation logic to your portlet where needed (for example, when the portlet is personalized) and make appropriate calls to wwpro_api_invalidation.

8.8.2 Configuring and Monitoring the Cache

The Oracle Application Server Portal Configuration Guide describes how to configure caching as well as how to monitor and tune performance.

8.8.3 Implementing Validation-Based Caching

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:

  1. Open the validcache_portlet.pkb file in an editor.

  2. 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';
    
    
  3. 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
    )
    
    
  4. 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;
    
    
  5. 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();
    
    
  6. 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;
    
    
  7. 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;
    
    
  8. 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.

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

8.8.4 Implementing Expiry-Based Caching

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:

  1. Open the expirycache_portlet.pkb file in an editor.

  2. 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';
    
    
  3. 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
    )
    
    
  4. 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;
    
    
  5. After that, the procedure sets the value of the caching period in minutes in a temporary variable:

       -- Set the Caching Period to one minute 
       l_cache_period := 1;
    
    
  6. 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;
    
    
  7. 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.

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

8.8.5 Implementing Invalidation-Based Caching

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:

  1. 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;
    ...
    
    
  2. 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;
    
    
  3. 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)
    );
    
    
  4. 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.

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

8.9 Implementing Error Handling

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:

8.9.1 Using Error Handling

In general, you set up error handling as follows:

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

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

Guidelines for Error Handling

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.

8.9.2 Adding Error Handling

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:

  1. Open the services_portlet.pkb file in an editor.

  2. 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';
    
    
  3. 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;
    
    
  4. 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;
    
    
  5. 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;
    
    
  6. 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;
    
    
  7. 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.

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

8.10 Implementing Event Logging

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:

8.10.1 Using Event Logging

In general, you can set up event logging as follows:

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

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

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

Guidelines for Event Logging

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.

8.10.2 Adding Event Logging

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:

  1. 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';
    
    
  2. Find the save_prefs procedure. This procedure provides personalizable functionality where you can personalize text and the portlet title in Edit mode. save_prefs stores these personalizations 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;
    
    
  3. 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);
    ...
    
    
  4. 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.

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

8.11 Writing Multilingual Portlets

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:

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:

8.11.1 Using Multilingual Support

In general, you can set up multilingual support as follows:

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

  2. Retrieve the strings you require with wwnls_api.get_string for the language that you desire.

8.11.2 Adding Multilingual Support

To add multilingual support, you need to perform the following tasks:

8.11.2.1 Loading Language Strings

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 (for example, HelloProvider) or subpage name (for example, 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:

  1. Open the services_seed.sql file in an editor.

  2. 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');
    

8.11.2.2 Retrieving Language Strings

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:

  1. Open the services_portlet.pkb file in an editor.

  2. 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';
    
    
  3. Find the get_portlet_info function. 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
                );
    ...
    
    
  4. 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.

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

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

8.12 Enhancing Portlets for Mobile Devices

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:

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


  2. 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 to text/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.

  3. 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 through 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 personalized 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; 
    

Accessing the DeviceClass Header

To further facilitate the creation of mobile-enabled portlets, you can access information in the DeviceClass header, which is sent to all portlets through 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


8.13 Registering Providers Programmatically

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:

8.13.1 Registration Prerequisites

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 through 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 (unless wwctx_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.

8.13.2 Provider Record Input

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


8.13.3 Registration Example

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 using wwpro_api_provider_registry.refresh_portlet_repository or through the OracleAS Portal user interface.