Liferay and Richfaces: Removing Portlets View-ID Caching-State
My current project at my work primarly concerned with Liferay-/Portletcreation. Therefore we have decided to use Richfaces as standard-rich-user-expierience framework as the way on how we can model UI-Objects as well as the afford on which way we want to transmit data from the client to the server in a more fine-grained decision way is very sophisticated. Well if you want to use a ajax-request to transmit the current state of an UI-Tree to the server, just do that on setting up the appropriated tree-element attribute to “ajax”. Particular elements in the tree can be handled in a more different way by transmitting this data through a full-page reload. You got the choice on every element you´ve been pasted on your UI-Site with respect to Richfaces. Very nice feature!
But thats not my comment this days. Well when i looking back into my last post-dates i should gonna be scary. So long i doesnt write any blog-entry? Oh where are my minds? Back to the ISSUE that got every developer that uses Richfaces as its UI-Library in Liferay (i guess in every portal-server supporting JCR-301) .
Well but theres one particular problem if you have some pages connected with each other in a portlet. For instance, XHTML-Site 1 (following being called dogs-view) referes to XHTML-Site 2 (formaly know dogs-card) through an h:commandLink or somewhat else that dives into a FacesRequest to build up the ComponentTree.
If you have visited the dogs-card(look up in you mind-index what this means, guy!) on follwing the commandlink from dogs-view the state will be saved within the current portletsession to restore later if no valid commandRequest (e.g. Commandlink request) have been pasted. This is a requirement can happen if you want to revisit dogs-view site. As you know: Dogs-View Site as well as Dogs-Card exists in the same Portlet! If you call the page where you have dropped in this portlet, you got the last state of the portlet. This could be(like explained above) the site dogs-card if this was the last site you´ve visited. But in some cases this is an inappropriated behaviour as it is whished to get the first - “the default” site of a portlet (or somewhat else).
As ive still introduced the portletbridge, jboss implemented the the JCR-301 as well with respect to its own Portal Server as well other Servers like Liferay. The behaviour within the portletbridge saves the current state of the last view of the portlet within the following request attribute:
PortletBridgeContext bridgeContext = (PortletBridgeContext) renderRequest .getAttribute(PortletBridgeContext.REQUEST_PARAMETER_NAME);
The parameter PortletBridgeContext.REQUEST_PARAMETER_NAME returns the current bridgeContext (bc). The bc itself will be builded up on each request time.
The portletContext bears the last visited viewid. You got this value on doing following request:
bridgeContext.getWindowState().getViewId();
Well, if you now want to set back portlets view state, you have several opportunities. I´ve decided to choose the way of a portletfilter which can be compared in a more simalary approach with respect to a ServletFilter.
Each time a portlet will be executed, the portletfilter will be hooking in on the processing line before the portletServlet even know wether the current request belongs to a RenderRequest or an ActionRequest. Thus we have the possibilty given to change pipelines behaviour. As we have said previously, we dont want to render the last portlet state of the portlet if no new actionrequest will be processed. That can be exposed looking for a particlar attribut being set if a link/button have been pressed: org.jboss.portletbridge.VIEWID
If no such Attribute exists in the current request, we change the viewstate of the portletcontext.
To manage this in a more convenient way, we add a xml-file where we can edit the default-view (but we could read out the default-portlet-view given from portlet.xml).
Heres are complete code-snippets:
Portlet1 /xhtml/DocumentsView.xhtml Portlet2 /xhtml/UploadView.xhtml Portlet3 /xhtml/SearchResultsView.xhtml
public class DefaultViewFilter implements RenderFilter {
private static final String facesExtensionResourceUrl = "/de/dmc/customer/web/faces-ext.xml";
private static HashMap defaultView;
private static Set defaultViewKeys;
/**
* Wrapperclass for RenderRequest
*
*
* @author wenzkseb
*
*/
public static final class FinalRenderRequestWrapper extends
RenderRequestWrapper {
private String portletName;
public FinalRenderRequestWrapper(RenderRequest rr, String portletName) {
super(rr);
this.portletName = portletName.substring(1);
}
/**
* Looking for a valid state where the viewid can be changed
*
* @param name the parameter to obtain
* @param bridgeContext BridgeContext
* @return the newly valid viewid or null if no valid status for change
* can be found
*/
private String retrieveViewState(String name,
PortletBridgeContext bridgeContext) {
/*
* 1.
*/
if (name.equals(”org.jboss.portletbridge.VIEWID”) == false)
return null;
if (super.getParameter(name) != null)
return null;
if (bridgeContext == null)
return null;
for (String _pn : defaultViewKeys) {
if (portletName.startsWith(_pn + “_WAR”) == true) {
return defaultView.get(_pn);
}
}
return null;
}
@Override
public String getParameter(String name) {
PortletBridgeContext bridgeContext = (PortletBridgeContext) getRequest()
.getAttribute(PortletBridgeContext.REQUEST_PARAMETER_NAME);
String direction = null;
if ((direction = retrieveViewState(name, bridgeContext)) != null) {
bridgeContext.getWindowState().setViewId(direction);
}
return super.getParameter(name);
}
}
public void doFilter(RenderRequest request, RenderResponse response,
FilterChain chain) throws IOException, PortletException {
chain.doFilter(new FinalRenderRequestWrapper(request, response
.getNamespace()), response);
}
public void destroy() {
System.out.println(”*********** destroying ****************”);
}
/**
* Reads the file faces-ext.xml to retrieve all defaultview-mappings:
*
*
* …
*
*
DocumentView
* /docview/DocumentTableView.xhtml
*
* …
*
*/
public void init(FilterConfig filterConfig) throws PortletException {
System.out.println(”*********** initializing ***********”);
System.out.println(”*********** Building up faces ”
+ “extension for defaultviews ***********”);
URL facesExtResource = this.getClass().getResource(
DefaultViewFilter.facesExtensionResourceUrl);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder;
defaultView = new HashMap();
try {
documentBuilder = dbf.newDocumentBuilder();
Document facesDocument = documentBuilder.parse(facesExtResource
.openConnection().getInputStream());
NodeList viewList = facesDocument
.getElementsByTagName(”default-view”);
for (int idx = 0; idx < viewList.getLength(); idx++) {
Element currentNode = (Element) viewList.item(idx);
NodeList _portletName = currentNode
.getElementsByTagName(”portletname”);
NodeList _defaultView = currentNode
.getElementsByTagName(”view-id”);
if (_portletName.getLength() != 1)
throw new RuntimeException(”Portletname must be exist”);
if (_portletName.getLength() != 1)
throw new RuntimeException(”Defaultview must be exist”);
_portletName = _portletName.item(0).getChildNodes();
_defaultView = _defaultView.item(0).getChildNodes();
if (_portletName.item(0).getNodeValue() == null)
throw new RuntimeException(”Portletname must no be null”);
if (_defaultView.item(0).getNodeValue() == null)
throw new RuntimeException(”Portletname must no be null”);
String portletName = _portletName.item(0).getNodeValue().trim();
String defaultView = _defaultView.item(0).getNodeValue().trim();
System.out.println(”ADD Entry: ” + portletName + “->”
+ defaultView);
DefaultViewFilter.defaultView.put(portletName, defaultView);
}
defaultViewKeys = defaultView.keySet();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Comments
2 Responses to “Liferay and Richfaces: Removing Portlets View-ID Caching-State”
Leave a Reply

Sebastian Wenzky works since october 09 as a ecm-consultant at Westernacher in Stuttgart. Alfresco, Spring, Hibernate, JBPM and - to much - coffee are now his companions. The corresponding company the right way to go.
really very nice information sharing and i am looking for such type of informative news and i get through this blog so i am very much thankful to you.
do you have an idea how we can achive the same thing on PortletBridge 2.X.
The methods which are used here are only available with PortletBridge 1.X…