How to use the Portlet Specification 2.0 Tag library in WebSphere Portal 6.1

If your building a JSR 286 compliant portlet and want to use one of the new tags introduced in JSR 286 such as resourceURL then you will have to include the http://java.sun.com/portlet_2_0 tag library in your JSP like this


<%@page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>

<portlet:defineObjects />
<a href='<portlet:resourceURL />'>Resource URL </a>


By default when you create a portlet JSP in RAD 7.5 it always adds Portlet Specification 1.0 related tag library like this <%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%> and with this you cannot use newer tags

Increasing no. of parallel downloads from same host

Most of the web 2.0 sites are rich in nature, by that i mean they have more than 30 resources( CSS, images, .js files). One disadvantage of the rich site is that it slows down the end user experience.

If you look at the portal site in firebug Net panel you will notice that the downloading of basic HTML takes less than 20-30 % time but major chunk of time is spent in downloading resources.

Basic problem is that the browsers use limited no. of connections for downloading resources from one host.Firefox 3.6, IE 8.0 use 6 and older browsers such as IE 6 or IE 7 use only 2 connections. So if your site has say 30 resources IE6 wont download all of them at the same time instead it will download 2 resources at a time. In one of the tests that i done i realized that the same site takes 1.5-2 times as long to render on IE 6 compared to IE 8 or Firefox

Both IE and Firefox allow you to change no. of parallel connections that should be used to download. This link has information on How do I configure Internet Explorer to download more than two files at one time?

You can make similar changes in Firefox by going to about:config and then changing value of network.http.max-persistent-http-connection-per-server.




We cant expect users to change the registry settings or change firefox configuration for your site. But these are nice to know tricks when debugging performance issues

Schema file for the xmlaccess

IBM WebSphere POrtal Server Infocenter or the other documentation from IBM does not have much information about the xmlaccess and what all elements it has, what are the attributes that they support and what should be there value.

I always thought that if i could somehow look into the .xsd file for xmlaccess then it would be a big help but did not know where to find it. TOday i realized that those files are in the WebSphere/wp_profile/installedApps/DefaultNode/wps.ear/wps.war/dtd/. It seems that it has the latest .xsd as well as all the .xsd for older version of portals server. This is how my dtd folder looks like



I wanted to find out more information about the PortalCOnfig_1.4.xsd, which is the default version for WPS 6.1.5 so when i opened it in Text Editor, this is what i found. As you can see it has lot of useful information

Using the serveResource() method for serving static Content

If you take a look at the implementation of serveResource() method in the GenericPortlet.java class you will notice that it is implemented like this


public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException {
if (request.getResourceID() != null) {
PortletRequestDispatcher rd = getPortletConfig().getPortletContext().getRequestDispatcher(
request.getResourceID());
if (rd != null)
rd.forward(request, response);
}
}


As you can see the default implementation reads the request.getResourceID() and forwards requests to that URL for generating response.

So lets say if i have a sampleimg.gif in my portlet .war file then i can include it in JSP either using the encodeURL method or using the serveResource() method like this

<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model" prefix="portlet-client-model"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portletx"%>

<portlet:defineObjects />


<%
javax.portlet.ResourceURL url = renderResponse.createResourceURL();
url.setResourceID("/sampleimg.gif");
%>

<img src='<%= url.toString() %>' />


If you take a look at the HTML generated by this


/wps/myportal/!ut/p/c5/hZC7DoJAEEW_xcJSZ9ThYbkShVUUWeMDG7MhK24CYkTx9wVtbJA75ZmT3Fw4QnVXWepEPnR-lSkc4GiedjvuLxfuAG2aMeSOycRkGg4QseKReXJc5pHlI9rcIeQ0CcRwGqA7N2u7iQpqsanF3tdtGz-Qj74cG8Lwr_9p_5cTrLw8UxBBZP1sZMzGyDdEcxEaI3SHsL-rIn_eYwWii4XMbqnSWdJP9BnCWMYX5atSpWuZKLhl2wNq3rNfrPMG5V2x7Q!!/


As you can see the resourceID is encoded in the URL and this URL is pointing to the portal engine so it will enter through portal engine and then control will be forwarded to the sampleimg.gif. Using the serveResource() for including static content is not a good idea because it will require more processing power than including a normal file serving.

The PortletResponse.encodeUrl() in WSRP portlet

