Package com.liferay.faces.bridge

Source Code of com.liferay.faces.bridge.BridgePhaseBaseImpl

/**
* Copyright (c) 2000-2014 Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library 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 Lesser General Public License for more
* details.
*/
package com.liferay.faces.bridge;

import javax.el.ELContext;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.component.UIViewRoot;
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.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.StateAwareResponse;
import javax.portlet.faces.Bridge;
import javax.portlet.faces.annotation.PortletNamingContainer;

import com.liferay.faces.bridge.config.BridgeConfig;
import com.liferay.faces.bridge.config.BridgeConfigFactory;
import com.liferay.faces.bridge.config.PortletConfigParam;
import com.liferay.faces.bridge.container.PortletContainer;
import com.liferay.faces.bridge.container.PortletContainerFactory;
import com.liferay.faces.bridge.context.BridgeContext;
import com.liferay.faces.bridge.context.BridgeContextFactory;
import com.liferay.faces.bridge.context.IncongruityContext;
import com.liferay.faces.bridge.context.IncongruityContextFactory;
import com.liferay.faces.bridge.helper.PortletModeHelper;
import com.liferay.faces.bridge.scope.BridgeRequestScope;
import com.liferay.faces.bridge.scope.BridgeRequestScopeCache;
import com.liferay.faces.bridge.scope.BridgeRequestScopeCacheFactory;
import com.liferay.faces.bridge.scope.BridgeRequestScopeFactory;
import com.liferay.faces.util.factory.FactoryExtensionFinder;
import com.liferay.faces.util.lang.StringPool;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;


/**
* @author  Neil Griffin
*/
public abstract class BridgePhaseBaseImpl implements BridgePhase {

  // Logger
  private static final Logger logger = LoggerFactory.getLogger(BridgePhaseBaseImpl.class);

  // Private Constants
  private static final String PARAM_BRIDGE_REQUEST_SCOPE_ID = "com.liferay.faces.bridge.bridgeRequestScopeId";

  // Protected Data Members
  protected BridgeConfig bridgeConfig;
  protected BridgeContext bridgeContext;
  protected BridgeRequestScope bridgeRequestScope;
  protected BridgeRequestScopeCache bridgeRequestScopeCache;
  protected FacesContext facesContext;
  protected IncongruityContext incongruityContext;
  protected Lifecycle facesLifecycle;
  protected PortletConfig portletConfig;
  protected PortletContext portletContext;
  protected String portletName;

  // Private Data Members
  private FacesContextFactory facesContextFactory;
  private String pathInfo;
  private String servletPath;

  public BridgePhaseBaseImpl(PortletConfig portletConfig) {
    this.portletConfig = portletConfig;
    this.portletContext = portletConfig.getPortletContext();
    this.portletName = portletConfig.getPortletName();

    BridgeConfigFactory bridgeConfigFactory = (BridgeConfigFactory) FactoryExtensionFinder.getFactory(
        BridgeConfigFactory.class);
    this.bridgeConfig = bridgeConfigFactory.getBridgeConfig(portletConfig);

    // Initialize the incongruity context implementation.
    IncongruityContextFactory incongruityContextFactory = (IncongruityContextFactory) FactoryExtensionFinder
      .getFactory(IncongruityContextFactory.class);
    this.incongruityContext = incongruityContextFactory.getIncongruityContext();

    // Get the bridge request scope cache from the factory.
    BridgeRequestScopeCacheFactory bridgeRequestScopeCacheFactory = (BridgeRequestScopeCacheFactory)
      FactoryExtensionFinder.getFactory(BridgeRequestScopeCacheFactory.class);
    this.bridgeRequestScopeCache = bridgeRequestScopeCacheFactory.getBridgeRequestScopeCache(portletContext);

    // Get the default lifecycle instance from the factory.
    LifecycleFactory lifecycleFactory = (LifecycleFactory) FactoryFinder.getFactory(
        FactoryFinder.LIFECYCLE_FACTORY);
    String lifecycleId = this.portletContext.getInitParameter(FacesServlet.LIFECYCLE_ID_ATTR);

    if (lifecycleId == null) {
      lifecycleId = LifecycleFactory.DEFAULT_LIFECYCLE;
    }

    this.facesLifecycle = lifecycleFactory.getLifecycle(lifecycleId);
  }

