Oracle® Fusion Middleware Developer's Guide for Oracle WebCenter 11g Release 1 (11.1.1) Part Number E10148-02 |
|
|
View PDF |
This chapter explains how you can enhance the Java portlets you created with the Oracle JDeveloper Portlet Wizard.
This chapter includes the following sections:
Before You Begin
Before you begin looking through this chapter ensure that:
You are familiar with portlet terminology such as portlet modes. For more information, see Chapter 27, "Overview of Portlets" and Section 29.2.5, "What You May Need to Know When Creating Java Portlets.".
You have access to WebLogic Server (WLS) managed servlet that is configured for use as a portlet container, such as the WLS_Portlet server.
You are familiar with JDeveloper and know how to build and deploy Java components using it. You can download JDeveloper from OTN:
When you have built your initial portlet in the Portlet Wizard as described in Section 29.2.1, "How to Create a JSR 168 Java Portlet," you will want to enhance it. Because JSR 168 portlets adhere to the Java standards, you can find substantial information about enhancing them from many different sources, such as third-party books and Web pages. Some of the more important enhancements that you might want to perform are as follows:
Adding personalization. For more information, see Section 30.1.1, "How to Add Personalization."
Adding navigational parameters. For more information, see Section 30.1.2, "How to Implement Navigational Parameters (WSRP 2.0)."
Exporting and importing of customizations. For more information, see Section 30.1.3, "How to Implement Export/Import of Customizations (WSRP 2.0)."
Rewriting URLs for a resource proxy. For more information, see Section 30.1.4, "How to Implement Rewritten URLs for Resource Proxy."
Implementing stateless resource proxying. For more information, see Section 30.1.5, "How to Implement Stateless Resource Proxying."
Disabling caching. For more information, see Section 30.1.6, "How to Disable Java Object Cache for Preference Store Access."
Adding security. For more information, see Section 30.1.7, "How to Implement Security for JSR 168 Portlets."
As a quick example of adding personalization, you can enhance the portlet you created in Section 29.2.1, "How to Create a JSR 168 Java Portlet" with some code that enables a user in Edit or Edit Defaults mode to paste HTML into a field for the portlet to render. You can then easily redeploy the portlet and then test it.
Before You Begin
The steps that follow assume that you have:
Built a portlet using the Create JSR 168 Java Portlet wizard in JDeveloper. For more information, see Section 29.2.1, "How to Create a JSR 168 Java Portlet."
Added a preference called portletContent
in the Customization Preferences page of the wizard.
Registered the producer with a custom WebCenter application and added the portlet to a page. For more information, see Section 9.2.1, "How to Register a WSRP Portlet Producer" and Section 9.3.1, "How to Add a Portlet to a Page."
Enabled Oracle ADF security for the application. For more information, see Section 24.3, "Setting Up Security for Your Application."
The user must be logged in to the application as an authenticated user to access the personalization feature.
To implement simple personalization:
Start JDeveloper.
In the Application Navigator, open the application that contains the portlet.
Expand the project that contains the portlet.
Right-click view.jsp
and choose Open.
In the visual editor, click the Source tab and add the code indicated in bold in Example 30-1 to display the portletContent
customization preference:
Example 30-1 view.jsp Sample Code
<%@ page contentType="text/html" import="javax.portlet.*,java.util.*,Portlets.Portlet1, Portlets.resource.Portlet1Bundle"%> <%@ taglib uri="http://java.sun.com/portlet" prefix="portlet"%> <portlet:defineObjects/> <% String[] str = {"Portlet Content"}; PortletPreferences prefs = renderRequest.getPreferences(); str = prefs.getValues("portletContent",str); for (int i=0; i<str.length; i++) { %><%=(i<str.length-1)?str[i]+", ":str[i]%><%}%>
In the Application Navigator, right-click edit.jsp
and choose Open.
Notice that the JSP consists of a form field, a form input field, and two form button fields.
In the visual editor, click the Source tab and add the code indicated in bold in Example 30-2 to implement a form field for users to enter a value for the portletContent
customization preference:
Example 30-2 edit.jsp Sample Code
<%@ page contentType = "text/html; charset=windows-1252" pageEncoding = "windows-1252" import = "javax.portlet.*, java.util.*, Portletenhance.Portletenhance, Portletenhance.resource.PortletenhanceBundle"%> @ <%@ taglib uri = "http://java.sun.com/portlet" prefix="portlet"%> <portlet:defineObjects/> <% PortletPreferences prefs = renderRequest.getPreferences(); ResourceBundle res = portletConfig.getResourceBundle(renderRequest.getLocale()); %> <form action="<portlet:actionURL/>" method="POST"> <table border="0"> <tr> <td width="20%"> <p class="portlet-form-field" align="right"> <%= res.getString(PortletenhanceBundle.PORTLETCONTENT) %> </p> </td> <td width="80%"> <input class="portlet-form-input-field" type="TEXT" name="<%= Portletenhance.PORTLETCONTENT_KEY %>" value="<%= Portletenhance.buildValue(prefs, Portletenhance.PORTLETCONTENT_KEY) %>" size="20"> </td> </tr> <tr> <td width="20%"> <p class="portlet-form-field" align="right"> <%= res.getString(PortletenhanceBundle.PORTLETTITLE) %> </p> </td> <td width="80%"> <input class="portlet-form-input-field" type="TEXT" name="<%= Portletenhance.PORTLETTITLE_KEY %>" value="<%= prefs.getValue(Portletenhance.PORTLETTITLE_KEY, res.getString("javax.portlet.title")) %>" size="20"> </td> </tr> <% String[] str = {"Portlet Content"}; str = prefs.getValues("portletContent",str); %> <tr><td width="20%"> <p class="portlet-form-field" align="right"> Content </p> </td><td width="80%"> <textarea rows="10" cols="60" class="portlet-form-input-field" name="portletContent"><% for (int i=0; i<str.length; i++) {%><%= (i<str.length-1) ? str[i]+", " : str[i] %><%}%> </textarea> </td></tr> <tr> <td colspan="2" align="center"> <input class="portlet-form-button" type="submit" name="<%=Portletenhance.OK_ACTION%>" value="<%=res.getString(PortletenhanceBundle.OK_LABEL)%>"> <input class="portlet-form-button" type="submit" name="<%=Portletenhance.APPLY_ACTION%>" value="<%=res.getString(PortletenhanceBundle.APPLY_LABEL)%>"> </td> </tr> </table> </form>
In the Application Navigator, right-click portletName
.java
and choose Open.
In the visual editor, click the Source tab and add the following two lines of code (indicated in bold) to the processAction
method:
// Save the preferences. PortletPreferences prefs = request.getPreferences(); String param = request.getParameter(PORTLETTITLE_KEY); prefs.setValues(PORTLETTITLE_KEY, buildValueArray(param)); String contentParam = request.getParameter("portletContent"); if (contentParam != null) { prefs.setValues("portletContent", buildValueArray(contentParam)); } prefs.store();
Redeploy the portlet.
Notice that JDeveloper automatically saves and compiles the code before deploying the portlet. For a reminder of how to perform this step, see Chapter 33, "Testing and Deploying Your Portlets."
Reload the page that contains the portlet and you can see that the portlet now displays the text Portlet Content, which was one of the changes you made.
Click the Personalize link to see the form field that you added. Enter some text in this field and close the dialog. You can see the new text displayed in the portlet.
While JSR 168 and WSRP 1.0 do not address public portlet parameters, WSRP 2.0 introduces navigational parameters to enable inter-portlet communication. With the release of the new portlet Application Programming Interface (API) standard, JSR 286, the need for vendor-specific API extensions will not be necessary any more. Until then, you are required to use the Oracle-specific portlet container and API extensions.
Using the Create JSR 168 Java Portlet wizard, you can easily create a portlet with navigational parameters. When you register the producer and drop the portlet on a page, the portlet's parameters are automatically linked to page variables.
To add public parameters to JSR 168 portlets using WSRP 2.0 navigational parameters:
Start JDeveloper.
In the Application Navigator, open the application under which you want to create the portlet.
Right-click the project under which you want to create the portlet and choose New.
In the New Gallery, expand Web Tier, select Portlets and then Standards-based Java Portlet (JSR 168), and click OK.
In the General Portlet Information page of the Create JSR 168 Java Portlet wizard, select Enable inter-portlet communication using Oracle WSRP V2 extensions as shown in Figure 30-1.
Figure 30-1 Creating a Portlet with Navigational Parameters
Proceed through the wizard until you reach the Portlet Navigation Parameters page. For basic information about going through the wizard, see Section 29.2.1, "How to Create a JSR 168 Java Portlet."
In the Portlet Navigation Parameters page (Figure 30-2), click Add.
This adds a new row to the table of parameters.
Figure 30-2 Portlet Navigation Parameters Page of Portlet Wizard
Replace the default values in the Name, Label, and Hint fields with something more meaningful for your parameter.
Add more parameters as required and then click Finish.
In the Applications Navigator, right-click oracle-portlet.xml and choose Open.
You should see entries for the parameters that you added when you created the portlet, as shown in Example 30-3.
Example 30-3 oracle-portlet.xml Sample, Navigational Parameters
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <portlet-app-extension xsi:schemaLocation="http://xmlns.oracle.com/portlet/oracle-portlet-app" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.oracle.com/portlet/oracle-portlet-app"> <portlet-extension> <portlet-name>portlet1</portlet-name> <navigation-parameters> <name>Parameter_01</name> <type>xsi:string</type> <label xml:lang="en">Parameter 1</label> <hint xml:lang="en">First parameter.</hint> </navigation-parameters> <navigation-parameters> <name>Parameter_02</name> <type>xsi:string</type> <label xml:lang="en">Parameter 2</label> <hint xml:lang="en">Second parameter.</hint> </navigation-parameters> <portlet-id>1164232649525</portlet-id> </portlet-extension> </portlet-app-extension>
Add code to the portlet that utilizes the parameters.
When the parameters are included in the oracle-portlet.xml
file, you can access and set them as you would any normal render parameter, and the values are automatically exposed by the consumer.
For an example of a portlet used to set the values of navigation parameters, see the Parameter Form portlet, provided with the sample WSRP producer.
You can use the following APIs to read parameters passed to the portlet.
String param1 = request.getParameter("Parameter_01"); String param2 = request.getParameter("Parameter_02");
For an example of a portlet used to read and display the values of navigation parameters, see the Parameter Display portlet, provided with the sample WSRP producer.
Application developers can add these portlets to a page and link them using the navigational parameters. For more information, see Section 9.7, "Contextually Linking WSRP 2.0 Portlets."
Another new feature that arrives with WSRP 2.0 is the ability to keep customizations with portlets when moving them from one deployment to another. Customizations are portlet preferences that are set in edit defaults mode. For example, suppose that you create a portlet and then customize its title within your development environment. If you have enabled export and import for that portlet and its producer, then the customized title is transported along with the portlet when you deploy it in production environment. If you do not enable export and import, then all customizations are lost when you transport the portlet from one deployment environment to another.
To implement export or import for a portlet and its producer:
Start JDeveloper.
In the Application Navigator, open the application that contains the portlet.
Expand the project that contains the portlet.
Right-click the oracle-portlet.xml
file for the portlet's producer and choose Open.
Ensure that the allow-export
and allow-import
tags are included for each portlet and the producer as shown in Example 30-4, adding them if necessary.
Example 30-4 oracle-portlet.xml Sample, Export/Import
<portlet-app-extension xsi:schemaLocation="./oracle-portlet-app.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="./oracle-portlet-app.xsd"> <portlet-extension> <portlet-name>portlet1</portlet-name> <navigation-parameters> <name>Parameter_01</name> <type>xsi:string</type> <label xml:lang="en">First Parameter</label> <hint xml:lang="en">hint0</hint> </navigation-parameters> <navigation-parameters> <name>Parameter_02</name> <type>xsi:string</type> <label xml:lang="en">Second Parameter</label> <hint xml:lang="en">hint1</hint> </navigation-parameters> <navigation-parameters> <name>Parameter_03</name> <type>xsi:string</type> <label xml:lang="en">Third Parameter</label> <hint xml:lang="en">hint2</hint> </navigation-parameters> <portlet-id>1</portlet-id> <allow-export>true</allow-export> <allow-import>true</allow-import> <portlet-name>portlet2</portlet-name> <navigation-parameters> <name>Parameter_01</name> <type>xsi:string</type> <label xml:lang="en">First Parameter</label> <hint xml:lang="en">hint0</hint> </navigation-parameters> <navigation-parameters> <name>Parameter_02</name> <type>xsi:string</type> <label xml:lang="en">Second Parameter</label> <hint xml:lang="en">hint1</hint> </navigation-parameters> <navigation-parameters> <name>Parameter_03</name> <type>xsi:string</type> <label xml:lang="en">Third Parameter</label> <hint xml:lang="en">hint2</hint> </navigation-parameters> <portlet-id>2</portlet-id> <allow-export>true</allow-export> <allow-import>true</allow-import> </portlet-extension> <allow-export>true</allow-export> <allow-import>true</allow-import> </portlet-app-extension>
Resource proxying is the standard way to retrieve resources with WSRP. To avoid problems with URLs within your portlet, you can set a flag to rewrite all of the URLs within a specified resource. For example, if have an HTML fragment that contains URLs, then you could set this flag to rewrite its URLs taking into account the WSRP resource proxying.
To indicate that URLs should be rewritten, set the PortletRequest
attribute, oracle.portlet.server.resourceRequiresRewriting
, to true
. For example, you might include code similar to the excerpt in Example 30-5 to use resource proxying for a URL that you are encoding. Note that typically you would want to encapsulate this code within a method to avoid repeating it for every URL individually.
Example 30-5 Resource Proxy for WSRP
request.setAttribute("oracle.portlet.server.resourceRequiresRewriting", Boolean.TRUE); String url = response.encodeURL(pathToResourceForRewriting); request.removeAttribute("oracle.portlet.server.resourceRequiresRewriting");
If you do not specifically set oracle.portlet.server.resourceRequiresRewriting
, then it defaults to false
, meaning that URLs are not rewritten. You must explicitly activate the feature by setting this attribute to true
.
If you have out of protocol resources that do not require rewriting, you may want to use stateless resource proxying. Stateless resource proxying means that the URLs returned to the browser do not need to include portlet IDs or any other contextual information. This increases the cache hit ratio for such resources. You might find stateless resource proxying useful for functionality such as static JavaScript files, static images, and so on.
To indicate that stateless proxying should be used, set the PortletRequest
attribute oracle.portlet.server.useStatelessProxying
to true
. For example, you might include code similar to the excerpt in Example 30-6 to use stateless proxying for a URL that you are encoding. Note that typically you would want to encapsulate this code within a method to avoid repeating it for every URL individually.
Example 30-6 Stateless Resource Proxying
request.setAttribute("oracle.portlet.server.useStatelessProxying", Boolean.TRUE); String url = response.encodeURL(pathToResource); request.removeAttribute("oracle.portlet.server.useStatelessProxying");
You can also use the following constant:
oracle.portlet.server.containerimpl.PortletRequestImpl.USE_STATELESS_PROXYING
This is shown in Example 30-7.
Example 30-7 Stateless Resource Proxying Using Constant
request.setAttribute(PortletRequestImpl.USE_STATELESS_PROXYING, Boolean.TRUE); String url = response.encodeURL(pathToResource); request.removeAttribute(PortletRequestImpl.USE_STATELESS_PROXYING);
If you do not specifically set oracle.portlet.server.useStatelessProxying
, it defaults to false
. You must explicitly activate the feature by setting this attribute to true
.
In some cases, you may prefer to avoid the use of the Java Object Cache by your WSRP preference store. You can configure the use of caching by the WSRP preference store with the following JNDI variable:
oracle/portal/wsrp/server/disableJavaObjectCache
By default, this variable is set to false
. You can set the variable yourself in the web.xml
file for you portlet application as follows:
<env-entry> <env-entry-name>oracle/portal/wsrp/server/disableJavaObjectCache</env-entry-name> <env-entry-type>java.lang.Boolean</env-entry-type> <env-entry-value>true</env-entry-value> </env-entry>
For more information about setting JNDI variables, see Section 30.2.4.2, "Setting JNDI Variable Values."
You can secure JSR 168 portlets that are deployed to a WSRP producer by configuring security at the WSRP producer end and the client end. For information about securing a JSR 168 portlet through its WSRP producer, see Section 24.12, "Securing Identity Propagation Through WSRP Producers with WS-Security."
When you have built your initial portlet in the Portlet Wizard as described in Section 29.2.3, "How to Create a PDK-Java Portlet," you will want to enhance it. You can find the JavaDoc reference for the PDK-Java on OTN at:
http://www.oracle.com/technology/products/webcenter/portlet_download.html
Some of the more important enhancements that you might want to perform are as follows:
Adding portlet modes. For more information, see Section 30.2.1, "How to Add Portlet Modes."
Adding parameters. For more information, see Section 30.2.2, "How to Implement Public Parameters."
Using JNDI variables. For more information, see Section 30.2.4, "How to Use JNDI Variables."
Accessing session information. For more information, see Section 30.2.5, "How to Access Session Information."
Enhancing portlet performance. For more information, see Section 30.2.6, "How to Enhance Portlet Performance with Caching."
The source code for many of the examples referenced in this section is available as part of the Portlet Developer's Kit (PDK).
When you unzip PDK-Java, find the examples in:
../pdk/jpdk/v2/src/oracle/portal/sample/v2/devguide
In the Portlet Wizard, you add portlet modes by checking boxes on the wizard pages. For more information about using the wizard, see Section 29.2.3, "How to Create a PDK-Java Portlet." For each portlet mode that you select in the wizard, a basic skeleton is created. If you want to add a portlet mode after creating the portlet, you can do that manually by updating provider.xml
and HTML or JSPs in JDeveloper.
The principles of implementing portlet modes using RenderManager
are the same for all modes.
For more detailed information about the PDK runtime classes used in this section, see the JavaDoc on OTN:
http://www.oracle.com/technology/products/webcenter/portlet_download.html
For more information about the syntax of provider.xml
, see the provider JavaDoc, also available on OTN.
Before You Begin
The steps that follow assume that you have:
Built a portlet using the wizard, successfully registered the producer, and added the portlet to the page.
To add a portlet mode:
Start JDeveloper.
In the Application Navigator, open the application that contains the portlet.
Expand the project that contains the portlet.
Expand the Web Content node and then the htdocs node and then the node for the producer.
Right-click the node for the portlet and choose New.
The node for the portlet is located under Web Content > htdocs > provider.
In the New Gallery, expand Web Tier, select HTML or JSP, and click OK.
You must create an HTML file or a JSP for each mode to add to your portlet. For example, to implement Help mode, you would create an HTML file to provide the help content.
In the resulting dialog, enter a file name for the HTML file or JSP and click OK.
In the visual editor, edit the content of the page to implement the desired functionality.
For example, for Help mode, you could add the following HTML:
<p>This is the <i>Help</i> mode of your portlet!</p>
In the Application Navigator, right-click the provider.xml
file for the provider that owns the portlet and choose Open.
The provider.xml
file is located under Web Content > WEB-INF > providers > provider.
Change the value of the appropriate tag for the mode you are adding to true
.
For example, if you are adding Help mode, change the hasHelp
tag as follows:
<hasHelp>true</hasHelp>
This indicates to the PDK Framework that a link or icon to that mode should be rendered.
Add the code to point to the HTML page or JSP that you created earlier for the mode.
For example, for the Help page, add the following code:
<helpPage>/htdocs/myprovider/myportlet/myHelpPage.html</helpPage>
Save your changes.
Redeploy your portlet. For more information, see Chapter 33, "Testing and Deploying Your Portlets."
When you redeploy, JDeveloper automatically saves and compiles the code before deploying the portlet.
Copy the HTML file or JSP you created and the updated provider.xml
file to the WLS instance where you plan to deploy the portlet.
Refresh the producer.
Refresh the page containing your portlet.
You should now be able to access the new mode. For example, if you added Help mode, you should be able to click the Help link.
PDK-Java and Oracle WebCenter Framework provide public and private portlet parameters to enable portlet developers to easily write reusable, complex portlets. The Portlet Wizard in JDeveloper creates portlets that are set up to use parameters. This feature enables you to focus solely on adding business logic to your portlets and does not require any changes to provider.xml
.
For an overview of parameters, see Section 27.2.11, "Public Portlet Parameter Support" and Section 27.2.12, "Private Portlet Parameter Support."
Before You Begin
The steps that follow assume that you have:
Followed through and understood Section 29.2.3, "How to Create a PDK-Java Portlet."
Built a portlet using the wizard and successfully added it to a page.
Note:
Each portlet is limited to 4K of data. The lengths of parameter and event names, display names, and descriptions all contribute toward this 4K limit. Hence, you should not use too many parameters and events for each portlet, or give them lengthy names and descriptions.Using the Portlet Wizard, you can easily create a portlet with public parameters. When you register the producer and drop the portlet on a page, the portlet's parameters are automatically linked to page variables.
To create a portlet with public parameters to your portlet:
Start JDeveloper.
In the Application Navigator, open the application that contains the portlet.
Right-click the project under which you want to create your portlet, and choose New.
Note:
To create the portlet in an existing producer, right-click the producer'sprovider.xml
file and choose Add Portlet. This takes you directly to the General Portlet Information page of the Create Oracle PDK-Java Portlet wizard.In the New Gallery, expand Web Tier, select Portlets and then Oracle PDK-Java Portlet, and click OK.
Proceed through the Create Oracle PDK-Java Portlet wizard as you normally would until you reach the Public Portlet Parameters page.
See Section 29.2.3, "How to Create a PDK-Java Portlet" for basic information about going through the wizard.
In the Public Portlet Parameters page (Figure 30-3), click Add.
This adds a new row to the table of parameters.
Figure 30-3 Public Portlet Parameters Page of Portlet Wizard
Replace the default values in the Name, Display Name, and Description fields with something more meaningful for your parameter.
Add more parameters as required and then click Finish.
In the Application Navigator, right-click the provider.xml
file for the provider that owns the portlet and choose Open.
The provider.xml
file is located under Web Content > WEB-INF > providers > provider.
You should see entries for the parameters that you added on the Public Portlet Parameters page in the wizard, for example, as shown in Example 30-8.
Example 30-8 provider.xml Sample, Public Parameters
<?xml version = '1.0' encoding = 'UTF-8'?><?providerDefinition version="3.1"?> <provider class="oracle.portal.provider.v2.DefaultProviderDefinition"> <session>false</session> <passAllUrlParams>false</passAllUrlParams> <preferenceStore class= "oracle.portal.provider.v2.preference.FilePreferenceStore"> <name>prefStore1</name> <useHashing>true</useHashing> </preferenceStore> <portlet class="oracle.portal.provider.v2.DefaultPortletDefinition"> <id>1</id> <name>MyPortlet</name> <title>My Portlet</title> <description>My Portlet Description</description> <timeout>40</timeout> <showEditToPublic>false</showEditToPublic> <hasAbout>false</hasAbout> <showEdit>true</showEdit> <hasHelp>false</hasHelp> <showEditDefault>false</showEditDefault> <showDetails>false</showDetails> <inputParameter class= "oracle.portal.provider.v2.DefaultParameterDefinition"> <name>Parameter_01</name> <displayName>Parameter_01</displayName> <description>My first parameter</description> </inputParameter> <inputParameter class= "oracle.portal.provider.v2.DefaultParameterDefinition"> <name>Parameter_02</name> <displayName>Parameter_02</displayName> <description>My second parameter</description> </inputParameter> <inputParameter class= "oracle.portal.provider.v2.DefaultParameterDefinition"> <name>Parameter_03</name> <displayName>Parameter_03</displayName> </inputParameter> <renderer class="oracle.portal.provider.v2.render.RenderManager"> <renderContainer>true</renderContainer> <renderCustomize>true</renderCustomize> <autoRedirect>true</autoRedirect> <contentType>text/html</contentType> <showPage>/htdocs/myportlet/MyPortletShowPage.jsp</showPage> <editPage>/htdocs/myportlet/MyPortletEditPage.jsp</editPage> </renderer> <personalizationManager class= "oracle.portal.provider.v2.personalize.PrefStorePersonalizationManager"> <dataClass> oracle.portal.provider.v2.personalize.NameValuePersonalizationObject </dataClass> </personalizationManager> </portlet> </provider>
In the Application Navigator, right-click the portletname
ShowPage.jsp
for your portlet and choose Open.
The file is located under Web Content > htdocs > provider > portlet.
The portlet includes logic for retrieving the parameters, for example, as shown in Figure 30-3.
Example 30-9 ShowPage.jsp Sample
<%@page contentType="text/html; charset=windows-1252" import="oracle.portal.provider.v2.render.PortletRenderRequest" import="oracle.portal.provider.v2.http.HttpCommonConstants" import="oracle.portal.provider.v2.ParameterDefinition" %> <% PortletRenderRequest pReq = (PortletRenderRequest) request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST); %> <P>Hello <%= pReq.getUser().getName() %>.</P> <P>This is the <b><i>Show</i></b> render mode!</P> <% ParameterDefinition[] params = pReq.getPortletDefinition().getInputParameters(); %> <p>This portlet's input parameters are...</p> <table align="left" width="50%" ><tr><td><span class="PortletHeading1">Name</span></td><td><span class="PortletHeading1">Value</span></td></tr> <% String name = null; String value = null; String[] values = null; for (int i = 0; i < params.length; i++) { name = params[i].getName(); values = pReq.getParameterValues(name); if (values != null) { StringBuffer temp = new StringBuffer(); for (int j = 0; j < values.length; j++) { temp.append(values[j]); if (j + 1 != values.length) { temp.append(", "); } } value = temp.toString(); } else { value = "No values have been submitted yet."; } %> <tr> <td><span class="PortletText2"><%= name %></span></td> <td><span class="PortletText2"><%= value %></span></td> </tr> <% } %> </table>
Add logic to your portlet that allows it to submit parameter values entered by users.
Create a second portlet using the same steps that simply displays parameter values that it retrieves.
Register the producer with a WebCenter application. For more information, see Section 9.2.3, "How to Register an Oracle PDK-Java Portlet Producer."
Add the two portlets to a page in the application. For more information, see Section 9.3, "Adding Portlets to a Page."
In the Structure panel of the Application Navigator, right-click an element of the page and choose Go to Page Definition.
The page definition should look similar to Example 30-10. Notice the variables at the page level and the parameters at the portlet level (indicated in bold).
Example 30-10 Page Definition File Sample
<?xml version="1.0" encoding="UTF-8"?> <pageDefinition xmlns="http://xmlns.oracle.com/adfm/uimodel" version="10.1.3.38.90" id="untitled1PageDef" Package="view.pageDefs"> <executables> <variableIterator id="variables"> <variable Name="portlet1_Parameter_01" Type="java.lang.Object"/> <variable Name="portlet1_Parameter_02" Type="java.lang.Object"/> <variable Name="portlet1_Parameter_03" Type="java.lang.Object"/> </variableIterator> <portlet id="portlet1" portletInstance="/oracle/adf/portlet/PdkPortletProducer1_1153936627784 /applicationPortlets/Portlet1_abfc5a10_010c_1000_8003_82235f50d831" class="oracle.adf.model.portlet.binding.PortletBinding" xmlns="http://xmlns.oracle.com/portlet/bindings"> <parameters> <parameter name="Parameter_01" pageVariable="portlet1_Parameter_01"/> <parameter name="Parameter_02" pageVariable="portlet1_Parameter_02"/> <parameter name="Parameter_03" pageVariable="portlet1_Parameter_03"/> </parameters> </portlet> </executables> </pageDefinition>
Run the WebCenter application.
Enter values in the first portlet and the same values should be displayed in the second portlet.
In some cases, you might need a parameter that is known only to the portlet instance. These parameters are known as private parameters because they have no connection to the page and are known only to the portlet. Private parameters often come in handy when you are building navigation for your portlet. For example, if you have a portlet made up of multiple pages, then you can use these private parameters to jump to another resource of the portlet.
Private parameters are used in classic Web applications to pass information from links or forms in the browser back to the server. The server in turn takes actions and returns the appropriate content. For example, if the user of a dictionary Web site asks for information about hedgehogs, then the URL submitted to the server might append a private parameter as follows:
http://dictionary.reference.com/search?q=Hedgehog
If the server is responsible for rendering the whole page and the client communicates directly with the server, then this form of URL works well. In a custom WebCenter application, the client does not communicate directly with portlets. Instead, Oracle WebCenter Framework mediates between the client and the portlet. Moreover, because most pages have multiple portlets, Oracle WebCenter Framework communicates with multiple portlets.
For example, suppose a page contains two portlets, a thesaurus portlet and a dictionary portlet. Both portlets use q
as a parameter to record the search queries made by the user. If the user queries the thesaurus portlet, then the URL used to rerequest the page with the updated thesaurus portlet must contain the thesaurus portlet's parameter, q
. The thesaurus parameter must also be distinguished from dictionary portlet parameter 1, which performs the same function for that portlet. An example URL with the properly qualified thesaurus parameter might look something like the following:
http://host/portal/page?_pageid=33,1&_dad=portal&_schema=PORTAL
&_piref33_38279_33_1_1.q=Hedgehog
Notice the fully qualified parameter name, _piref33_38279_33_1_1.q
. It identifies the parameter and distinguishes it from other parameters on the page. Further, notice that the URL contains some parameters unrelated to any portlet. These parameters are untouched by the portlet because it does not own them.
You must ensure that the portlet meets the following criteria:
It properly qualifies its own parameters when they are built into links and forms.
It leaves unchanged any parameters that do not belong to it.
The following API call transforms an unqualified parameter name into a qualified parameter name:
HttpPortletRendererUtil.portletParameter(HttpServletRequest request, String param);
HttpPortletRendererUtil
is in the package oracle.portal.provider.v2.render.http
.
For example:
qualParamQ = HttpPortletRendererUtil.portletParameter(r, "q");
To fetch the value of a portlet parameter from the incoming request, you can use the following API:
Note:
The API converts the parameter name into the qualified parameter name before fetching the value from the incoming request. Hence, you need not perform this step.PortletRenderRequest.getQualifiedParameter(String name)
PortletRenderRequest
is in the package oracle.portal.provider.v2.render
.
For example:
valueQ = r.getQualifiedParameter("q");
The other aspect of a portlet's responsibilities with private parameters is to not disturb the parameters on the URL that it does not own. The utilities you may use to ensure adherence to this rule are discussed in Section 30.2.3.3, "Building Links with the Portlet URL Types" and Section 30.2.3.4, "Building Forms with the Portlet URL Types."
When a portlet renders itself, Oracle WebCenter Framework passes it various URLs, which the portlet can then use to render links. You can fetch and manipulate these URLs to simplify the task of creating links. The following is a list of the URLs provided to portlets:
PAGE_LINK is a URL to the page upon which the portlet instance resides. You use this URL as the basis for all intraportlet links. If the portlet renders a link that navigates the user to another section of the same portlet, then this navigation must be encoded as a set of parameters using the PAGE_LINK.
DESIGN_LINK is a URL to the portlet's personalization (Edit mode) page. A portlet's Edit and Edit Defaults modes are not rendered on the same page as the portlet. The Edit and Edit Defaults modes take over the entire browser window. The portlet's Edit and Edit Defaults modes are not necessarily accessible to every user. It represents a minimal, static framework in which the portlet is free to render its personalization options. This URL is only of use when rendering Personalize links.
BACK_LINK is a URL to a useful return point from the current page where the portlet renders itself. For example, when the portlet is rendering it's personalization page (Edit mode), this link refers to the page on which the portlet resides and from which the user navigated to the personalization page. Consequently, it is the link you would encode in the buttons that accept or cancel the pending action. This URL is only useful for the desktop rendering of portlets (usually in Edit or Edit Defaults mode).
To build links with Portlet URL types, you must access them and use them when writing portlet rendering code. To fetch the URL for a link, you call the following APIs in PDK-Java:
portletRenderRequest.getRenderContext().getPageURL() portletRenderRequest.getRenderContext().getEventURL() portletRenderRequest.getRenderContext().getDesignURL() portletRenderRequest.getRenderContext().getLoginServerURL() portletRenderRequest.getRenderContext().getBackURL()
In portlet navigation, you must add (or update) your portlet's parameters in the page URL. To perform this task, you can use the following API to build a suitable URL:
UrlUtils.constructLink( PortletRenderRequest pr, int linkType, -- UrlUtils.PAGE_LINK in this case NameValue[] params, boolean encodeParams, boolean replaceParams)
UrlUtils
resides in the package called oracle.portal.provider.v2.url
. Notice that you do not actually fetch the page URL yourself. Rather you use the supplied portlet URL type, UrlUtils.PAGE_LINK
.
The parameter names in the params
argument should be fully qualified. Moreover, if you properly qualify the parameters, UrlUtils.constructLink
with the appropriate linkType
does not disturb other URL parameters that are not owned by the portlet.
An alternative version of UrlUtils.contructLink
accepts a URL as the basis for the returned URL. If you require an HTML link, then you can use UrlUtils.constructHTMLLink
to produce a complete anchor element.
The following example portlet, ThesaurusLink.jsp
, uses the parameter q
to identify the word for which to search the thesaurus. It then creates links on the found, related words that the user may follow to get the thesaurus to operate on that new word. To see the initial submission form that sets the value of q
, see the example in Section 30.2.3.4, "Building Forms with the Portlet URL Types."
<% String paramNameQ = "q"; String qualParamNameQ = HttpPortletRendererUtil.portletParameter(paramNameQ); PortletRenderRequest pRequest = (PortletRenderRequest) request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST); String paramValueQ = pRequest.getQualifiedParameter(paramNameQ); %> <!-- Output the HTML content --> <center> Words similar to <%= paramValueQ %> <br> Click the link to search for words related to that word. <br> <ul> <% String[] relatedWords = Thesaurus.getRelatedWords(paramValueQ); NameValue[] linkParams = new NameValue[1]; for (int i=0; i<=relatedWords.length; i++) { linkParams[0] = new NameValue( qualParamNameQ, relatedWords[i]); %> <li> <b> <%= relatedWords[i] %> </b> <%= UrlUtils.constructHTMLLink( pRequest, UrlUtils.PAGE_LINK, "(words related to " + relatedWords[i] + ")", "", linkParams, true, true)%> </li> <% } %> </ul> </center>
Use of portlet parameters in forms is little different from links. The following two fundamental rules continue to apply:
Qualify the portlet's parameter names.
Do not manipulate or remove the other parameters on the incoming URL.
In terms of markup and behavior, forms and links differ quite considerably. However, just as with links, PDK-Java contains utilities for complying with these two basic rules.
The code for properly qualifying the portlet's parameter name is the same as that described in Section 30.2.3.3, "Building Links with the Portlet URL Types." After all, a parameter name is just a string, whether it be a link on a page or the name of a form element.
Forms differ from links in the way you ensure that the other parameters in the URL remain untouched. Once you open the form in the markup, you can make use of the following APIs:
UrlUtils.htmlFormHiddenFields(pRequest,UrlUtils.PAGE_LINK, formName); UrlUtils.htmlFormHiddenFields(someURL);
where formName = UrlUtils.htmlFormName(pRequest,null)
.
Note:
Just as parameters in URLs and element names in forms require qualification to avoid clashing with other portlets on the page, form names must be fully qualified because any given page might have several forms on it.The htmlFormHiddenFields
utility writes HTML hidden form elements into the form, one form element for each parameter on the specified URL that is not owned by the portlet.
<INPUT TYPE="hidden" name="paramName" value="paramValue">
Thus, you need only to add their portlet's parameters to the form.
The other item of which you should be aware is how to derive the submission target of your form. In most cases, the submission target is the current page:
formTarget = UrlUtils.htmlFormActionLink(pRequest,UrlUtils.PAGE_LINK)
The value of formTarget
can be the action attribute in an HTML form or the target attribute in a SimpleForm
. Even though the method name includes HTML, it actually just returns a URL and thus you can use it in mobile portlets, too.
The following example form renders the thesaurus portlet's submission form. For the portlet that results from the submission of this form, see the example in Section 30.2.3.3, "Building Links with the Portlet URL Types."
<% String paramNameSubmit = "submit"; String paramNameQ = "q"; String qualParamNameQ = HttpPortletRendererUtil.portletParameter(paramNameQ); String qualParamNameSubmit = HttpPortletRendererUtil.portletParameter(paramNameSubmit); PortletRenderRequest pRequest = (PortletRenderRequest) request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST); String formName = UrlUtils.htmlFormName(pRequest,"query_form"); %> <!-- Output the HTML content --> <center> <b>Thesaurus</b> Enter the word you want to search for <form name="<%= formName %>" method="POST" action="<%= UrlUtils.htmlFormActionLink(pRequest,UrlUtils.PAGE_LINK) %>"> <%= UrlUtils.htmlFormHiddenFields(pRequest,UrlUtils.PAGE_LINK, formName)%> <table><tr><td> Word of interest: </td><td> <input type="text" size="20" name="<%= qualParamNameQ %>" value=""> </td></tr></table> <input type=submit name="<%= qualParamNameSubmit %>" Value="Search"> </form> </center>
You can implement navigation within a portlet in one of three ways:
Pass navigation information in rendered URLs using private portlet parameters. Branching logic within the portlet code then determines which section of the portlet to render based on the URL. This option represents a small extension to the thesaurus example presented in Section 30.2.3.3, "Building Links with the Portlet URL Types" and Section 30.2.3.4, "Building Forms with the Portlet URL Types." Basically, instead of performing thesaurus search operations using the value of parameter q
, the portlet branches based on the parameter value and renders different content accordingly.
Pass navigation information as described in the previous item but use PDK-Java to interpret the parameter and thus branch on its value. This option requires some further changes to the thesaurus example and is more fully explained later in this section.
Use session storage to record the portlet state and private parameters to represent actions rather than explicit navigation. This method provides the only way that you can restore the portlet to it's previous state when the user navigates off the page containing the portlet. Once the user leaves the page, all private portlet parameters are lost and you can only restore the state from session storage, assuming you previously stored it there. This option requires that you understand and implement session storage. For more information about implementing session storage, see Section 30.2.5.1, "Implementing Session Storage."
The following portlet code comes from the multipage example in the sample producer of PDK-Java:
<portlet>
<id>11</id>
<name>Multipage</name>
<title>MultiPage Sample</title>
<shortTitle>MultiPage</shortTitle>
<description>
This portlet depicts switching between two screens all
in an application page.
</description>
<timeout>40</timeout>
<timeoutMessage>MultiPage Sample timed out</timeoutMessage>
<renderer class="oracle.portal.provider.v2.render.RenderManager">
<contentType>text/html</contentType>
<showPage>/htdocs/multipage/first.jsp</showPage>
<pageParameterName>next_page</pageParameterName>
</renderer>
</portlet>
Notice that the value of pageParameterName
is the name of a portlet parameter, next_page
, that the PDK-Java framework intercepts and interprets as an override to the value of the showPage
parameter. If the PDK-Java framework encounters the qualified version of the parameter when the multipage portlet is requested, then it renders the resource identified by next_page
rather than first.jsp
. Note that PDK-Java does not render the parameter within the portlet, that responsibility falls to the portlet.
You can modify the thesaurus example to operate with the use of this parameter. Specifically, you can use the form submission portlet to be the input for the thesaurus (the first page of the portlet), then navigate the user to the results page, which contains links to drill further into the thesaurus. The following examples illustrate these changes.
Note:
The example that follows is most useful for relatively simple cases, such as this thesaurus example. If your requirements are more complex (for example, you want to build a wizard experience), then you should consider using an MVC framework such as Struts. For information about how to build portlets from struts applications, see Section 30.4, "Building Struts Portlets."ThesaurusForm.jsp
:
<% PortletRenderRequest pRequest = (PortletRenderRequest) request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST); String paramNameSubmit = "submit"; String paramNameQ = "q"; String qualParamNameQ = HttpPortletRendererUtil.portletParameter(pRequest, paramNameQ); String qualParamNameSubmit = HttpPortletRendererUtil.portletParameter(pRequest, paramNameSubmit); String formName = UrlUtils.htmlFormName(pRequest,"query_form"); %> <!-- Output the HTML content --> <center> <b>Thesaurus</b> Enter the word you want to search for <form name="<%= formName %>" method="POST" action="<%= UrlUtils.htmlFormActionLink(pRequest,UrlUtils.PAGE_LINK) %>"> <%= UrlUtils.htmlFormHiddenFields(pRequest,UrlUtils.PAGE_LINK, formName) %> <%= UrlUtils.emitHiddenField( HttpPortletRendererUtil.portletParameter(request, "next_page"), "htdocs/path/ThesaurusLink.jsp" ) %> <table><tr><td> Word of interest: </td><td> <input type="text" size="20" name="<%= qualParamNameQ %>" value=""> </td></tr></table> <input type=submit name="<%= qualParamNameSubmit %>" Value="Search"> </form> </center>
Notice how next_page
must be explicitly set to point to ThesaurusLink.jsp
. If you do not explicitly set next_page
in this way, then it defaults to the resource registered in provider.xml
, which is ThesaurusForm.jsp
.
ThesaurusLink.jsp
:
<% PortletRenderRequest pRequest = (PortletRenderRequest) request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST); String paramNameQ = "q"; String paramNameNextPage = "next_page"; String qualParamNameQ = HttpPortletRendererUtil.portletParameter(pRequest, paramNameQ); String qualParamNameNextPage = HttpPortletRendererUtil.portletParameter(pRequest, paramNameNextPage); String paramValueQ = pRequest.getQualifiedParameter(paramNameQ); %> <!-- Output the HTML content --> <center> Words similar to <%= paramValueQ %> <br> Click the link to search for words related to that word. <br> <ul> <% Thesaurus t = new Thesaurus(); String[] relatedWords = t.getRelatedWords(paramValueQ); NameValue[] linkParams = new NameValue[2]; linkParams[0] = new NameValue( qualParamNameNextPage, "htdocs/path/ThesaurusLink.jsp"); for (int i=0; i<relatedWords.length; i++) { linkParams[1] = new NameValue( qualParamNameQ, relatedWords[i]); %> <li> <b> <%= relatedWords[i] %> </b> <%= UrlUtils.constructHTMLLink( pRequest, UrlUtils.PAGE_LINK, "(words related to " + relatedWords[i] + ")", "", linkParams, true, true)%> </li> <% } %> </ul> <a href="<%=XMLUtil.escapeXMLAttribute (pRequest.getRenderContext().getPageURL())%>"> Reset Portlet </a> </center>
One danger of implementing navigation with private parameters is that users could potentially navigate to portlet resources that you prefer to restrict. To control the resources to which the user may navigate, you can create a whitelist of acceptable resources to which a user may navigate. If you do not construct a whitelist to restrict navigation, then your portlet's resources are accessible according to the following default rules:
Any path immediately beneath the servlet root context is navigable. For example, /index.jsp
is accessible but /WEB-INF/web.xml
is not.
Any path under the htdocs
directory is navigable. For example, both /htdocs/multipage/first.jsp
and /htdocs/lottery/lotto.jsp
are accessible.
To change this default behavior, you can add allowable path values to the provider definition file, provider.xml
. For example, suppose you have a portlet where a JSP is used as a controller to forward requests to other pages depending on the pageParameterName
private parameter. The XML excerpt in Example 30-11 would only allow resources under /htdocs/multiportlet
to be shown. All other resources would be restricted.
Example 30-11 Whitelist Excerpt from the provider.xml File
<portlet class="oracle.portal.provider.v2.DefaultPortletDefinition">
<id>1</id>
<name>Multipage</name>
<title>A MultiPage Portlet</title>
...
<renderer class="oracle.portal.provider.v2.render.RenderManager">
<contentType>text/html</contentType>
<showPage>/htdocs/multiportlet/controller.jsp</showPage>
<pageParameterName>show_page</pageParameterName>
<allowedPath>/htdocs/multiportlet/*</allowedPath>
</renderer>
</portlet>
The pattern matching rules for this feature are similar to URL pattern matching in web.xml
files. The rules are as follows:
To match the defined patterns, the resource path must exactly match unless wildcards are used.
The first wildcard is for path matching and consists of a string beginning with /
and ending with /*
. Any resource whose path starts with this string is matched. For an <allowedPath>
value of /htdocs/sub1/*
, valid values of the private parameter would include /htdocs/sub1/file.jsp
and /htdocs/sub1/sub2/file2.jsp
.
The second wildcard is for file type matching and consists of a string starting with *.
and ending with a file extension. Valid values for the page parameter end with that file extension. For an <allowedPathvalue>
of *.jsp
, valid values of the private parameter would include /htdocs/sub1/file.jsp
and /htdocs/sub1/file2.jsp
.
When writing Java portlets, you may set deployment specific properties through the JNDI service such that their values may be retrieved from your producer code. In this way, you can specify any property in a producer deployment and then easily access it anywhere in your producer code.
You can use JNDI variables to change producer property values after the producer has been deployed. The environment entry must be declared in web.xml.
It can then be updated on deployment using a deployment plan.
PDK-Java provides utilities to enable the retrieval of both producer and non-producer JNDI variables within a Java EE container.
You declare JNDI variables in the web.xml
file for your producer. The format for declaring a JNDI variable is as follows:
<env-entry> <env-entry-name>variableName</env-entry-name> <env-entry-type>variableType</env-entry-type> <env-entry-value>variableValue</env-entry-value> </env-entry>
The env-entry-name
element contains the name by which you want identify the variable. env-entry-type
contains the fully qualified Java type of the variable. env-entry-value
contains the variable's default value.
In the env-entry-type
element, you should supply the fully qualified Java type of the variable, which is expected by your Java code. The Java types you may use in your JNDI variables are as follows:
java.lang.Boolean
java.lang.String
java.lang.Integer
java.lang.Double
java.lang.Float
The Java EE container uses these type declarations to automatically construct an object of the specified type and gives it the specified value when you retrieve that variable in your code.
The PDK-Java defines environment variables that can be set at the individual producer service level or at the Web application level. To avoid naming conflicts between different producer services or different application components packaged in the same Web application, Oracle recommends you devise some naming convention.
Note:
If you use theEnvLookup
method, then you must use oracle/portal/provider/service/property
. You cannot substitute your own company name or component in this case.For example:
Producer service specific names should be of the form:
{company}/{component name}/{producer name}/{variable name}
Shared names should be of the form:
{company}/{component name}/{producer name}/global
where:
{company}
is the name of the company owning the application.
{component name}
is the name of the application or component with which the producer is associated.
{producer name}
is the service name of the producer.
{variable name}
is the name of the variable itself.
As you can see, these naming conventions are similar to those used for Java packages. This approach minimizes the chance of name collisions between applications or application components. PDK-Java provides utilities that enable you to retrieve variables in this form without hard coding the service name of the producer into your servlets or JSPs. The service name need only be defined in the producer's WAR file. For more information about retrieving JNDI variables, see Section 30.2.4.3, "Retrieving JNDI Variables."
In your producer deployment, you may want to set a new value for some or all of your JNDI variables. You can perform this task by setting the values manually within a WLS deployment plan. Deployment plans can be created for the producer deployment through the WLS console.
To set variable values manually within a deployment plan:
Go to the producer deployment with the WLS console and create a new deployment plan if one does not already exist.
Edit the deployment plan XML file. For each deployment property you want to set, add the following variable definition directly under the <deployment-plan> tag:
<variable-definition> <variable> <name>jndi_var_def</name> <value>false</value> </variable> </variable-definition>
To tie this variable definition to the actual JNDI variable, add the following for each property under the WEB-INF/web.xml module descriptor (oracle/portal/sample/rootDirectory is used as an example):
<module-descriptor external="false"> <root-element>web-app</root-element> <uri>WEB-INF/web.xml</uri> <variable-assignment> <name>jndi_var_def</name> <xpath>/web-app/env-entry/[env-entry-name="oracle/portal/sample/rootDirectory"]/env-entry-value</xpath> </variable-assignment> </module-descriptor>
Save and close the file.
Select Update on the producer deployment to apply the deployment plan for the new settings to take effect.
JNDI is a standard Java EE technology. As such, you can access JNDI variables through Java EE APIs. For example:
String myVarName = "oracle/portal/myProvider/myVar"
String myVar = null;
try
{
InitialContext ic = new InitialContext();
myVar = (String)ic.lookup("java:env/" + myVarName);
}
catch(NamingException ne)
{
exception handling logic
}
In addition to the basic Java EE APIs, PDK-Java includes a simple utility class for retrieving the values of variables defined and used by the PDK itself. These variables all conform to the naming convention described in Section 30.2.4.1.2, "Variable Naming Conventions" and are of the form:
oracle/portal/provider_service_name/variable_name oracle/portal/variable_name
To use these APIs, you need only provide the provider_service_name
and the variable_name
. The utilities construct the full JNDI variable name, based on the information you provide, and look up the variable using code similar to that shown earlier and return the value of the variable.
The EnvLookup
class (oracle.portal.utils.EnvLookup
) provides two lookup()
methods. One retrieves producer variables and the other retrieves non-producer variables. Both methods return a java.lang.Object
, which can be cast to the Java type you are expecting.
The following code example illustrates the retrieval of a producer variable:
EnvLookup el = new EnvLookup(); String s = (String)el.lookup(myProviderName, myVariableName);
myProviderName
represents the service name for your producer, which makes up part of the variable name. myVariableName
represents the portion of the variable name that would come after the producer's service name. The example assumes the variable being retrieved is of type java.lang.String
.
To retrieve a non-producer variable, you use the same code, you pass only one parameter, the variable name, to the lookup()
, again excluding the oracle/portal
prefix.
EnvLookup el = new EnvLookup();Object o = el.lookup(myVariableName);
Table 30-1 shows the JNDI variables provided by default with PDK-Java. If you do not declare these variables, then PDK-Java looks for their values in their original locations (web.xml
and the deployment properties file).
Table 30-1 PDK-Java JNDI Variables
Variable | Description |
---|---|
oracle/portal/provider/provider_name/autoReload
|
Boolean auto reload flag. Defaults to true. |
oracle/portal/provider/provider_name/definition
|
Location of producer's definition file. |
oracle/portal/provider/global/log/logLevel |
Log setting (0 through 8). 0 being no logging and 8 the most possible logging. |
oracle/portal/provider/provider_name/maxTimeDifference
|
Producer's HMAC time difference. |
oracle/portal/provider/<service_name>/resourceUrlKey |
Authentication key for resource proxying through the Parallel Page Engine. See Oracle Fusion Middleware Administrator's Guide for Oracle Portal for more information. |
oracle/portal/provider/provider_name/rootDirectory
|
Location for producer personalizations. No default value. |
oracle/portal/provider/provider_name/sharedKey
|
HMAC shared key. No default value. |
oracle/portal/provider/provider_name/showTestPage
|
(non-producer) A Boolean flag that determines if a producer's test page is accessible. Defaults to true. |
oracle/portal/provider/global/transportEnabled |
A Boolean flag that determines whether Edit Defaults personalizations may be exported and imported. |
When a user accesses a page, it initiates a public, unauthenticated session and tracks information about the session across requests. If the user logs in, then this session becomes an authenticated session of the logged-in user. This session terminates when any of the following occur:
The browser session terminates (that is, the user closes all the browser windows).
The user explicitly logs out.
The session times out because the user's idle time exceeds the configured limit.
As part of the metadata generation, all of the producers that contribute portlets to the page are contacted, if they specified during registration that they be called for some special processing. This call allows producers to do processing based on the user session, log the user in the producer's application if needed, and establish producer sessions. For producers, this call is referred to as initSession
. As most Web-enabled applications track sessions using cookies, this API call enables the producer of the application to return cookies.
You can use the session store to save and retrieve information that persists during the portal session. This information is only available, and useful, to you during the life of the session. You should store only temporary information in the session store. Application developers may use the session store to save information related to the current user session. Data in the session store can be shared across portlets.
If the information you want to store must persist across sessions, then you may want to store it in the preference store instead. Some common applications of the session store are as follows:
To cache data that is expensive to load or calculate (for example, search results).
To cache the current state of a portlet (for example, the current range, or page, of search results displayed in the portlet, or sequence of events performed by user).
Before you implement session storage, you should carefully consider the performance costs. Because portlets and producers are remote, it can be a relatively expensive operation to create and maintain even a small amount of information in the session store. For this reason, you may want to avoid altogether any session storage for public pages that are accessed frequently by many users.
Furthermore, while using the session store with producers, you create a stateful application that tracks state information in memory. Similarly, you create a stateful application if you use the file-system implementation of preference store.
If scalability is an important concern for you, then a stateful application may cause you problems. Stateful applications can affect the load-balancing and failover mechanism for your configuration. Even though you may deploy multiple middle-tiers, you must implement sticky routing (where the same node handles subsequent requests in the same session) to track state. Sticky routing may result in lopsided load-balancing or loss of session data in case a node crashes, affecting failover. This issue is one reason why many developers prefer to build stateless applications. However, if scalability is not a concern, then a stateful application should present no problems for you.
In the example in this section, session storage is used to count the number of times your portlet has rendered in Shared Screen mode.
Before You Begin
The steps that follow assume that you have:
Followed through and understood Section 29.2.3, "How to Create a PDK-Java Portlet."
Built a portlet using the wizard and successfully added it to a page.
The PDK Framework represents the session with a ProviderSession
object, which is established during the call to the Provider Instance's initSession
method. This object is associated with the ProviderUser
. To make data persistent between requests, you must write data into the session object using the setAttribute
method on the ProviderSession
object. This method maps a java.lang.Object
to a java.lang.String
and stores that mapping inside the session object. The String
can then be used to retrieve the Object
during a subsequent request, provided the session is still valid.
A producer session may become invalid for the following reasons:
The session times out.
The invalidate
method on ProviderSession
is called.
The JVM process running the servlet container is terminated.
All portlets contained by the same ProviderInstance
share the same session for a particular ProviderUser
. Therefore, data unique to a particular portlet instance must be mapped to a unique String
in the session. This is accomplished using the portletParameter
method in the PortletRendererUtil
class. This method makes a supplied String
parameter or attribute name unique to a PortletInstance
, by prefixing it with a generated identifier for that instance. You can use the returned instance-specific name to write portlet instance data into the session.
For more detailed information about the PDK Framework classes, see the JavaDoc on OTN:
http://www.oracle.com/technology/products/webcenter/portlet_download.html
To implement session storage:
Import ProviderSession
, PortletRendererUtil
, and HttpPortletRendererUtil
.
Retrieve the producer session.
Read and write the session by accessing it from within your Java portlet.
Set the session to true in provider.xml
.
Register the producer for session storage and set the Login Frequency.
The steps that follow describe how to add a session count to your portlet that displays how many times the portlet has been rendered for the current session.
After using the wizard to create a portlet, you can edit the JSP for the Show page in Oracle JDeveloper. You must import the following classes:
<%@page contentType="text/html; charset=windows-1252" import="oracle.portal.provider.v2.render.PortletRenderRequest" import="oracle.portal.provider.v2.http.HttpCommonConstants" import="oracle.portal.provider.v2.ProviderSession" import="oracle.portal.provider.v2.render.PortletRendererUtil" import="oracle.portal.provider.v2.render.http.HttpPortletRendererUtil" %>
Insert code that checks for a valid session first and then increments the count and displays it. If the session is valid and a previously stored value exists, then you display the value, increment the count, and store the new value. If the session is valid but no previously stored value exists, then you initialize a new count starting with 1, and display and store the value. You also want to obtain the unique string key for this portlet and then use an it in an array to count the session. If no session information was received, then you want to provide information to the user indicating they may need to log back in.
<% PortletRenderRequest pReq = (PortletRenderRequest) request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST); ProviderSession pSession = pReq.getSession(); if (pSession != null) { String key = PortletRendererUtil.portletParameter(pReq, "count"); Integer i = (Integer)pSession.getAttribute(key); if (i == null) { i = new Integer(0); } i = new Integer(i.intValue()+1); pSession.setAttribute(key, i); %> <p>Render count in this session: <%=i%> </p> <% } else { %> <p>The session has become invalid</p> <br> Please log out and log in again. <% } %>
By default, the wizard does not set session to true in provider.xml
. You must update this flag in order for the producer to receive session information from the portal. You should only set this tag to true if you are using session information in your producer or portlets. By setting this flag to true, extra load is added to the producer calls.
<provider class="oracle.portal.provider.v2.DefaultProviderDefinition">
<session>true</session>
For more information about the syntax of provider.xml
, see the provider JavaDoc on OTN:
http://www.oracle.com/technology/products/webcenter/portlet_download.html
Register your producer with session support. For a reminder on how to register your portlet, see Section 33.4, "Registering and Viewing Your Portlet."
In the previous sections of this chapter, you learned how to write fully functional Java portlets using the PDK Framework. Once you complete the basic functionality of your portlet, you may want to turn your attention to portlet performance.
Caching is a common technique for enhancing the performance of Web sites that include a great deal of dynamic content. The overhead involved in retrieving data and generating the output for dynamic content can be significantly reduced by proxying requests through a local agent backed by a large, low-latency data store known as a cache. The cache agent responds to a request in one of two ways, as follows:
If a valid version of the requested content exists in the cache, then the agent simply returns the existing cached copy, thus skipping the costly process of content retrieval and generation. This condition is called a cache hit.
If a valid version of the requested content does not exist in the cache, then the agent forwards the request to its destination and awaits the return of the content. The agent returns the content to the requester and stores a local copy in its cache for reuse if a subsequent request for the same content arises. This condition is called a cache miss.
Producers generate dynamic content (that is, portlets) and they reside remotely from the custom WebCenter application instance on which they are deployed. As such, caching might improve their performance. The architecture lends itself well to caching. You can cache the portlets rendered by your producer and reuse the cached copies to handle subsequent requests, minimizing the overhead your producer imposes on page assembly.
The producer can use any one of three different caching methods, depending upon which one is best suited to the application. The methods differ chiefly in how they determine whether content is still valid. Following are the three caching methods:
Expiry-based Caching: When a producer receives a render request, it stamps its response with an expiry time. The rendered response remains in the cache and fills all subsequent requests for the same content until its expiry time passes. This caching scheme is perhaps the simplest and most performant because the test for cache validity requires very little overhead and does not involve any network round trips. Expiry-based caching suits applications where the content has a well-defined life span. For content with a less certain life span, however, expiry-based caching is less effective. For more information, see Section 30.2.6.1, "Activating Caching" and Section 30.2.6.2, "Adding Expiry-Based Caching."
Validation-based Caching: When a producer receives a render request, it stamps its response with a version identifier (or E Tag). The response goes into the cache, but, before the PPE can reuse the cached response, it must determine whether the cached version is still valid. It sends the producer a render request that includes the version identifier of the cached content. The producer determines whether the version identifier remains valid. If the version identifier is still valid, then the producer immediately sends a lightweight response to the PPE without any content, which indicates the cached version can be used. Otherwise, the producer generates new content with a new version identifier, which replaces the previously cached version. In this form of caching, the PPE must always confirm with the producer whether the content is up to date. The validity of the cached copy is determined by some logic in the producer. The advantage of this approach is that the producer controls the use of the cached content rather than relying on a fixed period. For more information, see Section 30.2.6.1, "Activating Caching" and Section 30.2.6.3, "Adding Validation-Based Caching."
Before You Begin
The steps that follow assume that you have:
Followed through and understood Section 29.2.3, "How to Create a PDK-Java Portlet."
Built a portlet using the wizard and successfully added it to a page.
To use the caching features in your producers, you must first activate the middle tier cache. This cache is known as the PL/SQL Cache because it is the same cache used by mod_plsql, the Oracle HTTP Server plug-in that calls database procedures, and hence database producers, over HTTP.
Usually, your administrator is responsible for the configuration details of caching.
Expiry-based caching is a simple caching scheme to implement, and can be activated declaratively in your XML producer definition. You can set an expiry time for the output of any ManagedRenderer
you use by setting its pageExpires
property to the number of minutes you want the output to be cached for. For example, suppose you want portlet output to be cached for one minute.
To add expiry-based caching:
After you have used the Portlet Wizard to build a portlet as described in Section 29.2.3, "How to Create a PDK-Java Portlet," edit the provider.xml
file and set the pageExpires
property tag of showPage to 1. This sets an expires entry of 1 minute for the portlet.
By default the wizard generates a standard and compressed tag for showPage
. Expand the tag to include a subtag of pageExpires
:
<showPage class="oracle.portal.provider.v2.render.http.ResourceRenderer">
<resourcePath>/htdocs/mycacheportlet/MyCachePortletShowPage.jsp
</resourcePath>
<pageExpires>1</pageExpires>
</showPage>
For more information about the syntax of provider.xml
, see the provider JavaDoc on OTN:
http://www.oracle.com/technology/products/webcenter/portlet_download.html
Test that the portlet is cached for 1 minute by adding some JSP code to your show page. You can simply add the current time to your JSP.
<%@page contentType="text/html; charset=windows-1252" import="oracle.portal.provider.v2.render.PortletRenderRequest" import="oracle.portal.provider.v2.http.HttpCommonConstants" import="java.util.Date" import="java.text.DateFormat" %> <% PortletRenderRequest pReq = (PortletRenderRequest) request.getAttribute(HttpCommonConstants.PORTLET_RENDER_REQUEST); DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG,pReq.getLocale()); String time = df.format(new Date()); %> <P>Hello <%=pReq.getUser().getName() %>.</P> <P>This is the <b><i>Edit</i></b> render mode!</P> <P>This information is correct as of <%=time%>.</P>
When viewing the portlet, you see that the time (including seconds) is constant for 1 minute. After the time has expired, the portlet displays the most current time and a new cache is set.
Adding validation-based caching requires slightly more effort, but gives you explicit control over exactly which requests to your producer are cache hits. As an example, you may want to update the cache only when data within the portlet has changed. To implement this algorithm, you must override the prepareResponse
method. The signature of the BaseManagedRenderer.prepareResponse
method is:
public boolean prepareResponse(PortletRenderRequest pr) throws PortletException, PortletNotFoundException
In your version of prepareResponse()
, do the following:
Retrieve the cached version identifier set by the PPE in the render request by calling the HttpPortletRendererUtil.getCachedVersion()
method:
public static java.lang.String getCachedVersion (PortletRenderRequest request)
If the portlet finds the previously cached version valid, then the appropriate header has to be set by calling the HttpPortletRendererUtil.useCachedVersion()
method. It also instructs the RenderManager
that it won't be necessary to call renderBody()
to render the portlet body.
public static void useCachedVersion(PortletRenderRequest request)
Otherwise, use HttpPortletRendererUtil.setCachedVersion()
to generate a new version of the portlet, which is cached. It also indicates to the PPE that the renderBody()
method has to be called to regenerate the portlet content.
public static void setCachedVersion(PortletRenderRequest request, java.lang.String version, int level) throws java.lang.IllegalArgumentException
For validation-based caching, you need not update provider.xml
. You can view the portlet by refreshing the page or adding the portlet to a page and updating the content. If the content has changed, then the portlet shows the new content. If the content has not changed, then a cached version of the portlet is displayed.
If you have implemented personalization for your portlet, then the Personalize link only appears on the portlet for authenticated users. Hence, to test the personalization of a portlet (the Personalize link), you must have some form of security implemented for the application consuming the portlet. For testing purposes, you may prefer to just configure the most basic authentication possible. For more information, see Section 24.8, "Configuring Basic Authentication for Testing Portlet Personalization."
This section describes the framework for building Struts portlets with Oracle JDeveloper for use in a custom WebCenter application. You will learn how to build a Struts portlet from an existing application by adding the Struts Tag Library from the Oracle Portal Developer Kit (version 9.0.4.0.2 or later) to JDeveloper, then use the Oracle PDK Java Portlet wizard to create the Java portlet itself.
Oracle PDK contains extensions to integrate Apache Struts applications. This section explains how to build a portlet from an existing struts application. You can also follow these steps to create a portlet that uses the Model View Controller paradigm. The PDK-Java extensions described in this section rely on Apache Struts 1.1.
The Oracle PDK-Java contains numerous examples and documents regarding the usage of the APIs, such as personalization and caching. The integration of the application flow and business logic is not part of the portlet APIs. By using the Struts framework, however, you can leverage the MVC architecture to create and publish applications within your enterprise portal.
To create a portlet using the Struts framework, or to generate a portlet from an existing Struts application, you must deploy all the components in the Java EE container. In WebCenter, the Struts application is called by the PPE, and not by the browser as compared to a standalone Struts application. When a portlet show call is made, the page engine sends a request to the Struts portlet renderer, which then forwards the request to the Apache Struts Controller servlet, as shown in Figure 30-4.
Figure 30-4 Integrating Struts Applications with Oracle Portal
The following code shows a portion of the producer definition file (provider.xml
):
... <renderContainer>true</renderContainer> <renderCustomize>true</renderCustomize> <autoRedirect>true</autoRedirect> <contentType>text/html</contentType> <showPage class="oracle.portal.provider.v2.render.http.StrutsRenderer"> <defaultAction>showCustomer.do</defaultAction> </showPage> </renderer> ...
For more information about the syntax of provider.xml
, see the provider JavaDoc on OTN:
http://www.oracle.com/technology/products/webcenter/portlet_download.html
The showPage
tag defines the business logic that is executed in the portlet mode of the portlet. The showPage
of the Struts portlet contains two important components, which are as follows:
The renderer class (oracle.portal.provider.v2.render.http.StrutsRenderer
), which receives the portlet request from the PPE and acts as a proxy to forward the request to the Struts Action Servlet.
The defaultAction
tag, which defines the Struts action that is used by default when the portlet is called for the first time.
The PDK-Java enables you to easily develop a view (Portal View) of your Struts application. This view enforces a consistent look and feel of your Struts portlet using portal styles, and enables the end user to use the application within the portal.
To create a Struts portlet, you must use the Oracle Portal JSP tags, which are extensions of the default Struts JSP tags. This development process is similar to that of creating a standalone Struts application. Also, as the portlet and struts application must also be in the same Servlet Context, you must create a single Web application that contains both elements.
To publish a part of an existing Struts application as a portlet, Oracle recommends that you first create a new view to serve as the Portal View of your application. This view uses existing objects (Actions
, ActionForm
, and so on) with a new mapping and new JSPs.
Note:
Although Oracle recommends that you create a Portal View of your application, you could alternatively replace your application's struts tags with PDK-Java struts tags. This approach enables your application to run both as a standalone struts application and a portlet.In this example, you will create a portlet that enables you to add a new entry to a blog. Figure 30-5 and Figure 30-6 show how you submit a blog and save a blog entry.
prepareNewBlog
is a simple empty action that redirects the request to the enterNewBlog.jsp
page. This page shows a form for submitting a new blog.
The corresponding entry in the struts-config.xml
is:
<action path="/prepareNewBlog" scope="request" type="view.PrepareNewBlogAction" > <forward name="success" path="/view/enterNewBlog.jsp"/> </action> <action path="/saveNewBlog" name="blogForm" scope="request" type="view.SaveNewBlogAction" input"/view/enterNewBlog.jsp" > <forward name="success" path="/view/newBlogConfirmation.jsp"/> </action>
To create a new view, first create a new set of ActionMappings
(page flow) that redirects the various actions and requests to Portal-specific JSPs.
<action path="/portal/prepareNewBlog" scope="request" type="view.PrepareNewBlogAction" > <forward name="success" path="/view/portal/enterNewBlog.jsp"/> </action> <action path="/portal/saveNewBlog" name="blogForm" scope="request" type="view.SaveNewBlogAction" input="/view/enterNewBlog.jsp" > <forward name="success" path="/view/portal/newBlogConfirmation.jsp"/> </action>
As you can see, only the path attributes are modified. The FormBean
Action responsible for the application business logic remains unchanged.
As specified in the previous step, the actions forward the request to new JSPs, which are responsible for rendering the portlet content. Your new portlet view JSPs can share the HTML with the standalone view, but ensure the portlet meets the following criteria:
Uses styles that enforce a consistent look and feel with the rest of the page.
Contains HTML code that is allowed in HTML table cells (that is, no <html>
, <body>
, and <frame>
tags).
Renders application-aware links and forms. This is necessary to ensure that your Struts portlet renders its content inline, thus keeping your users within the page by rendering the requested content within the same portlet container.
To achieve inline rendering in your Struts portlet, you must use Oracle PDK tags:
<pdk-struts-html:form action="/portal/saveNewBlog.do"> ... ... </pdk-struts-html:form>
During the rendering of the portlet, a JSP tag (for example, the pdk-struts-html:form
tag), submits the form to the Parallel Page Engine (PPE), which then sends the parameters to the Struts portlet. The Struts controller executes the logic behind these actions and returns the next JSP to the portlet within the portal page.
The PDK contains all the Struts tags, and extends all the tags that are related to URLs. The following is a list of the PDK extended tags:
form
: creates an HTML form and embeds the portal page context in the form to ensure inline rendering
text
: renders fields on the form.
link
and rewrite
: create a link to the portal page, and are required for inline rendering
img
: creates an absolute link that points to the producer. To use this tag in Internet Web sites that have firewalls, you must make sure the producer is directly accessible from the Internet. If it is not possible, then you can deploy the images to the middle tier and use the Apache Struts image link to generate a relative link (relative to the portal, not to the application).
Note:
You can register the Oracle PDK with Oracle JDeveloper so that you can drop the tags from the Oracle JDeveloper Components Palette. For more information, see the Registering a Custom Tag Library in JDeveloper section in the Oracle JDeveloper online Help.You can create your Struts portlet either manually or by using the Java Portlet Wizard. Although the wizard does not explicitly offer Struts support, you can use the wizard to build your Struts portlet.
To create a portlet:
In Oracle JDeveloper, open the Java Portlet Wizard to create an Oracle PDK Java Portlet.
Note:
The Java Portlet and Oracle PDK Java Portlet options are used to create JSR 168-compliant portlets and PDK-Java portlets respectively. Clicking Java Portlet or Oracle PDK Java Portlet opens the Java Portlet Wizard. For more information about opening the wizard, see Section 29.2.3, "How to Create a PDK-Java Portlet."For the Implementation Style of the show page, select Java Class.
For the Package Name, enter oracle.portal.provider.v2.render.http
For the Class Name, enter StrutsRenderer
. This generates the skeleton of the portlet renderer class, StrutsRenderer
.
As the StrutsRenderer
is part of the PDK, you do not need this generated file. So, when you finish the wizard, you must delete the file generated by the wizard. To do so, click the file in the System Navigator window, then from the File menu, select Erase from Disk in Oracle JDeveloper.
Edit the provider.xml
and change the following properties:
At the producer level, perform the following:
If you want users to always return to the same portlet state as when they left the container page, then you can configure the struts renderer to save the struts action in the struts context:
<actionInSession>true</actionInSession>
If you prefer that users always start from the beginning of the portlet when they return from outside the container page, then you should not save the struts action:
<actionInSession>false</actionInSession>
Note that this setting is the default behavior.
If the Struts application uses sessions (for example, the form sysnchronizer token mechanism is used or <actionInSession>
is set to true), then enable session handling:
<session>true</session>
At the portlet level, perform the following:
Specify the first action to raise when the portlet is called. Use the following code:
<showPage class="oracle.portal.provider.v2.render.http.StrutsRenderer"> <defaultAction>/portal/prepareNewBlog.do</defaultAction> </showPage>
For more information about the syntax of provider.xml
, see the provider JavaDoc on OTN:
http://www.oracle.com/technology/products/webcenter/portlet_download.html
In your application, you should add code specific to your environment, such as the user's information, personalization, and localization. To do so, you can create a new Action
class that is only called in context, and handles all business logic.
Now that your portlet is ready to be used by consumers, you must make it accessible by registering it. For information about how to register your PDK-Java portlet, see Section 33.4, "Registering and Viewing Your Portlet".