All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.portlet.faces.GenericFacesPortlet Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
 * law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 * for the specific language governing permissions and limitations under the License.
 */
package javax.portlet.faces;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;

import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletMode;
import javax.portlet.PortletRequest;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.WindowState;

/**
 * The GenericFacesPortlet is provided to simplify development of a portlet that in
 * whole or part relies on the Faces bridge to process requests. If all requests are to be handled
 * by the bridge, GenericFacesPortlet is a turnkey implementation. Developers do not
 * need to subclass it. However, if there are some situations where the portlet doesn't require
 * bridge services then GenericFacesPortlet can be subclassed and overriden.
 * 

* Since GenericFacesPortlet subclasses GenericPortlet care is taken * to all subclasses to override naturally. For example, though doDispatch() is * overriden, requests are only dispatched to the bridge from here if the PortletMode * isn't VIEW, EDIT, or HELP. *

* The GenericFacesPortlet recognizes the following portlet initialization * parameters: *

    *
  • javax.portlet.faces.defaultViewId.[mode]: specifies on a per mode * basis the default viewId the Bridge executes when not already encoded in the incoming request. A * value must be defined for each PortletMode the Bridge is expected * to process.
  • *
  • javax.portlet.faces.excludedRequestAttributes: specifies on a per portlet * basis the set of request attributes the bridge is to exclude from its request scope. The * value of this parameter is a comma delimited list of either fully qualified attribute names or * a partial attribute name of the form packageName.*. In this later case all attributes * exactly prefixed by packageName are excluded, non recursive.
  • *
  • javax.portlet.faces.preserveActionParams: specifies on a per portlet * basis whether the bridge should preserve parameters received in an action request * and restore them for use during subsequent renders.
  • *
  • javax.portlet.faces.defaultContentType: specifies on a per mode * basis the content type the bridge should set for all render requests it processes.
  • *
  • javax.portlet.faces.defaultCharacterSetEncoding: specifies on a per mode * basis the default character set encoding the bridge should set for all render requests it * processes
  • *
* The GenericFacesPortlet recognizes the following application * (PortletContext) initialization parameters: *
    *
  • javax.portlet.faces.BridgeImplClass: specifies the Bridgeimplementation * class used by this portlet. Typically this initialization parameter isn't set as the * GenericFacesPortlet defaults to finding the class name from the bridge * configuration. However if more then one bridge is configured in the environment such * per application configuration is necessary to force a specific bridge to be used. *
  • *
*/ public class GenericFacesPortlet extends GenericPortlet { /** Application (PortletContext) init parameter that names the bridge class used * by this application. Typically not used unless more then 1 bridge is configured * in an environment as its more usual to rely on the self detection. */ public static final String BRIDGE_CLASS = Bridge.BRIDGE_PACKAGE_PREFIX + "BridgeClassName"; /** Portlet init parameter that defines the default ViewId that should be used * when the request doesn't otherwise convery the target. There must be one * initialization parameter for each supported mode. Each parameter is named * DEFAULT_VIEWID.mode, where mode is the name of the corresponding * PortletMode */ public static final String DEFAULT_VIEWID = Bridge.BRIDGE_PACKAGE_PREFIX + "defaultViewId"; /** Portlet init parameter that defines the render response ContentType the bridge * sets prior to rendering. If not set the bridge uses the request's preferred * content type. */ public static final String DEFAULT_CONTENT_TYPE = Bridge.BRIDGE_PACKAGE_PREFIX + "defaultContentType"; /** Portlet init parameter that defines the render response CharacterSetEncoding the bridge * sets prior to rendering. Typcially only set when the jsp outputs an encoding other * then the portlet container's and the portlet container supports response encoding * transformation. */ public static final String DEFAULT_CHARACTERSET_ENCODING = Bridge.BRIDGE_PACKAGE_PREFIX + "defaultCharacterSetEncoding"; /** Portlet init parameter containing the setting for whether the GenericFacesPortlet * overrides event processing by dispatching all events to the bridge or delegates * all event processing to the GenericPortlet. Default is true. */ public static final String BRIDGE_AUTO_DISPATCH_EVENTS = Bridge.BRIDGE_PACKAGE_PREFIX + "autoDispatchEvents"; /** Location of the services descriptor file in a brige installation that defines * the class name of the bridge implementation. */ public static final String BRIDGE_SERVICE_CLASSPATH = "META-INF/services/javax.portlet.faces.Bridge"; private static final String LOGGING_ENABLED = "org.apache.myfaces.portlet.faces.loggingEnabled"; private Class mFacesBridgeClass = null; private Bridge mFacesBridge = null; private HashMap mDefaultViewIdMap = null; private Object mLock = new Object(); // used to synchronize on when initializing the bridge. /** * Initialize generic faces portlet from portlet.xml */ @SuppressWarnings("unchecked") @Override public void init(PortletConfig portletConfig) throws PortletException { super.init(portletConfig); // Make sure the bridge impl class is defined -- if not then search for it // using same search rules as Faces String bridgeClassName = getBridgeClassName(); if (bridgeClassName != null) { try { ClassLoader loader = Thread.currentThread().getContextClassLoader(); mFacesBridgeClass = (Class) loader.loadClass(bridgeClassName); } catch (ClassNotFoundException cnfe) { throw new PortletException("Unable to load configured bridge class: " + bridgeClassName); } } else { throw new PortletException("Can't locate configuration parameter defining the bridge class to use for this portlet:" + getPortletName()); } // Get the other bridge configuration parameters and set as context attributes List excludedAttrs = getExcludedRequestAttributes(); if (excludedAttrs != null) { getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + Bridge.EXCLUDED_REQUEST_ATTRIBUTES, excludedAttrs); } Boolean preserveActionParams = new Boolean(isPreserveActionParameters()); getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + Bridge.PRESERVE_ACTION_PARAMS, preserveActionParams); String defaultRenderKitId = getDefaultRenderKitId(); if (defaultRenderKitId != null) { getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + Bridge.DEFAULT_RENDERKIT_ID, defaultRenderKitId); } Map defaultViewIdMap = getDefaultViewIdMap(); getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + Bridge.DEFAULT_VIEWID_MAP, defaultViewIdMap); BridgeEventHandler eventHandler = getBridgeEventHandler(); if (eventHandler != null) { getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + Bridge.BRIDGE_EVENT_HANDLER, eventHandler); } BridgePublicRenderParameterHandler prpHandler = getBridgePublicRenderParameterHandler(); if (prpHandler != null) { getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + Bridge.BRIDGE_PUBLIC_RENDER_PARAMETER_HANDLER, prpHandler); } // See if this portlet has enabled informational logging messages String s = getPortletConfig().getInitParameter(LOGGING_ENABLED); Boolean b = Boolean.valueOf(s); getPortletContext().setAttribute(Bridge.BRIDGE_PACKAGE_PREFIX + getPortletName() + "." + LOGGING_ENABLED, b); // Initialize the bridge as the double lock mechanism used for lazy instantiation doesn't (always) work in Java even if // declared a volitle -- and the bridge is likely to be used anyway -- so why worry about it initBridge(); } /** * Release resources, specifically it destroys the bridge. */ @Override public void destroy() { if (mFacesBridge != null) { mFacesBridge.destroy(); mFacesBridge = null; mFacesBridgeClass = null; } mDefaultViewIdMap = null; super.destroy(); } /** * If mode is VIEW, EDIT, or HELP -- defer to the doView, doEdit, doHelp so subclasses can * override. Otherwise handle mode here if there is a defaultViewId mapping for it. */ @Override public void doDispatch(RenderRequest request, RenderResponse response) throws PortletException, IOException { // Defer to helper methods for standard modes so subclasses can override PortletMode mode = request.getPortletMode(); if (mode.equals(PortletMode.EDIT) || mode.equals(PortletMode.HELP) || mode.equals(PortletMode.VIEW)) { super.doDispatch(request, response); } else { // Bridge didn't process this one -- so forge ahead if (!doRenderDispatchInternal(request, response)) { super.doDispatch(request, response); } } } @Override protected void doEdit(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException { doRenderDispatchInternal(request, response); } @Override protected void doHelp(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException { doRenderDispatchInternal(request, response); } @Override protected void doView(RenderRequest request, RenderResponse response) throws PortletException, java.io.IOException { doRenderDispatchInternal(request, response); } @Override public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException { doActionDispatchInternal(request, response); } /** * Handles resource requests and dispatches to the Bridge */ @Override public void serveResource(ResourceRequest request, ResourceResponse response) throws PortletException, IOException { doBridgeDispatch(request, response); } /** * Returns an instance of a BridgeEventHandler used to process portlet events * in a JSF environment. * This default implementation looks for a portlet initParameter that * names the class used to instantiate the handler. * @return an instance of BridgeEventHandler or null if there is none. */ public BridgeEventHandler getBridgeEventHandler() { String eventHandlerClass = getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.BRIDGE_EVENT_HANDLER); if (eventHandlerClass != null) { try { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class c = (Class) loader.loadClass(eventHandlerClass); return c.newInstance(); } catch (ClassNotFoundException cnfe) { // Do nothing and fall through to null check // TODO: log something } catch (InstantiationException ie) { // Do nothing and fall through to null check // TODO: log something } catch (Exception e) { // Do nothing and fall through to null check // TODO: log something } } return null; } /** * Returns an instance of a BridgePublicRenderParameterHandler used to post * process public render parameter changes that the bridge * has pushed into mapped models. * This default implementation looks for a portlet initParameter that * names the class used to instantiate the handler. * @return an instance of BridgeRenderParameterHandler or null if there is none. */ public BridgePublicRenderParameterHandler getBridgePublicRenderParameterHandler() { String prpHandlerClass = getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.BRIDGE_PUBLIC_RENDER_PARAMETER_HANDLER); if (prpHandlerClass != null) { try { ClassLoader loader = Thread.currentThread().getContextClassLoader(); Class c = (Class) loader.loadClass(prpHandlerClass); return c.newInstance(); } catch (ClassNotFoundException cnfe) { // Do nothing and fall through to null check // TODO: log something } catch (InstantiationException ie) { // Do nothing and fall through to null check // TODO: log something } catch (Exception e) { // Do nothing and fall through to null check // TODO: log something } } return null; } /** * Returns the set of RequestAttribute names that the portlet wants the bridge to * exclude from its managed request scope. This default implementation picks up * this list from the comma delimited init_param javax.portlet.faces.excludedRequestAttributes. * * @return a List containing the names of the attributes to be excluded. null if it can't be * determined. */ public List getExcludedRequestAttributes() { String excludedAttrs = getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.EXCLUDED_REQUEST_ATTRIBUTES); if (excludedAttrs == null) { return null; } String[] attrArray = excludedAttrs.split(","); // process comma delimited String into a List ArrayList list = new ArrayList(attrArray.length); for (int i = 0; i < attrArray.length; i++) { list.add(attrArray[i].trim()); } return list; } /** * Returns a boolean indicating whether or not the bridge should preserve all the * action parameters in the subsequent renders that occur in the same scope. This * default implementation reads the values from the portlet init_param * javax.portlet.faces.preserveActionParams. If not present, false is returned. * * @return a boolean indicating whether or not the bridge should preserve all the * action parameters in the subsequent renders that occur in the same scope. */ public boolean isPreserveActionParameters() { String preserveActionParams = getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.PRESERVE_ACTION_PARAMS); if (preserveActionParams == null) { return false; } else { return Boolean.parseBoolean(preserveActionParams); } } /** * Returns a String defining the default render kit id the bridge should ensure for this portlet. * If non-null, this value is used to override any default render kit id set on an app wide basis * in the faces-config.xml. This * default implementation reads the values from the portlet init_param * javax.portlet.faces.defaultRenderKitId. If not present, null is returned. * * @return a boolean indicating whether or not the bridge should preserve all the * action parameters in the subsequent renders that occur in the same scope. */ public String getDefaultRenderKitId() { return getPortletConfig().getInitParameter(Bridge.BRIDGE_PACKAGE_PREFIX + Bridge.DEFAULT_RENDERKIT_ID); } /** * Returns the className of the bridge implementation this portlet uses. Subclasses override to * alter the default behavior. Default implementation first checks for a portlet context init * parameter: javax.portlet.faces.BridgeImplClass. If it doesn't exist then it looks for the * resource file "META-INF/services/javax.portlet.faces.Bridge" using the current threads * classloader and extracts the classname from the first line in that file. * * @return the class name of the Bridge class the GenericFacesPortlet uses. null if it can't be * determined. */ public String getBridgeClassName() { String bridgeClassName = getPortletConfig().getPortletContext().getInitParameter(BRIDGE_CLASS); if (bridgeClassName == null) { bridgeClassName = getFromServicesPath(getPortletConfig().getPortletContext(), BRIDGE_SERVICE_CLASSPATH); } return bridgeClassName; } /** * @deprecated -- no longer used or called by the GenericFacesPortlet * but retained in case a subclass has called it. * * * @return request.getResponseContentType(). */ @Deprecated public String getResponseContentType(PortletRequest request) { return request.getResponseContentType(); } private boolean isInRequestedContentTypes(PortletRequest request, String contentTypeToCheck) { Enumeration e = request.getResponseContentTypes(); while (e.hasMoreElements()) { if (contentTypeToCheck.equalsIgnoreCase((String) e.nextElement())) { return true; } } return false; } /** * @deprecated -- no longer used or called by the GenericFacesPortlet * but retained in case a subclass has called it. * * * @return null. */ @Deprecated public String getResponseCharacterSetEncoding(PortletRequest request) { return null; } /** * Returns the defaultViewIdMap the bridge should use when its unable to resolve to a specific * target in the incoming request. There is one entry per support PortletMode * . The entry key is the name of the mode. The entry value is the default viewId * for that mode. * * @return the defaultViewIdMap */ public Map getDefaultViewIdMap() { if (mDefaultViewIdMap == null) { mDefaultViewIdMap = new HashMap(); // loop through all portlet initialization parameters looking for those in the // correct form PortletConfig config = getPortletConfig(); Enumeration e = config.getInitParameterNames(); int len = DEFAULT_VIEWID.length(); while (e.hasMoreElements()) { String s = e.nextElement(); if (s.startsWith(DEFAULT_VIEWID) && s.length() > DEFAULT_VIEWID.length()) { String viewId = config.getInitParameter(s); // Don't add if there isn't a view if (viewId == null || viewId.length() == 0) continue; // extract the mode s = s.substring(len + 1); mDefaultViewIdMap.put(s, viewId); } } } return mDefaultViewIdMap; } /** * Returns the value of the portlet initialization parameter * javax.portlet.faces.autoDispatchEvents if non-null or * true, otherwise. * * @return boolean indicating whether to auto-dispatch all events to the bridge * or not. */ public boolean isAutoDispatchEvents() { String configParam = getPortletConfig().getInitParameter(BRIDGE_AUTO_DISPATCH_EVENTS); if (configParam != null) { return Boolean.parseBoolean(configParam); } else { return true; } } /** * Returns an initialized bridge instance adequately prepared so the caller can * call doFacesRequest directly without further initialization. * * @return instance of the bridge. * @throws PortletException exception acquiring or initializting the bridge. */ public Bridge getFacesBridge(PortletRequest request, PortletResponse response) throws PortletException { initBridgeRequest(request, response); return mFacesBridge; } public void processEvent(EventRequest request, EventResponse response) throws PortletException, java.io.IOException { if (isAutoDispatchEvents()) { try { getFacesBridge(request, response).doFacesRequest(request, response); } catch (BridgeException e) { throw new PortletException("doBridgeDispatch failed: error from Bridge in executing the request", e); } } else { super.processEvent(request, response); } } private boolean isNonFacesRequest(PortletRequest request, PortletResponse response) { // Non Faces request is identified by either the presence of the _jsfBridgeNonFacesView // parameter or the request being for a portlet mode which doesn't have a default // Faces view configured for it. if (request.getParameter(Bridge.NONFACES_TARGET_PATH_PARAMETER) != null) { return true; } String modeDefaultViewId = mDefaultViewIdMap.get(request.getPortletMode().toString()); return modeDefaultViewId == null; } private void doActionDispatchInternal(ActionRequest request, ActionResponse response) throws PortletException, IOException { // First determine whether this is a Faces or nonFaces request if (isNonFacesRequest(request, response)) { throw new PortletException("GenericFacesPortlet: Action request is not for a Faces target. Such nonFaces requests must be handled by a subclass."); } else { doBridgeDispatch(request, response); } } private boolean doRenderDispatchInternal(RenderRequest request, RenderResponse response) throws PortletException, IOException { // First determine whether this is a Faces or nonFaces request if (isNonFacesRequest(request, response)) { return doNonFacesDispatch(request, response); } else { WindowState state = request.getWindowState(); if (!state.equals(WindowState.MINIMIZED)) { doBridgeDispatch(request, response); } return true; } } private boolean doNonFacesDispatch(RenderRequest request, RenderResponse response) throws PortletException { // Can only dispatch if the path is encoded in the request parameter String targetPath = request.getParameter(Bridge.NONFACES_TARGET_PATH_PARAMETER); if (targetPath == null) { // Didn't handle this request return false; } try { PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher(targetPath); dispatcher.forward(request, response); return true; } catch (Exception e) { throw new PortletException("Unable to dispatch to: " + targetPath, e); } } private void doBridgeDispatch(RenderRequest request, RenderResponse response) throws PortletException { try { getFacesBridge(request, response).doFacesRequest(request, response); } catch (BridgeException e) { throw new PortletException("doBridgeDispatch failed: error from Bridge in executing the request", e); } } private void doBridgeDispatch(ActionRequest request, ActionResponse response) throws PortletException { try { getFacesBridge(request, response).doFacesRequest(request, response); } catch (BridgeException e) { throw new PortletException("doBridgeDispatch failed: error from Bridge in executing the request", e); } } private void doBridgeDispatch(ResourceRequest request, ResourceResponse response) throws PortletException { try { getFacesBridge(request, response).doFacesRequest(request, response); } catch (BridgeException e) { throw new PortletException("doBridgeDispatch failed: error from Bridge in executing the request", e); } } private void initBridgeRequest(PortletRequest request, PortletResponse response) throws PortletException { // Now do any per request initialization // In this case look to see if the request is encoded (usually // from a NonFaces view response) with the specific Faces // view to execute. String view = request.getParameter(Bridge.FACES_VIEW_ID_PARAMETER); if (view != null) { request.setAttribute(Bridge.VIEW_ID, view); } else { view = request.getParameter(Bridge.FACES_VIEW_PATH_PARAMETER); if (view != null) { request.setAttribute(Bridge.VIEW_PATH, view); } } } private void initBridge() throws PortletException { // Ensure te Bridge has been constrcuted and initialized if (mFacesBridge == null) { try { // ensure we only ever create/init one bridge per portlet if (mFacesBridge == null) { mFacesBridge = mFacesBridgeClass.newInstance(); mFacesBridge.init(getPortletConfig()); } } catch (Exception e) { throw new PortletException("doBridgeDisptach: error instantiating the bridge class", e); } } } private String getFromServicesPath(PortletContext context, String resourceName) { // Check for a services definition String result = null; BufferedReader reader = null; InputStream stream = null; try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl == null) { return null; } stream = cl.getResourceAsStream(resourceName); if (stream != null) { // Deal with systems whose native encoding is possibly // different from the way that the services entry was created try { reader = new BufferedReader(new InputStreamReader(stream, "UTF-8")); } catch (UnsupportedEncodingException e) { reader = new BufferedReader(new InputStreamReader(stream)); } result = reader.readLine(); if (result != null) { result = result.trim(); } reader.close(); reader = null; stream = null; } } catch (IOException e) { } catch (SecurityException e) { } finally { if (reader != null) { try { reader.close(); stream = null; } catch (Throwable t) { ; } reader = null; } if (stream != null) { try { stream.close(); } catch (Throwable t) { ; } stream = null; } } return result; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy