0001: /*
0002: * This file is part of the WfMOpen project.
0003: * Copyright (C) 2001-2005 Danet GmbH (www.danet.de), BU BTS.
0004: * All rights reserved.
0005: *
0006: * This program is free software; you can redistribute it and/or modify
0007: * it under the terms of the GNU General Public License as published by
0008: * the Free Software Foundation; either version 2 of the License, or
0009: * (at your option) any later version.
0010: *
0011: * This program is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0014: * GNU General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU General Public License
0017: * along with this program; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0019: *
0020: * Derived from MyFacesGenericPortlet,
0021: * Copyright 2004 The Apache Software Foundation.
0022: *
0023: * $Id: MyFacesAdaptedPortlet.java,v 1.32 2007/05/27 15:23:34 mlipp Exp $
0024: *
0025: * $Log: MyFacesAdaptedPortlet.java,v $
0026: * Revision 1.32 2007/05/27 15:23:34 mlipp
0027: * Removed erroneously inserted localization in processAction.
0028: *
0029: * Revision 1.31 2007/05/27 10:03:05 mlipp
0030: * Improved locale detection/setting.
0031: *
0032: * Revision 1.30 2007/05/26 22:55:50 mlipp
0033: * Fixed file upload.
0034: *
0035: * Revision 1.29 2007/05/26 21:53:48 mlipp
0036: * More debug infos.
0037: *
0038: * Revision 1.28 2007/05/22 14:04:45 drmlipp
0039: * Avoid duplicate processing of multipart request.
0040: *
0041: * Revision 1.27 2007/02/26 22:12:28 mlipp
0042: * Updated to MyFaces core 1.1.5/Tomahawk 1.1.3.
0043: *
0044: * Revision 1.26 2006/12/12 09:53:20 drmlipp
0045: * Added Ajax support.
0046: *
0047: * Revision 1.25 2006/12/05 09:14:11 drmlipp
0048: * Suppressing superfluous warning.
0049: *
0050: * Revision 1.24 2006/11/20 13:46:30 drmlipp
0051: * Restore initial JSF state after exception.
0052: *
0053: * Revision 1.23 2006/10/11 19:31:59 mlipp
0054: * Fixed problem with language switching.
0055: *
0056: * Revision 1.22 2006/09/29 12:32:11 drmlipp
0057: * Consistently using WfMOpen as projct name now.
0058: *
0059: * Revision 1.21 2006/09/20 15:27:43 drmlipp
0060: * Workaround for strange ClasscastException.
0061: *
0062: * Revision 1.20 2006/09/12 12:56:18 drmlipp
0063: * Fixed autoscroll for portlets.
0064: *
0065: * Revision 1.19 2006/09/11 15:29:28 drmlipp
0066: * Improved portlet support.
0067: *
0068: * Revision 1.18 2006/09/08 14:08:06 drmlipp
0069: * Started handling of MyFaces resource loading.
0070: *
0071: * Revision 1.17 2006/08/29 15:03:11 drmlipp
0072: * Added JavaScript insertion to portlet bridge. Re-enabled scrolling support.
0073: *
0074: * Revision 1.16 2006/08/28 21:22:44 mlipp
0075: * Updated MyFaces to 1.1.3.
0076: *
0077: * Revision 1.15 2006/05/31 20:52:18 mlipp
0078: * Fixed problem with left over session data.
0079: *
0080: * Revision 1.14 2006/04/15 10:04:25 mlipp
0081: * Removed Liferay bug workaround.
0082: *
0083: * Revision 1.13 2005/11/14 13:26:02 drmlipp
0084: * Fixed problem with request attributes being passed between portlets
0085: * (breaks MyFaces).
0086: *
0087: * Revision 1.12 2005/11/14 09:34:25 drmlipp
0088: * Improved workaround for liferay bug.
0089: *
0090: * Revision 1.11 2005/11/10 20:52:55 mlipp
0091: * Fixed problem with classloader dependend Lifecycle access.
0092: *
0093: * Revision 1.10 2005/11/10 16:04:23 drmlipp
0094: * Workaround for liferay bug.
0095: *
0096: * Revision 1.9 2005/11/07 14:02:13 drmlipp
0097: * Make action request attributes available during rendering.
0098: *
0099: * Revision 1.8 2005/10/11 12:31:38 drmlipp
0100: * Fixed portlet mode comparison.
0101: *
0102: * Revision 1.7 2005/10/10 20:49:59 mlipp
0103: * Improved JSF lifecycle support.
0104: *
0105: * Revision 1.6 2005/09/28 15:12:41 drmlipp
0106: * Updated MyFaces to 1.1.
0107: *
0108: * Revision 1.5 2005/09/16 13:50:25 drmlipp
0109: * Improved file upload support.
0110: *
0111: * Revision 1.4 2005/09/15 22:06:21 mlipp
0112: * Upload implementation continued.
0113: *
0114: * Revision 1.3 2005/09/15 15:06:30 drmlipp
0115: * Continuing implementation of upload portlet.
0116: *
0117: * Revision 1.2 2005/09/15 11:03:34 drmlipp
0118: * Fixed mode issues.
0119: *
0120: * Revision 1.1 2005/09/13 13:43:29 drmlipp
0121: * Using portlet/JSF bridge from MyFaces again (in an adapted version).
0122: *
0123: */
0124: package de.danet.an.util.jsf;
0125:
0126: import java.io.BufferedReader;
0127: import java.io.IOException;
0128: import java.io.InputStream;
0129: import java.io.Serializable;
0130: import java.io.UnsupportedEncodingException;
0131: import java.security.Principal;
0132: import java.util.Collections;
0133: import java.util.Enumeration;
0134: import java.util.HashMap;
0135: import java.util.HashSet;
0136: import java.util.Iterator;
0137: import java.util.List;
0138: import java.util.Locale;
0139: import java.util.Map;
0140: import java.util.Set;
0141:
0142: import javax.faces.FactoryFinder;
0143: import javax.faces.application.Application;
0144: import javax.faces.application.ApplicationFactory;
0145: import javax.faces.application.FacesMessage;
0146: import javax.faces.application.ViewHandler;
0147: import javax.faces.component.UIViewRoot;
0148: import javax.faces.context.ExternalContext;
0149: import javax.faces.context.FacesContext;
0150: import javax.faces.context.FacesContextFactory;
0151: import javax.faces.lifecycle.Lifecycle;
0152: import javax.faces.lifecycle.LifecycleFactory;
0153: import javax.faces.webapp.FacesServlet;
0154: import javax.portlet.ActionRequest;
0155: import javax.portlet.ActionResponse;
0156: import javax.portlet.GenericPortlet;
0157: import javax.portlet.PortalContext;
0158: import javax.portlet.PortletContext;
0159: import javax.portlet.PortletException;
0160: import javax.portlet.PortletMode;
0161: import javax.portlet.PortletPreferences;
0162: import javax.portlet.PortletRequest;
0163: import javax.portlet.PortletResponse;
0164: import javax.portlet.PortletSession;
0165: import javax.portlet.RenderRequest;
0166: import javax.portlet.RenderResponse;
0167: import javax.portlet.UnavailableException;
0168: import javax.portlet.WindowState;
0169:
0170: import org.apache.commons.fileupload.FileItem;
0171: import org.apache.commons.fileupload.FileUploadException;
0172: import org.apache.commons.fileupload.disk.DiskFileItemFactory;
0173: import org.apache.commons.fileupload.portlet.PortletFileUpload;
0174: import org.apache.myfaces.config.FacesConfigurator;
0175: import org.apache.myfaces.context.ReleaseableExternalContext;
0176: import org.apache.myfaces.context.portlet.PortletExternalContextImpl;
0177: import org.apache.myfaces.context.servlet.ServletFacesContextImpl;
0178: import org.apache.myfaces.portlet.PortletUtil;
0179: import org.apache.myfaces.renderkit.html.util.AddResource;
0180: import org.apache.myfaces.renderkit.html.util.AddResourceFactory;
0181: import org.apache.myfaces.shared_impl.webapp.webxml.WebXml;
0182:
0183: import de.danet.an.util.Misc;
0184:
0185: /**
0186: * This portlet initializes MyFaces and converts portlet requests into
0187: * JSF requests.
0188: *
0189: * @author Stan Silvert (latest modification by $Author: mlipp $)
0190: */
0191: public class MyFacesAdaptedPortlet extends GenericPortlet {
0192: private static final org.apache.commons.logging.Log logger = org.apache.commons.logging.LogFactory
0193: .getLog(MyFacesAdaptedPortlet.class);
0194:
0195: // PortletSession attribute
0196: public static final String VIEW_ID = MyFacesAdaptedPortlet.class
0197: .getName()
0198: + ".VIEW_ID";
0199:
0200: public static final String PREV_MODE = MyFacesAdaptedPortlet.class
0201: .getName()
0202: + ".PREV_MODE";
0203:
0204: // PortletSession attribute
0205: public static final String CURRENT_FACES_CONTEXT = MyFacesAdaptedPortlet.class
0206: .getName()
0207: + ".CURRENT_FACES_CONTEXT";
0208:
0209: protected static final String FACES_INIT_DONE = MyFacesAdaptedPortlet.class
0210: .getName()
0211: + ".FACES_INIT_DONE";
0212:
0213: public static final String FILE_ITEMS = MyFacesAdaptedPortlet.class
0214: .getName()
0215: + ".FILE_ITEMS";
0216:
0217: public static final String REQUEST_ATTRIBUTES = MyFacesAdaptedPortlet.class
0218: .getName()
0219: + ".REQUEST_ATTRIBUTES";
0220:
0221: public static final String NAMESPACE_PREFIX = MyFacesAdaptedPortlet.class
0222: .getName()
0223: + ".NAMESPACE_PREFIX";
0224:
0225: public static final String LIFECYCLE_ID = MyFacesAdaptedPortlet.class
0226: .getName()
0227: + ".LIFECYCLE_ID";
0228:
0229: /** Name of portlet preference for Edit page. */
0230: protected static final String PARAM_EDIT_PAGE = "EditPage";
0231:
0232: /** Name of portlet preference for Edit page */
0233: protected static final String PARAM_HELP_PAGE = "HelpPage";
0234:
0235: /** Name of portlet preference for View page */
0236: protected static final String PARAM_VIEW_PAGE = "ViewPage";
0237:
0238: private static Set serializabilityWarnings = new HashSet();
0239:
0240: /** Private in JavascriptUtils, what a pity... */
0241: private static final String AUTO_SCROLL_PARAM = "autoScroll";
0242:
0243: /** Default URL for the edit page. */
0244: private String defaultEditPage = null;
0245:
0246: /** Default URL for the help page. */
0247: private String defaultHelpPage = null;
0248:
0249: /** Default URL for the view page. */
0250: private String defaultViewPage = null;
0251:
0252: private String uploadMaxFileSize = null;
0253: private String uploadThresholdSize = null;
0254:
0255: protected PortletContext portletContext;
0256:
0257: protected FacesContextFactory facesContextFactory;
0258: protected Lifecycle lifecycle;
0259:
0260: /**
0261: * Creates a new instance of MyFacesPortlet
0262: */
0263: public MyFacesAdaptedPortlet() {
0264: }
0265:
0266: /**
0267: * Portlet lifecycle.
0268: */
0269: public void destroy() {
0270: super .destroy();
0271: FactoryFinder.releaseFactories();
0272: }
0273:
0274: /**
0275: * Portlet lifecycle.
0276: */
0277: public void init() throws PortletException, UnavailableException {
0278: this .portletContext = getPortletContext();
0279: this .defaultViewPage = getPortletConfig().getInitParameter(
0280: PARAM_VIEW_PAGE);
0281: this .defaultEditPage = getPortletConfig().getInitParameter(
0282: PARAM_EDIT_PAGE);
0283: this .defaultHelpPage = getPortletConfig().getInitParameter(
0284: PARAM_HELP_PAGE);
0285: uploadMaxFileSize = getPortletConfig().getInitParameter(
0286: "uploadMaxFileSize");
0287: uploadThresholdSize = getPortletConfig().getInitParameter(
0288: "uploadThresholdSize");
0289:
0290: if (null == this .defaultViewPage) {
0291: // A Faces Portlet is required to have at least the
0292: // defaultViewPage
0293: // defined!
0294: throw new PortletException(
0295: "Portlet "
0296: + getPortletConfig().getPortletName()
0297: + " is incorrectly configured. No default View page is defined.");
0298: }
0299: initMyFaces();
0300:
0301: facesContextFactory = (FacesContextFactory) FactoryFinder
0302: .getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
0303:
0304: // Javadoc says: Lifecycle instance is shared across multiple simultaneous requests, it must be
0305: // implemented in a thread-safe manner. So we can acquire it here once:
0306: LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder
0307: .getFactory(FactoryFinder.LIFECYCLE_FACTORY);
0308: lifecycle = lifecycleFactory.getLifecycle(getLifecycleId());
0309: }
0310:
0311: protected void setContentType(RenderRequest request,
0312: RenderResponse response) {
0313:
0314: if (response.getContentType() == null) {
0315: String portalPreferredContentType = request
0316: .getResponseContentType();
0317: if (portalPreferredContentType != null) {
0318: response.setContentType(portalPreferredContentType);
0319: } else {
0320: response.setContentType("text/html");
0321: }
0322: }
0323: }
0324:
0325: private String getLifecycleId() {
0326: String lifecycleId = getPortletConfig().getInitParameter(
0327: FacesServlet.LIFECYCLE_ID_ATTR);
0328: return lifecycleId != null ? lifecycleId
0329: : LifecycleFactory.DEFAULT_LIFECYCLE;
0330: }
0331:
0332: protected void initMyFaces() {
0333: try {
0334: Boolean b = (Boolean) portletContext
0335: .getAttribute(FACES_INIT_DONE);
0336:
0337: if (b == null || b.booleanValue() == false) {
0338: logger.trace("Initializing MyFaces");
0339:
0340: //Load the configuration
0341: ExternalContext externalContext = new PortletExternalContextImpl(
0342: portletContext, null, null);
0343:
0344: //And configure everything
0345: new FacesConfigurator(externalContext).configure();
0346:
0347: // parse web.xml - not sure if this is needed for portlet
0348: WebXml.init(externalContext);
0349:
0350: portletContext.setAttribute(FACES_INIT_DONE,
0351: Boolean.TRUE);
0352: } else {
0353: logger.info("MyFaces already initialized");
0354: }
0355: } catch (Exception ex) {
0356: logger
0357: .error("Error initializing MyFacesAdaptedPortlet",
0358: ex);
0359: }
0360:
0361: logger.info("PortletContext '"
0362: + portletContext.getRealPath("/") + "' initialized.");
0363: }
0364:
0365: /**
0366: * Called by the portlet container to allow the portlet to process an
0367: * action request.
0368: */
0369: public void processAction(ActionRequest request,
0370: ActionResponse response) throws PortletException,
0371: IOException {
0372: if (logger.isTraceEnabled())
0373: logger.trace("called processAction");
0374:
0375: if (sessionTimedOut(request)) {
0376: return;
0377: }
0378:
0379: if (logger.isDebugEnabled()) {
0380: dumpRequestInfo(request);
0381: }
0382:
0383: setPortletRequestFlag(request);
0384:
0385: FileUploadException uploadException = null;
0386: if (PortletFileUpload.isMultipartContent(request)) {
0387: try {
0388: DiskFileItemFactory dfif = new DiskFileItemFactory();
0389: if (uploadMaxFileSize != null) {
0390: dfif
0391: .setSizeThreshold(resolveSize(uploadThresholdSize));
0392: }
0393: PortletFileUpload pfu = new PortletFileUpload(dfif);
0394: if (uploadMaxFileSize != null) {
0395: pfu.setSizeMax(resolveSize(uploadMaxFileSize));
0396: }
0397: List items = pfu.parseRequest(request);
0398: Map reqParms = new HashMap(request.getParameterMap());
0399: // Liferay (and may be others) process multipart content
0400: // before calling processAction. Avoid doing it twice.
0401: Set preprocessed = new HashSet(reqParms.keySet());
0402: PortletSession session = request.getPortletSession();
0403: for (Iterator i = items.iterator(); i.hasNext();) {
0404: FileItem item = (FileItem) i.next();
0405: if (logger.isDebugEnabled()) {
0406: logger.debug("Got file item: " + item);
0407: }
0408: if (item.isFormField()) {
0409: if (preprocessed.contains(item.getFieldName())) {
0410: continue;
0411: }
0412: if (!reqParms.containsKey(item.getFieldName())) {
0413: reqParms.put(item.getFieldName(),
0414: new String[] { item.getString() });
0415: } else {
0416: String[] oldVals = ((String[]) reqParms
0417: .get(item.getFieldName()));
0418: String[] newVals = new String[oldVals.length + 1];
0419: System.arraycopy(oldVals, 0, newVals, 0,
0420: oldVals.length);
0421: newVals[oldVals.length] = item.getString();
0422: reqParms.put(item.getFieldName(), newVals);
0423: }
0424: } else {
0425: if (session.getAttribute(FILE_ITEMS) == null) {
0426: session.setAttribute(FILE_ITEMS,
0427: new HashMap());
0428: }
0429: ((Map) session.getAttribute(FILE_ITEMS)).put(
0430: item.getFieldName(), item);
0431: }
0432: }
0433: request = new ActionRequestWrapper(request, reqParms);
0434: } catch (FileUploadException e) {
0435: uploadException = e;
0436: }
0437: }
0438:
0439: FacesContext facesContext = facesContext(request, response);
0440:
0441: if (uploadException != null) {
0442: JSFUtil
0443: .addMessage(FacesMessage.SEVERITY_ERROR,
0444: facesContext.getViewRoot().getLocale(),
0445: "de.danet.an.util.I18n",
0446: "error.sizeLimitExceeded",
0447: new Object[] { uploadMaxFileSize },
0448: uploadException);
0449: }
0450:
0451: try {
0452: request.setAttribute(JSFUtil.LIFECYCLE, lifecycle);
0453: List oldAttrs = Collections.list(request
0454: .getAttributeNames());
0455: lifecycle.execute(facesContext);
0456: Map newAttrs = new HashMap();
0457: for (Enumeration e = request.getAttributeNames(); e
0458: .hasMoreElements();) {
0459: String name = (String) e.nextElement();
0460: if (oldAttrs.contains(name)
0461: || (name
0462: .equals("org.apache.myfaces.application.jsp"
0463: + ".JspStateManagerImpl.RESTORED_SERIALIZED_VIEW"))) {
0464: continue;
0465: }
0466: Object val = request.getAttribute(name);
0467: request.removeAttribute(name);
0468: if (!(val instanceof Serializable)) {
0469: String valClassName = val.getClass().getName();
0470: if (!serializabilityWarnings.contains(valClassName)) {
0471: logger
0472: .warn("Request attribute "
0473: + name
0474: + " is of "
0475: + "non-serializable type "
0476: + valClassName
0477: + " and will not be available during rendering");
0478: serializabilityWarnings.add(valClassName);
0479: }
0480: continue;
0481: }
0482: newAttrs.put(name, val);
0483: }
0484: request.getPortletSession().setAttribute(
0485: REQUEST_ATTRIBUTES, newAttrs);
0486: // Carry AUTO_SCROLL_PARAM over to rendering
0487: if (request.getParameter(AUTO_SCROLL_PARAM) != null) {
0488: request.getPortletSession().setAttribute(
0489: AUTO_SCROLL_PARAM,
0490: request.getParameter(AUTO_SCROLL_PARAM));
0491: }
0492:
0493: if (!facesContext.getResponseComplete()) {
0494: request.getPortletSession().setAttribute(VIEW_ID,
0495: facesContext.getViewRoot().getViewId());
0496: }
0497:
0498: request.getPortletSession().setAttribute(
0499: CURRENT_FACES_CONTEXT, facesContext);
0500: } catch (Throwable e) {
0501: facesContext.release();
0502: handleExceptionFromLifecycle(e);
0503: } finally {
0504: Map fileItemMap = ((Map) request.getPortletSession()
0505: .getAttribute(FILE_ITEMS));
0506: if (fileItemMap != null) {
0507: for (Iterator i = fileItemMap.values().iterator(); i
0508: .hasNext();) {
0509: FileItem item = (FileItem) i.next();
0510: item.delete();
0511: }
0512: request.getPortletSession().removeAttribute(FILE_ITEMS);
0513: }
0514: }
0515: }
0516:
0517: private int resolveSize(String param) {
0518: param = param.toLowerCase();
0519: int factor = 1;
0520: String number = param;
0521:
0522: if (param.endsWith("g")) {
0523: factor = 1024 * 1024 * 1024;
0524: number = param.substring(0, param.length() - 1);
0525: } else if (param.endsWith("m")) {
0526: factor = 1024 * 1024;
0527: number = param.substring(0, param.length() - 1);
0528: } else if (param.endsWith("k")) {
0529: factor = 1024;
0530: number = param.substring(0, param.length() - 1);
0531: }
0532: return Integer.parseInt(number) * factor;
0533: }
0534:
0535: protected void handleExceptionFromLifecycle(Throwable e)
0536: throws PortletException, IOException {
0537: logException(e, null);
0538:
0539: if (e instanceof IOException) {
0540: throw (IOException) e;
0541: }
0542:
0543: if (e instanceof PortletException) {
0544: throw (PortletException) e;
0545: }
0546:
0547: if (e.getMessage() != null) {
0548: throw new PortletException(e.getMessage(), e);
0549: }
0550:
0551: throw new PortletException(e);
0552: }
0553:
0554: /**
0555: * Helper method to serve up the view mode.
0556: */
0557: protected void doView(RenderRequest request, RenderResponse response)
0558: throws PortletException, IOException {
0559: facesRender(request, response);
0560: }
0561:
0562: /**
0563: * Helper method to serve up the edit mode. Can be overridden to add
0564: * the edit mode concept to a JSF application.
0565: */
0566: protected void doEdit(RenderRequest request, RenderResponse response)
0567: throws PortletException, IOException {
0568: facesRender(request, response);
0569: }
0570:
0571: /**
0572: * Helper method to serve up the edit mode. Can be overridden to add
0573: * the help mode concept to a JSF application.
0574: */
0575: protected void doHelp(RenderRequest request, RenderResponse response)
0576: throws PortletException, IOException {
0577: facesRender(request, response);
0578: }
0579:
0580: /**
0581: * This method follows JSF Spec section 2.1.1. It renders the default view from a non-faces
0582: * request.
0583: *
0584: * @param request The portlet render request.
0585: * @param response The portlet render response.
0586: */
0587: protected void nonFacesRequest(RenderRequest request,
0588: RenderResponse response) throws PortletException {
0589: nonFacesRequest(request, response, selectDefaultView(request,
0590: response));
0591:
0592: }
0593:
0594: /**
0595: * This method follows JSF Spec section 2.1.1. It renders a view from a non-faces
0596: * request. This is useful for a default view as well as for views that need to
0597: * be rendered from the portlet's edit and help buttons.
0598: *
0599: * @param request The portlet render request.
0600: * @param response The portlet render response.
0601: * @param view The name of the view that needs to be rendered.
0602: */
0603: protected void nonFacesRequest(RenderRequest request,
0604: RenderResponse response, String view)
0605: throws PortletException {
0606: if (logger.isTraceEnabled())
0607: logger.trace("Non-faces request: contextPath = "
0608: + request.getContextPath());
0609: setContentType(request, response); // do this in case nonFacesRequest is called by a subclass
0610: ApplicationFactory appFactory = (ApplicationFactory) FactoryFinder
0611: .getFactory(FactoryFinder.APPLICATION_FACTORY);
0612: Application application = appFactory.getApplication();
0613: ViewHandler viewHandler = application.getViewHandler();
0614: FacesContext facesContext = facesContext(request, response);
0615: UIViewRoot viewRoot = viewHandler
0616: .createView(facesContext, view);
0617: viewRoot.setViewId(view);
0618: facesContext.setViewRoot(viewRoot);
0619: renderProtected(request, response, facesContext, false);
0620: }
0621:
0622: /**
0623: * Save current request attributes before rendering and restore them
0624: * afterward. This avoids interaction of two or more JSF based portlets
0625: * on one page.
0626: * @param request the request
0627: * @param response the response
0628: * @param facesContext the faces context
0629: * @param addActionAttributes if <code>true</code> add attributes
0630: * created by portlet in previous <code>lifecycle.execute</code>
0631: * @throws PortletException
0632: */
0633: private void renderProtected(RenderRequest request,
0634: RenderResponse response, FacesContext facesContext,
0635: boolean addActionAttributes) throws PortletException {
0636: if (logger.isDebugEnabled()) {
0637: dumpRequestInfo(request);
0638: }
0639: // Update locale (may change between requests)
0640: facesContext.getViewRoot().setLocale(getLocale(request));
0641: // for use by Ajax servlet
0642: request.getPortletSession().setAttribute(
0643: MyFacesAjaxServlet.RENDER_NAMESPACE,
0644: response.getNamespace());
0645: request.getPortletSession().setAttribute(NAMESPACE_PREFIX,
0646: facesContext.getExternalContext().encodeNamespace(""));
0647: request.getPortletSession().setAttribute(LIFECYCLE_ID,
0648: getLifecycleId());
0649: // save attributes
0650: List oldAttrs = Collections.list(request.getAttributeNames());
0651: if (addActionAttributes) {
0652: // add request parameters added during performAction
0653: Map reqAttrs = (Map) request.getPortletSession()
0654: .getAttribute(REQUEST_ATTRIBUTES);
0655: if (reqAttrs != null) {
0656: for (Iterator i = reqAttrs.entrySet().iterator(); i
0657: .hasNext();) {
0658: Map.Entry e = (Map.Entry) i.next();
0659: request.setAttribute((String) e.getKey(), e
0660: .getValue());
0661: }
0662: }
0663: }
0664: // Add carried over AUTO_SCROLL_PARAM, but only once
0665: if (request.getPortletSession().getAttribute(AUTO_SCROLL_PARAM) != null) {
0666: if (facesContext.getExternalContext() instanceof MyPortletExternalContextImpl) {
0667: ((MyPortletExternalContextImpl) facesContext
0668: .getExternalContext()).addParameter(
0669: AUTO_SCROLL_PARAM, (String) request
0670: .getPortletSession().getAttribute(
0671: AUTO_SCROLL_PARAM));
0672: } else {
0673: logger
0674: .warn("Encountered faces context with foreign external context");
0675: }
0676: request.getPortletSession().removeAttribute(
0677: AUTO_SCROLL_PARAM);
0678: }
0679: request.setAttribute(JSFUtil.LIFECYCLE, lifecycle);
0680:
0681: try {
0682: lifecycle.render(facesContext);
0683: } catch (RuntimeException e) {
0684: // restores entry view, which should work
0685: request.getPortletSession().removeAttribute(VIEW_ID);
0686: throw e;
0687: }
0688:
0689: AddResource addResource = AddResourceFactory
0690: .getInstance(facesContext);
0691: try {
0692: if (addResource instanceof PortletAppAddResource) {
0693: ((PortletAppAddResource) addResource)
0694: .processAppendices(request, response,
0695: facesContext);
0696: }
0697: } catch (IOException e) {
0698: throw new PortletException(e);
0699: }
0700:
0701: // restore request parameters
0702: for (Enumeration e = request.getAttributeNames(); e
0703: .hasMoreElements();) {
0704: String name = (String) e.nextElement();
0705: if (oldAttrs.contains(name)) {
0706: continue;
0707: }
0708: request.removeAttribute(name);
0709: }
0710: }
0711:
0712: protected String selectDefaultView(RenderRequest request,
0713: RenderResponse response) throws PortletException {
0714: if (request.getPortletMode().equals(PortletMode.EDIT)
0715: && defaultEditPage != null) {
0716: return defaultEditPage;
0717: }
0718: if (request.getPortletMode().equals(PortletMode.HELP)
0719: && defaultHelpPage != null) {
0720: return defaultHelpPage;
0721: }
0722: return defaultViewPage;
0723: }
0724:
0725: protected FacesContext facesContext(PortletRequest request,
0726: PortletResponse response) {
0727: FacesContext facesContext = facesContextFactory
0728: .getFacesContext(portletContext, request, response,
0729: lifecycle);
0730: return facesContext;
0731: }
0732:
0733: protected ReleaseableExternalContext makeExternalContext(
0734: PortletRequest request, PortletResponse response) {
0735: return (ReleaseableExternalContext) new MyPortletExternalContextImpl(
0736: portletContext, request, response);
0737: }
0738:
0739: protected boolean sessionTimedOut(PortletRequest request) {
0740: return request.getPortletSession(false) == null;
0741: }
0742:
0743: protected void setPortletRequestFlag(PortletRequest request) {
0744: request.getPortletSession().setAttribute(
0745: PortletUtil.PORTLET_REQUEST_FLAG, "true");
0746: }
0747:
0748: protected Locale getLocale(PortletRequest request) {
0749: // Liferay leaves a locale here
0750: Locale locale = (Locale) request.getPortletSession()
0751: .getAttribute("org.apache.struts.action.LOCALE",
0752: PortletSession.APPLICATION_SCOPE);
0753: if (locale != null) {
0754: return locale;
0755: }
0756: // Fallback: use request locale
0757: return request.getLocale();
0758: }
0759:
0760: /**
0761: * Render a JSF view.
0762: */
0763: protected void facesRender(RenderRequest request,
0764: RenderResponse response) throws PortletException,
0765: java.io.IOException {
0766: if (logger.isTraceEnabled()) {
0767: logger.trace("called facesRender");
0768: }
0769:
0770: setContentType(request, response);
0771:
0772: String prevMode = (String) request.getPortletSession()
0773: .getAttribute(PREV_MODE);
0774: if (prevMode == null
0775: || !prevMode
0776: .equals(request.getPortletMode().toString())) {
0777: request.getPortletSession().removeAttribute(VIEW_ID);
0778: request.getPortletSession().setAttribute(PREV_MODE,
0779: request.getPortletMode().toString());
0780: }
0781:
0782: ServletFacesContextImpl facesContext = (ServletFacesContextImpl) request
0783: .getPortletSession()
0784: .getAttribute(CURRENT_FACES_CONTEXT);
0785: String viewId = (String) request.getPortletSession()
0786: .getAttribute(VIEW_ID);
0787: if (facesContext == null || viewId == null
0788: || sessionTimedOut(request)) {
0789: setPortletRequestFlag(request);
0790: nonFacesRequest(request, response);
0791: return;
0792: }
0793:
0794: setPortletRequestFlag(request);
0795:
0796: try {
0797: // TODO: not sure if this can happen. Also double check this against spec section 2.1.3
0798: if (facesContext.getResponseComplete())
0799: return;
0800:
0801: facesContext.setExternalContext(makeExternalContext(
0802: request, response));
0803: renderProtected(request, response, facesContext, true);
0804: } catch (Throwable e) {
0805: handleExceptionFromLifecycle(e);
0806: }
0807: }
0808:
0809: protected void logException(Throwable e, String msgPrefix) {
0810: String msg;
0811: if (msgPrefix == null) {
0812: if (e.getMessage() == null) {
0813: msg = "Exception in FacesServlet";
0814: } else {
0815: msg = e.getMessage();
0816: }
0817: } else {
0818: if (e.getMessage() == null) {
0819: msg = msgPrefix;
0820: } else {
0821: msg = msgPrefix + ": " + e.getMessage();
0822: }
0823: }
0824:
0825: portletContext.log(msg, e);
0826:
0827: Throwable cause = e.getCause();
0828: if (cause != null && cause != e) {
0829: logException(cause, "Root cause");
0830: }
0831:
0832: if (e instanceof PortletException) {
0833: cause = ((PortletException) e).getCause();
0834:
0835: if (cause != null && cause != e) {
0836: logException(cause, "Root cause of PortletException");
0837: }
0838: }
0839: }
0840:
0841: public class ActionRequestWrapper implements ActionRequest {
0842: private ActionRequest delegee;
0843: Map reqParams;
0844:
0845: /**
0846: * @param delegee
0847: * @param params
0848: */
0849: public ActionRequestWrapper(ActionRequest delegee, Map params) {
0850: super ();
0851: this .delegee = delegee;
0852: reqParams = params;
0853: }
0854:
0855: /* (non-Javadoc)
0856: * @see javax.portlet.PortletRequest#getParameterNames()
0857: */
0858: public Enumeration getParameterNames() {
0859: return Collections.enumeration(reqParams.keySet());
0860: }
0861:
0862: /* (non-Javadoc)
0863: * @see javax.portlet.PortletRequest#getParameter(java.lang.String)
0864: */
0865: public String getParameter(String arg0) {
0866: String[] values = (String[]) reqParams.get(arg0);
0867: if (values == null) {
0868: return null;
0869: }
0870: return values[0];
0871: }
0872:
0873: /* (non-Javadoc)
0874: * @see javax.portlet.PortletRequest#getParameterMap()
0875: */
0876: public Map getParameterMap() {
0877: return reqParams;
0878: }
0879:
0880: /* (non-Javadoc)
0881: * @see javax.portlet.PortletRequest#getParameterValues(java.lang.String)
0882: */
0883: public String[] getParameterValues(String arg0) {
0884: String[] values = (String[]) reqParams.get(arg0);
0885: return values;
0886: }
0887:
0888: /* (non-Javadoc)
0889: * @see javax.portlet.PortletRequest#getAttribute(java.lang.String)
0890: */
0891: public Object getAttribute(String arg0) {
0892: return delegee.getAttribute(arg0);
0893: }
0894:
0895: /* (non-Javadoc)
0896: * @see javax.portlet.PortletRequest#getAttributeNames()
0897: */
0898: public Enumeration getAttributeNames() {
0899: return delegee.getAttributeNames();
0900: }
0901:
0902: /* (non-Javadoc)
0903: * @see javax.portlet.PortletRequest#getAuthType()
0904: */
0905: public String getAuthType() {
0906: return delegee.getAuthType();
0907: }
0908:
0909: /* (non-Javadoc)
0910: * @see javax.portlet.ActionRequest#getCharacterEncoding()
0911: */
0912: public String getCharacterEncoding() {
0913: return delegee.getCharacterEncoding();
0914: }
0915:
0916: /* (non-Javadoc)
0917: * @see javax.portlet.ActionRequest#getContentLength()
0918: */
0919: public int getContentLength() {
0920: return delegee.getContentLength();
0921: }
0922:
0923: /* (non-Javadoc)
0924: * @see javax.portlet.ActionRequest#getContentType()
0925: */
0926: public String getContentType() {
0927: return delegee.getContentType();
0928: }
0929:
0930: /* (non-Javadoc)
0931: * @see javax.portlet.PortletRequest#getContextPath()
0932: */
0933: public String getContextPath() {
0934: return delegee.getContextPath();
0935: }
0936:
0937: /* (non-Javadoc)
0938: * @see javax.portlet.PortletRequest#getLocale()
0939: */
0940: public Locale getLocale() {
0941: return delegee.getLocale();
0942: }
0943:
0944: /* (non-Javadoc)
0945: * @see javax.portlet.PortletRequest#getLocales()
0946: */
0947: public Enumeration getLocales() {
0948: return delegee.getLocales();
0949: }
0950:
0951: /* (non-Javadoc)
0952: * @see javax.portlet.PortletRequest#getPortalContext()
0953: */
0954: public PortalContext getPortalContext() {
0955: return delegee.getPortalContext();
0956: }
0957:
0958: /* (non-Javadoc)
0959: * @see javax.portlet.ActionRequest#getPortletInputStream()
0960: */
0961: public InputStream getPortletInputStream() throws IOException {
0962: return delegee.getPortletInputStream();
0963: }
0964:
0965: /* (non-Javadoc)
0966: * @see javax.portlet.PortletRequest#getPortletMode()
0967: */
0968: public PortletMode getPortletMode() {
0969: return delegee.getPortletMode();
0970: }
0971:
0972: /* (non-Javadoc)
0973: * @see javax.portlet.PortletRequest#getPortletSession()
0974: */
0975: public PortletSession getPortletSession() {
0976: return delegee.getPortletSession();
0977: }
0978:
0979: /* (non-Javadoc)
0980: * @see javax.portlet.PortletRequest#getPortletSession(boolean)
0981: */
0982: public PortletSession getPortletSession(boolean arg0) {
0983: return delegee.getPortletSession(arg0);
0984: }
0985:
0986: /* (non-Javadoc)
0987: * @see javax.portlet.PortletRequest#getPreferences()
0988: */
0989: public PortletPreferences getPreferences() {
0990: return delegee.getPreferences();
0991: }
0992:
0993: /* (non-Javadoc)
0994: * @see javax.portlet.PortletRequest#getProperties(java.lang.String)
0995: */
0996: public Enumeration getProperties(String arg0) {
0997: return delegee.getProperties(arg0);
0998: }
0999:
1000: /* (non-Javadoc)
1001: * @see javax.portlet.PortletRequest#getProperty(java.lang.String)
1002: */
1003: public String getProperty(String arg0) {
1004: return delegee.getProperty(arg0);
1005: }
1006:
1007: /* (non-Javadoc)
1008: * @see javax.portlet.PortletRequest#getPropertyNames()
1009: */
1010: public Enumeration getPropertyNames() {
1011: return delegee.getPropertyNames();
1012: }
1013:
1014: /* (non-Javadoc)
1015: * @see javax.portlet.ActionRequest#getReader()
1016: */
1017: public BufferedReader getReader()
1018: throws UnsupportedEncodingException, IOException {
1019: return delegee.getReader();
1020: }
1021:
1022: /* (non-Javadoc)
1023: * @see javax.portlet.PortletRequest#getRemoteUser()
1024: */
1025: public String getRemoteUser() {
1026: return delegee.getRemoteUser();
1027: }
1028:
1029: /* (non-Javadoc)
1030: * @see javax.portlet.PortletRequest#getRequestedSessionId()
1031: */
1032: public String getRequestedSessionId() {
1033: return delegee.getRequestedSessionId();
1034: }
1035:
1036: /* (non-Javadoc)
1037: * @see javax.portlet.PortletRequest#getResponseContentType()
1038: */
1039: public String getResponseContentType() {
1040: return delegee.getResponseContentType();
1041: }
1042:
1043: /* (non-Javadoc)
1044: * @see javax.portlet.PortletRequest#getResponseContentTypes()
1045: */
1046: public Enumeration getResponseContentTypes() {
1047: return delegee.getResponseContentTypes();
1048: }
1049:
1050: /* (non-Javadoc)
1051: * @see javax.portlet.PortletRequest#getScheme()
1052: */
1053: public String getScheme() {
1054: return delegee.getScheme();
1055: }
1056:
1057: /* (non-Javadoc)
1058: * @see javax.portlet.PortletRequest#getServerName()
1059: */
1060: public String getServerName() {
1061: return delegee.getServerName();
1062: }
1063:
1064: /* (non-Javadoc)
1065: * @see javax.portlet.PortletRequest#getServerPort()
1066: */
1067: public int getServerPort() {
1068: return delegee.getServerPort();
1069: }
1070:
1071: /* (non-Javadoc)
1072: * @see javax.portlet.PortletRequest#getUserPrincipal()
1073: */
1074: public Principal getUserPrincipal() {
1075: return delegee.getUserPrincipal();
1076: }
1077:
1078: /* (non-Javadoc)
1079: * @see javax.portlet.PortletRequest#getWindowState()
1080: */
1081: public WindowState getWindowState() {
1082: return delegee.getWindowState();
1083: }
1084:
1085: /* (non-Javadoc)
1086: * @see javax.portlet.PortletRequest#isPortletModeAllowed(javax.portlet.PortletMode)
1087: */
1088: public boolean isPortletModeAllowed(PortletMode arg0) {
1089: return delegee.isPortletModeAllowed(arg0);
1090: }
1091:
1092: /* (non-Javadoc)
1093: * @see javax.portlet.PortletRequest#isRequestedSessionIdValid()
1094: */
1095: public boolean isRequestedSessionIdValid() {
1096: return delegee.isRequestedSessionIdValid();
1097: }
1098:
1099: /* (non-Javadoc)
1100: * @see javax.portlet.PortletRequest#isSecure()
1101: */
1102: public boolean isSecure() {
1103: return delegee.isSecure();
1104: }
1105:
1106: /* (non-Javadoc)
1107: * @see javax.portlet.PortletRequest#isUserInRole(java.lang.String)
1108: */
1109: public boolean isUserInRole(String arg0) {
1110: return delegee.isUserInRole(arg0);
1111: }
1112:
1113: /* (non-Javadoc)
1114: * @see javax.portlet.PortletRequest#isWindowStateAllowed(javax.portlet.WindowState)
1115: */
1116: public boolean isWindowStateAllowed(WindowState arg0) {
1117: return delegee.isWindowStateAllowed(arg0);
1118: }
1119:
1120: /* (non-Javadoc)
1121: * @see javax.portlet.PortletRequest#removeAttribute(java.lang.String)
1122: */
1123: public void removeAttribute(String arg0) {
1124: delegee.removeAttribute(arg0);
1125: }
1126:
1127: /* (non-Javadoc)
1128: * @see javax.portlet.PortletRequest#setAttribute(java.lang.String, java.lang.Object)
1129: */
1130: public void setAttribute(String arg0, Object arg1) {
1131: delegee.setAttribute(arg0, arg1);
1132: }
1133:
1134: /* (non-Javadoc)
1135: * @see javax.portlet.ActionRequest#setCharacterEncoding(java.lang.String)
1136: */
1137: public void setCharacterEncoding(String arg0)
1138: throws UnsupportedEncodingException {
1139: delegee.setCharacterEncoding(arg0);
1140: }
1141: }
1142:
1143: /**
1144: * This class provides a very crude workaround for carrying the "autoscroll"
1145: * request parameter from the process stage to the render stage. While
1146: * it would be a bit more elegant to wrap the RenderRequest, this is not
1147: * possible as it leads to a class cast exception in pluto 1.0.1.
1148: *
1149: * @author Michael Lipp
1150: */
1151: public class MyPortletExternalContextImpl extends
1152: PortletExternalContextImpl {
1153:
1154: private Map reqParams;
1155: private Map reqParamsImmutable;
1156:
1157: /**
1158: * Create a new instance with all atributes initialized
1159: * to defaults or the given values.
1160: *
1161: * @param portletContext
1162: * @param portletRequest
1163: * @param portletResponse
1164: */
1165: public MyPortletExternalContextImpl(
1166: PortletContext portletContext,
1167: PortletRequest portletRequest,
1168: PortletResponse portletResponse) {
1169: super (portletContext, portletRequest, portletResponse);
1170: reqParams = new HashMap(portletRequest.getParameterMap());
1171: reqParamsImmutable = Collections.unmodifiableMap(reqParams);
1172: }
1173:
1174: public void addParameter(String key, String value) {
1175: reqParams.put(key, value);
1176: }
1177:
1178: public Map getRequestParameterMap() {
1179: return reqParamsImmutable;
1180: }
1181:
1182: }
1183:
1184: private void dumpRequestInfo(PortletRequest request) {
1185: logger.debug("Session attributes (application scope):");
1186: PortletSession pSession = request.getPortletSession();
1187: for (Enumeration e = pSession
1188: .getAttributeNames(PortletSession.APPLICATION_SCOPE); e
1189: .hasMoreElements();) {
1190: String attrName = (String) e.nextElement();
1191: logMappingProtected(attrName, pSession.getAttribute(
1192: attrName, PortletSession.APPLICATION_SCOPE)
1193: .toString());
1194: }
1195: logger.debug("Session attributes (portlet scope):");
1196: for (Enumeration e = pSession
1197: .getAttributeNames(PortletSession.PORTLET_SCOPE); e
1198: .hasMoreElements();) {
1199: String attrName = (String) e.nextElement();
1200: logMappingProtected(attrName, pSession.getAttribute(
1201: attrName, PortletSession.PORTLET_SCOPE).toString());
1202: }
1203: logger.debug("Request attributes:");
1204: for (Enumeration e = request.getAttributeNames(); e
1205: .hasMoreElements();) {
1206: String attrName = (String) e.nextElement();
1207: logMappingProtected(attrName, request
1208: .getAttribute(attrName).toString());
1209: }
1210: logger.debug("Request parameters:");
1211: for (Iterator i = request.getParameterMap().entrySet()
1212: .iterator(); i.hasNext();) {
1213: Map.Entry e = (Map.Entry) i.next();
1214: String[] values = (String[]) e.getValue();
1215: logMappingProtected(e.getKey().toString(), "["
1216: + Misc.join(values, ", ") + "]");
1217: }
1218: logger.debug("Request properties:");
1219: for (Enumeration e = request.getPropertyNames(); e
1220: .hasMoreElements();) {
1221: String prop = (String) e.nextElement();
1222: logMappingProtected(prop.toString(), "["
1223: + Misc.join(request.getProperties(prop), ", ")
1224: + "]");
1225: }
1226: }
1227:
1228: private void logMappingProtected(String key, String value) {
1229: if (key.indexOf("PASSWORD") >= 0) {
1230: logger.debug(" " + key + " => ********");
1231: } else {
1232: logger.debug(" " + key + " => " + value);
1233: }
1234: }
1235: }
|