/*
* This file is part of the WfMOpen project.
* Copyright (C) 2001-2005 Danet GmbH (www.danet.de), BU BTS.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Derived from MyFacesGenericPortlet,
* Copyright 2004 The Apache Software Foundation.
*
* $Id: MyFacesAdaptedPortlet.java 2921 2009-02-14 20:41:30Z mlipp $
*
* $Log$
* Revision 1.32 2007/05/27 15:23:34 mlipp
* Removed erroneously inserted localization in processAction.
*
* Revision 1.31 2007/05/27 10:03:05 mlipp
* Improved locale detection/setting.
*
* Revision 1.30 2007/05/26 22:55:50 mlipp
* Fixed file upload.
*
* Revision 1.29 2007/05/26 21:53:48 mlipp
* More debug infos.
*
* Revision 1.28 2007/05/22 14:04:45 drmlipp
* Avoid duplicate processing of multipart request.
*
* Revision 1.27 2007/02/26 22:12:28 mlipp
* Updated to MyFaces core 1.1.5/Tomahawk 1.1.3.
*
* Revision 1.26 2006/12/12 09:53:20 drmlipp
* Added Ajax support.
*
* Revision 1.25 2006/12/05 09:14:11 drmlipp
* Suppressing superfluous warning.
*
* Revision 1.24 2006/11/20 13:46:30 drmlipp
* Restore initial JSF state after exception.
*
* Revision 1.23 2006/10/11 19:31:59 mlipp
* Fixed problem with language switching.
*
* Revision 1.22 2006/09/29 12:32:11 drmlipp
* Consistently using WfMOpen as projct name now.
*
* Revision 1.21 2006/09/20 15:27:43 drmlipp
* Workaround for strange ClasscastException.
*
* Revision 1.20 2006/09/12 12:56:18 drmlipp
* Fixed autoscroll for portlets.
*
* Revision 1.19 2006/09/11 15:29:28 drmlipp
* Improved portlet support.
*
* Revision 1.18 2006/09/08 14:08:06 drmlipp
* Started handling of MyFaces resource loading.
*
* Revision 1.17 2006/08/29 15:03:11 drmlipp
* Added JavaScript insertion to portlet bridge. Re-enabled scrolling support.
*
* Revision 1.16 2006/08/28 21:22:44 mlipp
* Updated MyFaces to 1.1.3.
*
* Revision 1.15 2006/05/31 20:52:18 mlipp
* Fixed problem with left over session data.
*
* Revision 1.14 2006/04/15 10:04:25 mlipp
* Removed Liferay bug workaround.
*
* Revision 1.13 2005/11/14 13:26:02 drmlipp
* Fixed problem with request attributes being passed between portlets
* (breaks MyFaces).
*
* Revision 1.12 2005/11/14 09:34:25 drmlipp
* Improved workaround for liferay bug.
*
* Revision 1.11 2005/11/10 20:52:55 mlipp
* Fixed problem with classloader dependend Lifecycle access.
*
* Revision 1.10 2005/11/10 16:04:23 drmlipp
* Workaround for liferay bug.
*
* Revision 1.9 2005/11/07 14:02:13 drmlipp
* Make action request attributes available during rendering.
*
* Revision 1.8 2005/10/11 12:31:38 drmlipp
* Fixed portlet mode comparison.
*
* Revision 1.7 2005/10/10 20:49:59 mlipp
* Improved JSF lifecycle support.
*
* Revision 1.6 2005/09/28 15:12:41 drmlipp
* Updated MyFaces to 1.1.
*
* Revision 1.5 2005/09/16 13:50:25 drmlipp
* Improved file upload support.
*
* Revision 1.4 2005/09/15 22:06:21 mlipp
* Upload implementation continued.
*
* Revision 1.3 2005/09/15 15:06:30 drmlipp
* Continuing implementation of upload portlet.
*
* Revision 1.2 2005/09/15 11:03:34 drmlipp
* Fixed mode issues.
*
* Revision 1.1 2005/09/13 13:43:29 drmlipp
* Using portlet/JSF bridge from MyFaces again (in an adapted version).
*
*/
package de.danet.an.util.jsf;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
import javax.faces.application.FacesMessage;
import javax.faces.application.ViewHandler;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.FacesContextFactory;
import javax.faces.lifecycle.Lifecycle;
import javax.faces.lifecycle.LifecycleFactory;
import javax.faces.webapp.FacesServlet;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortalContext;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletMode;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.UnavailableException;
import javax.portlet.WindowState;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.portlet.PortletFileUpload;
import org.apache.myfaces.config.FacesConfigurator;
import org.apache.myfaces.context.ReleaseableExternalContext;
import org.apache.myfaces.context.portlet.PortletExternalContextImpl;
import org.apache.myfaces.context.servlet.ServletFacesContextImpl;
import org.apache.myfaces.portlet.PortletUtil;
import org.apache.myfaces.renderkit.html.util.AddResource;
import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
import org.apache.myfaces.shared_impl.webapp.webxml.WebXml;
import de.danet.an.util.Misc;
import de.danet.an.util.logging.RequestLog;
import de.danet.an.util.logging.RequestScope;
/**
* This portlet initializes MyFaces and converts portlet requests into
* JSF requests.
*
* @author Stan Silvert (latest modification by $Author: mlipp $)
*/
public class MyFacesAdaptedPortlet extends GenericPortlet {
private static final org.apache.commons.logging.Log logger
= org.apache.commons.logging.LogFactory
.getLog(MyFacesAdaptedPortlet.class);
// PortletSession attribute
public static final String VIEW_ID
= MyFacesAdaptedPortlet.class.getName() + ".VIEW_ID";
public static final String PREV_MODE
= MyFacesAdaptedPortlet.class.getName() + ".PREV_MODE";
// PortletSession attribute
public static final String CURRENT_FACES_CONTEXT
= MyFacesAdaptedPortlet.class.getName() + ".CURRENT_FACES_CONTEXT";
protected static final String FACES_INIT_DONE
= MyFacesAdaptedPortlet.class.getName() + ".FACES_INIT_DONE";
public static final String FILE_ITEMS
= MyFacesAdaptedPortlet.class.getName() + ".FILE_ITEMS";
public static final String REQUEST_ATTRIBUTES
= MyFacesAdaptedPortlet.class.getName() + ".REQUEST_ATTRIBUTES";
public static final String NAMESPACE_PREFIX
= MyFacesAdaptedPortlet.class.getName() + ".NAMESPACE_PREFIX";
public static final String LIFECYCLE_ID
= MyFacesAdaptedPortlet.class.getName() + ".LIFECYCLE_ID";
/** Name of portlet preference for Edit page. */
protected static final String PARAM_EDIT_PAGE = "EditPage";
/** Name of portlet preference for Edit page */
protected static final String PARAM_HELP_PAGE = "HelpPage";
/** Name of portlet preference for View page */
protected static final String PARAM_VIEW_PAGE = "ViewPage";
private static Set serializabilityWarnings = new HashSet();
/** Private in JavascriptUtils, what a pity... */
private static final String AUTO_SCROLL_PARAM = "autoScroll";
/** Default URL for the edit page. */
private String defaultEditPage = null;
/** Default URL for the help page. */
private String defaultHelpPage = null;
/** Default URL for the view page. */
private String defaultViewPage = null;
private String uploadMaxFileSize = null;
private String uploadThresholdSize = null;
protected PortletContext portletContext;
protected FacesContextFactory facesContextFactory;
protected Lifecycle lifecycle;
/**
* Creates a new instance of MyFacesPortlet
*/
public MyFacesAdaptedPortlet() {
}
/**
* Portlet lifecycle.
*/
public void destroy()
{
super.destroy();
FactoryFinder.releaseFactories();
}
/**
* Portlet lifecycle.
*/
public void init() throws PortletException, UnavailableException
{
this.portletContext = getPortletContext();
this.defaultViewPage = getPortletConfig()
.getInitParameter(PARAM_VIEW_PAGE);
this.defaultEditPage = getPortletConfig()
.getInitParameter(PARAM_EDIT_PAGE);
this.defaultHelpPage = getPortletConfig()
.getInitParameter(PARAM_HELP_PAGE);
uploadMaxFileSize = getPortletConfig()
.getInitParameter("uploadMaxFileSize");
uploadThresholdSize = getPortletConfig()
.getInitParameter("uploadThresholdSize");
if (null == this.defaultViewPage) {
// A Faces Portlet is required to have at least the
// defaultViewPage
// defined!
throw new PortletException(
"Portlet "
+ getPortletConfig().getPortletName()
+ " is incorrectly configured. No default View page is defined.");
}
initMyFaces();
facesContextFactory = (FacesContextFactory) FactoryFinder
.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
// Javadoc says: Lifecycle instance is shared across multiple simultaneous requests, it must be
// implemented in a thread-safe manner. So we can acquire it here once:
LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
.getFactory(FactoryFinder.LIFECYCLE_FACTORY);
lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
}
protected void setContentType(RenderRequest request, RenderResponse response)
{
if (response.getContentType() == null)
{
String portalPreferredContentType = request.getResponseContentType();
if (portalPreferredContentType != null)
{
response.setContentType(portalPreferredContentType);
}
else
{
response.setContentType("text/html");
}
}
}
private String getLifecycleId() {
String lifecycleId = getPortletConfig().getInitParameter(
FacesServlet.LIFECYCLE_ID_ATTR);
return lifecycleId != null ? lifecycleId
: LifecycleFactory.DEFAULT_LIFECYCLE;
}
protected void initMyFaces()
{
try
{
Boolean b = (Boolean)portletContext.getAttribute(FACES_INIT_DONE);
if (b == null || b.booleanValue() == false) {
logger.trace("Initializing MyFaces");
//Load the configuration
ExternalContext externalContext = new PortletExternalContextImpl(
portletContext, null, null);
//And configure everything
new FacesConfigurator(externalContext).configure();
// parse web.xml - not sure if this is needed for portlet
WebXml.init(externalContext);
portletContext.setAttribute(FACES_INIT_DONE, Boolean.TRUE);
} else {
logger.info("MyFaces already initialized");
}
} catch (Exception ex) {
logger.error("Error initializing MyFacesAdaptedPortlet", ex);
}
logger.info("PortletContext '" + portletContext.getRealPath("/")
+ "' initialized.");
}
/**
* Called by the portlet container to allow the portlet to process an
* action request.
*/
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException {
RequestScope scope = RequestLog.enterScope
(this, "processAction", new Object[] { request, response });
try {
doProcessAction(request, response);
} finally {
scope.leave();
}
}
/**
* Called by the portlet container to allow the portlet to process an
* action request.
*/
private void doProcessAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException {
if (logger.isTraceEnabled())
logger.trace("called processAction");
if (sessionTimedOut(request)) {
return;
}
if (logger.isDebugEnabled()) {
dumpRequestInfo(request);
}
setPortletRequestFlag(request);
FileUploadException uploadException = null;
if (PortletFileUpload.isMultipartContent(request)) {
try {
DiskFileItemFactory dfif = new DiskFileItemFactory();
if (uploadMaxFileSize != null) {
dfif.setSizeThreshold(resolveSize(uploadThresholdSize));
}
PortletFileUpload pfu = new PortletFileUpload(dfif);
if (uploadMaxFileSize != null) {
pfu.setSizeMax(resolveSize(uploadMaxFileSize));
}
List items = pfu.parseRequest(request);
Map reqParms = new HashMap (request.getParameterMap());
// Liferay (and may be others) process multipart content
// before calling processAction. Avoid doing it twice.
Set preprocessed = new HashSet (reqParms.keySet());
PortletSession session = request.getPortletSession();
for (Iterator i = items.iterator(); i.hasNext();) {
FileItem item = (FileItem) i.next();
if (logger.isDebugEnabled()) {
logger.debug("Got file item: " + item);
}
if (item.isFormField()) {
if (preprocessed.contains (item.getFieldName())) {
continue;
}
if (!reqParms.containsKey(item.getFieldName())) {
reqParms.put(item.getFieldName(),
new String[] { item.getString() });
} else {
String[] oldVals
= ((String[])reqParms.get(item.getFieldName()));
String[] newVals = new String[oldVals.length + 1];
System.arraycopy
(oldVals, 0, newVals, 0, oldVals.length);
newVals[oldVals.length] = item.getString();
reqParms.put(item.getFieldName(), newVals);
}
} else {
if (session.getAttribute(FILE_ITEMS) == null) {
session.setAttribute(FILE_ITEMS, new HashMap());
}
((Map)session.getAttribute(FILE_ITEMS))
.put(item.getFieldName(), item);
}
}
request = new ActionRequestWrapper(request, reqParms);
} catch (FileUploadException e) {
uploadException = e;
}
}
FacesContext facesContext = facesContext(request, response);
if (uploadException != null) {
JSFUtil.addMessage
(FacesMessage.SEVERITY_ERROR,
facesContext.getViewRoot().getLocale(),
"de.danet.an.util.I18n", "error.sizeLimitExceeded",
new Object [] { uploadMaxFileSize }, uploadException);
}
try {
request.setAttribute(JSFUtil.LIFECYCLE, lifecycle);
List oldAttrs = Collections.list(request.getAttributeNames());
lifecycle.execute(facesContext);
Map newAttrs = new HashMap ();
for (Enumeration e = request.getAttributeNames();
e.hasMoreElements();) {
String name = (String)e.nextElement();
if (oldAttrs.contains(name)
|| (name.equals
("org.apache.myfaces.application.jsp"
+ ".JspStateManagerImpl.RESTORED_SERIALIZED_VIEW"))) {
continue;
}
Object val = request.getAttribute(name);
request.removeAttribute(name);
if (!(val instanceof Serializable)) {
String valClassName = val.getClass().getName();
if (!serializabilityWarnings.contains(valClassName)) {
logger.warn("Request attribute " + name + " is of "
+ "non-serializable type " + valClassName
+ " and will not be available during rendering");
serializabilityWarnings.add (valClassName);
}
continue;
}
newAttrs.put(name, val);
}
request.getPortletSession()
.setAttribute(REQUEST_ATTRIBUTES, newAttrs);
// Carry AUTO_SCROLL_PARAM over to rendering
if (request.getParameter(AUTO_SCROLL_PARAM) != null) {
request.getPortletSession().setAttribute
(AUTO_SCROLL_PARAM, request.getParameter(AUTO_SCROLL_PARAM));
}
if (!facesContext.getResponseComplete()) {
request.getPortletSession().setAttribute(VIEW_ID,
facesContext.getViewRoot().getViewId());
}
request.getPortletSession().setAttribute(CURRENT_FACES_CONTEXT,
facesContext);
} catch (Throwable e) {
facesContext.release();
handleExceptionFromLifecycle(e);
} finally {
Map fileItemMap = ((Map)request
.getPortletSession().getAttribute (FILE_ITEMS));
if (fileItemMap != null) {
for (Iterator i=fileItemMap.values().iterator(); i.hasNext();) {
FileItem item = (FileItem)i.next();
item.delete();
}
request.getPortletSession().removeAttribute(FILE_ITEMS);
}
}
}
private int resolveSize(String param) {
param = param.toLowerCase();
int factor = 1;
String number = param;
if (param.endsWith("g")) {
factor = 1024 * 1024 * 1024;
number = param.substring(0, param.length() - 1);
} else if (param.endsWith("m")) {
factor = 1024 * 1024;
number = param.substring(0, param.length() - 1);
} else if (param.endsWith("k")) {
factor = 1024;
number = param.substring(0, param.length() - 1);
}
return Integer.parseInt(number) * factor;
}
protected void handleExceptionFromLifecycle(Throwable e)
throws PortletException, IOException
{
logException(e, null);
if (e instanceof IOException)
{
throw (IOException)e;
}
if (e instanceof PortletException)
{
throw (PortletException)e;
}
if (e.getMessage() != null)
{
throw new PortletException(e.getMessage(), e);
}
throw new PortletException(e);
}
/**
* Helper method to serve up the view mode.
*/
protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
RequestScope scope = RequestLog.enterScope
(this, "doView", new Object[] { request, response });
try {
facesRender(request, response);
} finally {
scope.leave();
}
}
/**
* Helper method to serve up the edit mode. Can be overridden to add
* the edit mode concept to a JSF application.
*/
protected void doEdit(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
RequestScope scope = RequestLog.enterScope
(this, "doEdit", new Object[] { request, response });
try {
facesRender(request, response);
} finally {
scope.leave();
}
}
/**
* Helper method to serve up the edit mode. Can be overridden to add
* the help mode concept to a JSF application.
*/
protected void doHelp(RenderRequest request, RenderResponse response)
throws PortletException, IOException
{
RequestScope scope = RequestLog.enterScope
(this, "doHelp", new Object[] { request, response } );
try {
facesRender(request, response);
} finally {
scope.leave();
}
}
/**
* This method follows JSF Spec section 2.1.1. It renders the default view from a non-faces
* request.
*
* @param request The portlet render request.
* @param response The portlet render response.
*/
protected void nonFacesRequest(RenderRequest request, RenderResponse response) throws PortletException
{
nonFacesRequest(request, response, selectDefaultView(request, response));
}
/**
* This method follows JSF Spec section 2.1.1. It renders a view from a non-faces
* request. This is useful for a default view as well as for views that need to
* be rendered from the portlet's edit and help buttons.
*
* @param request The portlet render request.
* @param response The portlet render response.
* @param view The name of the view that needs to be rendered.
*/
protected void nonFacesRequest(RenderRequest request, RenderResponse response, String view)
throws PortletException
{
if (logger.isTraceEnabled())
logger.trace("Non-faces request: contextPath = "
+ request.getContextPath());
setContentType(request, response); // do this in case nonFacesRequest is called by a subclass
ApplicationFactory appFactory = (ApplicationFactory) FactoryFinder
.getFactory(FactoryFinder.APPLICATION_FACTORY);
Application application = appFactory.getApplication();
ViewHandler viewHandler = application.getViewHandler();
FacesContext facesContext = facesContext(request, response);
UIViewRoot viewRoot = viewHandler.createView(facesContext, view);
viewRoot.setViewId(view);
facesContext.setViewRoot(viewRoot);
renderProtected(request, response, facesContext, false);
}
/**
* Save current request attributes before rendering and restore them
* afterward. This avoids interaction of two or more JSF based portlets
* on one page.
* @param request the request
* @param response the response
* @param facesContext the faces context
* @param addActionAttributes if <code>true</code> add attributes
* created by portlet in previous <code>lifecycle.execute</code>
* @throws PortletException
*/
private void renderProtected
(RenderRequest request, RenderResponse response,
FacesContext facesContext, boolean addActionAttributes)
throws PortletException {
if (logger.isDebugEnabled()) {
dumpRequestInfo(request);
}
// Update locale (may change between requests)
facesContext.getViewRoot().setLocale(getLocale(request));
// for use by Ajax servlet
request.getPortletSession()
.setAttribute(MyFacesAjaxServlet.RENDER_NAMESPACE, response.getNamespace());
request.getPortletSession()
.setAttribute(NAMESPACE_PREFIX, facesContext.getExternalContext()
.encodeNamespace(""));
request.getPortletSession()
.setAttribute(LIFECYCLE_ID, getLifecycleId());
// save attributes
List oldAttrs = Collections.list(request.getAttributeNames());
if (addActionAttributes) {
// add request parameters added during performAction
Map reqAttrs = (Map)
request.getPortletSession().getAttribute(REQUEST_ATTRIBUTES);
if (reqAttrs != null) {
for (Iterator i=reqAttrs.entrySet().iterator(); i.hasNext();) {
Map.Entry e = (Map.Entry)i.next();
request.setAttribute((String)e.getKey(), e.getValue());
}
}
}
// Add carried over AUTO_SCROLL_PARAM, but only once
if (request.getPortletSession()
.getAttribute(AUTO_SCROLL_PARAM) != null) {
if (facesContext.getExternalContext()
instanceof MyPortletExternalContextImpl) {
((MyPortletExternalContextImpl)
facesContext.getExternalContext())
.addParameter(AUTO_SCROLL_PARAM, (String)request
.getPortletSession().getAttribute(AUTO_SCROLL_PARAM));
} else {
logger.warn
("Encountered faces context with foreign external context");
}
request.getPortletSession().removeAttribute(AUTO_SCROLL_PARAM);
}
request.setAttribute(JSFUtil.LIFECYCLE, lifecycle);
try {
lifecycle.render(facesContext);
} catch (RuntimeException e) {
// restores entry view, which should work
request.getPortletSession().removeAttribute(VIEW_ID);
throw e;
}
AddResource addResource
= AddResourceFactory.getInstance(facesContext);
try {
if (addResource instanceof PortletAppAddResource) {
((PortletAppAddResource)addResource)
.processAppendices(request, response, facesContext);
}
} catch (IOException e) {
throw new PortletException(e);
}
// restore request parameters
for (Enumeration e = request.getAttributeNames();
e.hasMoreElements();) {
String name = (String)e.nextElement();
if (oldAttrs.contains(name)) {
continue;
}
request.removeAttribute(name);
}
}
protected String selectDefaultView(RenderRequest request,
RenderResponse response) throws PortletException {
if (request.getPortletMode().equals(PortletMode.EDIT)
&& defaultEditPage != null) {
return defaultEditPage;
}
if (request.getPortletMode().equals(PortletMode.HELP)
&& defaultHelpPage != null) {
return defaultHelpPage;
}
return defaultViewPage;
}
protected FacesContext facesContext
(PortletRequest request, PortletResponse response) {
FacesContext facesContext = facesContextFactory.getFacesContext
(portletContext, request, response, lifecycle);
return facesContext;
}
protected ReleaseableExternalContext makeExternalContext(
PortletRequest request, PortletResponse response) {
return (ReleaseableExternalContext) new MyPortletExternalContextImpl(
portletContext, request, response);
}
protected boolean sessionTimedOut(PortletRequest request) {
return request.getPortletSession(false) == null;
}
protected void setPortletRequestFlag(PortletRequest request) {
request.getPortletSession().setAttribute(
PortletUtil.PORTLET_REQUEST_FLAG, "true");
}
protected Locale getLocale (PortletRequest request) {
// Liferay leaves a locale here
Locale locale = (Locale)request.getPortletSession().getAttribute
("org.apache.struts.action.LOCALE",
PortletSession.APPLICATION_SCOPE);
if (locale != null) {
return locale;
}
// Fallback: use request locale
return request.getLocale();
}
/**
* Render a JSF view.
*/
protected void facesRender(RenderRequest request, RenderResponse response)
throws PortletException, java.io.IOException {
if (logger.isTraceEnabled()) {
logger.trace("called facesRender");
}
setContentType(request, response);
String prevMode = (String)
request.getPortletSession().getAttribute(PREV_MODE);
if (prevMode == null
|| !prevMode.equals(request.getPortletMode().toString())) {
request.getPortletSession().removeAttribute(VIEW_ID);
request.getPortletSession().setAttribute
(PREV_MODE, request.getPortletMode().toString());
}
ServletFacesContextImpl facesContext = (ServletFacesContextImpl) request
.getPortletSession().getAttribute(CURRENT_FACES_CONTEXT);
String viewId = (String) request.getPortletSession().getAttribute(VIEW_ID);
if (facesContext == null || viewId == null || sessionTimedOut(request)) {
setPortletRequestFlag(request);
nonFacesRequest(request, response);
return;
}
setPortletRequestFlag(request);
try {
// TODO: not sure if this can happen. Also double check this against spec section 2.1.3
if (facesContext.getResponseComplete())
return;
facesContext.setExternalContext
(makeExternalContext(request, response));
renderProtected(request, response, facesContext, true);
} catch (Throwable e) {
handleExceptionFromLifecycle(e);
}
}
protected void logException(Throwable e, String msgPrefix) {
String msg;
if (msgPrefix == null) {
if (e.getMessage() == null) {
msg = "Exception in FacesServlet";
} else {
msg = e.getMessage();
}
} else {
if (e.getMessage() == null) {
msg = msgPrefix;
} else {
msg = msgPrefix + ": " + e.getMessage();
}
}
portletContext.log(msg, e);
Throwable cause = e.getCause();
if (cause != null && cause != e) {
logException(cause, "Root cause");
}
if (e instanceof PortletException) {
cause = ((PortletException) e).getCause();
if (cause != null && cause != e) {
logException(cause, "Root cause of PortletException");
}
}
}
public class ActionRequestWrapper implements ActionRequest {
private ActionRequest delegee;
Map reqParams;
/**
* @param delegee
* @param params
*/
public ActionRequestWrapper(ActionRequest delegee, Map params) {
super();
this.delegee = delegee;
reqParams = params;
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getParameterNames()
*/
public Enumeration getParameterNames() {
return Collections.enumeration(reqParams.keySet());
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getParameter(java.lang.String)
*/
public String getParameter(String arg0) {
String[] values = (String[])reqParams.get(arg0);
if (values == null) {
return null;
}
return values[0];
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getParameterMap()
*/
public Map getParameterMap() {
return reqParams;
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getParameterValues(java.lang.String)
*/
public String[] getParameterValues(String arg0) {
String[] values = (String[])reqParams.get(arg0);
return values;
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getAttribute(java.lang.String)
*/
public Object getAttribute(String arg0) {
return delegee.getAttribute(arg0);
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getAttributeNames()
*/
public Enumeration getAttributeNames() {
return delegee.getAttributeNames();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getAuthType()
*/
public String getAuthType() {
return delegee.getAuthType();
}
/* (non-Javadoc)
* @see javax.portlet.ActionRequest#getCharacterEncoding()
*/
public String getCharacterEncoding() {
return delegee.getCharacterEncoding();
}
/* (non-Javadoc)
* @see javax.portlet.ActionRequest#getContentLength()
*/
public int getContentLength() {
return delegee.getContentLength();
}
/* (non-Javadoc)
* @see javax.portlet.ActionRequest#getContentType()
*/
public String getContentType() {
return delegee.getContentType();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getContextPath()
*/
public String getContextPath() {
return delegee.getContextPath();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getLocale()
*/
public Locale getLocale() {
return delegee.getLocale();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getLocales()
*/
public Enumeration getLocales() {
return delegee.getLocales();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getPortalContext()
*/
public PortalContext getPortalContext() {
return delegee.getPortalContext();
}
/* (non-Javadoc)
* @see javax.portlet.ActionRequest#getPortletInputStream()
*/
public InputStream getPortletInputStream() throws IOException {
return delegee.getPortletInputStream();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getPortletMode()
*/
public PortletMode getPortletMode() {
return delegee.getPortletMode();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getPortletSession()
*/
public PortletSession getPortletSession() {
return delegee.getPortletSession();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getPortletSession(boolean)
*/
public PortletSession getPortletSession(boolean arg0) {
return delegee.getPortletSession(arg0);
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getPreferences()
*/
public PortletPreferences getPreferences() {
return delegee.getPreferences();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getProperties(java.lang.String)
*/
public Enumeration getProperties(String arg0) {
return delegee.getProperties(arg0);
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getProperty(java.lang.String)
*/
public String getProperty(String arg0) {
return delegee.getProperty(arg0);
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getPropertyNames()
*/
public Enumeration getPropertyNames() {
return delegee.getPropertyNames();
}
/* (non-Javadoc)
* @see javax.portlet.ActionRequest#getReader()
*/
public BufferedReader getReader() throws UnsupportedEncodingException, IOException {
return delegee.getReader();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getRemoteUser()
*/
public String getRemoteUser() {
return delegee.getRemoteUser();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getRequestedSessionId()
*/
public String getRequestedSessionId() {
return delegee.getRequestedSessionId();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getResponseContentType()
*/
public String getResponseContentType() {
return delegee.getResponseContentType();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getResponseContentTypes()
*/
public Enumeration getResponseContentTypes() {
return delegee.getResponseContentTypes();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getScheme()
*/
public String getScheme() {
return delegee.getScheme();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getServerName()
*/
public String getServerName() {
return delegee.getServerName();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getServerPort()
*/
public int getServerPort() {
return delegee.getServerPort();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getUserPrincipal()
*/
public Principal getUserPrincipal() {
return delegee.getUserPrincipal();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#getWindowState()
*/
public WindowState getWindowState() {
return delegee.getWindowState();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#isPortletModeAllowed(javax.portlet.PortletMode)
*/
public boolean isPortletModeAllowed(PortletMode arg0) {
return delegee.isPortletModeAllowed(arg0);
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#isRequestedSessionIdValid()
*/
public boolean isRequestedSessionIdValid() {
return delegee.isRequestedSessionIdValid();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#isSecure()
*/
public boolean isSecure() {
return delegee.isSecure();
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#isUserInRole(java.lang.String)
*/
public boolean isUserInRole(String arg0) {
return delegee.isUserInRole(arg0);
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#isWindowStateAllowed(javax.portlet.WindowState)
*/
public boolean isWindowStateAllowed(WindowState arg0) {
return delegee.isWindowStateAllowed(arg0);
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#removeAttribute(java.lang.String)
*/
public void removeAttribute(String arg0) {
delegee.removeAttribute(arg0);
}
/* (non-Javadoc)
* @see javax.portlet.PortletRequest#setAttribute(java.lang.String, java.lang.Object)
*/
public void setAttribute(String arg0, Object arg1) {
delegee.setAttribute(arg0, arg1);
}
/* (non-Javadoc)
* @see javax.portlet.ActionRequest#setCharacterEncoding(java.lang.String)
*/
public void setCharacterEncoding(String arg0) throws UnsupportedEncodingException {
delegee.setCharacterEncoding(arg0);
}
}
/**
* This class provides a very crude workaround for carrying the "autoscroll"
* request parameter from the process stage to the render stage. While
* it would be a bit more elegant to wrap the RenderRequest, this is not
* possible as it leads to a class cast exception in pluto 1.0.1.
*
* @author Michael Lipp
*/
public class MyPortletExternalContextImpl
extends PortletExternalContextImpl {
private Map reqParams;
private Map reqParamsImmutable;
/**
* Create a new instance with all atributes initialized
* to defaults or the given values.
*
* @param portletContext
* @param portletRequest
* @param portletResponse
*/
public MyPortletExternalContextImpl
(PortletContext portletContext,
PortletRequest portletRequest, PortletResponse portletResponse) {
super(portletContext, portletRequest, portletResponse);
reqParams = new HashMap (portletRequest.getParameterMap());
reqParamsImmutable = Collections.unmodifiableMap(reqParams);
}
public void addParameter (String key, String value) {
reqParams.put(key, value);
}
public Map getRequestParameterMap() {
return reqParamsImmutable;
}
}
private void dumpRequestInfo (PortletRequest request) {
logger.debug("Session attributes (application scope):");
PortletSession pSession = request.getPortletSession();
for (Enumeration e = pSession
.getAttributeNames(PortletSession.APPLICATION_SCOPE);
e.hasMoreElements();) {
String attrName = (String)e.nextElement();
logMappingProtected(attrName, pSession.getAttribute
(attrName, PortletSession.APPLICATION_SCOPE));
}
logger.debug("Session attributes (portlet scope):");
for (Enumeration e = pSession
.getAttributeNames(PortletSession.PORTLET_SCOPE);
e.hasMoreElements();) {
String attrName = (String)e.nextElement();
logMappingProtected(attrName, pSession.getAttribute
(attrName, PortletSession.PORTLET_SCOPE));
}
logger.debug("Request attributes:");
for (Enumeration e = request.getAttributeNames();
e.hasMoreElements();) {
String attrName = (String)e.nextElement();
logMappingProtected
(attrName, request.getAttribute(attrName));
}
logger.debug("Request parameters:");
for (Iterator i = request.getParameterMap().entrySet().iterator();
i.hasNext();) {
Map.Entry e = (Map.Entry)i.next();
String[] values = (String[])e.getValue();
logMappingProtected
(e.getKey().toString(), "[" + Misc.join(values, ", ") + "]");
}
logger.debug("Request properties:");
for (Enumeration e = request.getPropertyNames(); e.hasMoreElements();) {
String prop = (String)e.nextElement();
logMappingProtected (prop.toString(),
"[" + Misc.join(request.getProperties(prop), ", ") + "]");
}
}
private void logMappingProtected (String key, Object value) {
if (value != null && !(value instanceof String)) {
value = value.toString();
}
if (key.indexOf("PASSWORD") >= 0) {
logger.debug (" " + key + " => ********");
} else {
logger.debug (" " + key + " => " + value);
}
}
}