In the How the PortletResponse.encodeUrl() method works method i mentioned that the PortletResponse.encodeUrl() method does not have any effect on the URL generated.But you must use it if you want your static resource serving to work in the WSRP Portlet.

I do have this sample ResourceServing.war portlet, which is very simple only thing that the Portlet does is forward control to the resource.jsp. And the resource.jsp includes a sampleimg.gif file in the markup like this


<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model" prefix="portlet-client-model"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portletx"%>

<portlet:defineObjects />
<b><img src='<%= renderResponse.encodeURL("renderRequest.getContextPath() + "/sampleimg.gif") %>' /></b>


As i mentioned in the previous post the renderRequest.getContextPath() returns the context root where your portlet application is installed. Which is sufficient to get URL to resource. But in case of WSRP that is not sufficient. In case of WSRP the request for /sampleimg.gif should first go to the consumer portal which will do the tunneling to get the request from the producer portal (If your producer portal is directly available to the user then you can also create hard-coded URL pointing to the producer portlet in the markup but its not recommended practice)

In case when the ResourceServing portlet is served through WSRP the above JSP will generate this HTML Markup

<img src="/wps/WsrpProxyPortlet/ResourceProxy/PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48dT48Yj5odHRwOi8vbG9jYWxob3N0OjEwMDQwPC9iPjxwPjxuPndzcnAtc2VjdXJlVVJMPC9uPjx2PmZhbHNlPC92PjwvcD48cD48bj53c3JwLXVybFR5cGU8L24-PHY-cmVzb3VyY2U8L3Y-PC9wPjxwPjxuPnA8L24-PHY-MTJfVlZJTE1LRzEwODVGOTBJUzQ0SlJRNTMwMDc8L3Y-PC9wPjxwPjxuPmc8L24-PHY-MV9WVklMTUtHMTA4NUY5MElTNDRKUlE1MzAwMDwvdj48L3A-PC91Pg!!/SjPAEvQqcAICDYyb-sViNKWZad0!/wps/PA_ResourceServing/sampleimg.gif">


As you can see the image URL is pointing to the consumer portal server at /wps/WsrpProxyPortlet/ResourceProxy then there is a big token with session information,.. And at the end of the URL is the actual URL of the sampleimg.gif on the producer portlet.

I thought i should take a closer look at /wps/WsrpProxyPortlet/ResourceProxy URL. THe /wps/WsrpProxyPortlet points to the PA_PortalWSRPProxy.ear file. The application.xml for that file is like this

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE application PUBLIC "-//Sun Microsystems, Inc.//DTD J2EE Application 1.3//EN" "http://java.sun.com/dtd/application_1_3.dtd">
<application id="Application_ID">
<display-name>wsrpproxy_war</display-name>
<module>
<web>
<web-uri>wsrpproxy.war</web-uri>
<context-root>/wps/WsrpProxyPortlet</context-root>
</web>
</module>
</application>


