Getting name of the page where your portlet is getting rendered

Knowing name of the page where your portlet is getting rendered is one of the very common requirement, i know as per portlet specification your portlet should not be aware about where it is getting rendered but in reality there are requirements that portlet needs to behave differently based on the position where it is getting rendered.

The WebSphere Portal Server has concept of NavigationSelectionModel SPI that you can use to know about the current page.This SPI is used by the theme to know the page which should be displayed to the user. I built a PageNameFilter that makes use of the NavigationSelectionModel to find out where the page is getting rendered and passing it to the portlet as value of com.webspherenotes.filter.pageName request attribute, so that it works on both local portlet as well as cases when the portlet is getting consumed as WSRP (in case of WSRP, it will give you name of the page where portlet is getting consumed)


package com.webspherenotes.portlet.filter;

import java.io.IOException;
import java.util.Locale;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.filter.FilterChain;
import javax.portlet.filter.FilterConfig;
import javax.portlet.filter.RenderFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ibm.portal.ModelException;
import com.ibm.portal.content.ContentNode;
import com.ibm.portal.model.NavigationSelectionModelHome;
import com.ibm.portal.model.NavigationSelectionModelProvider;
import com.ibm.portal.navigation.NavigationNode;
import com.ibm.portal.navigation.NavigationSelectionModel;

public class PageNameFilter implements RenderFilter{
private static final Logger logger = LoggerFactory.getLogger(PageNameFilter.class);
public void doFilter(RenderRequest request, RenderResponse response,
FilterChain filterChain) throws IOException, PortletException {
logger.debug("Entering PageNameFilter.doFilter()");
String pageName = getPageTitle(request, response);
System.out.println("Page Name inside PageNameFilter " + pageName);
PageNameRenderRequestWrapper pageNameRequestWrapper = new PageNameRenderRequestWrapper(request);
pageNameRequestWrapper.setPageName(pageName);
filterChain.doFilter(pageNameRequestWrapper, response);
logger.debug("Exiting PageNameFilter.doFilter()");
}

private String getPageTitle(PortletRequest request, PortletResponse response){
try {
if (navigationSelectionModelHome != null) {
NavigationSelectionModelProvider provider =
navigationSelectionModelHome.getNavigationSelectionModelProvider();
NavigationSelectionModel model =
provider.getNavigationSelectionModel((ServletRequest)request, (ServletResponse)response);
NavigationNode navigationNode = (NavigationNode) model.getSelectedNode();
ContentNode contentNode = navigationNode.getContentNode();
if( contentNode.getObjectID().getUniqueName() != null){
logger.debug("The portlet is getting rendered on " + contentNode.getObjectID().getUniqueName());
}else{
logger.debug("The portlet is getting rendered on " + contentNode.getObjectID());
}
String pageTitle = contentNode.getTitle(request.getLocale());
if(pageTitle == null){
pageTitle = contentNode.getTitle(new Locale("en"));
if(pageTitle == null){
pageTitle = contentNode.getObjectID().getUniqueName();
if(pageTitle == null)
pageTitle = contentNode.getObjectID().toString();
}
}
return pageTitle;
}
} catch (ModelException e) {
logger.error("Error in PageNameFilter.getPageTitle() " + e.getMessage(),e);
}
return null;
}

private NavigationSelectionModelHome navigationSelectionModelHome;
public void init(FilterConfig filterConfig) throws PortletException {
try {
InitialContext context = new InitialContext();
navigationSelectionModelHome = (NavigationSelectionModelHome) context
.lookup(NavigationSelectionModelHome.JNDI_NAME);
} catch (NamingException e) {
logger.error("Error in PageNameFilter.init() " + e.getMessage(),e);
}
}
public void destroy() {
}
}


The PageNameFilter implements RenderFilter and in the doFilter() method it is passing control to getPageTitle method to get title of the page in the current locale or English. The getPageTitle, method is making use of the NavigationSelectionModel and callings its model.getSelectedNode() to first get the users current page and then reading the contentNode of the page from it.

I had to create PageNameRenderRequestWrapper that will override the actual RenderRequest and pass pageName as request attribute. This is how my PageNameRenderRequestWrapper looks like

package com.webspherenotes.portlet.filter;

import java.util.Enumeration;
import java.util.Vector;

import javax.portlet.RenderRequest;

public class PageNameRenderRequestWrapper extends javax.portlet.filter.RenderRequestWrapper{
private String pageName;
public static final String PAGENAME_ATTRIBUTE ="com.webspherenotes.filter.pageName";

public PageNameRenderRequestWrapper(RenderRequest request) {
super(request);
}

public Object getAttribute(String name) {
if(name.equals(PAGENAME_ATTRIBUTE)){
return pageName;
}
return super.getAttribute(name);
}

public Enumeration getAttributeNames() {
Enumeration originalAttributeEnum = super.getAttributeNames();
Vector wrappedEnum = new Vector();
while(originalAttributeEnum.hasMoreElements()){
wrappedEnum.add(originalAttributeEnum.nextElement());
}
wrappedEnum.add(PAGENAME_ATTRIBUTE);
return wrappedEnum.elements();
}

public String getPageName() {
return pageName;
}

public void setPageName(String pageName) {
this.pageName = pageName;
}



}


Inside the portlet you can read com.webspherenotes.filter.pageName request attribute to get name of the page where portlet is getting rendered

4 comments:

Anonymous said...

Hello!

I'm trying to use this classes in my websphere portlet, but I'm not sure how to call them. They look exactly as what I need, and my guess is I should use the doFilter method, passing the RenderRequest and RenderResponse. But I don't understand where should I get FilterChain. Please, could you post a little example on how to use them. That would be great.

Thanks a lot :)
Thanks a lot :)

Sunil patil said...

You dont have to call the doFilter() method explicitly. You should define your filter class in portlet.xml and then portlet container will call its doFilter() method. Take a look at http://wpcertification.blogspot.com/2010/05/hello-portletfilter-sample.html for details

Shitsurei said...
This comment has been removed by the author.
Shitsurei said...

hmmm I've have problems with some import, I think!

NavigationSelectionModelHome.JNDI_NAME doesn't exist even if the class itself is loaded :(
I'm using RAD 8 to target portal 6.1.0.33; any Ideas? Thanks!
Matteo