Oracle9iAS Portal Developer Kit (PDK)
Implementing Validation-based Caching in PL/SQL Portlets

Last Update: Aug 04, 2003
Status: Production
Version: Any PDK Release

Introduction

Oracle9iAS Portal provides functionality for caching of PL/SQL portlets.  This functionality permits PL/SQL portlets to have their Web content cached by 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. 

Oracle9iAS Portal provides two ways to enable caching in your PL/SQL portlets.  You can either choose to use Validation based caching or Expiry based caching.  The first method compares a key value to check whether the cache is still valid.  If the key value doesn't change, it uses the cached content otherwise it makes a round trip to the Portal node to fetch the portlet content.  The second method uses a given expiration period to use the cache for rendering the portlet.

This article describes how Validation based caching can be implemented in your portlets.  It provides a guideline for adding caching to your portlet functionality.

Assumptions

How to use Caching

Before you can start using Caching, it must be enabled in your Portal installation. The section on 'How to Enable Caching' in the article  A Primer on Caching explains how this setup can be done.

The general model for using Caching can be described as follows:

  1. Choose between using Validation based caching or Expiration based caching for your portlets. For this purpose review your portlet functionality.  Check to see whether it makes more sense to use the cache for a given period of time always, which might be the case if you know that the portlet usually doesn't change for a given period. Otherwise choose to use Validation based caching when you can generate a key that can be used to check whether the content is now changed.
  2. If you plan to use Expiry based caching, you can set the caching_period field of the portlet_runtime_record parameter that the show procedure of the portlet receives. 
  3. If you plan to use Validation based caching, you can use the caching_key field of the portlet_runtime_record parameter that the show procedure of the portlet receives.  Add a check to compare the value of the current caching key with the value of the caching_key field of the portlet_runtime_record parameter. The first time, this show method is called, the key will be null and its value will have to be set.
  4. Check to see whether you want to use System level caching or User level caching. Set your caching_level field of the portlet_runtime_record parameter accordingly.

Implementing Validation-based Caching

This section describes how the Validation based caching is incorporated in a PL/SQL portlet.
  1. From the downloaded Caching Example, review the validcache_portlet.pkb file which is the package body for this portlet. An excerpt is provided below.
  2. The Caching Level constants are provided aliases at the start. This code segment is highlighted below. 
  3. Scroll the file to the section that contains the procedure get_portlet_info. Observe that the portlet sets the values for this particular portlet, like its name, title, description etc. You would do this any time you create a new portlet. The article 'How to Build a PL/SQL Portlet' describes in detail, what you need to do when you use existing portlet source code to modify it to create your own portlet.  
     

    CREATE OR REPLACE

    package body VALIDCACHE_PORTLET

    is

           --  Caching Constants  --

        CACHE_LEVEL_SYSTEM constant varchar2(10) := 'SYSTEM';

        CACHE_LEVEL_USER constant varchar2(10) := 'USER';

     

        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 := cache_provider.PORTLET_VALIDCACHE;
            l_portlet.provider_id := p_provider_id;

            l_portlet.title := 'Validation Based Caching';

            l_portlet.name := 'Validation_Cache';

            l_portlet_descriptin := 'This portlet illustrates validation based caching';

            ...

     end VALIDCACHE_PORTLET;

    /

  4. Scroll to the show procedure. Here the p_portlet_record, the IN parameter to the procedure has been changed to an IN OUT parameter, since here we also modify the portlet_runtime_record field values.  A corresponding change needs to be made in the package specification for the procedure definition.
  5. Additionally the portlet checks for security access to portlet, and if it is not available, it resets the caching fields to null values.
  6. Now call your own function to get your cache key and set a temporary variable with this value.
     

    CREATE OR REPLACE

    package body VALIDCACHE_PORTLET

    is

       ...

        procedure show

        (

            p_portlet_record    in out     wwpro_api_provider.portlet_runtime_record

        )

        is

            l_portlet      wwpro_api_provider.portlet_record;  

        begin

            -- Perform the Security Check

            if not is_runnable(p_provider_id, null)

            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.PROVIDER_SECURITY_EXCEPTION;

            end if;

            --

            -- CHECK CACHE IS VALID

            --

            l_cache_key := get_cache_key();

            ...

        end show;

    end VALIDCACHE_PORTLET;

    /

  7. You can use the get_cache_key function to generate a key based on your own portlet functionality.  Given below is our way of generating a key for our purposes. This is just an example of one way you can generate your key.
     

    CREATE OR REPLACE

    package body VALIDCACHE_PORTLET

    is

       ...

        -- Key is substring of time, upto the first digit of the seconds

        -- which is effectively the YYYY:MM:DD:HH:MI:S string.

        -- This ensures that the portlet is cached for 10 seconds at least,

        -- till the new key value has a changed value for the first digit

        -- of the seconds field.

        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;

         ...

    end VALIDCACHE_PORTLET;

    /



  8. After getting your cache key and setting a temporary value, check your portlet_runtime_record parameter for its current values of the caching_key as well as the caching_level. You can use this same piece of code for comparing your caching_key values.

    CREATE OR REPLACE

    package body VALIDCACHE_PORTLET

    is

        ...

        procedure show

        (

             p_portlet_record    in out     wwpro_api_provider.portlet_runtime_record

        )

        ...

            l_cache_key := get_cache_key();

            -- SYSTEM CACHE is nothing but an empty portlet. The user has done

            -- nothing yet!

            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 still valid.

                end if;

            elsif p_portlet_record.caching_level is null then

                if p_portlet_record.caching_key is not null then

                    -- Cache does not exist for the user, create it

                    p_portlet_record.caching_level := CACHE_LEVEL_USER;

                    p_portlet_record.caching_key := l_cache_key;

                else

                    -- Define a system 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 value is messed up!

                p_portlet_record.caching_level := CACHE_LEVEL_SYSTEM;

                p_portlet_record.caching_key := 'MY_INITIAL_CACHE_KEY';

            end if;

            if (p_portlet_record.exec_mode = wwpro_api_provider.MODE_SHOW) then    

            ...

        end show;

        ...

     end VALIDCACHE_PORTLET;

    /

     
  9. This way by setting your cache key and comparing it before rendering the portlet, you can enable Validation based Caching for your portlets.

View Portlet functionality

  1. Create a page and add the Validation based Caching portlet to your page.  Take note to view the change in the time displayed every time you reload the page.  You will find that the if you reload within the 10 seconds where the first digit of the seconds field has not yet changed, the portlet still displays the old time. Only if you refresh the page after the key changes, the time displayed is changed.
  2. Additionally add the Expiry based Caching portlet to the same page and compare how the caching on the two portlets works differently.
Revision History:
Revision No Last Update
1.0

Jan 25, 2000


Oracle Corporation
World Headquarters
500 Oracle Parkway
Redwood Shores, CA 94065, USA
http://www.oracle.com/
Worldwide Inquiries:
1-800-ORACLE1
Fax 650.506.7200
Copyright and Corporate Info