The PA_PortalWSRPProxy.ear has wsrpproxy.war file which includes the com.ibm.wps.wsrp.consumer.std.impl.ProxyPortlet portlet, which is proxy portlet for consuming WSRP portlet. WHen i looked at the web.xml for that portlet it has a com.ibm.wps.wsrp.consumer.std.impl.ResourceProxy Servlet which is supposed to handle the /ResourceProxy URL.


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="com.ibm.wps.wsrp.proxyportletapp">
<display-name>PortalWSRPProxyPortlet</display-name>
<servlet>
<servlet-name>resourceproxy</servlet-name>
<servlet-class>com.ibm.wps.wsrp.consumer.std.impl.ResourceProxy</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>resourceproxy</servlet-name>
<url-pattern>/ResourceProxy/*</url-pattern>
</servlet-mapping>
</web-app>



In case of WSRP portlet, when it comes to serving a static request, it will first go to the the ResourceProxy servlet on the consumer portal and then ResourceProxy servlet will forward it to the producer portal for getting response and then return that response to the browser

How the PortletResponse.encodeUrl() method works

I was looking for information about encodeURL() method and this is what i found

Portlets should encode all resource URLs pointing to resources in the portlet application via this method in order to ensure that they get served via the portal application. Some portal/portlet-container implementation may require those URLs to contain implementation specific data encoded in it. Because of that, portlets should use this method to create such URLs.
The encodeURL method may include the session ID and other portal/portlet-container specific information into the URL. If encoding is not needed, it returns the URL unchanged. Portlet developer should be aware that the returned URL might not be a well formed URL but a special token at the time the portlet is generating its content. Thus portlets should not add additional parameters on the resulting URL or expect to be able to parse the URL. As a result, the outcome of the encodeURL call may be different than calling encodeURL in the servlet world.


As you can see its very difficult to understand how it works so i did some experiment to figure out the exact behavior

When you want to include a static resource in your portlet for example a image or JavaScript file that is packaged inside your portlets .war file you can include it like this

<%= renderResponse.encodeURL(renderRequest.getContextPath() + "filepathinsidewebmodule") %>


For example i want to include sampleimg.gif which is at the root of my web application i.e. at the same as that of WEB-INF then i can include it my application using this URL


<img src='<%= renderResponse.encodeURL(renderRequest.getContextPath() + "sampleimg.gif") %>'>


This JSP code will get converted into following HTML markup

/wps/PA_ResourceServing/sampleimg.gif


In this the /wps/PA_ResourceServing part is the application context of the portlet which contains this URL.

You can find the context root of the portlet in two ways. While deploying the portlet in 6.1 it lets you set the context root for the portlet. You can find the context root of a portlet which is already installed by going to /wp_profile/installedApps/DefaultNode/yourportlet.ear directory and then inside META-INF there will be application.xml, open it and you will notice it is something like this


<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Application_ID" version="1.4" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/application_1_4.xsd">
<display-name>ResourceServing_war</display-name>
<module>
<web>
<web-uri>ResourceServing.war</web-uri>
<context-root>/wps/PA_ResourceServing</context-root>
</web>
</module>
</application>


As you can see in my case the ResourceServing.war file is installed at the /wps/PA_ResourceServing URL.

Inside your JSP you can find this context root by calling renderRequest.getContextPath(). The encodeUrl() does not have any effect of the URL. But you should always include your URL

Finding out the fix packs, fixes installed on from SystemOut.log

When you start WebSphere Portal Server, first it prints out the list of fixes installed on WebSphere Application Server. Then the WAS will start j2ee applications one by one and when it comes to starting websphere portal application, it lists out all the fixes that are installed on WPS in SystemOut.log like this

As you can see it lists out the fix ids along with short description of that fix PK81425 (WSRP Consumer cannot handle multiple cookies in Set-Cookie header)


[2/22/10 11:41:32:845 CST] 00000026 WebApp A SRVE0180I: [wps#wps.war] [/cisco] [Servlet.LOG]: ServiceManager: Loading from file:/opt/ibm/cepapp-nprd1-01/dev/samba/websphere/current/appserver/profiles/node01/PortalServer/config/config/services.properties
[2/22/10 11:41:32:891 CST] 00000026 LogManagerDef I com.ibm.wps.logging.LogManagerDefaultImpl init
--------------------------------------------------------------------------------
IBM WebSphere Portal 6.1.0.1

Licensed Materials - Property of IBM
5724-E76, 5655-R17, and 5655-M44
(C) Copyright IBM Corp. 2001, 2007 - All Rights Reserved.
US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
--------------------------------------------------------------------------------
Build Level:
wp6101_115_01 (2008-11-15 11:04)
--------------------------------------------------------------------------------
[2/22/10 11:41:33:206 CST] 00000026 ServiceLogger I com.ibm.ws.ffdc.IncidentStreamImpl initialize FFDC0009I: FFDC opened incident stream file /opt/httpd/logs/apps/samba/dev/cepapp-nprd1-01/ffdc/portal_node01_00000026_10.02.22_11.41.33_0.txt
[2/22/10 11:41:33:285 CST] 00000026 ServiceLogger I com.ibm.ws.ffdc.IncidentStreamImpl resetIncidentStream FFDC0010I: FFDC closed incident stream file /opt/httpd/logs/apps/samba/dev/cepapp-nprd1-01/ffdc/portal_node01_00000026_10.02.22_11.41.33_0.txt
[2/22/10 11:41:33:521 CST] 00000026 ProductServic I com.ibm.wps.services.product.ProductServiceImpl findInstalledFixes EJPFD0051I: The following fix packs have been installed:
WP_PTF_6101 (IBM WebSphere Portal, Version 6.1.0.1 Fix Pack)
[2/22/10 11:41:33:636 CST] 00000026 ProductServic I com.ibm.wps.services.product.ProductServiceImpl findInstalledFixes EJPFD0053I: The following fix packs have been installed:
PK76960 (Creating URL Mapping to a child page in VP doesn't work properly)
PK76660 (Stale value exception editing data before DST time change)
PK81425 (WSRP Consumer cannot handle multiple cookies in Set-Cookie header)
PK79235 (Invalid action identifier caused by wrong user session key)
PK82601 (Invalid action IDs caused by legacy portlet state manager )
PK77174 (PZN:Profilers should allow users to directly edit lists)
PK77497 (PZN:Update CAF and runtime logging to use portal admin portlet trace settings)
PK77734 (PZN:Web Content and Site Area pickers are slow in large sites)
PK78529 (PZN:nullpointer exception when create visibility rule)
PK80778 (Pzn Picker not showing proper choices initially)
PK81996 (PZN editor text entry field, changing blank to another value)
PK82085 (PZN:Use WCM api to get document ID)
PK83587 (PZN:Perf: Misc. pzn performance improvements)
PK85090 (PZN:RuleMappings may not execute)
PM04793 (PZN:ItemNotFoundException from Content Spot Rule execution)
PK75569 (Delete virtual portal having exceptions)
PK76988 (Cluster Performance Degradation by PK72702 - large amount of DRS invalidation messages)

Finding out the fix packs, fixes installed on WAS from SystemOut.log

When the WebSphere Application Server or portal server is starting up the first thing that it does is write list of fixes, fix packs installed on that server in the SystemOut.log

This is content from one of the WebSphere Server that i have as you can see it has lisiting of fixes on was as well as Java SDK fixes

************ Start Display Current Environment ************
WebSphere Platform 6.1 [ND 6.1.0.21 cf210844.13] running with process name portalcell\node01\WebSphere_Portal and process id 28991
Detailed IFix information: ID: was.server.common.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: sdk.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: was.embed.FP61021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: was.ndonly.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: 6.1.0-WS-WAS-LinuxX32-FP0000017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: was.ndonly.FP61021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: was.server.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: was.embed.common.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: 6.1.0-WS-WAS-LinuxX32-FP0000021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: was.license.FP61021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: was.embed.common.FP61021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: was.server.FP61021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: was.itlm.nd.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: was.ndonly.common.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: was.embed.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17
ID: was.itlm.nd.FP61021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: was.server.common.FP61021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: 6.1.0-WS-WASSDK-LinuxX32-FP0000017 BuildVrsn: null Desc: Software Developer Kit 6.1.0.17
ID: was.ndonly.common.FP61021 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.21
ID: was.license.FP61017 BuildVrsn: null Desc: WebSphere Application Server 6.1.0.17

How to read the LTPA Token using API

Recently i had a requirement to read the LTPA Token from API and pass it to the third party application that i am using

We have two options to do this

  • Cookie: You can use the LtpaToken from the cookie. This approach works in all cases but one, which is that as soon as you login the first request wont have this cookie.

  • Programmatic API: You can always read the LtpaToken from the cookie




private String doesLTPATokenCookieExists(PortletRequest servletRequest){
HttpServletRequest servletRequest =(PortletRequest)request;

Cookie[] cookie =servletRequest.getCookies();
for(int i = 0 ; i < cookie.length ;i++){
System.out.println("Cookie Name " + cookie[i].getName() );
if( cookie[i].getName().equals("LtpaToken"))
return cookie[i].getValue();
}
return false;
}


In cases where the portlet is rendering on a first page that gets invoked after login the LtpaToken wont be there in the cookie. The basic idea is portal server will generate LtpaToken and send it in first response and thereafter the request will always have the LtpaToken cookie but that first request wont have the LtpaToken cookie, in those cases we can use this programmatic method for reading cookie


private String getSecurityToken(){
byte[] token = null;
try{
// Get current security subject
Subject security_subject = WSSubject.getRunAsSubject();
if (security_subject != null){
// Get all security credentials from the security subject
Set security_credentials =
security_subject.getPublicCredentials(WSCredential.class);

// Get the first credential
WSCredential security_credential =
(WSCredential)security_credentials.iterator().next();
String user = (String) security_credential.getSecurityName();
if(user.equalsIgnoreCase("UNAUTHENTICATED")){
return null;
}
token = security_credential.getCredentialToken();
if(token == null){
return null;
}
String ltpaToken =
com.ibm.ws.webservices.engine.encoding.Base64.encode(token);
return ltpaToken;
}
}
catch (Exception e){
e.printStackTrace();
}
return null;
}