This note summarise my experience of JSF portlet file download using WebSphere JSF 1.2 Portlet Bridge.
One approach to implement file download from portlets is to use the JSR 286 resource serving mechanism. In order to make it working in JSF portlets, one needs to mix portlet and JSF programming as there is no direct support of the mechanism from JSF 1.2 Portlet Bridge.
The implementation consists of three components: a portlet class that extends FacesPortlet and overrides the serveResource method; a JSF page that provides use the download link; and a JSF managed bean that provides the file content.
The portlet class
package demo; import java.io.IOException; import java.io.OutputStream; import javax.el.ExpressionFactory; import javax.el.ValueExpression; import javax.faces.context.FacesContext; import javax.faces.lifecycle.Lifecycle; import javax.portlet.PortletException; import javax.portlet.PortletSession; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import com.ibm.faces.portlet.FacesPortlet; import com.ibm.faces.portlet.httpbridge.PortletRequestWrapper; import com.ibm.faces.portlet.httpbridge.PortletResponseWrapper; import com.ibm.faces.portlet.httpbridge.ResourceRequestWrapper; import com.ibm.faces.portlet.httpbridge.ResourceResponseWrapper; public class JSFPortlet extends FacesPortlet { @Override public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException { super.serveResource(request, response); TestBean testBean = (TestBean) getJSFManagedBean( request, response, TestBean.BEAN_NAME, TestBean.class); final OutputStream out = response.getPortletOutputStream(); byte[] bytes = testBean.getCsv(); response.setContentType("text/csv"); response.setProperty("Content-Disposition", "attachment; filename=download.csv"); response.setProperty("Content-length", String.valueOf(bytes.length)); out.write(bytes); out.flush(); out.close(); } public Object getJSFManagedBean(ResourceRequest request, ResourceResponse response, String beanName, Class beanClass) throws PortletException { PortletSession portletSession = request.getPortletSession(); Object jsfBean = (TestBean) portletSession.getAttribute(beanName); if (jsfBean == null) { PortletRequestWrapper requestWrapper = new ResourceRequestWrapper( request); requestWrapper.setPortletContext(getPortletContext()); PortletResponseWrapper responseWrapper = new ResourceResponseWrapper( response); Lifecycle lifecycle = getLifecycle(requestWrapper); FacesContext context = getFacesContext(requestWrapper, responseWrapper, lifecycle); final ExpressionFactory expressionFactory = context .getApplication().getExpressionFactory(); final ValueExpression valueExpression = expressionFactory .createValueExpression(context.getELContext(), "#{" + beanName + "}", beanClass); jsfBean = (TestBean) valueExpression.getValue(context .getELContext()); } return jsfBean; } }
The JSF page
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%> <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%> <%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%> <%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model" prefix="portlet-client-model" %> <%@ page language="java" contentType="text/html" pageEncoding="ISO-8859-1" session="false"%> <portlet:defineObjects /> <portlet-client-model:init> <portlet-client-model:require module="ibm.portal.xml.*"/> <portlet-client-model:require module="ibm.portal.portlet.*"/> </portlet-client-model:init> <f:view> <portlet:resourceURL var="resourceUrl" > <portlet:param name="action" value="csv" /> </portlet:resourceURL> <a href="<%=resourceUrl%>">Download CSV</a> </f:view>
The JSF managed bean
package demo; import java.util.Date; public class TestBean { public static final String BEAN_NAME = "testBean"; public byte[] getCsv() { return new Date().toString().getBytes(); } public String getText() { return "Hello"; } }
Some notes are:
- The IBM JSF 1.2 Portlet Bridge doesn't provide a Facelet taglib xml for the <portlet:resourceURL> tag, so the tag cannot be used in Facelet based JSF pages. This issue has been addressed in IBM JSF 2 Portlet Bridge.
- The <portlet:resourceURL> tag provides a var attribute that can be used to export the resource URL. Based on the JSR 286 spec, the exported variable is created in JSP page scope. As JSF code has no access to JSP page scope, the exported variable can not be used in JSF code.
- In traditional Servlet programming, the response.setHeader method is used to set HTTP response heads like Content-Disposition and Content-length, but in portlet, the ResourceResponse.setProperty method is used.
- There are two ways to access JSF managed beans from the portlet code: if the managed bean is a session scope bean and it's already exists in the session, the portletSession.getAttribute(BEAN_NAME) call can be used; otherwise, JSF value expression can be used to get and/or create the bean from FacesContext, as the IBM JSF 1.2 Portlet Bridge doesn't provide any method that the portlet implementation class can directly access FacesContext, some internal code must be used to achieve this.
Excellent... This is all I need!
ReplyDeleteI made some refactoring but the idea is perfect...
Thank you!
I am really very happy to find this particular site. I just wanted to say thank you for this huge read!! I absolutely enjoying every petite bit of it and I have you bookmarked to test out new substance you post.
ReplyDeleteData Science Training in Chennai
Data Science course in anna nagar
Data Science course in chennai
Data science course in Bangalore
Data Science course in marathahalli
This comment has been removed by the author.
ReplyDeleteThanks for sharing your valuable post and keep doing Looking towards more devops training in chennai | devops training in anna nagar | devops training in omr | devops training in porur | devops training in tambaram | devops training in velachery
ReplyDeleteExcellent... This is all I need!
ReplyDeleteI made some refactoring but the idea is perfect...
data science training in chennai
data science training in omr
android training in chennai
android training in omr
devops training in chennai
devops training in omr
artificial intelligence training in chennai
artificial intelligence training in omr
This is the information that ive been looking for. Great insights & you have explained it really well. Thank you & looking forward for more of such valuable updates.
ReplyDeletedata science training in chennai
data science training in velachery
android training in chennai
android training in velachery
devops training in chennai
devops training in velachery
artificial intelligence training in chennai
artificial intelligence training in velachery
Great post. keep sharing such a worthy information.
ReplyDeleteData Science Certification in Chennai