public RequestParameterMapFactory(BridgeContext bridgeContext) {

    PortletRequest portletRequest = bridgeContext.getPortletRequest();

    if (portletRequest instanceof ClientDataRequest) {
      ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest;
      String contentType = clientDataRequest.getContentType();

      // Note that ICEfaces ace:fileEntry cannot rely on RequestParameterValuesMapImpl because it
      // relies on its
      // own mechanism for handling file upload.
      Product iceFaces = ProductMap.getInstance().get(ProductConstants.ICEFACES);

      if ((contentType != null)
          && contentType.toLowerCase().startsWith(BridgeConstants.MULTIPART_CONTENT_TYPE_PREFIX)
          && !iceFaces.isDetected()) {
        RequestParameterMapMultiPartImpl requestParameterMapMultiPartImpl =
            new RequestParameterMapMultiPartImpl(bridgeContext, clientDataRequest);
        requestParameterMap = requestParameterMapMultiPartImpl;
        requestParameterValuesMap =
            new RequestParameterValuesMapMultiPartImpl(requestParameterMapMultiPartImpl);
      } else {
        requestParameterMap = new RequestParameterMapImpl(bridgeContext);
        requestParameterValuesMap = new RequestParameterValuesMapImpl(bridgeContext);
      }
    } else {
      requestParameterMap = new RequestParameterMapImpl(bridgeContext);
      requestParameterValuesMap = new RequestParameterValuesMapImpl(bridgeContext);
    }
  }
  @Override
  public Map<String, Object> getRequestCookieMap(BridgeContext bridgeContext) {
    PortletRequest portletRequest = bridgeContext.getPortletRequest();
    Cookie[] cookies = portletRequest.getCookies();

    return new RequestCookieMap(cookies);
  }
  protected FacesRequestParameterMap getFacesRequestParameterMap(BridgeContext bridgeContext) {

    FacesRequestParameterMap facesRequestParameterMap = null;
    PortletRequest portletRequest = bridgeContext.getPortletRequest();
    PortletResponse portletResponse = bridgeContext.getPortletResponse();
    String namespace = portletResponse.getNamespace();
    BridgeRequestScope bridgeRequestScope = bridgeContext.getBridgeRequestScope();
    String defaultRenderKitId = bridgeContext.getDefaultRenderKitId();
    Map<String, String> facesViewParameterMap = getFacesViewParameterMap(bridgeContext);

    if (portletRequest instanceof ClientDataRequest) {

      ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest;
      String contentType = clientDataRequest.getContentType();

      // Note: ICEfaces ace:fileEntry relies on its own mechanism for handling file upload.
      if (!ICEFACES_DETECTED
          && (contentType != null)
          && contentType.toLowerCase().startsWith(BridgeConstants.MULTIPART_CONTENT_TYPE_PREFIX)) {

        MultiPartFormData multiPartFormData =
            (MultiPartFormData) portletRequest.getAttribute(MULTIPART_FORM_DATA_FQCN);

        if (multiPartFormData == null) {
          facesRequestParameterMap =
              new FacesRequestParameterMapImpl(
                  namespace, bridgeRequestScope, facesViewParameterMap, defaultRenderKitId);

          MultiPartFormDataProcessor multiPartFormDataProcessor =
              new MultiPartFormDataProcessorImpl();
          Map<String, List<UploadedFile>> uploadedFileMap =
              multiPartFormDataProcessor.process(
                  clientDataRequest, bridgeContext.getPortletConfig(), facesRequestParameterMap);

          multiPartFormData = new MultiPartFormDataImpl(facesRequestParameterMap, uploadedFileMap);

          // Save the multipart/form-data in a request attribute so that it can be referenced
          // later-on in the
          // JSF lifecycle by file upload component renderers.
          portletRequest.setAttribute(MULTIPART_FORM_DATA_FQCN, multiPartFormData);
        } else {
          facesRequestParameterMap = multiPartFormData.getFacesRequestParameterMap();
        }
      }
    }

    if (facesRequestParameterMap == null) {
      Map<String, String[]> parameterMap = portletRequest.getParameterMap();
      facesRequestParameterMap =
          new FacesRequestParameterMapImpl(
              parameterMap,
              namespace,
              bridgeRequestScope,
              facesViewParameterMap,
              defaultRenderKitId);
    }

    return facesRequestParameterMap;
  }
  @Override
  public Map<String, List<UploadedFile>> getUploadedFileMap(BridgeContext bridgeContext) {

    PortletRequest portletRequest = bridgeContext.getPortletRequest();
    MultiPartFormData multiPartFormData =
        (MultiPartFormData) portletRequest.getAttribute(MULTIPART_FORM_DATA_FQCN);
    Map<String, List<UploadedFile>> uploadedFileMap = null;

    if (multiPartFormData != null) {
      uploadedFileMap = multiPartFormData.getUploadedFileMap();
    }

    return uploadedFileMap;
  }
  /**
   * This method is called prior to the {@link PhaseId#RENDER_RESPONSE} phase of the JSF lifecycle.
   */
  @Override
  public void beforePhase(PhaseEvent phaseEvent) {

    // Determine if there are any resources in the LIFERAY_SHARED_PAGE_TOP request attribute, so
    // that execution of
    // the {@link #afterPhase(PhaseEvent)} can be optimized.
    liferaySharedPageTopLength = 0;

    BridgeContext bridgeContext = BridgeContext.getCurrentInstance();
    PortletRequest portletRequest = bridgeContext.getPortletRequest();
    StringBundler pageTop = getPageTop(portletRequest);

    if (pageTop != null) {
      liferaySharedPageTopLength = pageTop.length();
    }
  }
  /** This method is called after the {@link PhaseId#RENDER_RESPONSE} phase of the JSF lifecycle. */
  @Override
  public void afterPhase(PhaseEvent phaseEvent) {

    BridgeContext bridgeContext = BridgeContext.getCurrentInstance();

    // Remove duplicate resources from the LIFERAY_SHARED_PAGE_TOP request attribute. For more
    // information, see:
    // http://issues.liferay.com/browse/FACES-1216
    if (liferaySharedPageTopLength > 0) {

      PortletRequest portletRequest = bridgeContext.getPortletRequest();

      StringBundler pageTop = getPageTop(portletRequest);

      if (pageTop != null) {

        LiferaySharedPageTop liferaySharedPageTop = new LiferaySharedPageTop(pageTop);
        liferaySharedPageTop.removeDuplicates();
        pageTop = liferaySharedPageTop.toStringBundler();

        setPageTop(portletRequest, pageTop);
      }
    }
  }
  @SuppressWarnings("unchecked")
  public void restoreState(FacesContext facesContext) {

    logger.debug("restoreState(facesContext)");

    boolean restoreNonExcludedRequestAttributes =
        ((beganInPhase == Bridge.PortletPhase.ACTION_PHASE)
            || (beganInPhase == Bridge.PortletPhase.EVENT_PHASE)
            || (beganInPhase == Bridge.PortletPhase.RESOURCE_PHASE));

    BridgeContext bridgeContext = BridgeContext.getCurrentInstance();

    PortletPhase portletRequestPhase = bridgeContext.getPortletRequestPhase();

    if (portletRequestPhase == Bridge.PortletPhase.RENDER_PHASE) {

      if (!portletMode.equals(bridgeContext.getPortletRequest().getPortletMode())) {
        setPortletModeChanged(true);
        restoreNonExcludedRequestAttributes = false;
      }
    }

    if ((beganInPhase == Bridge.PortletPhase.ACTION_PHASE)
        || (beganInPhase == Bridge.PortletPhase.EVENT_PHASE)
        || (beganInPhase == Bridge.PortletPhase.RESOURCE_PHASE)) {

      // Restore the view root that may have been saved during the ACTION_PHASE of the portlet
      // lifecycle.
      UIViewRoot uiViewRoot = (UIViewRoot) getAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_VIEW_ROOT);

      if (uiViewRoot != null) {
        facesContext.setViewRoot(uiViewRoot);
        logger.debug("Restored viewId=[{0}] uiViewRoot=[{1}]", uiViewRoot.getViewId(), uiViewRoot);
      } else {
        logger.debug("Did not restore uiViewRoot");
      }

      // Restore the faces messages that may have been saved during the ACTION_PHASE of the portlet
      // lifecycle.
      List<FacesMessageWrapper> facesMessages =
          (List<FacesMessageWrapper>) getAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_MESSAGES);

      boolean restoredFacesMessages = false;

      if (facesMessages != null) {

        for (FacesMessageWrapper facesMessageWrapper : facesMessages) {
          String clientId = facesMessageWrapper.getClientId();
          FacesMessage facesMessage = facesMessageWrapper.getFacesMessage();
          facesContext.addMessage(clientId, facesMessage);
          logger.trace("Restored facesMessage=[{0}]", facesMessage.getSummary());
          restoredFacesMessages = true;
        }
      }

      if (restoredFacesMessages) {
        logger.debug("Restored facesMessages");
      } else {
        logger.debug("Did not restore any facesMessages");
      }

      // NOTE: PROPOSE-FOR-BRIDGE3-API: https://issues.apache.org/jira/browse/PORTLETBRIDGE-203
      // Restore the
      // FacesContext attributes that may have been saved during the ACTION_PHASE of the portlet
      // lifecycle.
      restoreJSF2FacesContextAttributes(facesContext);
    }

    if (restoreNonExcludedRequestAttributes) {

      // Restore the non-excluded request attributes.
      List<RequestAttribute> savedRequestAttributes =
          (List<RequestAttribute>) getAttribute(BRIDGE_REQ_SCOPE_ATTR_REQUEST_ATTRIBUTES);

      boolean restoredNonExcludedRequestAttributes = false;

      if (savedRequestAttributes != null) {
        Map<String, Object> currentRequestAttributes =
            facesContext.getExternalContext().getRequestMap();

        // If a redirect did not occur, then restore the non-excluded request attributes.
        if (!isRedirectOccurred()) {

          for (RequestAttribute requestAttribute : savedRequestAttributes) {
            String name = requestAttribute.getName();
            Object value = requestAttribute.getValue();
            logger.trace(
                "Restoring non-excluded request attribute name=[{0}] value=[{1}]", name, value);
            currentRequestAttributes.put(name, value);
            restoredNonExcludedRequestAttributes = true;
          }
        }
      }

      if (restoredNonExcludedRequestAttributes) {
        logger.debug("Restored non-excluded request attributes");
      } else {
        logger.debug("Did not restore any non-excluded request attributes");
      }
    }

    // If running in the RENDER_PHASE, then the Flash scope must be restored.
    if (portletRequestPhase == Bridge.PortletPhase.RENDER_PHASE) {

      // NOTE: PROPOSED-FOR-BRIDGE3-API: https://issues.apache.org/jira/browse/PORTLETBRIDGE-201
      // Restore the flash scope.
      restoreFlashState(facesContext);
    }

    // If running in the RENDER_PHASE, then the incongruity context must be restored.
    if (((beganInPhase == Bridge.PortletPhase.ACTION_PHASE)
            || (beganInPhase == Bridge.PortletPhase.EVENT_PHASE))
        && (portletRequestPhase == Bridge.PortletPhase.RENDER_PHASE)) {

      List<IncongruityAttribute> savedIncongruityAttributes =
          (List<IncongruityAttribute>)
              getAttribute(BRIDGE_REQ_SCOPE_ATTR_INCONGRUITY_CONTEXT_ATTRIBUTES);

      if (savedIncongruityAttributes != null) {

        IncongruityContext incongruityContext = bridgeContext.getIncongruityContext();
        Map<String, Object> incongruityContextAttributes = incongruityContext.getAttributes();

        for (IncongruityAttribute incongruityAttribute : savedIncongruityAttributes) {
          String key = incongruityAttribute.getName();
          Object value = incongruityAttribute.getValue();
          incongruityContextAttributes.put(key, value);
        }
      }
    }
  }