Friday, March 26, 2010

Failsafe HTML Content Layout for Oracle Portal

One well known feature of Oracle Portal is the ability to create HTML Content Layout, and apply these layouts to page regions. The online documentation has for instance an example on how to check if a link should open in the current window or in a new window:

if '#item.displayoption#' = 'link' then
htp.p('<a href="#item.url#">View item in current window</a>');
elsif '#item.displayoption#' = 'linktonewwindow' then
htp.p('<a href="#item.url#" target="_blank">View item in new window</a>');
htp.p('Display item directly in page');;
end if;

On the surface that looks very good, but what if you got regions that shall support both links and text items ? The problem of referring to #item.content# (or the #item.content.value#) multiple times, is that the generated code allocates space for the length of #item.content# each time it is referred. For instance, if your region contains both links and a 15k text item, and you refer to #item.content# three times, the space used will be 45k + the size of the links. This is far above the PL/SQL 32k limit, and your portal page will not render properly, and you will get the following error thrown in the browser:

Internal Error (WWC-00006)
Execution of the PL/SQL-block failed: , (WWC-40015)
Preference path not found: oracle.portal.wsrp.<YOUR_PORTLET_1_NAME> (WWC-51000)
Preference path not found: oracle.portal.wsrp.<YOUR_PORTLET_2_NAME> (WWC-51000)
Preference path not found: oracle.portal.wsrp.<YOUR_PORTLET_3_NAME> (WWC-51000)
Preference path not found: oracle.portal.wsrp.<YOUR_PORTLET_4_NAME> (WWC-51000)
and so on, for each of the portlets mounted on your page.

The solution is to use more PL/SQL code, and less HTML Content Layout Substitution tags:

p_target VARCHAR2(6);
p_content VARCHAR2(32000);
p_content := SUBSTR('#item.content.value#',1,32000);
if '#item.displayoption#' IN ('link','linktonewwindow') then
if '#item.displayoption#' = 'link' then
p_target := '_self';
elsif '#item.displayoption#' = 'linktonewwindow' then
p_target := '_blank';
end if;
htp.p('<a href="'||p_content||'" target="'||p_target||'">#ITEM.TITLE.VALUE#</a>');
end if;

This way, the potentially huge #item.content.value# is referred to only once, and it's also made sure it never exceeds 32k. (You cannot create text items larger than 32k through the Rich Text Editor or through the Portal PL/SQL API. But since text items are saved in CLOBs, they could potentially have been populated through a custom API and be larger than 32k).

No comments:

Post a Comment