  @SuppressWarnings("deprecation")
  protected void cleanup() {

    if (facesContext != null) {
      facesContext.release();
    }

    if (bridgeContext != null) {

      // Cleanup request attributes.
      PortletRequest portletRequest = bridgeContext.getPortletRequest();

      if (portletRequest != null) {
        portletRequest.removeAttribute(BridgeExt.BRIDGE_CONTEXT_ATTRIBUTE);
        portletRequest.removeAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);

        // Restore the cached attributes.
        portletRequest.setAttribute(BridgeConstants.REQ_ATTR_PATH_INFO, pathInfo);
        portletRequest.setAttribute(BridgeConstants.REQ_ATTR_SERVLET_PATH, servletPath);
      }

      bridgeContext.release();
    }

  }

  protected void indicateNamespacingToConsumers(UIViewRoot uiViewRoot, PortletResponse portletResponse) {

    if (uiViewRoot != null) {

      // This method helps satisfy the namespacing requirements of Section 6.6 of the specification. It might be
      // the case that the consumer (portal engine / portlet container) needs to know if all of the form fields
      // have been namespaced properly. If that's the case, then it can check for the existence of the
      // "X-JAVAX-PORTLET-FACES-NAMESPACED-RESPONSE" property on the response, which will be set to "true" if the
      // UIViewRoot is annotated with {@link PortletNamingContainer}.
      if (uiViewRoot.getClass().getAnnotation(PortletNamingContainer.class) != null) {
        portletResponse.addProperty(Bridge.PORTLET_NAMESPACED_RESPONSE_PROPERTY, Boolean.TRUE.toString());
      }
    }
    else {

      // http://issues.liferay.com/browse/FACES-267 Sometimes there are requests that the bridge may see as valid
      // ResourceRequests (e.g. related to Ajax Push) where a ViewRoot might not be available -- this is not an
      // error.
      logger.debug("UIViewRoot is null -- might be push related");
    }
  }

  @SuppressWarnings("deprecation")
  protected void init(PortletRequest portletRequest, PortletResponse portletResponse,
    Bridge.PortletPhase portletPhase) {

    // Save the Bridge.PortletPhase as a request attribute so that it can be picked up by the
    // BridgeRequestAttributeListener.
    portletRequest.setAttribute(Bridge.PORTLET_LIFECYCLE_PHASE, portletPhase);

    // Initialize the portlet container implementation.
    PortletContainerFactory portletContainerFactory = (PortletContainerFactory) FactoryExtensionFinder.getFactory(
        PortletContainerFactory.class);
    PortletContainer portletContainer = portletContainerFactory.getPortletContainer(portletRequest, portletResponse,
        portletContext, bridgeConfig);

    // Initialize the bridge request scope.
    initBridgeRequestScope(portletRequest, portletResponse, portletPhase, portletContainer, incongruityContext);

    // Get the bridge context.
    BridgeContextFactory bridgeContextFactory = (BridgeContextFactory) FactoryExtensionFinder.getFactory(
        BridgeContextFactory.class);
    bridgeContext = bridgeContextFactory.getBridgeContext(bridgeConfig, bridgeRequestScope, portletConfig,
        portletContext, portletRequest, portletResponse, portletPhase, portletContainer, incongruityContext);

    // Save the BridgeContext as a request attribute for legacy versions of ICEfaces.
    portletRequest.setAttribute(BridgeExt.BRIDGE_CONTEXT_ATTRIBUTE, bridgeContext);

    // Get the FacesContext.
    facesContext = getFacesContext(portletRequest, portletResponse, facesLifecycle);

    // Some portlet containers (like the one provided by Liferay Portal) uses a servlet dispatcher when executing
    // the portlet lifecycle. This approach requires the portal to save some standard Servlet-API request attributes
    // like javax.servlet.include.path_info and javax.servlet.include.servlet_path. Unfortunately, some JSF
    // implementations (like Mojarra) assume a servlet (non-portlet) environment and check for attributes. In order
    // to prevent the JSF implementation from working with bad values, the attributes must be removed before the
    // Faces lifecycle is run, and then restored afterwards.
    pathInfo = (String) portletRequest.getAttribute(BridgeConstants.REQ_ATTR_PATH_INFO);
    portletRequest.removeAttribute(BridgeConstants.REQ_ATTR_PATH_INFO);
    servletPath = (String) portletRequest.getAttribute(BridgeConstants.REQ_ATTR_SERVLET_PATH);
    portletRequest.removeAttribute(BridgeConstants.REQ_ATTR_SERVLET_PATH);

    // If not set by a previous request, then set the default viewIdHistory for the portlet modes.
    for (String portletMode : PortletModeHelper.PORTLET_MODE_NAMES) {
      StringBuilder buf = new StringBuilder();
      buf.append(Bridge.VIEWID_HISTORY);
      buf.append(StringPool.PERIOD);
      buf.append(portletMode);

      String attributeName = buf.toString();
      PortletSession portletSession = portletRequest.getPortletSession();

      if (portletSession.getAttribute(attributeName) == null) {
        portletSession.setAttribute(attributeName, bridgeContext.getDefaultViewIdMap().get(portletMode));
      }
    }
  }

  protected void initBridgeRequestScope(PortletRequest portletRequest, PortletResponse portletResponse,
    Bridge.PortletPhase portletPhase, PortletContainer portletContainer, IncongruityContext incongruityContext) {

    boolean bridgeRequestScopeEnabled = true;

    if (portletPhase == Bridge.PortletPhase.RESOURCE_PHASE) {
      bridgeRequestScopeEnabled = PortletConfigParam.BridgeRequestScopeAjaxEnabled.getBooleanValue(portletConfig);
    }

    if (bridgeRequestScopeEnabled) {

      // Determine if there is a bridge request scope "id" saved as a render parameter. Note that in order to
      // avoid collisions with bridge request scopes for other portlets, the render parameter name has to be
      // namespaced with the portlet name.
      String portletName = portletConfig.getPortletName();
      String bridgeRequestScopeKey = portletName + PARAM_BRIDGE_REQUEST_SCOPE_ID;

      // If there is a render parameter value found for the "id", then return the cached bridge request scope
      // associated with the "id".
      String bridgeRequestScopeId = (String) portletRequest.getParameter(bridgeRequestScopeKey);

      if (bridgeRequestScopeId != null) {

        bridgeRequestScope = bridgeRequestScopeCache.get(bridgeRequestScopeId);

        if (bridgeRequestScope != null) {
          logger.debug("Found render parameter name=[{0}] value=[{1}] and cached bridgeRequestScope=[{2}]",
            bridgeRequestScopeKey, bridgeRequestScopeId, bridgeRequestScope);
        }
        else {
          logger.error(
            "Found render parameter name=[{0}] value=[{1}] BUT bridgeRequestScope is NOT in the cache",
            bridgeRequestScopeKey, bridgeRequestScopeId);
        }
      }

      // Otherwise, if there is a portlet session attribute found for the "id", then return the cached bridge
      // request scope associated with the "id". Note: This occurs after an Ajax-based ResourceRequest so that
      // non-excluded request attributes can be picked up by a subsequent RenderRequest.
      if (bridgeRequestScope == null) {

        // TCK TestPage071: nonFacesResourceTest
        // TCK TestPage073: scopeAfterRedisplayResourcePPRTest
        PortletSession portletSession = portletRequest.getPortletSession();
        bridgeRequestScopeId = (String) portletSession.getAttribute(bridgeRequestScopeKey);

        if (bridgeRequestScopeId != null) {

          portletSession.removeAttribute(bridgeRequestScopeKey);

          bridgeRequestScope = bridgeRequestScopeCache.get(bridgeRequestScopeId);

          if (bridgeRequestScope != null) {

            logger.debug(
              "Found (and removed) session-attribute name=[{0}] value=[{1}] and cached bridgeRequestScope=[{2}]",
              bridgeRequestScopeKey, bridgeRequestScopeId, bridgeRequestScope);

            if (portletResponse instanceof StateAwareResponse) {
              logger.debug("Setting former session-attribute as render parameter name=[{0}] value=[{1}]",
                bridgeRequestScopeKey, bridgeRequestScopeId);

              StateAwareResponse stateAwareResponse = (StateAwareResponse) portletResponse;
              stateAwareResponse.setRenderParameter(bridgeRequestScopeKey, bridgeRequestScopeId);
            }
          }
          else {
            logger.error(
              "Found session attribute name=[{0}] value=[{1}] but bridgeRequestScope is not in the cache",
              bridgeRequestScopeKey, bridgeRequestScopeId);
          }
        }
      }

      // Otherwise, return a new factory created instance.
      if (bridgeRequestScope == null) {
        BridgeRequestScopeFactory bridgeRequestScopeFactory = (BridgeRequestScopeFactory) FactoryExtensionFinder
          .getFactory(BridgeRequestScopeFactory.class);
        bridgeRequestScope = bridgeRequestScopeFactory.getBridgeRequestScope(portletConfig, portletContext,
            portletRequest);
      }
    }
  }

  protected void maintainBridgeRequestScope(PortletRequest portletRequest, PortletResponse portletResponse,
    BridgeRequestScope.Transport bridgeRequestScopeTransport) {

    String bridgeRequestScopeId = bridgeRequestScope.getId();

    bridgeRequestScopeCache.put(bridgeRequestScopeId, bridgeRequestScope);

    String bridgeRequestScopeKey = portletName + PARAM_BRIDGE_REQUEST_SCOPE_ID;

    if (bridgeRequestScopeTransport == BridgeRequestScope.Transport.PORTLET_SESSION_ATTRIBUTE) {

      // TCK TestPage071: nonFacesResourceTest
      // TCK TestPage073: scopeAfterRedisplayResourcePPRTest
      PortletSession portletSession = portletRequest.getPortletSession(true);
      portletSession.setAttribute(bridgeRequestScopeKey, bridgeRequestScopeId);
    }
    else {

      if (portletResponse instanceof StateAwareResponse) {
        logger.debug("Setting render parameter name=[{0}] value=[{1}]", bridgeRequestScopeKey,
          bridgeRequestScopeId);

        try {
          StateAwareResponse stateAwareResponse = (StateAwareResponse) portletResponse;
          stateAwareResponse.setRenderParameter(bridgeRequestScopeKey, bridgeRequestScopeId);
        }
        catch (IllegalStateException e) {

          // If a redirect occurred, then swallow/ignore the IllegalStateException
          if (bridgeRequestScope.isRedirectOccurred()) {

            // The Portlet API JavaDocs indicate that StateAwareResponse.setRenderParameter(String, String)
            // must throw an IllegalStateException if ActionResponse.sendRedirect(String) was previously
            // called. The JSR 329 TCK TestPage039 (requestNoScopeOnRedirectTest) and TestPage176
            // (redirectActionTest) both perform pseudo-redirects (effectively treated like navigation-rules
            // from one JSF viewId to another). Since the tests don't actually call
            // ActionResponse.sendRedirect(String), this condition is never reached by the TCK. However,
            // this condition is a real-world use-case and so the IllegalStateException must be
            // swallowed/ignored here so that portlet lifecycle processing is able to continue. For more
            // information, see: http://issues.liferay.com/browse/FACES-1367
          }

          // Otherwise throw the IllegalStateException.
          else {
            throw e;
          }
        }
      }
    }
  }

  protected FacesContext getFacesContext(PortletRequest portletRequest, PortletResponse portletResponse,
    Lifecycle lifecycle) throws FacesException {

    FacesContext newFacesContext = getFacesContextFactory().getFacesContext(portletContext, portletRequest,
        portletResponse, lifecycle);

    // TCK TestPage203 (JSF_ELTest) ensure that the #{facesContext} implicit object is set to the current instance.
    ELContext elContext = newFacesContext.getELContext();
    elContext.putContext(FacesContext.class, newFacesContext);

    return newFacesContext;
  }

  protected FacesContextFactory getFacesContextFactory() throws FacesException {

    if (facesContextFactory == null) {
      facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY);
    }

    return facesContextFactory;
  }
}
TOP

Related Classes of com.liferay.faces.bridge.BridgePhaseBaseImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.