Introduction
HTTP is a stateless protocol. Many web designers have utilized a combination of cookies, parameters in URLs, and other techniques to preserve state information for users visiting their websites. WebSphere Portal as a part of its design simplifies the stateless nature of HTTP and automatically encodes state information into its URLs. WebSphere Portal also encodes navigation information into its URLs (e.g. language, back button behavior, etc.). Decoding techniques do exist to decipher the URLs but by default WebSphere Portal encoded URLs cannot be viewed in plaintext and easily determine what information the URL contains.
An unfortunate side effect of encoding all of this information into the URLs is that WebSphere Portal URLs tend to be long and ugly out of the box. For example, if you access the default Portal page by its stateless URL - e.g. http://myportalsite.ibm.com:10039/wps/portal, this is automatically redirected to a stateful URL such as:
http://myportalsite.ibm.com:10039/wps/portal/!ut/p/a0/04_Sj9CPykssy0xPLMnMz0vMAfIj83Kt8jNTrMoLivV88tMz8_QLsh0VAVTAxWw!/
This article will discuss techniques to keep the Portal URLs short and clean.
2015.10.30 EDIT: Portal 8.5 cumulative fix 08 has introduced several configuration options which simplifies creating stateless URLs. See the 8.5 Infocenter for more details. This blog entry will be updated in the near future to discuss how the new parameters introduced in CF08 will interact with other configuration settings noted in this blog entry.
Out of the Box Settings
For WebSphere Portal 6.1 and later the out of the box settings will generally result in a stateful URLs. There are two primary factors that play into whether or not a stateful URL will be display:
1) The type of page - standard page or static page
2) The type of URL - a URL mapping, a Friendly URL, or a Vanity URL (8.5 and newer only)
For #1, Portal 6.1 and earlier utilized standard pages for its default page type. These were shipped with pre-defined page layout templates provided by IBM code and once portlets were added to the page they largely didn't change. Over time it was determined a new design was needed to allow for more flexibility, hence the use of static pages. Portal 7.0 and later utilized static pages for its default page type. Static pages offers many advantages over standard pages, one in particular is "You can include portlets as dynamic elements and containers as placeholders for portlets in your pages. You can display these portlets by using server side aggregation, AJAX". The general recommendation would be to utilize static pages in your WebSphere Portal design.
For #2, Portal 6.0 and earlier offered URL Mappings as a short and clean means of managing URLs. URL Mappings were not dependent on the Portal page hierarchy, hence, a URL Mapping of /wps/myportal/thisblogentry may resolve to /wps/myportal/US/en/IBM/Industry/Cloud/Solutions/WebSphere/Portal/Support/This/Blog/Entry. Over time management of URL mappings becomes difficult for large Portal sites. Portal 6.1 began offering a new feature called Friendly URLs. Friendly URLs are dependent on the Portal page hierarchy and as a result allowed for simplified management of URLs. URL Mappings and Friendly URLs are for the most part mutually exclusive ... you should try to design your Portal site with one of the two, but not both, and the recommendation would be to utilize Friendly URLs given URL mappings are now deprecated with Portal 8.5. Finally, in Portal 8.5 a new type of URL - called a vanity URL - was introduced. Vanity URLs are a complement to Friendly URLs. Friendly URLs are still available and are dependent on the site hierarchy, while vanity URLs are not dependent on the site hierarchy. Using the same example above, a vanity URL of /wps/vanityurl/thisblogentry could be created that would resolve to an actual page in the Portal page hierarchy. Vanity URLs are advantageous in cases where we want a VERY short and clean URL that does not contain the entire page hierarchy information, such as a Friendly URL. For purposes of this blog entry, we will assume every page in your page hierarchy has either a Friendly URL or URL Mapping to allow for stateless URLs. If your Portal site does not have either a Friendly URL or URL Mapping on it and you implement the steps below, some pages may no longer be accessible.
Returning to our stateful vs. stateless discussion, we have 2 * 3 = 6 possible combinations above. With the out of the box settings, here is what should happen:
- Standard Page + URL Mapping = Stateless
- Standard Page + Friendly URL = Stateless
- Standard Page + Vanity URL = Stateful
- Static Page + URL Mapping = Stateful
- Static Page + Friendly URL = Stateful
- Static Page + Vanity URL = Stateful
Note in particular that the fifth combination - Static Page + Friendly URL - is the recommended settings for WebSphere Portal. While an end user may be able to bookmark a short and clean url, e.g. /wps/myportal/Home/somefriendyurl, WebSphere Portal in its design will automatically 302 redirect the user to the stateful URL. The page will render successfully, but the URL in the address bar looks long and ugly. In the next section we'll discuss how to modify that behavior so it stays short and clean.
Primary references
1) The Portal 8.0 and 8.5 Infocenters offer some excellent details on how to make Portal stateless. However, there are multiple settings noted in the Infocenter and not all settings may be required for all Portal deployments. We'll explore each setting one by one.
2) The Chief Programmer of WebSphere Portal URLs has a presentation discussing the design elements of stateful URLs available here:
http://www.socialbizug.org/files/app#/file/443ae822-48ad-40d1-b106-8750f0e79447
Change #1 - Theme change with XMLAccess
1) The primary setting of interest is the hasBaseURL setting. From a Portal 85x system, I implemented this parameter via an XMLAccess script as follows:
<?xml version="1.0" encoding="UTF-8"?>
<request build="20140424-1749" type="update" version="8.5.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="PortalConfig_8.5.0.xsd">
<portal action="locate">
<theme action="update" active="true" context-root="/wps/defaultTheme85" default="true" defaultskinref="ZK_00000000000000A0BR2B300670" domain="rel" objectid="ZJ_00000000000000A0BR2B300QC6" resourceroot="dynamicSpots" uniquename="ibm.portal.85Theme">
<parameter name="com.ibm.portal.theme.hasBaseURL" type="string" update="set"><![CDATA[true]]></parameter>
</theme>
</portal>
</request>
After changing this setting, I observed the following results:
- Standard Page + URL Mapping = Stateless
- Standard Page + Friendly URL = Stateless
- Standard Page + Vanity URL = Stateful (redirects to stateful Friendly)
- Static Page + URL Mapping = Stateless
- Static Page + Friendly URL = Stateless
- Static Page + Vanity URL = Stateful (redirects to stateful Friendly)
*Author technical note: I had to manually create a new URL mapping via an XMLAccess script for the Standard Page + URL Mapping test.
Change #2 - friendly.redirect.enabled
2) Our second setting of interest is friendly.redirect.enabled noted on the following Infocenter page. To summarize the effect this setting has on your Portal environment:
- true (default) = send redirect to url with Friendly URL if comes in stateful WITHOUT friendly URL context send it to a Friendly URL ... hasBaseURL will then determine if it stays stateless, or, redirects to Friendly URL + stateful --> GOOD for Friendly URLs
- false = no redirect is sent "a request for a URL mapping will be served an HTTP 200 and the page content rather than a 302 redirect to the URL with navigational state encoded" --> GOOD for URL Mappings
Portal 85x environments should be moving away from URL Mappings, however, if your environment is migrated you may still have some URL Mappings in place and wish to have this setting as false. I did not enable this setting in my 8.5 environment given I am not using URL mappings and wanted the remote possibility of an end user coming in from a stateful URL with friendly URL context to be handled. However, this setting also affects 302 vs. 404 behavior in Portal, in addition to stateless vs. stateful behavior and you may wish to set it to false in a system with Friendly URLs only and no URL mappings. See this Technote for more details.
Change #3 - URL generation in themes
3) Our third setting is the navigation.jsp files. OK, so what exactly are these things if the tests in #1 above resulted in stateless URLs? The tests in #1 assume the user is coming into the Portal via a link sent by email, a bookmarked link, etc. If the user is already IN the Portal and navigation around by clicking the navigation at the top/sides of the page, this is where the navigation.jsp files come into play.
For example: If I manually enter my friendly URL, it retain this same friendly URL, short and clean, in the address bar:
http://myportalsite.ibm.com:10039/wps/myportal/Home/Welcome
However, if I hover over the same link at the top of the page and click it - I observed the following result:
http://myportalsite.ibm.com:10039/wps/myportal/Home/Welcome/!ut/p/z1/04_Sj9CPykssy0xPLMnMz0vMAfIjo8ziDVCAo4FTkJGTsYGBe7CBfjheBf5G-lFAaX9_H1d3I38DbwNHQzcDR2dfQ3_3EC9DAxcjrPqRTSJOPx4FUYTcH4VXCcgHWBSgOLEgNzQ0wiDTEQDA0a2H/dz/d5/L2dBISEvZ0FBIS9nQSEh/?uri=nm%3Aoid%3AZ6_00000000000000A0BR2B300GS0
For purposes of this blog entry, I performed an edit of these files on the Portal 85 default theme. HOWEVER, cumulative fixes installation may overwrite these files and it is NOT RECOMMENDED to change the default Portal 85 theme files. You should copy the theme and modify per your business requirements, implementing the navigation.jsp changes as needed. Once the files were edited, my navigation.jsp looked like the following modified:
My updated navigation.jsp under wp.theme.themes (which will affect the Welcome, Getting Started, etc. links) looked like:
<portal-navigation:urlGeneration contentNode="${nodeID}" keepNavigationalState="false"><a href="<%wpsURL.write(out);%>" class="wpthemeLeft<c:if test="${childrenStatus.count == 1}"> wpthemeFirst</c:if>"><span lang="${node.title.xmlLocale}" dir="${node.title.direction}"><c:choose><c:when test="${node.projectID != null}">(<c:choose><c:when test="${isHiddenPage}">[<c:out value="${node.title}"/>]</c:when><c:otherwise><c:out value="${node.title}"/></c:otherwise></c:choose>)</c:when><c:when test="${isHiddenPage}">[<c:out value="${node.title}"/>]</c:when><c:otherwise><c:out value="${node.title}"/></c:otherwise></c:choose><c:if test="${selectedNodeID == nodeID}"><span class="wpthemeAccess"> <portal-fmt:text key="currently_selected" bundle="nls.commonTheme"/></span></c:if></span></a></portal-navigation:urlGeneration>
My updated navigation.jsp under wp.theme.modules was slightly different and looked like
<portal-navigation:urlGeneration contentNode="${nodeID}" keepNavigationalState="false"><a href="<%wpsURL.write(out);%>"<c:choose><c:when test="${wp.selectionModel[node] != null}"><strong><span lang="${node.title.xmlLocale}" dir="${node.title.direction}"><c:out value="${node.title}"/><c:if test="${selectedNodeID == nodeID}"><span class="wpthemeAccess"> <portal-fmt:text key="currently_selected" bundle="nls.Theme"/></span></c:if></span></strong></c:when><c:otherwise><span lang="${node.title.xmlLocale}" dir="${node.title.direction}"><c:out value="${node.title}"/></span></c:otherwise></c:choose></a></portal-navigation:urlGeneration>
etc. for sideNavigation.jsp and mobileNavigation.jsp
Change #4 - WCM URL Generation
4) The final consideration is WCM content. Short and Clean URLs can be created to reference WCM content. That is a task typically associated with site design of WCM. However, WCM URL generation does not generate friendly URLs. We needed to update the themes in item #3 above to prevent the long and stateful URLs from showing, a similar change will be needed for WCM URL generation.
"
With friendly URLs for web content, you can construct URLs to content items that are clear and concise. Although you can construct friendly URLs that reference web content items, IBM® Web Content Manager itself does not generate friendly URLs by default. However, to cause the web content viewer to generate friendly URLs, you can create a plug-in that implements a content URL generation filter.
"
WCM URL generation unfortunately requires a bit more custom coding than updating a few jsp files. This custom coding was not performed for this blog article. Further, the requirements of the sample code provided note:
"
To use the sample filter that is described here, each page for which a content URL is generated must have these characteristics:
- The page must be a web content page with a friendly name.
- The page must have a default content association that references the parent site area of the content item.
"
...which may not be applicable in all environments. Also note you must have Portal/WCM v8 or higher to leverage this feature. If you are interested in this feature, please see this article for a step-by-step implementation.
Final Thoughts
- The steps outlined in the Infocenter and this blog entry should be considered a starting point for configuring stateless URLs. As a quick example, the login and logout links in commonActions.jsp will generate stateful URLs by default as keepNavigationalState="true" is preserved.
<portal-navigation:urlGeneration allowRelativeURL="true" keepNavigationalState="true" contentNode="wps.content.root" home="protected" >
<a href='<% wpsURL.write(escapeXmlWriter); %>' ><portal-fmt:text key="link.login" bundle="nls.engine"/></a>
</portal-navigation:urlGeneration>
...this would also need to be updated, and, you would need to weigh in on the consequences of losing navigational state information, e.g. returning the user to the same page they were on prior to logging in, should you change this setting to false. Many other examples exist and must be weighed out to keep or remove functionality.
- Carefully consider which area(s) of the Portal site you wish to have stateless URLs. For those areas, it may be advantageous to create a separate theme with the updated keepNavagationState="false" jsps and and hasBaseURL parameter in that theme.
- Remember: WebSphere Portal in its design assumes stateful URLs and completely eliminating all stateful URLs will require some significant effort. However, use of Friendly URLs with the configuration options noted above to keep 95%+ of your Portal site clean and consistent is a very real and achievable goal.