ShowTable of Contents
Introduction
This article was written based on IBM® WebSphere® Portal (hereafter called “Portal”) 7, and the portlet was tested on Portal 7 Fix Pack 2.
It will be useful for Portal implementers who need to customize Portal 7 features, using an API or Service Provider Interface (SPI) to suit customer requirements, including customizing menu displays, portlets display on a page, user registration and the user management module.
To get the most from this article, you should have basic understanding of Portal configuration and JavaTM Portlet Specification (JSR) portlet development.
Implementing
In the default Portal 7 theme, page navigation is displayed at the top. However, in certain scenarios, a custom navigation portlet can be used to replace the top navigation. Using the JSR Portlet, Portal 7 SPI, Portal JavaServer Pages (JSP) tag, and the Portal page parameter/title feature, the menu portlet can automatically render a set of pages created under a parent label/page, and we can:
define individual page icon to be displayed in the menu portlet, using the page parameter feature, to further enhance the UI
localize the portlet by retrieving the page tile configured in Portal page title
use Portal JSP to generate the URL to the target page
Configure Portal pages and parameters
In this section, we explain the necessary configuration steps to be done for Portal.
- Using the Edit Pages portlet, create a parent page or label, and create a set of child pages underneath. For each page that you create, specify a unique name, which is used to generate page URL in the portlet later. Table 1 shows the page structure I defined.
Table 1. Defined page structure
2. (Optional) To enhance the menu UI, we want to display the page icons together with the page title. In my case, I uploaded these icons to the Portal 7 Theme (using WebDav) and defined the icon path in the Portal page parameter for each child page, as follows:
a) Using any WebDav client, upload the page icons to the Portal Theme (ibm.portal.7002Theme). In this example, I uploaded the icons directly under the WebDav URL, /dav/fs-type1/themes/ibm.portal.7002Theme/images/menu/.
b) For each child page, access its Page Properties page, expand Advanced Options, click the “I want to set parameters” link, and specify the new parameter and value. Click the Add button, to add the parameter, and click OK to apply. This is the defined page parameter:
Parameter Name: page.icon
Parameter Value: (/dav/fs-type1/themes/ibm.portal.7002Theme/images/menu/<file name>
3. (Optional) To localize the menu by retrieving the page title according to Portal Locale/Language, I specify the child page title for each supported language, as follows:
a) For each child page, access its Page Properties page, expand Advanced Options, click the “I want to set titles” link, select the language you want to support, and specify the localized page title. Click OK to apply.
Create Portal menu portlet
In this section, we develop a JSR portlet, and use the Portal 7 SPI to retrieve all the child pages and the page parameter and title configured in the above section:
1. Create a JavaBean class to store individual page information, for easy retrieval in the JSP, as shown in listing 1.
Listing 1. Code to create JavaBean class
public class PageBean implements Serializable{
private String portletIcon;
private String pageUniquename;
private String pageType;
private Map<Locale, String> localizedTitleMap;
public String getPageUniquename() {
return pageUniquename;
}
public void setPageUniquename(String pageUniquename) {
this.pageUniquename = pageUniquename;
}
public String getPageType() {
return pageType;
}
public void setPageType(String pageType) {
this.pageType = pageType;
}
public void setLocalizedTitle(Locale locale, String title) {
if(localizedTitleMap == null) {
localizedTitleMap = new HashMap<Locale, String>();
localizedTitleMap.put(locale, title);
} else {
localizedTitleMap.put(locale, title);
}
}
public Map getLocalizedTitleMap() {
return localizedTitleMap;
}
public String getLocalizedTitle(Locale locale) {
if(localizedTitleMap != null) {
if(localizedTitleMap.containsKey(locale)) {
return localizedTitleMap.get(locale);
}
}
return pageUniquename;
}
public String getLocalizedTitleEN() {
if(localizedTitleMap != null) {
if(localizedTitleMap.containsKey(Locale.ENGLISH)) {
return localizedTitleMap.get(Locale.ENGLISH);
}
}
return pageUniquename;
}
public void setLocalizedTitleMap(Map localizedTitleMap) {
this.localizedTitleMap = localizedTitleMap;
}
public String getPortletIcon() {
return portletIcon;
}
public void setPortletIcon(String portletIcon) {
this.portletIcon = portletIcon;
}
For the complete code, refer to “PageBean.java” in the .zip file attached to this article (under “portal7Project/src/com/ibm/portal7project.”)
2. Next, create a Utility Class that contains a method that retrieves child pages of a parent, using Portal 7 SPI (NavigationModelProvider class), and set all the necessary page information into the PageBean object.
The code snippet in listing 2 initializes the necessary provider class to retrieve the Portal page.
Listing 2. Code to initialize the provider class
private static PortletServiceHome pshNavModelProvider;
private static NavigationModelProvider navModelProvider;
private static void init(){
try {
if(navModelProvider == null) {
Context ic = new javax.naming.InitialContext();
pshNavModelProvider = (PortletServiceHome)ic.lookup(NavigationModelProvider.JNDI_NAME);
navModelProvider = (NavigationModelProvider)pshNavModelProvider.getPortletService(NavigationModelProvider.class);
ic.close();
}
} catch(javax.naming.NamingException ne) {
ne.printStackTrace();
} catch (PortletServiceUnavailableException localPortletServiceUnavailableException) {
localPortletServiceUnavailableException.printStackTrace();
}
}
This code snippet obtains the parent page node by its unique name:
NavigationModel model = navModelProvider.getNavigationModel(request,response);
Object parentNode = model.getLocator().findByUniqueName(parentName);
The code snippet in listing 3 obtains all the child nodes under the parent node.
Listing 3. Code to obtain child nodes
private static Iterator getChildNode(NavigationModel model, Object parentNode, PortletRequest request, PortletResponse response) {
try {
if(model.hasChildren(parentNode)) {
return model.getChildren(parentNode);
}
} catch (ModelException e) {
e.printStackTrace();
}
return null;
}
The code snippet in listing 4 process each child node by retrieving its unique name, localized page title, and page parameter that stores the icon URL, and identifies whether the child node is a page type of type label.
Listing 4. Code to process each child node
if(parentNode !=null) {
Iterator it = getChildNode(model, parentNode, request, response);
if(it !=null) {
while(it.hasNext()){
NavigationNode childNode = (NavigationNode)it.next();
PageBean bean = new PageBean();
//to retrieve page unique name
bean.setPageUniquename(childNode.getObjectID().getUniqueName());
//to retrieve page title
bean.setLocalizedTitle(Locale.ENGLISH, childNode.getTitle(Locale.ENGLISH));
//to identify if the child page is a page or label
if(ContentNodeType.PAGE.equals(childNode.getContentNode().getContentNodeType()) || ContentNodeType.STATICPAGE.equals(childNode.getContentNode().getContentNodeType()))
bean.setPageType("page");
else if(ContentNodeType.LABEL.equals(childNode.getContentNode().getContentNodeType()))
bean.setPageType("label");
//to retrieve page parameter (page icon)
if (childNode instanceof com.ibm.portal.MetaDataProvider) {
com.ibm.portal.MetaData iMetaData = ((com.ibm.portal.MetaDataProvider) childNode).getMetaData();
Object pageIcon = iMetaData.getValue("page.icon");
if (pageIcon != null){
bean.setPortletIcon((String)pageIcon);
}
}
pages.add(bean);
}
}
}
For the complete code, refer to “PortalNavigationUtil.java” in the .zip file attached to this article (under “portal7Project/src/com/ibm/portal7project.”)
3. Next, create a Portlet class and, in the doView() method, invoke the method in PortalNavigationUtil.java, and set the child pages arraylist into request attribute (see listing 5).
Listing 5. Code to create Portlet class
public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
response.setContentType(request.getResponseContentType());
//specify the parent page 'unique name'
List<PageBean> pages = PortalNavigationUtil.getChildPage("sample.parent", request, response);
request.setAttribute("pages", pages);
getPortletContext().getRequestDispatcher("/jsp/html/PageMenuPortletView.jsp").include(request,response);
}
For the complete code, refer to “PageMenuPortlet.java” in the attached .zip file (under portal7Project/src/com/ibm/portal7project.”)
4. Finally, create a view JSP for the portlet that renders the child pages' arraylist. The sample in listing 6 renders the list of child pages, together with their page icon and localized English (EN) title. Portal JSP tag (wps) is used to generate the URL to the child page (by unique name).
Listing 6. Render list of child pages
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="/WEB-INF/tld/portal.tld" prefix="wps" %>
<div>
<ul>
<c:forEach var="page" items="${pages}">
<c:if test="${page.pageType eq 'page'}">
<li>
<c:set var="childPageName" value="${page.pageUniquename}"/>
<wps:urlGeneration contentNode="${childPageName}" accessControlCheck="NoCheck">
<a href="<% wpsURL.write(out); %>">
<img src="${page.portletIcon}"/>
</a>
</wps:urlGeneration>
<div>
<span>${page.localizedTitleEN}</span>
</div>
</li>
</c:if>
</c:forEach>
</ul>
</div>
For the complete code, refer to “PageMenuPortletview.jsp” in the attached .zip file (under “portal7Project/WebContent/jsp/html.”)
NOTE: The sample code listings above are able only to render child pages under a particular parent page. However, you can modify the code to retrieve a set of child pages under multiple parents, to build a more extensive navigation portlet.
Conclusion
This article has shown how to replace the default WebSphere Portal top navigation with a customized navigation portlet. You can easily extend the code snippets in the listings herein to customize the menu display according to your own needs.
Resources
IBM WebSphere Portal, Version 7.0.0.0 SPI Specification:
http://public.dhe.ibm.com/software/dw/lotus/portal_javadoc/7/portal/spi_docs/index.html
developerWorks WebSphere Portal zone:
http://www.ibm.com/developerworks/websphere/zones/portal/
About the author
Chew Chiau Ping is a Solution Architect specializing in designing solutions built on top of WebSphere Portal, IBM Web Content Manager, and IBM WebSphere Application Server. She can be reached at
chiauping@yahoo.com.