/**
   * This method is called before the {@link PhaseId#INVOKE_APPLICATION} phase of the JSF lifecycle
   * is executed. The purpose of this timing is to handle the case when the user clicks on a {@link
   * UICommand} component (like h:commandButton or h:commandLink) that has been either
   * Auto-ajaxified by ICEfaces, or manually Ajaxified by the developer using code like the
   * following:
   *
   * <p><code>&lt;f:ajax execute="@form" render=" @form" /&gt;</code>
   *
   * <p>When this happens, we need to somehow remember the list of JavaScript and/or CSS resources
   * that are currently in the &lt;head&gt; section of the portal page. This is because a
   * navigation-rule might fire which could cause a new view to be rendered in the {@link
   * PhaseId#RENDER_RESPONSE} phase that is about to follow this {@link PhaseId#INVOKE_APPLICATION}
   * phase. The list of resources would be contained in the {@link HeadManagedBean} {@link
   * ViewScoped} instance that is managed by the JSF managed-bean facility. The list would have been
   * populated initially in the {@link HeadManagedBean} by the {@link HeadRender} during the initial
   * HTTP-GET of the portal page. The way we "remember" the list is by placing it into the JSF 2
   * {@link Flash} scope. This scope is used because it is very short-lived and survives any
   * navigation-rules that might fire, thereby causing the rendering of a new JSF view.
   *
   * <p>The story is continued in the {@link #beforeRenderResponsePhase(PhaseEvent)} method below...
   */
  protected void beforeInvokeApplicationPhase(PhaseEvent phaseEvent) {

    // Get the list of resourceIds that might be contained in the Flash scope. Note that they would
    // have been
    // placed into the Flash scope by this very same method, except during in the case below for the
    // RENDER_RESPONSE phase.
    FacesContext facesContext = phaseEvent.getFacesContext();
    Flash flash = facesContext.getExternalContext().getFlash();

    @SuppressWarnings("unchecked")
    Set<String> headResourceIdsFromFlash = (Set<String>) flash.get("HEAD_RESOURCE_IDS");

    // Log the viewId so that it can be visually compared with the value that is to be logged after
    // the
    // INVOKE_APPLICATION phase completes.
    logger.debug("Before INVOKE_APPLICATION: viewId=[{0}]", facesContext.getViewRoot().getViewId());

    // If the Flash scope does not yet contain a list of head resourceIds, then the scope needs to
    // be populated
    // with a list so that the {@link #beforeRenderResponsePhase(PhaseEvent)} method below can
    // retrieve it.
    if (headResourceIdsFromFlash == null) {

      HeadManagedBean headManagedBean = HeadManagedBean.getInstance(facesContext);

      // Note that in the case where a portlet RESOURCE_PHASE was invoked with a "portlet:resource"
      // type of URL,
      // there will be no HeadManagedBean available.
      if (headManagedBean != null) {
        flash.put("HEAD_RESOURCE_IDS", headManagedBean.getHeadResourceIds());
      }
    }
  }
  /**
   * Adds a "Content-Type" header to the hashmap, according to the content-type and
   * character-encoding in the specified request. Example Value: Content-Type: text/html;
   * charset=ISO-8859-4
   *
   * @param portletRequest The current portlet request.
   * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17
   */
  protected void addContentTypeHeader(PortletRequest portletRequest) {

    // If the specified portletRequest contains characterSetEncoding and contentType information,
    // then
    // use that to build the header.
    if (portletRequest instanceof ClientDataRequest) {
      ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest;
      String contentType = clientDataRequest.getContentType();
      String characterSetEncoding = clientDataRequest.getCharacterEncoding();

      StringBuilder header = new StringBuilder();
      header.append(HEADER_CONTENT_TYPE);
      header.append(BridgeConstants.CHAR_COLON);
      header.append(BridgeConstants.CHAR_SPACE);
      header.append(contentType);

      if (characterSetEncoding != null) {
        header.append(BridgeConstants.CHAR_SEMICOLON);
        header.append(BridgeConstants.CHAR_SPACE);
        header.append(CHARSET);
        header.append(BridgeConstants.CHAR_EQUALS);
        header.append(characterSetEncoding);
      }

      String contentTypeHeader = header.toString();
      logger.debug("Adding contentTypeHeader=[{0}] to header map", contentTypeHeader);
      put(HEADER_CONTENT_TYPE, new String[] {header.toString()});
    } else {
      // TCK TestPage142: getRequestHeaderMapRenderTest
    }
  }
  public void afterPhase(PhaseEvent phaseEvent) {

    // This method just does some logging. It's useful to the developer to determine if a
    // navigation-rule
    // fired, causing new JSF view to be restored after the INVOKE_APPLICATION phase finished.
    if (logger.isDebugEnabled() && (phaseEvent.getPhaseId() == PhaseId.INVOKE_APPLICATION)) {
      FacesContext facesContext = phaseEvent.getFacesContext();
      String viewId = facesContext.getViewRoot().getViewId();
      logger.debug("After INVOKE_APPLICATION: viewId=[{0}]", viewId);
    }
  }
  /**
   * This method is called before the {@link PhaseId#RENDER_RESPONSE} phase of the JSF lifecycle is
   * executed. The purpose of this timing is to pick up where the {@link
   * #beforeInvokeApplicationPhase(PhaseEvent)} method left off. It might be the case that a
   * navigation-rule has fired and a NEW JSF view has been loaded up after the INVOKE_APPLICATION
   * phase completed. If this is the case, then the list of head resourceIds in the {@link
   * HeadManagedBean} needs to be repopulated from the list found in the Flash scope.
   */
  protected void beforeRenderResponsePhase(PhaseEvent phaseEvent) {
    FacesContext facesContext = phaseEvent.getFacesContext();
    Flash flash = facesContext.getExternalContext().getFlash();
    String viewId = facesContext.getViewRoot().getViewId();

    @SuppressWarnings("unchecked")
    Set<String> headResourceIdsFromFlash = (Set<String>) flash.get("HEAD_RESOURCE_IDS");

    if (headResourceIdsFromFlash != null) {
      HeadManagedBean headManagedBean = HeadManagedBean.getInstance(facesContext);
      Set<String> managedBeanResourceIds = headManagedBean.getHeadResourceIds();

      for (String resourceIdFromFlash : headResourceIdsFromFlash) {

        if (!managedBeanResourceIds.contains(resourceIdFromFlash)) {
          managedBeanResourceIds.add(resourceIdFromFlash);
          logger.debug(
              "Added resourceId=[{0}] from the Flash scope to the list of resourceIds in the HeadManagedBean for viewId=[{1}]",
              resourceIdFromFlash, viewId);
        }
      }
    }
  }
  /**
   * Adds an "Accept" header to the hashmap, according to the response content types in the
   * specified request. Example Value: Accept: text/html
   *
   * @param portletRequest The current portlet request.
   * @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
   */
  protected void addAcceptHeader(PortletRequest portletRequest) {
    StringBuilder header = new StringBuilder();
    header.append(HEADER_ACCEPT);
    header.append(": ");

    Enumeration<String> responseContentTypes = portletRequest.getResponseContentTypes();
    boolean firstElement = true;

    while (responseContentTypes.hasMoreElements()) {

      if (!firstElement) {
        header.append(",");
      }

      String responseContentType = responseContentTypes.nextElement();
      header.append(responseContentType);
      firstElement = false;
    }

    String acceptHeader = header.toString();
    logger.debug("Adding acceptHeader=[{0}] to header map", acceptHeader);
    put(HEADER_ACCEPT, new String[] {header.toString()});
  }
  /**
   * Restores the state of the FacesContext as required by section 5.1.2 of the JSR 329 spec. This
   * method is designed to be called during the RENDER_PHASE of the portlet lifecycle.
   *
   * @param facesContext The current faces context.
   * @return Flag indicating whether or not a restoration took place.
   */
  @SuppressWarnings("unchecked")
  public boolean restoreScopedData(FacesContext facesContext) {

    if (beganInActionOrEventRequest) {

      // 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");
      }

      // 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();

        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");
      }

      // 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.
      List<FacesContextAttribute> savedFacesContextAttributes =
          (List<FacesContextAttribute>)
              getAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_CONTEXT_ATTRIBUTES);

      boolean restoredFacesContextAttibutes = false;

      if (savedFacesContextAttributes != null) {
        Map<Object, Object> currentFacesContextAttributes = facesContext.getAttributes();

        for (FacesContextAttribute facesContextAttribute : savedFacesContextAttributes) {
          Object name = facesContextAttribute.getName();

          // Note: Don't want to restore the BridgeContext because that would be invalid data -- it
          // would
          // contain the ActionRequest/ActionResponse or EventRequest/EventResponse and would
          // overwrite the
          // current RenderRequest/RenderResponse.
          if (!BridgeExt.BRIDGE_CONTEXT_ATTRIBUTE.equals(name)) {
            Object value = facesContextAttribute.getValue();
            logger.trace("Restoring FacesContext attribute name=[{0}] value=[{1}]", name, value);
            currentFacesContextAttributes.put(name, value);
            restoredFacesContextAttibutes = true;
          }
        }
      }

      if (restoredFacesContextAttibutes) {
        logger.debug("Restored FacesContext attributes");
      } else {
        logger.debug("Did not restore any FacesContext attributes");
      }

      return true;
    } else {
      return false;
    }
  }
  /**
   * Saves the state of the FacesContext as required by section 5.1.2 of the JSR 329 spec. This
   * method is designed to be called during the ACTION_PHASE of the portlet lifecycle.
   *
   * @param facesContext The current faces context.
   */
  public void preserveScopedData(FacesContext facesContext) {

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

    // Get the ExternalContext.
    ExternalContext externalContext = facesContext.getExternalContext();

    // Save the view root.
    setAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_VIEW_ROOT, facesContext.getViewRoot());

    // If the PortletMode hasn't changed, then preserve the "javax.faces.ViewState" request
    // parameter value.
    if (!portletModeChanged) {
      PortletResponse portletResponse =
          (PortletResponse) facesContext.getExternalContext().getResponse();

      if (portletResponse instanceof ActionResponse) {
        String viewState =
            facesContext
                .getExternalContext()
                .getRequestParameterMap()
                .get(ResponseStateManager.VIEW_STATE_PARAM);

        if (viewState != null) {

          // NOTE: Although it is possible to save this as a render parameter, can't use that
          // approach because
          // portlet containers like Pluto will add the "javax.faces.ViewState" parameter to any
          // ResourceURLs
          // that are created during the RENDER_PHASE of the portlet lifecycle.
          setAttribute(ResponseStateManager.VIEW_STATE_PARAM, viewState);
        }
      }
    }

    // If specified in the WEB-INF/portlet.xml descriptor, then preserve the action parameters.
    BridgeContext bridgeContext =
        (BridgeContext) facesContext.getAttributes().get(BridgeExt.BRIDGE_CONTEXT_ATTRIBUTE);

    if (bridgeContext.isPreserveActionParams()) {
      Map<String, String> actionRequestParameterMap =
          new HashMap<String, String>(externalContext.getRequestParameterMap());
      actionRequestParameterMap.remove(ResponseStateManager.VIEW_STATE_PARAM);
      actionRequestParameterMap.remove(JAVAX_FACES_ENCODED_URL_PARAM);
      setAttribute(BRIDGE_REQ_SCOPE_ATTR_ACTION_PARAMS, actionRequestParameterMap);
    }

    // Save the list of faces messages.
    List<FacesMessageWrapper> facesMessageWrappers = new ArrayList<FacesMessageWrapper>();
    Iterator<String> clientIds = facesContext.getClientIdsWithMessages();

    while (clientIds.hasNext()) {
      String clientId = clientIds.next();
      Iterator<FacesMessage> facesMessages = facesContext.getMessages(clientId);

      while (facesMessages.hasNext()) {
        FacesMessage facesMessage = facesMessages.next();
        FacesMessageWrapper facesMessageWrapper = new FacesMessageWrapper(clientId, facesMessage);
        facesMessageWrappers.add(facesMessageWrapper);
      }
    }

    if (facesMessageWrappers.size() > 0) {
      setAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_MESSAGES, facesMessageWrappers);
    } else {
      logger.trace("Not saving any faces messages");
    }

    // Save the non-excluded request attributes. This would include, for example, managed-bean
    // instances that may
    // have been created during the ACTION_PHASE that need to survive to the RENDER_PHASE.
    if ((!redirect) && (!portletModeChanged)) {
      Map<String, Object> currentRequestAttributes = externalContext.getRequestMap();

      if (currentRequestAttributes != null) {
        List<RequestAttribute> savedRequestAttributes = new ArrayList<RequestAttribute>();
        Iterator<Map.Entry<String, Object>> itr = currentRequestAttributes.entrySet().iterator();

        if (itr != null) {

          while (itr.hasNext()) {
            Map.Entry<String, Object> mapEntry = itr.next();
            String name = mapEntry.getKey();
            Object value = mapEntry.getValue();

            if (isExcludedRequestAttribute(name, value)) {
              logger.trace("Not saving EXCLUDED attribute name=[{0}]", name);
            } else if ((value != null)
                && (value.getClass().getAnnotation(ExcludeFromManagedRequestScope.class) != null)) {
              logger.trace(
                  "Not saving EXCLUDED attribute name=[{0}] due to ExcludeFromManagedRequestScope annotation",
                  name);
            } else {
              logger.trace(
                  "Saving non-excluded request attribute name=[{0}] value=[{1}]", name, value);
              savedRequestAttributes.add(new RequestAttribute(name, value));
            }
          }

          if (savedRequestAttributes.size() > 0) {
            setAttribute(BRIDGE_REQ_SCOPE_ATTR_REQUEST_ATTRIBUTES, savedRequestAttributes);
          } else {
            logger.trace("Not saving any non-excluded request attributes");
          }
        }
      } else {
        logger.trace(
            "Not saving any non-excluded request attributes because there are no request attributes!");
      }
    } else {
      logger.trace("Not saving any non-excluded request attributes due to redirect");
    }

    // NOTE: PROPOSED-FOR-BRIDGE3-API: https://issues.apache.org/jira/browse/PORTLETBRIDGE-203 Build
    // up a list of
    // attributes found in the FacesContext attribute map and save them. It has to be copied in this
    // manner because
    // the Faces implementation likely calls the clear() method during the call to its
    // FacesContextImpl.release()
    // method.
    Map<Object, Object> currentFacesContextAttributes = facesContext.getAttributes();
    int mapSize = currentFacesContextAttributes.size();
    List<FacesContextAttribute> savedFacesContextAttributes =
        new ArrayList<FacesContextAttribute>(mapSize);
    Iterator<Map.Entry<Object, Object>> itr = currentFacesContextAttributes.entrySet().iterator();

    while (itr.hasNext()) {
      Map.Entry<Object, Object> mapEntry = itr.next();
      Object name = mapEntry.getKey();
      Object value = mapEntry.getValue();
      logger.trace("Saving FacesContext attribute name=[{0}] value=[{1}]", name, value);
      savedFacesContextAttributes.add(new FacesContextAttribute(name, value));
    }

    setAttribute(BRIDGE_REQ_SCOPE_ATTR_FACES_CONTEXT_ATTRIBUTES, savedFacesContextAttributes);
  }
  @SuppressWarnings("unchecked")
  public RequestParameterMapMultiPartImpl(
      BridgeContext bridgeContext, ClientDataRequest clientDataRequest) {

    try {

      PortletSession portletSession = clientDataRequest.getPortletSession();
      PortletContext portletContext = portletSession.getPortletContext();

      // Determine the uploaded files directory path according to the JSF 2.2 proposal:
      // https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=690
      String uploadedFilesDir = portletContext.getInitParameter(CONTEXT_PARAM_UPLOADED_FILES_DIR);

      if (uploadedFilesDir == null) {
        uploadedFilesDir = System.getProperty(JAVA_IO_TMPDIR);

        if (logger.isDebugEnabled()) {
          logger.debug(
              "The web.xml context-param name=[{0}] not found, using default system property=[{1}] value=[{2}]",
              new Object[] {CONTEXT_PARAM_UPLOADED_FILES_DIR, JAVA_IO_TMPDIR, uploadedFilesDir});
        }
      } else {

        if (logger.isDebugEnabled()) {
          logger.debug(
              "Using web.xml context-param name=[{0}] value=[{1}]",
              new Object[] {CONTEXT_PARAM_UPLOADED_FILES_DIR, uploadedFilesDir});
        }
      }

      // Using the portlet sessionId, determine a unique folder path and create the path if it does
      // not exist.
      String sessionId = portletSession.getId();
      File uploadedFilesPath = new File(uploadedFilesDir, sessionId);

      if (!uploadedFilesPath.exists()) {

        try {
          uploadedFilesPath.mkdirs();
        } catch (SecurityException e) {
          uploadedFilesDir = System.getProperty(JAVA_IO_TMPDIR);
          logger.error(
              "Security exception message=[{0}] when trying to create unique path=[{1}] so using default system property=[{2}] value=[{3}]",
              new Object[] {
                e.getMessage(), uploadedFilesPath.toString(), JAVA_IO_TMPDIR, uploadedFilesDir
              });
          uploadedFilesPath = new File(uploadedFilesDir, sessionId);
          uploadedFilesPath.mkdirs();
        }
      }

      // Initialize commons-fileupload with the file upload path.
      DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
      diskFileItemFactory.setRepository(uploadedFilesPath);

      // Initialize commons-fileupload so that uploaded temporary files are not automatically
      // deleted.
      diskFileItemFactory.setFileCleaningTracker(null);

      // Initialize the commons-fileupload size threshold to zero, so that all files will be dumped
      // to disk
      // instead of staying in memory.
      diskFileItemFactory.setSizeThreshold(0);

      // Determine the max file upload size threshold in bytes.
      String uploadedFilesMaxSize =
          portletContext.getInitParameter(CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE);
      int fileMaxSize = DEFAULT_FILE_MAX_SIZE;

      if (uploadedFilesMaxSize == null) {

        if (logger.isDebugEnabled()) {
          logger.debug(
              "The web.xml context-param name=[{0}] not found, using default=[{1}] bytes",
              new Object[] {CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE, DEFAULT_FILE_MAX_SIZE});
        }
      } else {

        try {
          fileMaxSize = Integer.parseInt(uploadedFilesMaxSize);

          if (logger.isDebugEnabled()) {
            logger.debug(
                "Using web.xml context-param name=[{0}] value=[{1}] bytes",
                new Object[] {CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE, fileMaxSize});
          }
        } catch (NumberFormatException e) {
          logger.error(
              "Invalid value=[{0}] for web.xml context-param name=[{1}] using default=[{2}] bytes.",
              new Object[] {
                uploadedFilesMaxSize, CONTEXT_PARAM_UPLOADED_FILE_MAX_SIZE, DEFAULT_FILE_MAX_SIZE
              });
        }
      }

      // Parse the request parameters and save all uploaded files in a map.
      PortletFileUpload portletFileUpload = new PortletFileUpload(diskFileItemFactory);
      portletFileUpload.setFileSizeMax(fileMaxSize);
      requestParameterMap = new HashMap<String, String>();
      requestParameterFileMap = new HashMap<String, List<UploadedFile>>();

      // Get the namespace that might be found in request parameter names.
      String namespace = bridgeContext.getPortletContainer().getResponseNamespace();

      // FACES-271: Include name+value pairs found in the ActionRequest.
      PortletContainer portletContainer = bridgeContext.getPortletContainer();
      Set<Map.Entry<String, String[]>> actionRequestParameterSet =
          clientDataRequest.getParameterMap().entrySet();

      for (Map.Entry<String, String[]> mapEntry : actionRequestParameterSet) {

        String parameterName = mapEntry.getKey();
        int pos = parameterName.indexOf(namespace);

        if (pos >= 0) {
          parameterName = parameterName.substring(pos + namespace.length());
        }

        String[] parameterValues = mapEntry.getValue();

        if (parameterValues.length > 0) {
          String fixedRequestParameterValue =
              portletContainer.fixRequestParameterValue(parameterValues[0]);
          requestParameterMap.put(parameterName, fixedRequestParameterValue);
          logger.debug(
              "Found in ActionRequest: {0}=[{1}]", parameterName, fixedRequestParameterValue);
        }
      }

      UploadedFileFactory uploadedFileFactory =
          (UploadedFileFactory) BridgeFactoryFinder.getFactory(UploadedFileFactory.class);

      // Begin parsing the request for file parts:
      try {
        FileItemIterator fileItemIterator = null;

        if (clientDataRequest instanceof ResourceRequest) {
          ResourceRequest resourceRequest = (ResourceRequest) clientDataRequest;
          fileItemIterator =
              portletFileUpload.getItemIterator(new ActionRequestAdapter(resourceRequest));
        } else {
          ActionRequest actionRequest = (ActionRequest) clientDataRequest;
          fileItemIterator = portletFileUpload.getItemIterator(actionRequest);
        }

        boolean optimizeNamespace =
            BooleanHelper.toBoolean(
                bridgeContext.getInitParameter(
                    BridgeConfigConstants.PARAM_OPTIMIZE_PORTLET_NAMESPACE1),
                true);

        if (fileItemIterator != null) {

          int totalFiles = 0;

          // For each field found in the request:
          while (fileItemIterator.hasNext()) {

            try {
              totalFiles++;

              // Get the stream of field data from the request.
              FileItemStream fieldStream = (FileItemStream) fileItemIterator.next();

              // Get field name from the field stream.
              String fieldName = fieldStream.getFieldName();

              // If namespace optimization is enabled and the namespace is present in the field
              // name,
              // then remove the portlet namespace from the field name.
              if (optimizeNamespace) {
                int pos = fieldName.indexOf(namespace);

                if (pos >= 0) {
                  fieldName = fieldName.substring(pos + namespace.length());
                }
              }

              // Get the content-type, and file-name from the field stream.
              String contentType = fieldStream.getContentType();
              boolean formField = fieldStream.isFormField();

              String fileName = null;

              try {
                fileName = fieldStream.getName();
              } catch (InvalidFileNameException e) {
                fileName = e.getName();
              }

              // Copy the stream of file data to a temporary file. NOTE: This is necessary even if
              // the
              // current field is a simple form-field because the call below to
              // diskFileItem.getString()
              // will fail otherwise.
              DiskFileItem diskFileItem =
                  (DiskFileItem)
                      diskFileItemFactory.createItem(fieldName, contentType, formField, fileName);
              Streams.copy(fieldStream.openStream(), diskFileItem.getOutputStream(), true);

              // If the current field is a simple form-field, then save the form field value in the
              // map.
              if (diskFileItem.isFormField()) {
                String requestParameterValue =
                    diskFileItem.getString(clientDataRequest.getCharacterEncoding());
                String fixedRequestParameterValue =
                    portletContainer.fixRequestParameterValue(requestParameterValue);
                requestParameterMap.put(fieldName, fixedRequestParameterValue);
                logger.debug("{0}=[{1}]", fieldName, fixedRequestParameterValue);
              } else {

                File tempFile = diskFileItem.getStoreLocation();

                // If the copy was successful, then
                if (tempFile.exists()) {

                  // Copy the commons-fileupload temporary file to a file in the same temporary
                  // location, but with the filename provided by the user in the upload. This has
                  // two
                  // benefits: 1) The temporary file will have a nice meaningful name. 2) By copying
                  // the file, the developer can have access to a semi-permanent file, because the
                  // commmons-fileupload DiskFileItem.finalize() method automatically deletes the
                  // temporary one.
                  String tempFileName = tempFile.getName();
                  String tempFileAbsolutePath = tempFile.getAbsolutePath();

                  String copiedFileName = stripIllegalCharacters(fileName);

                  String copiedFileAbsolutePath =
                      tempFileAbsolutePath.replace(tempFileName, copiedFileName);
                  File copiedFile = new File(copiedFileAbsolutePath);
                  FileUtils.copyFile(tempFile, copiedFile);

                  // If present, build up a map of headers.
                  Map<String, List<String>> headersMap = new HashMap<String, List<String>>();
                  FileItemHeaders fileItemHeaders = fieldStream.getHeaders();

                  if (fileItemHeaders != null) {
                    Iterator<String> headerNameItr = fileItemHeaders.getHeaderNames();

                    if (headerNameItr != null) {

                      while (headerNameItr.hasNext()) {
                        String headerName = headerNameItr.next();
                        Iterator<String> headerValuesItr = fileItemHeaders.getHeaders(headerName);
                        List<String> headerValues = new ArrayList<String>();

                        if (headerValuesItr != null) {

                          while (headerValuesItr.hasNext()) {
                            String headerValue = headerValuesItr.next();
                            headerValues.add(headerValue);
                          }
                        }

                        headersMap.put(headerName, headerValues);
                      }
                    }
                  }

                  // Put a valid UploadedFile instance into the map that contains all of the
                  // uploaded file's attributes, along with a successful status.
                  Map<String, Object> attributeMap = new HashMap<String, Object>();
                  String id = Long.toString(((long) hashCode()) + System.currentTimeMillis());
                  String message = null;
                  UploadedFile uploadedFile =
                      uploadedFileFactory.getUploadedFile(
                          copiedFileAbsolutePath,
                          attributeMap,
                          diskFileItem.getCharSet(),
                          diskFileItem.getContentType(),
                          headersMap,
                          id,
                          message,
                          fileName,
                          diskFileItem.getSize(),
                          UploadedFile.Status.FILE_SAVED);

                  requestParameterMap.put(fieldName, copiedFileAbsolutePath);
                  addUploadedFile(fieldName, uploadedFile);
                  logger.debug(
                      "Received uploaded file fieldName=[{0}] fileName=[{1}]", fieldName, fileName);
                }
              }
            } catch (Exception e) {
              logger.error(e);

              UploadedFile uploadedFile = uploadedFileFactory.getUploadedFile(e);
              String fieldName = Integer.toString(totalFiles);
              addUploadedFile(fieldName, uploadedFile);
            }
          }
        }
      }

      // If there was an error in parsing the request for file parts, then put a bogus UploadedFile
      // instance in
      // the map so that the developer can have some idea that something went wrong.
      catch (Exception e) {
        logger.error(e);

        UploadedFile uploadedFile = uploadedFileFactory.getUploadedFile(e);
        addUploadedFile("unknown", uploadedFile);
      }

      clientDataRequest.setAttribute(PARAM_UPLOADED_FILES, requestParameterFileMap);

      // If not found in the request, Section 6.9 of the Bridge spec requires that the value of the
      // ResponseStateManager.RENDER_KIT_ID_PARAM request parameter be set to the value of the
      // "javax.portlet.faces.<portletName>.defaultRenderKitId" PortletContext attribute.
      String renderKitIdParam = requestParameterMap.get(ResponseStateManager.RENDER_KIT_ID_PARAM);

      if (renderKitIdParam == null) {
        renderKitIdParam = bridgeContext.getDefaultRenderKitId();

        if (renderKitIdParam != null) {
          requestParameterMap.put(ResponseStateManager.RENDER_KIT_ID_PARAM, renderKitIdParam);
        }
      }
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    }
  }