/** @author Neil Griffin */
public abstract class LiferayFacesContext extends FacesContext
    implements FacesContextHelper, PortletHelper, LiferayPortletHelper {

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

  // Singleton Instance
  private static transient LiferayFacesContext instance;

  /** Returns the implementation singleton instance. */
  public static LiferayFacesContext getInstance() {

    if (instance == null) {
      logger.error("Instance not initialized -- caller might be static");
    }

    return instance;
  }

  /** Sets the implementation singleton instance. */
  public static void setInstance(LiferayFacesContext liferayFacesContext) {
    instance = liferayFacesContext;
  }

  /** Returns the Liferay build number. */
  public abstract int getBuildNumber();
}
/**
 * This class wraps the Liferay {@link NamespaceServletRequest} class, so that calls to {@link
 * #setAttribute(String, Object)} do not cause attribute names to be prefixed with the response
 * namespace. This is necessary so that Liferay Portal JSP tag classes will be able to set request
 * attributes that can be picked up by JSPs. For example, the {@link InputEditorTag} sets attributes
 * that are picked up by the portal-web/docroot/html/js/editor/ckeditor.jsp page.
 *
 * @author Neil Griffin
 */
public class NonNamespacedHttpServletRequest extends HttpServletRequestWrapper {

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

  // Private Constants
  private static final String AUI_FORM_USE_NAMESPACE = "aui:form:useNamespace";
  private static final String NAMESPACE_SERVLET_REQUEST_FQCN =
      "com.liferay.portal.servlet.NamespaceServletRequest";

  public NonNamespacedHttpServletRequest(HttpServletRequest httpServletRequest) {
    super(httpServletRequest);
  }

  @Override
  public Object getAttribute(String name) {

    if (AUI_FORM_USE_NAMESPACE.equals(name)) {

      // Note: The portal-web/docroot/html/taglib/init.jsp file asks the value of this attribute.
      // Need to return
      // false in order to ensure that the portlet namespace is not prepended to method names and
      // element ids.
      return Boolean.FALSE.toString();
    } else {
      return super.getAttribute(name);
    }
  }

  @Override
  public void setAttribute(String name, Object value) {

    Object wrappedRequest = getRequest();

    if (wrappedRequest.getClass().getName().equals(NAMESPACE_SERVLET_REQUEST_FQCN)) {

      try {

        // Calling NameSpaceServletRequest.setAttribute(String, Object, false) instead of
        // NameSpaceServletRequest.setAttribute(String, Object) will prevent the attribute name from
        // getting
        // prefixed with the response namespace. The method must be called reflectively since the
        // NameSpaceServletRequest is packaged in portal-impl.jar and is not available at
        // compile-time.
        Method method =
            wrappedRequest
                .getClass()
                .getMethod("setAttribute", String.class, Object.class, boolean.class);
        method.invoke(wrappedRequest, name, value, false);
      } catch (Exception e) {
        logger.error(e);
      }
    } else {
      super.setAttribute(name, value);
    }
  }
}
/** @author Neil Griffin */
public class LiferayThemeDisplayUtil {

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

  // Private Constants
  private static final Method IS_ISOLATED_METHOD;
  private static final Method IS_STATE_EXCLUSIVE_METHOD;

  static {
    Method isIsolatedMethod = null;
    Method isStateExclusiveMethod = null;

    try {
      Class<?> portletClass = Class.forName("com.liferay.portal.theme.ThemeDisplay");
      isIsolatedMethod = portletClass.getMethod("isIsolated", new Class[] {});
      isStateExclusiveMethod = portletClass.getMethod("isStateExclusive", new Class[] {});
    } catch (Exception e) {
      // ignore
    }

    IS_ISOLATED_METHOD = isIsolatedMethod;
    IS_STATE_EXCLUSIVE_METHOD = isStateExclusiveMethod;
  }

  public static boolean isIsolated(Object themeDisplay) {

    boolean isolated = false;

    if ((IS_ISOLATED_METHOD != null) && (themeDisplay != null)) {

      try {
        isolated = (Boolean) IS_ISOLATED_METHOD.invoke(themeDisplay, new Object[] {});
      } catch (Exception e) {
        logger.error(e);
      }
    }

    return isolated;
  }

  public static boolean isStateExclusive(Object themeDisplay) {

    boolean stateExclusive = false;

    if ((IS_STATE_EXCLUSIVE_METHOD != null) && (themeDisplay != null)) {

      try {
        stateExclusive = (Boolean) IS_STATE_EXCLUSIVE_METHOD.invoke(themeDisplay, new Object[] {});
      } catch (Exception e) {
        logger.error(e);
      }
    }

    return stateExclusive;
  }
}
/**
 * Custom {@link ResponseWriter} that has the ability to write to the <head>...</head> section of
 * the portal page via the standard Portlet 2.0 MimeResponse.MARKUP_HEAD_ELEMENT mechanism.
 *
 * @author Neil Griffin
 */
public class HeadResponseWriterImpl extends HeadResponseWriter {

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

  // Private Data Members
  private PortletResponse portletResponse;

  public HeadResponseWriterImpl(
      ResponseWriter wrappedResponseWriter, PortletResponse portletResponse) {
    super(wrappedResponseWriter);
    this.portletResponse = portletResponse;
  }

  @Override
  public Element createElement(String name) {
    return portletResponse.createElement(name);
  }

  @Override
  public void endElement(String name) throws IOException {

    try {
      ElementWriter elementWriter = elementWriterStack.pop();
      Element element = elementWriter.getElement();
      String nodeName = element.getNodeName();
      logger.trace("POPPED element name=[{0}]", nodeName);

      if (!StringPool.HEAD.equals(nodeName)) {

        // NOTE: The Portlet 2.0 Javadocs for the addProperty method indicate that if the key
        // already exists,
        // then the element will be added to any existing elements under that key name. There is a
        // risk that
        // multiple portlet instances on the same portal page could cause multiple <script />
        // elements to be
        // added to the <head>...</head> section of the rendered portal page. See:
        // http://portals.apache.org/pluto/portlet-2.0-apidocs/javax/portlet/PortletResponse.html#addProperty(java.lang.String,
        // org.w3c.dom.Element)
        portletResponse.addProperty(MimeResponse.MARKUP_HEAD_ELEMENT, element);
        logger.debug(
            "Added resource to portal's <head>...</head> section nodeName=[{0}]", nodeName);
      }
    } catch (EmptyStackException e) {
      throw new IOException(EmptyStackException.class.getSimpleName());
    }
  }

  @Override
  public void startElement(String name, UIComponent component) throws IOException {

    Element element = createElement(name);
    ElementWriter elementWriter = new ElementWriter(element);
    elementWriterStack.push(elementWriter);
  }
}
/** @author Kyle Stiemann */
@ManagedBean
@RequestScoped
public class FieldBackingBean {

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

  @ManagedProperty(value = "#{fieldModelBean}")
  private FieldModelBean fieldModelBean;

  public void errorValidator(FacesContext facesContext, UIComponent uiComponent, Object value)
      throws ValidatorException {

    FacesMessage facesMessage = new FacesMessage();
    facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
    facesMessage.setDetail("This is an error message.");
    facesContext.addMessage(uiComponent.getClientId(), facesMessage);
  }

  public void infoValidator(FacesContext facesContext, UIComponent uiComponent, Object value)
      throws ValidatorException {

    FacesMessage facesMessage = new FacesMessage();
    facesMessage.setSeverity(FacesMessage.SEVERITY_INFO);
    facesMessage.setDetail("This is an info message.");
    facesContext.addMessage(uiComponent.getClientId(), facesMessage);
  }

  public void submit() {

    FacesMessage globalFacesMessage = new FacesMessage("Your request processed successfully.");
    FacesContext facesContext = FacesContext.getCurrentInstance();
    facesContext.addMessage(null, globalFacesMessage);

    logger.info("submit: firstName = " + fieldModelBean.getFirstName());
  }

  public void warningValidator(FacesContext facesContext, UIComponent uiComponent, Object value)
      throws ValidatorException {

    FacesMessage facesMessage = new FacesMessage();
    facesMessage.setSeverity(FacesMessage.SEVERITY_WARN);
    facesMessage.setDetail("This is a warning message.");
    facesContext.addMessage(uiComponent.getClientId(), facesMessage);
  }

  public void setFieldModelBean(FieldModelBean fieldModelBean) {
    this.fieldModelBean = fieldModelBean;
  }
}
/** @author Neil Griffin */
@ManagedBean(name = "customersModelBean")
@RequestScoped
public class CustomersModelBean implements Serializable {

  // serialVersionUID
  private static final long serialVersionUID = 2241487919972557504L;

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

  // Injections
  @ManagedProperty(name = "customerService", value = "#{customerService}")
  private CustomerService customerService;

  // Private Bean Properties
  private List<Customer> allCustomers;
  private String selectedCustomerId;

  @PostConstruct
  public void postConstruct() {
    logger.trace("@PostConstruct annotation worked");
    allCustomers = customerService.getAllCustomers();
  }

  @PreDestroy
  public void preDestroy() {
    logger.trace("@PreDestroy annotation worked");
  }

  public List<Customer> getAllCustomers() {
    return allCustomers;
  }

  public void setCustomerService(CustomerService customerService) {

    // Injected via ManagedProperty annotation
    this.customerService = customerService;
  }

  public String getSelectedCustomerId() {
    return selectedCustomerId;
  }

  public void setSelectedCustomerId(String selectedCustomerId) {
    this.selectedCustomerId = selectedCustomerId;
  }
}
public class AbstractGB {

  protected static final Logger logger = LoggerFactory.getLogger(AbstractGB.class);

  protected static final String UNEXPECTED_ERROR_MSG_ID = "an-unexpected-error-occurred";
  protected static final String SUCCESS_INFO_MSG_ID = "your-request-processed-successfully";

  public void addGlobalSuccessInfoMessage() {
    LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance();
    liferayFacesContext.addGlobalSuccessInfoMessage();
  }

  public void addGlobalUnexpectedErrorMessage() {
    LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance();
    liferayFacesContext.addGlobalUnexpectedErrorMessage();
  }
}
/** @author Vernon Singleton */
@ManagedBean
@RequestScoped
public class SelectBooleanCheckboxBackingBean {

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

  @ManagedProperty(
      name = "selectBooleanCheckboxModelBean",
      value = "#{selectBooleanCheckboxModelBean}")
  private SelectBooleanCheckboxModelBean selectBooleanCheckboxModelBean;

  public void submit() {
    PhaseId phaseId = FacesContext.getCurrentInstance().getCurrentPhaseId();
    logger.info(
        "submit: phaseId=[{0}] agree=[{1}]",
        phaseId.toString(), selectBooleanCheckboxModelBean.getAgree());
  }

  public void valueChangeListener(ValueChangeEvent valueChangeEvent) {

    FacesContext facesContext = FacesContext.getCurrentInstance();
    PhaseId phaseId = facesContext.getCurrentPhaseId();
    logger.debug("valueChangeListener: phaseId=[{0}]", phaseId.toString());

    String phaseName = phaseId.getName();
    FacesMessage facesMessage =
        new FacesMessage(
            "The valueChangeListener method was called during the "
                + phaseName
                + " phase of the JSF lifecycle.");
    facesContext.addMessage(null, facesMessage);
  }

  public void setSelectBooleanCheckboxModelBean(
      SelectBooleanCheckboxModelBean selectBooleanCheckboxModelBean) {
    this.selectBooleanCheckboxModelBean = selectBooleanCheckboxModelBean;
  }
}
/** @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 BridgeRequestScope bridgeRequestScope;
  protected BridgeRequestScopeCache bridgeRequestScopeCache;
  protected boolean bridgeRequestScopePreserved;
  protected FacesContext facesContext;
  protected IncongruityContext incongruityContext;
  protected Lifecycle facesLifecycle;
  protected PortletConfig portletConfig;
  protected PortletContext portletContext;
  protected String portletName;

  // Private Data Members
  private FacesContextFactory facesContextFactory;

  public BridgePhaseBaseImpl(PortletConfig portletConfig, BridgeConfig bridgeConfig) {

    this.portletConfig = portletConfig;
    this.bridgeConfig = bridgeConfig;
    this.portletName = portletConfig.getPortletName();
    this.bridgeRequestScopePreserved =
        PortletConfigParam.BridgeRequestScopePreserved.getBooleanValue(portletConfig);

    this.portletContext =
        BridgePortletContextFactory.getPortletContextInstance(portletConfig.getPortletContext());

    // Initialize the incongruity context implementation.
    this.incongruityContext = IncongruityContextFactory.getIncongruityContextInstance();

    // Get the bridge request scope cache from the factory.
    this.bridgeRequestScopeCache =
        BridgeRequestScopeCacheFactory.getBridgeRequestScopeCacheInstance(portletContext);

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

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

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

  protected abstract void removeBridgeContextAttribute(PortletRequest portletRequest);

  protected abstract void setBridgeContextAttribute(PortletRequest portletRequest);

  protected void cleanup(PortletRequest portletRequest) {

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

    // Cleanup request attributes.
    if (portletRequest != null) {
      removeBridgeContextAttribute(portletRequest);
      portletRequest.removeAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);
      portletRequest.removeAttribute(PortletConfig.class.getName());
      portletRequest.removeAttribute(BridgeConfig.class.getName());
      portletRequest.removeAttribute(BridgeRequestScope.class.getName());
      portletRequest.removeAttribute(IncongruityContext.class.getName());
    }
  }

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

    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() {

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

    return facesContextFactory;
  }

  protected String getFacesViewId(ExternalContext externalContext) {

    String viewId = externalContext.getRequestPathInfo();

    if (viewId == null) {
      viewId = externalContext.getRequestServletPath();
    }

    return viewId;
  }

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

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

    // Save the PortletConfig as a request attribute.
    portletRequest.setAttribute(PortletConfig.class.getName(), portletConfig);

    // Save the BridgeConfig as a request attribute.
    portletRequest.setAttribute(BridgeConfig.class.getName(), bridgeConfig);

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

    // Save the BridgeRequestScope as a request attribute.
    portletRequest.setAttribute(BridgeRequestScope.class.getName(), bridgeRequestScope);

    // Save the IncongruityContext as a request attribute.
    portletRequest.setAttribute(IncongruityContext.class.getName(), incongruityContext);

    // Save the BridgeContext as a request attribute for legacy versions of ICEfaces.
    setBridgeContextAttribute(portletRequest);

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

    // If not set by a previous request, then set the default viewIdHistory for the portlet modes.
    for (String portletMode : PortletModeHelper.PORTLET_MODE_NAMES) {

      String attributeName = Bridge.VIEWID_HISTORY + "." + portletMode;
      PortletSession portletSession = portletRequest.getPortletSession();

      if (portletSession.getAttribute(attributeName) == null) {
        Map<String, String> defaultViewIdMap = ViewUtil.getDefaultViewIdMap(portletConfig);
        portletSession.setAttribute(attributeName, defaultViewIdMap.get(portletMode));
      }
    }
  }

  protected void initBridgeRequestScope(
      PortletRequest portletRequest,
      PortletResponse portletResponse,
      Bridge.PortletPhase portletPhase) {

    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 = 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 {

          if (bridgeRequestScopePreserved) {
            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) {
        bridgeRequestScope =
            BridgeRequestScopeFactory.getBridgeRequestScopeInstance(
                portletRequest, portletConfig, bridgeConfig);
      }
    }
  }

  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;
          }
        }
      }
    }
  }
}
/** @author Neil Griffin */
public class ExternalContextImpl extends ExternalContextCompat_2_2_Impl {

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

  // Private Constants
  private static final boolean LIFERAY_PORTAL_DETECTED =
      ProductMap.getInstance().get(ProductConstants.LIFERAY_PORTAL).isDetected();
  private static final boolean RICHFACES_DETECTED =
      ProductMap.getInstance().get(ProductConstants.RICHFACES).isDetected();
  private static final String ORG_RICHFACES_EXTENSION = "org.richfaces.extension";

  // Pre-initialized Data Members
  private ApplicationMap applicationMap;
  private BeanManager beanManager;
  private Map<String, Object> requestAttributeMap;
  private Iterator<Locale> requestLocales;
  private Map<String, Object> sessionMap;

  // Lazily-Initialized Data Members
  private String authType;
  private BridgeAfterViewContentRequest bridgeAfterViewContentRequest;
  private BridgeAfterViewContentResponse bridgeAfterViewContentResponse;
  private Map<String, String> initParameterMap;
  private String remoteUser;
  private Map<String, Object> requestCookieMap;
  private Locale requestLocale;
  private Principal userPrincipal;

  public ExternalContextImpl(
      PortletContext portletContext,
      PortletRequest portletRequest,
      PortletResponse portletResponse) {

    super(portletContext, portletRequest, portletResponse);

    BeanManagerFactory beanManagerFactory =
        (BeanManagerFactory) FactoryExtensionFinder.getFactory(BeanManagerFactory.class);
    this.beanManager = beanManagerFactory.getBeanManager();

    try {
      boolean requestChanged = false;
      boolean responseChanged = false;
      preInitializeObjects(requestChanged, responseChanged);
    } catch (Exception e) {
      logger.error(e);
    }
  }

  @Override
  public void dispatch(String path) throws IOException {

    // Indicate that JSP AFTER_VIEW_CONTENT processing has been de-activated. This will make it
    // possible for the
    // Mojarra JspViewHandlingStrategy#executePageToBuildView(FacesContext, UIViewRoot) method to
    // successfully call
    // {@link ExternalContextImpl#setResponse(Object)} in order to undo the
    // ViewHandlerResponseWrapper and restore
    // the original PortletResponse.
    bridgeContext.setProcessingAfterViewContent(false);

    logger.debug("De-activated JSP AFTER_VIEW_CONTENT");

    bridgeContext.dispatch(path);
  }

  /** @see ExternalContext#encodeNamespace(String) */
  @Override
  public String encodeNamespace(String name) {

    if (name == null) {
      return bridgeContext.getResponseNamespace();
    } else if (RICHFACES_DETECTED && (name.equals(ORG_RICHFACES_EXTENSION))) {

      // http://issues.liferay.com/browse/FACES-1416
      return name;
    } else {
      return bridgeContext.getResponseNamespace() + name;
    }
  }

  /** @see ExternalContext#encodeResourceURL(String) */
  @Override
  public String encodeResourceURL(String url) {
    return bridgeContext.encodeResourceURL(url).toString();
  }

  @Override
  public void log(String message) {
    portletContext.log(message);
  }

  @Override
  public void log(String message, Throwable exception) {
    portletContext.log(message, exception);
  }

  @Override
  public void redirect(String url) throws IOException {
    bridgeContext.redirect(url);
  }

  /**
   * In order to increase runtime performance, this method caches values of objects that are
   * typically called more than once during the JSF lifecycle. Other values will be cached lazily,
   * or might not be cached since their getter methods may never get called.
   *
   * @param requestChanged Flag indicating that this method is being called because {@link
   *     #setRequest(Object)} was called.
   * @param responseChanged Flag indicating that this method is being called because {@link
   *     #setResponse(Object)} was called.
   */
  protected void preInitializeObjects(boolean requestChanged, boolean responseChanged) {

    if (requestChanged) {
      bridgeContext.setPortletRequest(portletRequest);
    }

    if (responseChanged) {
      bridgeContext.setPortletResponse(portletResponse);
    }

    // Retrieve the portlet lifecycle phase.
    portletPhase = bridgeContext.getPortletRequestPhase();

    // Determines whether or not methods annotated with the &#064;PreDestroy annotation are
    // preferably invoked
    // over the &#064;BridgePreDestroy annotation.
    String preferPreDestroyInitParam =
        getInitParameter(BridgeConfigConstants.PARAM_PREFER_PRE_DESTROY1);

    if (preferPreDestroyInitParam == null) {

      // Backward compatibility
      preferPreDestroyInitParam = getInitParameter(BridgeConfigConstants.PARAM_PREFER_PRE_DESTROY2);
    }

    boolean preferPreDestroy = BooleanHelper.toBoolean(preferPreDestroyInitParam, true);

    // Initialize the application map.
    applicationMap = new ApplicationMap(portletContext, beanManager, preferPreDestroy);

    // Determines whether or not JSF @ManagedBean classes annotated with @RequestScoped should be
    // distinct for
    // each portlet when running under Liferay Portal.
    boolean distinctRequestScopedManagedBeans = false;

    if (LIFERAY_PORTAL_DETECTED) {
      distinctRequestScopedManagedBeans =
          BooleanHelper.toBoolean(
              getInitParameter(BridgeConfigConstants.PARAM_DISTINCT_REQUEST_SCOPED_MANAGED_BEANS),
              false);
    }

    // Initialize the request attribute map.
    Set<String> removedAttributeNames = null;
    BridgeRequestScope bridgeRequestScope = bridgeContext.getBridgeRequestScope();

    if (bridgeRequestScope != null) {
      removedAttributeNames = bridgeRequestScope.getRemovedAttributeNames();
    } else {
      removedAttributeNames = new HashSet<String>();
    }

    requestAttributeMap =
        new RequestAttributeMap(
            portletRequest,
            beanManager,
            bridgeContext.getPortletContainer().getResponseNamespace(),
            preferPreDestroy,
            distinctRequestScopedManagedBeans,
            removedAttributeNames);

    // Initialize the session map.
    sessionMap =
        new SessionMap(
            portletRequest.getPortletSession(),
            beanManager,
            PortletSession.PORTLET_SCOPE,
            preferPreDestroy);

    // Initialize the init parameter map.
    initParameterMap = Collections.unmodifiableMap(new InitParameterMap(portletContext));

    // Initialize the request context path.
    requestContextPath = portletRequest.getContextPath();

    // Initialize the request locales.
    requestLocales = new LocaleIterator(portletRequest.getLocales());
  }

  @Override
  public Map<String, Object> getApplicationMap() {
    return applicationMap;
  }

  @Override
  public String getAuthType() {

    if (authType == null) {
      authType = portletRequest.getAuthType();
    }

    return authType;
  }

  @Override
  public Object getContext() {
    return portletContext;
  }

  @Override
  public boolean isUserInRole(String role) {
    return portletRequest.isUserInRole(role);
  }

  @Override
  public String getInitParameter(String name) {
    return bridgeContext.getInitParameter(name);
  }

  @Override
  public Map<String, String> getInitParameterMap() {
    return initParameterMap;
  }

  @Override
  public String getRemoteUser() {

    if (remoteUser == null) {
      remoteUser = portletRequest.getRemoteUser();
    }

    return remoteUser;
  }

  @Override
  public Object getRequest() {

    // If JSP AFTER_VIEW_CONTENT processing has been activated by the
    // JspViewDeclarationLanguage#buildView(FacesContext, UIViewRoot) method, then return a
    // ServletRequest that
    // wraps/decorates the current PortletRequest. This is necessary because the MyFaces
    // JspViewDeclarationLanguage#buildView(FacesContext, UIViewRoot) method has a Servlet API
    // dependency due to
    // explicit casts to HttpServletRequest.
    if (bridgeContext.isProcessingAfterViewContent()) {

      if ((bridgeAfterViewContentRequest == null)
          || (bridgeAfterViewContentRequest.getWrapped() != portletRequest)) {

        BridgeWriteBehindSupportFactory bridgeWriteBehindSupportFactory =
            (BridgeWriteBehindSupportFactory)
                FactoryExtensionFinder.getFactory(BridgeWriteBehindSupportFactory.class);
        bridgeAfterViewContentRequest =
            bridgeWriteBehindSupportFactory.getBridgeAfterViewContentRequest(portletRequest);
      }

      return bridgeAfterViewContentRequest;
    } else {
      return portletRequest;
    }
  }

  @Override
  public void setRequest(Object request) {
    this.portletRequest = (PortletRequest) request;

    try {
      boolean requestChanged = true;
      boolean responseChanged = false;
      preInitializeObjects(requestChanged, responseChanged);
    } catch (Exception e) {
      logger.error(e);
    }
  }

  @Override
  public String getRequestCharacterEncoding() {

    if (portletRequest instanceof ClientDataRequest) {
      ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest;
      String requestCharacterEncoding = clientDataRequest.getCharacterEncoding();

      if (manageIncongruities) {

        try {
          incongruityContext.setRequestCharacterEncoding(requestCharacterEncoding);
        } catch (Exception e) {
          logger.error(e);
        }
      }

      return requestCharacterEncoding;
    } else {

      if (manageIncongruities) {
        return incongruityContext.getRequestCharacterEncoding();
      } else {

        // The Mojarra 2.x {@link MultiViewHandler#initView(FacesContext)} method expects a null
        // value to be
        // returned, so throwing an IllegalStateException is not an option.
        return null;
      }
    }
  }

  @Override
  public void setRequestCharacterEncoding(String encoding)
      throws UnsupportedEncodingException, IllegalStateException {

    // Although the JSF API's ViewHandler.initView(FacesContext) method will call this method during
    // the portlet
    // RENDER_PHASE, the RenderRequest does not implement the ClientDataRequest interface, which
    // means it does not
    // have a setCharacterEncoding(String) method, therefore this should only be done in the case of
    // a
    // ClientDataRequest.
    if (portletRequest instanceof ClientDataRequest) {
      ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest;

      try {
        clientDataRequest.setCharacterEncoding(encoding);
      } catch (IllegalStateException e) {
        // TestPage141: setRequestCharacterEncodingActionTest -- exception is to be ignored
      }
    } else {

      if (manageIncongruities) {
        incongruityContext.setRequestCharacterEncoding(encoding);
      } else {
        // TestPage140: setRequestCharacterEncodingRenderTest expects this to be a no-op so throwing
        // an
        // IllegalStateException is not an option.
      }
    }
  }

  @Override
  public String getRequestContentType() {

    if (portletRequest instanceof ClientDataRequest) {
      ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest;

      // If using ICEfaces 3.0.x/2.0.x then need to return the legacy value.
      // http://issues.liferay.com/browse/FACES-1228
      String requestContentType = null;

      if (isICEfacesLegacyMode(clientDataRequest)) {
        requestContentType = clientDataRequest.getResponseContentType();
      } else {
        requestContentType = clientDataRequest.getContentType();
      }

      if (manageIncongruities) {
        incongruityContext.setRequestContentType(requestContentType);
      }

      return requestContentType;
    } else {

      if (manageIncongruities) {
        return incongruityContext.getRequestContentType();
      } else {

        // TestPage166: getRequestContentTypeEventTest expects this condition to return null so
        // throwing an
        // IllegalStateException is not an option.
        return null;
      }
    }
  }

  @Override
  public String getRequestContextPath() {
    return requestContextPath;
  }

  @Override
  public Map<String, Object> getRequestCookieMap() {

    if (requestCookieMap == null) {
      requestCookieMap = new RequestCookieMap(portletRequest.getCookies());
    }

    return requestCookieMap;
  }

  @Override
  public Map<String, String> getRequestHeaderMap() {
    return bridgeContext.getRequestHeaderMap();
  }

  @Override
  public Map<String, String[]> getRequestHeaderValuesMap() {
    return bridgeContext.getRequestHeaderValuesMap();
  }

  @Override
  public Locale getRequestLocale() {

    if (requestLocale == null) {
      requestLocale = portletRequest.getLocale();
    }

    return requestLocale;
  }

  @Override
  public Iterator<Locale> getRequestLocales() {
    return requestLocales;
  }

  @Override
  public Map<String, Object> getRequestMap() {
    return requestAttributeMap;
  }

  @Override
  public Map<String, String> getRequestParameterMap() {
    return bridgeContext.getRequestParameterMap();
  }

  @Override
  public Iterator<String> getRequestParameterNames() {
    return getRequestParameterMap().keySet().iterator();
  }

  @Override
  public Map<String, String[]> getRequestParameterValuesMap() {
    return bridgeContext.getRequestParameterValuesMap();
  }

  /**
   * This method returns the relative path to the viewId that is to be rendered.
   *
   * @see javax.faces.context.ExternalContext#getRequestPathInfo()
   */
  @Override
  public String getRequestPathInfo() {
    return bridgeContext.getRequestPathInfo();
  }

  /** Section 6.1.3.1 of the JSR 329 spec describes the logic for this method. */
  @Override
  public String getRequestServletPath() {
    return bridgeContext.getRequestServletPath();
  }

  @Override
  public URL getResource(String path) throws MalformedURLException {
    return portletContext.getResource(path);
  }

  @Override
  public InputStream getResourceAsStream(String path) {
    return portletContext.getResourceAsStream(path);
  }

  @Override
  public Set<String> getResourcePaths(String path) {
    return portletContext.getResourcePaths(path);
  }

  @Override
  public Object getResponse() {

    // If JSP AFTER_VIEW_CONTENT processing has been activated by the
    // JspViewDeclarationLanguage#buildView(FacesContext, UIViewRoot) method, then return a
    // ServletResponse that is
    // able to handle the AFTER_VIEW_CONTENT feature. This is necessary because the Mojarra
    // JspViewHandlingStrategy#getWrapper(ExternalContext) method has a Servlet API dependency due
    // to explicit casts
    // to HttpServletResponse. Additionally, the MyFaces
    // JspViewDeclarationLanguage#buildView(FacesContext,
    // UIViewRoot) method has an explicit cast to HttpServletResponse.
    if (bridgeContext.isProcessingAfterViewContent()) {

      if (facesImplementationServletResponse == null) {

        if ((bridgeAfterViewContentResponse == null)
            || (bridgeAfterViewContentResponse.getWrapped() != portletResponse)) {
          BridgeWriteBehindSupportFactory bridgeWriteBehindSupportFactory =
              (BridgeWriteBehindSupportFactory)
                  FactoryExtensionFinder.getFactory(BridgeWriteBehindSupportFactory.class);
          bridgeAfterViewContentResponse =
              bridgeWriteBehindSupportFactory.getBridgeAfterViewContentResponse(
                  portletResponse, getRequestLocale());
        }

        return bridgeAfterViewContentResponse;
      } else {
        return facesImplementationServletResponse;
      }
    } else {

      if (isBridgeFlashServletResponseRequired()) {
        return createFlashHttpServletResponse();
      } else {
        return portletResponse;
      }
    }
  }

  @Override
  public void setResponse(Object response) {

    // Assume that the JSP_AFTER_VIEW_CONTENT feature is deactivated.
    facesImplementationServletResponse = null;

    // If JSP AFTER_VIEW_CONTENT processing has been activated by the bridge's
    // ViewDeclarationLanguageJspImpl#buildView(FacesContext, UIViewRoot) method, then wrap the
    // specified response
    // object with a ServletResponse that is able to handle the AFTER_VIEW_CONTENT feature. This is
    // necessary
    // because the Mojarra JspViewHandlingStrategy#getWrapper(ExternalContext) method has a Servlet
    // API dependency
    // due to explicit casts to HttpServletResponse.
    if (bridgeContext.isProcessingAfterViewContent()) {

      // If the specified response is of type HttpServletResponseWrapper, then it is almost certain
      // that Mojarra's
      // JspViewHandlingStrategy#executePageToBuildView(FacesContext, UIViewRoot) method is
      // attempting to wrap the
      // bridge's response object (that it originally got by calling the
      // ExternalContext#getResponse() method)
      // with it's ViewHandlerResponseWrapper, which extends HttpServletResponseWrapper.
      if (response instanceof HttpServletResponseWrapper) {

        this.facesImplementationServletResponse = (ServletResponse) response;

        HttpServletResponseWrapper httpServletResponseWrapper =
            (HttpServletResponseWrapper) response;
        ServletResponse wrappedServletResponse = httpServletResponseWrapper.getResponse();

        if (wrappedServletResponse instanceof BridgeAfterViewContentResponse) {
          BridgeAfterViewContentResponse bridgeAfterViewContentPreResponse =
              (BridgeAfterViewContentResponse) wrappedServletResponse;
          PortletResponse wrappedPortletResponse = bridgeAfterViewContentPreResponse.getWrapped();

          BridgeWriteBehindSupportFactory bridgeWriteBehindSupportFactory =
              (BridgeWriteBehindSupportFactory)
                  FactoryExtensionFinder.getFactory(BridgeWriteBehindSupportFactory.class);
          BridgeWriteBehindResponse bridgeWriteBehindResponse =
              bridgeWriteBehindSupportFactory.getBridgeWriteBehindResponse(
                  (MimeResponse) wrappedPortletResponse, facesImplementationServletResponse);

          // Note: See comments in BridgeContextImpl#dispatch(String) regarding Liferay's inability
          // to
          // accept a wrapped response. This is indeed supported in Pluto.
          this.portletResponse = (PortletResponse) bridgeWriteBehindResponse;
        } else {

          // Since we're unable to determine the wrapped PortletResponse, the following line will
          // throw an
          // intentional ClassCastException. Note that this case should never happen.
          this.portletResponse = (PortletResponse) response;
        }
      }

      // Otherwise, the specified response is of type BridgeAfterViewContentResponse, then Mojarra's
      // JspViewHandlingStrategy#executePageToBuildView(FacesContext, UIViewRoot) method is trying
      // to restore the
      // bridge's response object that it originally got from calling the
      // ExternalContext#getResponse() method
      // prior to wrapping with it's ViewHandlerResponseWrapper.
      else if (response instanceof BridgeAfterViewContentResponse) {
        BridgeAfterViewContentResponse bridgeAfterViewContentResponse =
            (BridgeAfterViewContentResponse) response;
        this.portletResponse = bridgeAfterViewContentResponse.getWrapped();
      }

      // Otherwise, assume that the specified response is a PortletResponse.
      else {
        this.portletResponse = (PortletResponse) response;
      }

    }

    // Otherwise, since the JSF AFTER_VIEW_CONTENT feature is not activated, assume that the
    // specified response is
    // a PortletResponse.
    else {
      this.portletResponse = (PortletResponse) response;
    }

    try {
      boolean requestChanged = false;
      boolean responseChanged = true;
      preInitializeObjects(requestChanged, responseChanged);
    } catch (Exception e) {
      logger.error(e);
    }
  }

  @Override
  public String getResponseCharacterEncoding() {

    if (portletResponse instanceof MimeResponse) {
      MimeResponse mimeResponse = (MimeResponse) portletResponse;
      String characterEncoding = mimeResponse.getCharacterEncoding();

      if (manageIncongruities) {
        incongruityContext.setResponseCharacterEncoding(characterEncoding);
      }

      return characterEncoding;
    } else {

      if (manageIncongruities) {
        return incongruityContext.getResponseCharacterEncoding();
      } else {

        if (portletResponse instanceof StateAwareResponse) {

          String characterEncoding =
              (String)
                  bridgeContext.getAttributes().get(ViewHandlerImpl.RESPONSE_CHARACTER_ENCODING);

          if (characterEncoding != null) {

            // Workaround for patch applied to Mojarra in JAVASERVERFACES-3023
            return characterEncoding;
          } else {

            // TCK TestPage169: getResponseCharacterEncodingActionTest
            // TCK TestPage180: getResponseCharacterEncodingEventTest
            throw new IllegalStateException();
          }
        } else {
          return null;
        }
      }
    }
  }

  /** @see ExternalContext#setResponseCharacterEncoding(String) */
  @Override
  public void setResponseCharacterEncoding(String encoding) {

    if (encoding != null) {

      if (portletResponse instanceof ResourceResponse) {
        ResourceResponse resourceResponse = (ResourceResponse) portletResponse;
        resourceResponse.setCharacterEncoding(encoding);
      } else {

        if (manageIncongruities) {
          incongruityContext.setResponseCharacterEncoding(encoding);
        } else {
          // TestPage196: setResponseCharacterEncodingTest expects this to be a no-op so throwing
          // IllegalStateException is not an option.
        }
      }
    }
  }

  /** @see {@link ExternalContext#getResponseContentType()} */
  @Override
  public String getResponseContentType() {

    if (portletResponse instanceof MimeResponse) {

      MimeResponse mimeResponse = (MimeResponse) portletResponse;

      String responseContentType = mimeResponse.getContentType();

      if (responseContentType == null) {
        responseContentType = portletRequest.getResponseContentType();
      }

      return responseContentType;
    } else {

      // TCK TestPage173: getResponseContentTypeActionTest
      // TCK TestPage174: getResponseContentTypeEventTest
      throw new IllegalStateException();
    }
  }

  /** @see {@link ExternalContext#getSession(boolean)} */
  @Override
  public Object getSession(boolean create) {
    return portletRequest.getPortletSession(create);
  }

  @Override
  public Map<String, Object> getSessionMap() {
    return sessionMap;
  }

  @Override
  public Principal getUserPrincipal() {

    if (userPrincipal == null) {
      userPrincipal = portletRequest.getUserPrincipal();
    }

    return userPrincipal;
  }
}
/** @author Neil Griffin */
@RequestScoped
@ManagedBean
public class HtmlInputFileBackingBean {

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

  // Injections
  @ManagedProperty(value = "#{htmlInputFileModelBean}")
  private HtmlInputFileModelBean htmlInputFileModelBean;

  // Private Data Members
  private Part uploadedPart;

  public void deleteUploadedFile(ActionEvent actionEvent) {

    UICommand uiCommand = (UICommand) actionEvent.getComponent();
    String fileId = (String) uiCommand.getValue();

    try {
      List<UploadedFile> uploadedFiles = htmlInputFileModelBean.getUploadedFiles();

      UploadedFile uploadedFileToDelete = null;

      for (UploadedFile uploadedFile : uploadedFiles) {

        if (uploadedFile.getId().equals(fileId)) {
          uploadedFileToDelete = uploadedFile;

          break;
        }
      }

      if (uploadedFileToDelete != null) {
        uploadedFileToDelete.delete();
        uploadedFiles.remove(uploadedFileToDelete);
        logger.debug("Deleted file=[{0}]", uploadedFileToDelete.getName());
      }
    } catch (Exception e) {
      logger.error(e);
    }
  }

  public Part getUploadedPart() {
    return uploadedPart;
  }

  public void setHtmlInputFileModelBean(HtmlInputFileModelBean htmlInputFileModelBean) {

    // Injected via @ManagedProperty annotation
    this.htmlInputFileModelBean = htmlInputFileModelBean;
  }

  public void setUploadedPart(Part uploadedPart) {
    this.uploadedPart = uploadedPart;

    String id = Long.toString(((long) hashCode()) + System.currentTimeMillis());
    UploadedFile uploadedFile =
        new UploadedFilePart(uploadedPart, id, UploadedFile.Status.FILE_SAVED);
    htmlInputFileModelBean.getUploadedFiles().add(uploadedFile);
  }
}
/**
 * This class represents a simple "non-encoded" {@link BaseURL}, meaning an implementation that
 * simply wraps a String based URL without providing any encoding. The only methods that are meant
 * to be called is {@link BaseURLNonEncodedStringImpl#toString()} and {@link
 * BaseURLNonEncodedStringImpl#write(Writer, boolean)}. All other methods throw an {@link
 * UnsupportedOperationException}.
 *
 * @author Neil Griffin
 */
public class BaseURLNonEncodedStringImpl implements BaseURL {

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

  // Private Data Members
  private String url;
  private Map<String, String[]> parameterMap;
  private String query;
  private String main;
  private String toStringValue;

  public BaseURLNonEncodedStringImpl(String urlWithParameters) {
    this.url = urlWithParameters;
    this.parameterMap = new HashMap<String, String[]>();
  }

  public BaseURLNonEncodedStringImpl(String url, Map<String, String[]> parameterMap) {
    this.url = url;
    this.parameterMap = parameterMap;
  }

  public void addProperty(String key, String value) {
    throw new UnsupportedOperationException();
  }

  @Override
  public String toString() {

    if (toStringValue == null) {
      StringBuilder buf = new StringBuilder();
      buf.append(getMain());

      String queryString = getQuery();

      if (queryString.length() > 0) {
        buf.append(StringPool.QUESTION);
        buf.append(queryString);
      }

      toStringValue = buf.toString();
    }

    return toStringValue;
  }

  public void write(Writer out) throws IOException {
    throw new UnsupportedOperationException();
  }

  public void write(Writer out, boolean escapeXML) throws IOException {

    // Note: Ignore the escapeXML parameter because this class is simply supposed to return the
    // original URL string.
    out.write(url);
  }

  /** Returns the main part of the URL, which is everything up until the question mark. */
  protected String getMain() {

    if (main == null) {
      int queryPos = url.indexOf(StringPool.QUESTION);

      if (queryPos >= 0) {
        main = url.substring(0, queryPos);
      } else {
        main = url;
      }
    }

    return main;
  }

  public void setParameter(String name, String value) {
    throw new UnsupportedOperationException();
  }

  public void setParameter(String name, String[] values) {
    throw new UnsupportedOperationException();
  }

  public Map<String, String[]> getParameterMap() {
    throw new UnsupportedOperationException();
  }

  public void setParameters(Map<String, String[]> parameters) {
    throw new UnsupportedOperationException();
  }

  public void setProperty(String key, String value) {
    throw new UnsupportedOperationException();
  }

  /** Returns the query-string part of the URL (without a leading question mark). */
  protected String getQuery() {

    if (query == null) {

      StringBuilder buf = new StringBuilder();

      // Get the original query-string from the URL.
      String originalQuery = StringPool.BLANK;
      boolean firstParam = true;
      int queryPos = url.indexOf(StringPool.QUESTION);

      if (queryPos >= 0) {
        originalQuery = url.substring(queryPos + 1);
      }

      // Keep track of all the parameters that are appended to the return value.
      Set<String> processedParameterNames = new HashSet<String>(parameterMap.size());

      // The TCK expects query parameters to appear in exactly the same order as they do in the
      // query-string of
      // the original URL. For this reason, need to iterate over the parameters found in the
      // original
      // query-string.
      String[] queryParameters = originalQuery.split(BridgeConstants.REGEX_AMPERSAND_DELIMITER);

      // For each parameter found in the original query-string:
      for (String queryParameter : queryParameters) {

        if ((queryParameter != null) && (queryParameter.length() > 0)) {

          // Parse the name and value from the name=value pair.
          String[] nameValueArray = queryParameter.split("[=]");

          String name = null;
          String[] values = null;

          if (nameValueArray.length == 1) {
            name = nameValueArray[0];
            values = new String[] {StringPool.BLANK};
          } else if (nameValueArray.length == 2) {
            name = nameValueArray[0];

            // If the parameter name is present in the parameter map, then that means it should be
            // appended
            // to the return value. Otherwise, it should not be appended, because absence from the
            // parameter
            // map means that it was deliberately removed.
            values = parameterMap.get(name);
          }

          if ((name != null) && (values != null) && (values.length > 0)) {

            if (firstParam) {
              firstParam = false;
            } else {
              buf.append(StringPool.AMPERSAND);
            }

            buf.append(name);
            buf.append(StringPool.EQUAL);
            buf.append(values[0]);
            processedParameterNames.add(name);
          }

          // Otherwise, log an error.
          else {

            // Note that "javax.portlet.faces.BackLink" is sometimes deliberately removed and
            // therefore is
            // not an error.
            if (!Bridge.BACK_LINK.equals(name)) {
              logger.error("Invalid name=value pair=[{0}] in URL=[{1}]", queryParameter, url);
            }
          }
        }
      }

      // Now iterate through the entire parameter map to see and append any additional parameters to
      // the return
      // value.
      Set<Entry<String, String[]>> mapEntries = parameterMap.entrySet();

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

        String name = mapEntry.getKey();

        if (!processedParameterNames.contains(name)) {
          String[] values = mapEntry.getValue();

          if ((values != null) && (values.length > 0)) {

            if (firstParam) {
              firstParam = false;
            } else {
              buf.append(StringPool.AMPERSAND);
            }

            buf.append(name);
            buf.append(StringPool.EQUAL);
            buf.append(values[0]);
          }
        }
      }

      query = buf.toString();
    }

    return query;
  }

  public void setSecure(boolean secure) throws PortletSecurityException {
    throw new UnsupportedOperationException();
  }
}
/**
 * This class is a runtime wrapper around the RichFaces FileUploadRenderer class that makes the
 * rich:fileUpload component compatible with a portlet environment.
 *
 * @author Neil Griffin
 */
public class FileUploadRendererRichFacesImpl extends RendererWrapper {

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

  // Private Constants
  private static final String RICHFACES_UPLOADED_FILE_FQCN = "org.richfaces.model.UploadedFile";
  private static final String RICHFACES_FILE_UPLOAD_EVENT_FQCN =
      "org.richfaces.event.FileUploadEvent";

  // Private Data Members
  private Renderer wrappedRenderer;

  public FileUploadRendererRichFacesImpl(Renderer renderer) {
    this.wrappedRenderer = renderer;
  }

  /**
   * This method overrides the {@link #decode(FacesContext, UIComponent)} method so that it can
   * avoid a Servlet-API dependency in the RichFaces FileUploadRenderer. Note that rich:fileUpload
   * will do an Ajax postback and invoke the JSF lifecycle for each individual file.
   */
  @Override
  public void decode(FacesContext facesContext, UIComponent uiComponent) {

    try {

      // Get the UploadedFile from the request attribute map.
      ContextMapFactory contextMapFactory =
          (ContextMapFactory) FactoryExtensionFinder.getFactory(ContextMapFactory.class);
      BridgeContext bridgeContext = BridgeContext.getCurrentInstance();
      Map<String, Collection<UploadedFile>> uploadedFileMap =
          contextMapFactory.getUploadedFileMap(bridgeContext);

      if (uploadedFileMap != null) {

        // Use reflection to create a dynamic proxy class that implements the RichFaces UploadedFile
        // interface.
        Class<?> uploadedFileInterface = Class.forName(RICHFACES_UPLOADED_FILE_FQCN);
        Class<?> fileUploadEventClass = Class.forName(RICHFACES_FILE_UPLOAD_EVENT_FQCN);
        ClassLoader classLoader = uploadedFileInterface.getClassLoader();

        String clientId = uiComponent.getClientId(facesContext);
        Collection<UploadedFile> uploadedFiles = uploadedFileMap.get(clientId);

        if (uploadedFiles != null) {

          for (UploadedFile uploadedFile : uploadedFiles) {
            RichFacesUploadedFileHandler richFacesUploadedFileHandler =
                new RichFacesUploadedFileHandler(uploadedFile);
            Object richFacesUploadedFile =
                Proxy.newProxyInstance(
                    classLoader, new Class[] {uploadedFileInterface}, richFacesUploadedFileHandler);
            FacesEvent fileUploadEvent =
                (FacesEvent)
                    fileUploadEventClass
                        .getConstructor(UIComponent.class, uploadedFileInterface)
                        .newInstance(uiComponent, richFacesUploadedFile);

            // Queue the RichFaces FileUploadEvent instance so that it can be handled with an
            // ActionListener.
            uiComponent.queueEvent(fileUploadEvent);
          }
        }
      }
    } catch (Exception e) {
      logger.error(e);
    }
  }

  @Override
  public Renderer getWrapped() {
    return wrappedRenderer;
  }

  public class RichFacesUploadedFileHandler implements InvocationHandler {

    // Private Constants
    private static final String METHOD_DELETE = "delete";
    private static final String METHOD_GET_CONTENT_TYPE = "getContentType";
    private static final String METHOD_GET_DATA = "getData";
    private static final String METHOD_GET_INPUT_STREAM = "getInputStream";
    private static final String METHOD_GET_NAME = "getName";
    private static final String METHOD_GET_SIZE = "getSize";
    private static final String METHOD_WRITE = "write";

    // Private Data Members
    private UploadedFile uploadedFile;

    public RichFacesUploadedFileHandler(UploadedFile uploadedFile) {
      this.uploadedFile = uploadedFile;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

      String methodName = method.getName();

      if (METHOD_DELETE.equals(methodName)) {
        File file = new File(uploadedFile.getAbsolutePath());
        file.delete();

        return null;
      } else if (METHOD_GET_CONTENT_TYPE.equals(methodName)) {
        return uploadedFile.getContentType();
      } else if (METHOD_GET_DATA.equals(methodName)) {
        return getBytes();
      } else if (METHOD_GET_INPUT_STREAM.equals(methodName)) {
        return new FileInputStream(uploadedFile.getAbsolutePath());
      } else if (METHOD_GET_NAME.equals(methodName)) {
        return uploadedFile.getName();
      } else if (METHOD_GET_SIZE.equals(methodName)) {
        return uploadedFile.getSize();
      } else if (METHOD_WRITE.equals(methodName)) {
        String fileName = (String) args[0];
        OutputStream outputStream = new FileOutputStream(fileName);
        outputStream.write(getBytes());
        outputStream.close();

        return null;
      } else {

        // Unsupported method.
        return null;
      }
    }

    protected byte[] getBytes() {
      byte[] bytes = null;

      try {
        File file = new File(uploadedFile.getAbsolutePath());

        if (file.exists()) {
          RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
          bytes = new byte[(int) randomAccessFile.length()];
          randomAccessFile.readFully(bytes);
          randomAccessFile.close();
        }
      } catch (Exception e) {
        logger.error(e);
      }

      return bytes;
    }
  }
}
/** @author Neil Griffin */
public class BridgePhaseEventImpl extends BridgePhaseCompat_2_2_Impl {

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

  // Private Data Members
  private EventRequest eventRequest;
  private EventResponse eventResponse;

  public BridgePhaseEventImpl(
      EventRequest eventRequest, EventResponse eventResponse, PortletConfig portletConfig) {
    super(portletConfig);
    this.eventRequest = eventRequest;
    this.eventResponse = eventResponse;
  }

  public void execute() throws BridgeDefaultViewNotSpecifiedException, BridgeException {

    logger.debug(Logger.SEPARATOR);
    logger.debug("execute(EventRequest, EventResponse) portletName=[{0}]", portletName);

    try {

      // If there is a bridgeEventHandler registered in portlet.xml, then
      String bridgeEventHandlerAttributeName =
          Bridge.BRIDGE_PACKAGE_PREFIX + portletName + "." + Bridge.BRIDGE_EVENT_HANDLER;
      BridgeEventHandler bridgeEventHandler =
          (BridgeEventHandler) portletContext.getAttribute(bridgeEventHandlerAttributeName);

      init(eventRequest, eventResponse, Bridge.PortletPhase.EVENT_PHASE);

      if (bridgeEventHandler != null) {

        // Restore the BridgeRequestScope that may have started during the ACTION_PHASE.
        bridgeRequestScope.restoreState(facesContext);

        // PROPOSED-FOR-BRIDGE3-API: https://issues.apache.org/jira/browse/PORTLETBRIDGE-202
        bridgeRequestScope.setPortletMode(eventRequest.getPortletMode());

        // Execute the JSF lifecycle so that ONLY the RESTORE_VIEW phase executes (note that this
        // this is
        // accomplished by the IPCPhaseListener).
        facesLifecycle.execute(facesContext);

        // If there were any "handled" exceptions queued, then throw a BridgeException.
        Throwable handledException = getJSF2HandledException(facesContext);

        if (handledException != null) {
          throw new BridgeException(handledException);
        }

        // Otherwise, if there were any "unhandled" exceptions queued, then throw a BridgeException.
        Throwable unhandledException = getJSF2UnhandledException(facesContext);

        if (unhandledException != null) {
          throw new BridgeException(unhandledException);
        }

        // Set a flag on the bridge request scope indicating that the Faces Lifecycle has executed.
        bridgeRequestScope.setFacesLifecycleExecuted(true);

        // If there is a bridgeEventHandler registered in portlet.xml, then invoke the handler so
        // that it
        // can process the event payload.

        logger.debug(
            "Invoking {0} for class=[{1}]",
            bridgeEventHandlerAttributeName, bridgeEventHandler.getClass());

        Event event = eventRequest.getEvent();
        EventNavigationResult eventNavigationResult =
            bridgeEventHandler.handleEvent(facesContext, event);

        if (eventNavigationResult != null) {
          String oldViewId = facesContext.getViewRoot().getViewId();
          String fromAction = eventNavigationResult.getFromAction();
          String outcome = eventNavigationResult.getOutcome();
          logger.debug(
              "Invoking navigationHandler fromAction=[{0}] outcome=[{1}]", fromAction, outcome);

          NavigationHandler navigationHandler =
              facesContext.getApplication().getNavigationHandler();
          navigationHandler.handleNavigation(facesContext, fromAction, outcome);

          String newViewId = facesContext.getViewRoot().getViewId();
          bridgeRequestScope.setNavigationOccurred(!oldViewId.equals(newViewId));
        }

        // Save the faces view root and any messages in the faces context so that they can be
        // restored during
        // the RENDER_PHASE of the portlet lifecycle.
        bridgeRequestScope.saveState(facesContext);

        // Assume that the bridge request scope should be maintained from the EVENT_PHASE into the
        // RENDER_PHASE by utilizing render parameters.
        BridgeRequestScope.Transport bridgeRequestScopeTransport =
            BridgeRequestScope.Transport.RENDER_PARAMETER;
        Serializable eventPayload = event.getValue();

        // FACES-1465: If the portlet developer intentionally wrapped the event payload is with an
        // EventPayloadWrapper, then determine whether or not this is happening during a redirect.
        // If this is
        // the case, then the bridge request scope must be maintained from the EVENT_PHASE into the
        // RENDER_PHASE
        // by utilizing a portlet session attribute. This is because render parameters will not
        // survive a
        // redirect.
        if ((eventPayload != null) && (eventPayload instanceof EventPayloadWrapper)) {
          EventPayloadWrapper eventPayloadWrapper = (EventPayloadWrapper) eventPayload;

          if (eventPayloadWrapper.isRedirect()) {

            bridgeRequestScopeTransport = BridgeRequestScope.Transport.PORTLET_SESSION_ATTRIBUTE;
          }
        }

        maintainBridgeRequestScope(eventRequest, eventResponse, bridgeRequestScopeTransport);

        // Process the outgoing public render parameters.
        // TCK TestPage064: eventControllerTest
        processOutgoingPublicRenderParameters(facesLifecycle);
      }

      // Maintain the render parameters set in the ACTION_PHASE so that they carry over to the
      // RENDER_PHASE.
      bridgeContext.getPortletContainer().maintainRenderParameters(eventRequest, eventResponse);

      // Spec 6.6 (Namespacing)
      indicateNamespacingToConsumers(facesContext.getViewRoot(), eventResponse);
    } catch (Throwable t) {
      throw new BridgeException(t);
    } finally {
      cleanup();
    }
  }

  protected void processOutgoingPublicRenderParameters(Lifecycle lifecycle) {

    PhaseListener[] phaseListeners = lifecycle.getPhaseListeners();

    for (PhaseListener phaseListener : phaseListeners) {

      if (phaseListener instanceof IPCPhaseListener) {
        IPCPhaseListener ipcPhaseListener = (IPCPhaseListener) phaseListener;
        ipcPhaseListener.processOutgoingPublicRenderParameters(bridgeContext, facesContext);

        break;
      }
    }
  }
}
/**
 * This class provides a compatibility layer that isolates differences between JSF1 and JSF2.
 *
 * @author Neil Griffin
 */
public abstract class ExternalContextCompatImpl extends ExternalContext {

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

  // Private Constants
  private static final String COOKIE_PROPERTY_COMMENT = "comment";
  private static final String COOKIE_PROPERTY_DOMAIN = "domain";
  private static final String COOKIE_PROPERTY_MAX_AGE = "maxAge";
  private static final String COOKIE_PROPERTY_PATH = "path";
  private static final String COOKIE_PROPERTY_SECURE = "secure";

  // Lazy-Initialized Data Members
  private BridgeFlash bridgeFlash;
  private Boolean iceFacesLegacyMode;
  private String portletContextName;

  // Private Data Members
  private BridgeConfig bridgeConfig;

  // Protected Data Members
  protected BridgeContext bridgeContext;
  protected ServletResponse facesImplementationServletResponse;
  protected IncongruityContext incongruityContext;
  protected boolean manageIncongruities;
  protected PortletContext portletContext;
  protected PortletRequest portletRequest;
  protected PortletResponse portletResponse;
  protected Bridge.PortletPhase portletPhase;
  protected String requestContextPath;

  public ExternalContextCompatImpl(
      PortletContext portletContext,
      PortletRequest portletRequest,
      PortletResponse portletResponse) {

    this.portletContext = portletContext;
    this.portletRequest = portletRequest;
    this.portletResponse = portletResponse;

    // Get the bridge configuration.
    BridgeConfigFactory bridgeConfigFactory =
        (BridgeConfigFactory) BridgeFactoryFinder.getFactory(BridgeConfigFactory.class);
    this.bridgeConfig = bridgeConfigFactory.getBridgeConfig();

    // Get the BridgeContext.
    this.bridgeContext = BridgeContext.getCurrentInstance();

    this.incongruityContext = bridgeContext.getIncongruityContext();

    // Determine whether or not lifecycle incongruities should be managed.
    this.manageIncongruities =
        BooleanHelper.toBoolean(
            bridgeContext.getInitParameter(BridgeConfigConstants.PARAM_MANAGE_INCONGRUITIES), true);
  }

  /**
   * @see {@link ExternalContext#addResponseCookie(String, String, Map)}
   * @since JSF 2.0
   */
  @Override
  public void addResponseCookie(String name, String value, Map<String, Object> properties) {
    Cookie cookie = new Cookie(name, value);

    if ((properties != null) && !properties.isEmpty()) {

      try {
        String comment = (String) properties.get(COOKIE_PROPERTY_COMMENT);

        if (comment != null) {
          cookie.setComment(comment);
        }

        String domain = (String) properties.get(COOKIE_PROPERTY_DOMAIN);

        if (domain != null) {
          cookie.setDomain(domain);
        }

        Integer maxAge = (Integer) properties.get(COOKIE_PROPERTY_MAX_AGE);

        if (maxAge != null) {
          cookie.setMaxAge(maxAge);
        }

        String path = (String) properties.get(COOKIE_PROPERTY_PATH);

        if (path != null) {
          cookie.setPath(path);
        }

        Boolean secure = (Boolean) properties.get(COOKIE_PROPERTY_SECURE);

        if (secure != null) {
          cookie.setSecure(secure);
        }
      } catch (ClassCastException e) {
        logger.error(e.getMessage(), e);
      }
    }

    portletResponse.addProperty(cookie);
  }

  /**
   * @see {@link ExternalContext#addResponseHeader(String, String)}
   * @since JSF 2.0
   */
  @Override
  public void addResponseHeader(String name, String value) {

    if (portletResponse instanceof ResourceResponse) {
      ResourceResponse resourceResponse = (ResourceResponse) portletResponse;
      resourceResponse.addProperty(name, value);
    } else {
      logger.warn(
          "Unable to call {0} for portletResponse=[{1}] because it is not a ResourceResponse.",
          "portletResponse.addProperty(String, String)", portletResponse.getClass().getName());
    }
  }

  /**
   * Note: The reason why this method appears here in {@link ExternalContextCompatImpl} is because
   * it needs to be overridden by {@link ExternalContextCompat_2_2_Impl} since it has special
   * requirements for JSF 2.2.
   *
   * @see {@link ExternalContext#encodeActionURL(String, Map)}
   * @since JSF 1.0
   */
  @Override
  public String encodeActionURL(String url) {

    if (isEncodingFormWithPrimeFacesAjaxFileUpload()) {
      return encodePartialActionURL(url);
    } else {
      return bridgeContext.encodeActionURL(url).toString();
    }
  }

  /**
   * @see {@link ExternalContext#encodeBookmarkableURL(String, Map)}
   * @since JSF 2.0
   */
  @Override
  public String encodeBookmarkableURL(String baseUrl, Map<String, List<String>> parameters) {

    String renderURL = null;

    if (baseUrl != null) {
      String viewId = baseUrl;

      if (baseUrl.startsWith(requestContextPath)) {
        viewId = baseUrl.substring(requestContextPath.length());
      }

      try {

        if ((portletPhase == Bridge.PortletPhase.RENDER_PHASE)
            || (portletPhase == Bridge.PortletPhase.RESOURCE_PHASE)) {
          PortletURL portletRenderURL =
              bridgeContext.getPortletContainer().createRenderURL(baseUrl);
          portletRenderURL.setParameter(bridgeConfig.getViewIdRenderParameterName(), viewId);

          if (parameters != null) {

            for (Map.Entry<String, List<String>> parameter : parameters.entrySet()) {
              String name = parameter.getKey();

              if (name != null) {
                List<String> values = parameter.getValue();

                if (values != null) {
                  int size = values.size();

                  if (size > 0) {

                    if (size == 1) {
                      String value = values.get(0);

                      if (value != null) {
                        portletRenderURL.setParameter(name, value);
                      }
                    } else {
                      logger.warn("Unable to append multiple values for parameter name=[{0]", name);
                    }
                  }
                }
              }
            }
          }

          renderURL = portletRenderURL.toString();
        } else {
          logger.error(
              "Unable to encode bookmarkable URL during Bridge.PortletPhase.[{0}] -- you should call BridgeUtil.getPortletRequestPhase() and check for Bridge.PortletPhase.RENDER_PHASE or Bridge.PortletPhase.RESOURCE_PHASE before calling ExternalContext.encodeBookmarkableURL(...).",
              portletPhase);
        }
      } catch (Exception e) {
        logger.error(e.getMessage(), e);
      }
    } else {
      logger.warn("Unable to encode RenderURL for url=[null]");
    }

    return renderURL;
  }

  /**
   * @see {@link ExternalContext#encodePartialActionURL(String)}
   * @since JSF 2.0
   */
  @Override
  public String encodePartialActionURL(String url) {
    return bridgeContext.encodePartialActionURL(url).toString();
  }

  /**
   * @see {@link ExternalContext#encodeRedirectURL(String, Map)}
   * @since JSF 2.0
   */
  @Override
  public String encodeRedirectURL(String baseUrl, Map<String, List<String>> parameters) {
    return bridgeContext.encodeRedirectURL(baseUrl, parameters).toString();
  }

  /**
   * @see {@link ExternalContext#invalidateSession()}
   * @since JSF 2.0
   */
  @Override
  public void invalidateSession() {
    portletRequest.getPortletSession().invalidate();
  }

  /**
   * @see {@link ExternalContext#responseFlushBuffer()}
   * @since JSF 2.0
   */
  @Override
  public void responseFlushBuffer() throws IOException {

    if (portletResponse instanceof MimeResponse) {

      if (facesImplementationServletResponse != null) {

        // This happens when Mojarra's JspViewHandlingStrategy#buildView(FacesContext context,
        // UIViewRoot)
        // executes.
        facesImplementationServletResponse.flushBuffer();
      } else {
        MimeResponse mimeResponse = (MimeResponse) portletResponse;
        mimeResponse.flushBuffer();
      }
    } else {

      if (manageIncongruities) {
        incongruityContext.responseFlushBuffer();
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * @see {@link ExternalContext#responseReset()}
   * @since JSF 2.0
   */
  @Override
  public void responseReset() {

    if (portletResponse instanceof MimeResponse) {
      MimeResponse mimeResponse = (MimeResponse) portletResponse;
      mimeResponse.reset();
    } else {

      if (manageIncongruities) {
        incongruityContext.responseReset();
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * The Portlet API does not have an equivalent to {@link HttpServletResponse.sendError(int,
   * String)}. Since the Mojarra JSF implementation basically only calls this when a Facelet is not
   * found, better in a portlet environment to simply log an error and throw an IOException up the
   * call stack so that the portlet will give the portlet container a chance to render an error
   * message.
   *
   * @see {@link ExternalContext#responseSendError(int, String)}
   * @since JSF 2.0
   */
  @Override
  public void responseSendError(int statusCode, String message) throws IOException {
    String errorMessage = "Status code " + statusCode + ": " + message;
    logger.error(errorMessage);
    throw new IOException(errorMessage);
  }

  protected HttpServletResponse createFlashHttpServletResponse() {
    return new FlashHttpServletResponse(portletResponse, getRequestLocale());
  }

  // NOTE: PROPOSED-FOR-JSR344-API
  // http://java.net/jira/browse/JAVASERVERFACES_SPEC_PUBLIC-1070
  // NOTE: PROPOSED-FOR-BRIDGE3-API (Called by BridgeRequestScope in order to restore the Flash
  // scope)
  // https://issues.apache.org/jira/browse/PORTLETBRIDGE-207
  public void setBridgeFlash(BridgeFlash bridgeFlash) {
    this.bridgeFlash = bridgeFlash;
  }

  /**
   * @see {@link ExternalContext#getContextName()}
   * @since JSF 2.0
   */
  @Override
  public String getContextName() {

    if (portletContextName == null) {
      portletContextName = portletContext.getPortletContextName();
    }

    return portletContextName;
  }

  /**
   * @see {@link ExternalContext#isResponseCommitted()}
   * @since JSF 2.0
   */
  @Override
  public boolean isResponseCommitted() {

    if (portletResponse instanceof MimeResponse) {
      MimeResponse mimeResponse = (MimeResponse) portletResponse;
      boolean responseCommitted = mimeResponse.isCommitted();

      if (manageIncongruities) {
        incongruityContext.setResponseCommitted(responseCommitted);
      }

      return responseCommitted;
    } else {

      if (manageIncongruities) {
        return incongruityContext.isResponseCommitted();
      } else {
        throw new IllegalStateException();
      }
    }
  }

  protected boolean isBridgeFlashServletResponseRequired() {
    return ((bridgeFlash != null) && bridgeFlash.isServletResponseRequired());
  }

  protected boolean isEncodingFormWithPrimeFacesAjaxFileUpload() {
    FacesContext facesContext = FacesContext.getCurrentInstance();

    if (facesContext.getAttributes().get(PrimeFacesFileUpload.AJAX_FILE_UPLOAD) != null) {
      return true;
    } else {
      return false;
    }
  }

  @Override
  public boolean isSecure() {
    return portletRequest.isSecure();
  }

  protected boolean isICEfacesLegacyMode(ClientDataRequest clientDataRequest) {

    if (iceFacesLegacyMode == null) {

      iceFacesLegacyMode = Boolean.FALSE;

      String requestContentType = clientDataRequest.getContentType();

      if ((requestContentType != null)
          && requestContentType
              .toLowerCase()
              .startsWith(BridgeConstants.MULTIPART_CONTENT_TYPE_PREFIX)) {

        Product iceFaces = ProductMap.getInstance().get(ProductConstants.ICEFACES);

        if (iceFaces.isDetected()
            && ((iceFaces.getMajorVersion() == 2)
                || ((iceFaces.getMajorVersion() == 3) && (iceFaces.getMinorVersion() == 0)))) {

          iceFacesLegacyMode = Boolean.TRUE;
        }
      }
    }

    return iceFacesLegacyMode;
  }

  @Override
  public Flash getFlash() {

    if (bridgeFlash == null) {
      BridgeFlashFactory bridgeFlashFactory =
          (BridgeFlashFactory) BridgeFactoryFinder.getFactory(BridgeFlashFactory.class);
      bridgeFlash = bridgeFlashFactory.getBridgeFlash();
    }

    return bridgeFlash;
  }

  /**
   * @see {@link ExternalContext#getMimeType(String)}
   * @since JSF 2.0
   */
  @Override
  public String getMimeType(String fileName) {
    String mimeType = portletContext.getMimeType(fileName);

    if ((mimeType == null) || (mimeType.length() == 0)) {
      mimeType = FileNameUtil.getFileNameMimeType(fileName);
    }

    return mimeType;
  }

  /**
   * @see {@link ExternalContext#getRealPath(String)}
   * @since JSF 2.0
   */
  @Override
  public String getRealPath(String path) {
    return portletContext.getRealPath(path);
  }

  /**
   * @see {@link ExternalContext#getRequestContentLength()}
   * @since JSF 2.0
   */
  @Override
  public int getRequestContentLength() {

    int requestContentLength = -1;

    if (portletRequest instanceof ClientDataRequest) {
      ClientDataRequest clientDataRequest = (ClientDataRequest) portletRequest;
      requestContentLength = clientDataRequest.getContentLength();

      if (manageIncongruities) {
        incongruityContext.setRequestContentLength(requestContentLength);
      }

      return requestContentLength;
    } else {

      if (manageIncongruities) {
        return incongruityContext.getRequestContentLength();
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * @see {@link ExternalContext#getRequestScheme()}
   * @since JSF 2.0
   */
  @Override
  public String getRequestScheme() {
    return portletRequest.getScheme();
  }

  /**
   * @see {@link ExternalContext#getRequestServerName()}
   * @since JSF 2.0
   */
  @Override
  public String getRequestServerName() {
    return portletRequest.getServerName();
  }

  /**
   * @see {@link ExternalContext#getRequestServerPort()}
   * @since JSF 2.0
   */
  @Override
  public int getRequestServerPort() {
    return portletRequest.getServerPort();
  }

  /**
   * @see {@link ExternalContext#getResponseBufferSize()}
   * @since JSF 2.0
   */
  @Override
  public int getResponseBufferSize() {

    if (portletResponse instanceof MimeResponse) {
      MimeResponse mimeResponse = (MimeResponse) portletResponse;
      int responseBufferSize = mimeResponse.getBufferSize();

      if (manageIncongruities) {
        incongruityContext.setResponseBufferSize(responseBufferSize);
      }

      return responseBufferSize;
    } else {

      if (manageIncongruities) {
        return incongruityContext.getResponseBufferSize();
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * @see {@link ExternalContext#setResponseBufferSize(int)}
   * @since JSF 2.0
   */
  @Override
  public void setResponseBufferSize(int size) {

    if (portletResponse instanceof ResourceResponse) {

      if (bridgeContext.getPortletContainer().isAbleToSetResourceResponseBufferSize()) {
        ResourceResponse resourceResponse = (ResourceResponse) portletResponse;
        resourceResponse.setBufferSize(size);
      }
    } else {

      if (manageIncongruities) {
        incongruityContext.setResponseBufferSize(size);
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * @see {@link ExternalContext#setResponseContentLength(int)}
   * @since JSF 2.0
   */
  @Override
  public void setResponseContentLength(int length) {

    if (portletResponse instanceof ResourceResponse) {
      ResourceResponse resourceResponse = (ResourceResponse) portletResponse;
      resourceResponse.setContentLength(length);
    } else {

      if (manageIncongruities) {
        incongruityContext.setResponseContentLength(length);
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * @see {@link ExternalContext#setResponseContentType(String)}
   * @since JSF 2.0
   */
  @Override
  public void setResponseContentType(String contentType) {

    if (portletResponse instanceof MimeResponse) {
      MimeResponse mimeResponse = (MimeResponse) portletResponse;
      bridgeContext.getPortletContainer().setMimeResponseContentType(mimeResponse, contentType);
    } else {

      if (manageIncongruities) {
        incongruityContext.setResponseContentType(contentType);
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * @see {@link ExternalContext#setResponseHeader(String, String)}
   * @since JSF 2.0
   */
  @Override
  public void setResponseHeader(String name, String value) {
    addResponseHeader(name, value);
  }

  /**
   * @see {@link ExternalContext#getResponseOutputStream()}
   * @since JSF 2.0
   */
  @Override
  public OutputStream getResponseOutputStream() throws IOException {

    if (portletResponse instanceof MimeResponse) {

      if (facesImplementationServletResponse != null) {
        logger.debug(
            "Delegating to AFTER_VIEW_CONTENT servletResponse=[{0}]",
            facesImplementationServletResponse);

        return facesImplementationServletResponse.getOutputStream();
      } else {
        MimeResponse mimeResponse = (MimeResponse) portletResponse;

        return mimeResponse.getPortletOutputStream();
      }
    } else {

      if (manageIncongruities) {
        return incongruityContext.getResponseOutputStream();
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * @see {@link ExternalContext#getResponseOutputWriter()}
   * @since JSF 2.0
   */
  @Override
  public Writer getResponseOutputWriter() throws IOException {

    if (portletResponse instanceof MimeResponse) {

      if (facesImplementationServletResponse != null) {
        logger.debug(
            "Delegating to AFTER_VIEW_CONTENT servletResponse=[{0}]",
            facesImplementationServletResponse);

        return facesImplementationServletResponse.getWriter();
      } else {
        return bridgeContext.getResponseOutputWriter();
      }

    } else {

      if (manageIncongruities) {
        return incongruityContext.getResponseOutputWriter();
      } else {
        throw new IllegalStateException();
      }
    }
  }

  /**
   * Sets the status of the portlet response to the specified status code. Note that this is only
   * possible for a portlet request of type PortletResponse because that is the only type of portlet
   * response that is delivered directly back to the client (without additional markup added by the
   * portlet container).
   *
   * @see {@link ExternalContext#setResponseStatus(int)}
   * @since JSF 2.0
   */
  @Override
  public void setResponseStatus(int statusCode) {

    if (portletResponse instanceof ResourceResponse) {
      ResourceResponse resourceResponse = (ResourceResponse) portletResponse;
      resourceResponse.setProperty(ResourceResponse.HTTP_STATUS_CODE, Integer.toString(statusCode));
    } else {

      if (manageIncongruities) {
        incongruityContext.setResponseStatus(statusCode);
      } else {
        // Mojarra will call this method if a runtime exception occurs during execution of the JSF
        // lifecycle, so
        // must not throw an IllegalStateException.
      }
    }
  }

  @Override
  public int getSessionMaxInactiveInterval() {

    PortletSession portletSession = (PortletSession) getSession(true);

    return portletSession.getMaxInactiveInterval();
  }

  @Override
  public void setSessionMaxInactiveInterval(int sessionMaxInactiveInterval) {
    PortletSession portletSession = (PortletSession) getSession(true);
    portletSession.setMaxInactiveInterval(sessionMaxInactiveInterval);
  }
}
/**
 * This class is designed to support the {@link BridgeRequestScopeAttributeAdded} annotation. It has
 * to be specified as a listener in the WEB-INF/web.xml descriptor like this: <code>
 * <pre>
 * &lt;listener&gt;
 * &lt;listener-class&gt;com.liferay.faces.bridge.context.map.BridgeRequestAttributeListener&lt;/listener-class&gt;
 * &lt;/listener&gt;
 * </pre>
 * </code>
 *
 * @see http://issues.liferay.com/browse/FACES-146
 * @author Neil Griffin
 */
public class BridgeRequestAttributeListener implements ServletRequestAttributeListener {

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

  /**
   * This method is called after an attribute is added to the ServletRequest. Note that this should
   * only get called for remote WSRP portlets. For more info, see:
   * http://issues.liferay.com/browse/FACES-146
   */
  public void attributeAdded(ServletRequestAttributeEvent servletRequestAttributeEvent) {

    // NOTE: We only care about phases prior to the RENDER_PHASE because we're concerned here about
    // managed beans
    // that get added to the request scope when the BridgeRequestScope begins. We're trying to
    // provide those managed
    // beans with an opportunity to prepare for an unexpected invocation of their methods annotated
    // with
    // @PreDestroy.
    ServletRequest servletRequest = servletRequestAttributeEvent.getServletRequest();
    PortletPhase phase = (PortletPhase) servletRequest.getAttribute(Bridge.PORTLET_LIFECYCLE_PHASE);

    // If this is taking place within a PortletRequest handled by the bridge in any phase prior to
    // the
    // RENDER_PHASE, then
    if ((phase != null) && (phase != PortletPhase.RENDER_PHASE)) {

      // If the attribute being added is not excluded, then invoke all methods on the attribute
      // value (class
      // instance) that are annotated with the BridgeRequestScopeAttributeAdded annotation.
      String attributeName = servletRequestAttributeEvent.getName();
      BridgeContext bridgeContext = BridgeContext.getCurrentInstance();
      BridgeConfig bridgeConfig = bridgeContext.getBridgeConfig();
      Set<String> excludedRequestScopeAttributes = bridgeConfig.getExcludedRequestAttributes();

      if (!excludedRequestScopeAttributes.contains(attributeName)) {

        Object attributeValue = servletRequestAttributeEvent.getValue();
        logger.trace("Attribute added name=[{0}] value=[{1}]", attributeName, attributeValue);

        if (attributeValue != null) {
          Method[] methods = attributeValue.getClass().getMethods();

          if (methods != null) {

            for (Method method : methods) {

              if (method != null) {

                if (method.isAnnotationPresent(BridgeRequestScopeAttributeAdded.class)) {

                  try {
                    method.invoke(attributeValue, new Object[] {});
                  } catch (Exception e) {
                    logger.error(e);
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  /**
   * This method is called after an attribute is removed from the ServletRequest. One might expect
   * that this is a good time to call any managed bean methods annotated with @BridgePreDestroy, but
   * that actually takes place in the Bridge's {@link RequestAttributeMap#remove(Object)} method.
   * Note that this should only get called for remote WSRP portlets. For more info, see:
   * http://issues.liferay.com/browse/FACES-146
   */
  public void attributeRemoved(ServletRequestAttributeEvent servletRequestAttributeEvent) {
    String attributeName = servletRequestAttributeEvent.getName();
    Object attributeValue = servletRequestAttributeEvent.getValue();
    logger.trace("Attribute removed name=[{0}] value=[{1}]", attributeName, attributeValue);
  }

  /**
   * This method is called after an attribute is replaced in the ServletRequest. One might expect
   * that this is a good time to call any managed bean methods annotated with @BridgePreDestroy, but
   * that actually takes place in the Bridge's {@link RequestAttributeMap#remove(Object)} method.
   * Note that this should only get called for remote WSRP portlets. For more info, see:
   * http://issues.liferay.com/browse/FACES-146
   */
  public void attributeReplaced(ServletRequestAttributeEvent servletRequestAttributeEvent) {
    String attributeName = servletRequestAttributeEvent.getName();
    Object attributeValue = servletRequestAttributeEvent.getValue();
    logger.trace("Attribute replaced name=[{0}] value=[{1}]", attributeName, attributeValue);
  }
}
/**
 * This abstract class serves as a generic JSF {@link Renderer} that invokes the JSP tag lifecycle
 * of a Liferay Portal JSP tag and encodes the output. Unlike its parent {@link PortalTagRenderer},
 * encoding of the JSP tag output is delayed so that child JSP tags have an opportunity to influence
 * rendering of their parent JSP tag.
 *
 * @author Juan Gonzalez
 */
public abstract class DelayedPortalTagRenderer<U extends UIComponent, T extends Tag>
    extends PortalTagRenderer<U, T> {

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

  @Override
  public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    // Create an instance of the JSP tag that corresponds to the JSF component.
    T tag = newTag();
    copyAttributes(facesContext, cast(uiComponent), tag);
    uiComponent.getAttributes().put(CORRESPONDING_JSP_TAG, tag);
  }

  @Override
  public void encodeChildren(FacesContext facesContext, UIComponent uiComponent)
      throws IOException {

    // Encode each of the children using a writer that can capture the child markup as a string.
    ResponseWriter originalResponseWriter = facesContext.getResponseWriter();
    RenderKit renderKit = facesContext.getRenderKit();
    StringWriter bufferedChildrenMarkupWriter = new StringWriter();
    ResponseWriter stringResponseWriter =
        renderKit.createResponseWriter(bufferedChildrenMarkupWriter, null, StringPool.UTF8);
    facesContext.setResponseWriter(stringResponseWriter);

    List<UIComponent> children = uiComponent.getChildren();

    for (UIComponent child : children) {
      child.encodeAll(facesContext);
    }

    facesContext.setResponseWriter(originalResponseWriter);

    // Get the output of the JSP tag (and all child JSP tags).
    Map<String, Object> componentAttributes = uiComponent.getAttributes();
    Tag tag = (Tag) componentAttributes.get(CORRESPONDING_JSP_TAG);
    PortalTagOutput portalTagOutput;

    try {
      portalTagOutput = getPortalTagOutput(facesContext, uiComponent, tag);

      String preChildMarkup = portalTagOutput.getMarkup();
      String postChildMarkup = null;

      // Determine the point at which children should be inserted into the markup.
      String childInsertionMarker = getChildInsertionMarker();

      if (childInsertionMarker != null) {

        int pos = preChildMarkup.indexOf(childInsertionMarker);

        if (pos > 0) {
          postChildMarkup = preChildMarkup.substring(pos).trim();
          preChildMarkup = preChildMarkup.substring(0, pos).trim();
        }
      }

      // Encode the output of the JSP tag up until the point at which children should be inserted.
      StringBuilder markup = new StringBuilder(3);

      markup.append(preChildMarkup);

      // Ensure that scripts are rendered at the bottom of the page.
      String scripts = portalTagOutput.getScripts();

      if (scripts != null) {
        RendererUtil.renderScript(scripts, null);
      }

      // Encode the children markup.
      String childrenMarkup = bufferedChildrenMarkupWriter.toString();

      if (childrenMarkup != null) {
        markup.append(childrenMarkup);
      }

      // Encode the output of the JSP tag that is to appear after the children.
      if (postChildMarkup != null) {
        markup.append(postChildMarkup);
      }

      ResponseWriter responseWriter = facesContext.getResponseWriter();
      logger.debug("Markup before transformation:{0}", markup);
      StringBuilder processedMarkup = getMarkup(uiComponent, markup);
      logger.debug("Markup after transformation:{0}", processedMarkup);
      responseWriter.write(processedMarkup.toString());
    } catch (Exception e) {
      throw new IOException(e);
    }
  }

  @Override
  public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException {
    uiComponent.getAttributes().remove(CORRESPONDING_JSP_TAG);
  }

  @Override
  public boolean getRendersChildren() {
    return true;
  }

  protected StringBuilder getMarkup(UIComponent uiComponent, StringBuilder markup)
      throws Exception {
    return markup;
  }
}
/** @author Neil Griffin */
public class BridgeRequestScopeLiferayImpl extends BridgeRequestScopeImpl {

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

  // serialVersionUID
  private static final long serialVersionUID = 1814762389345663517L;

  // Private Constants
  private static final String[] LIFERAY_ATTRIBUTE_NAMES;
  private static final String[] PORTLET_REQUEST_ATTRIBUTE_NAMES =
      new String[] {
        PortletRequest.CCPP_PROFILE, PortletRequest.LIFECYCLE_PHASE, PortletRequest.RENDER_HEADERS,
        PortletRequest.RENDER_MARKUP, PortletRequest.RENDER_PART, PortletRequest.USER_INFO
      };

  static {

    // Set the value of the LIFERAY_ATTRIBUTE_NAMES constant. Need to use reflection in order to
    // determine all of
    // the public constants because different versions of the portal source have different sets of
    // constants. This
    // approach minimizes diffs in the different source branches for the bridge.
    List<String> fieldList = new ArrayList<String>();
    Field[] fields = JavaConstants.class.getFields();

    for (Field field : fields) {

      String fieldName = field.getName();

      if ((fieldName != null) && fieldName.startsWith("JAVAX")) {

        try {
          Object value = field.get(null);

          if ((value != null) && (value instanceof String)) {
            fieldList.add((String) value);
          }
        } catch (Exception e) {
          logger.error(e);
        }
      }
    }

    LIFERAY_ATTRIBUTE_NAMES = fieldList.toArray(new String[fieldList.size()]);
  }

  public BridgeRequestScopeLiferayImpl(
      PortletRequest portletRequest, PortletConfig portletConfig, BridgeConfig bridgeConfig) {
    super(portletRequest, portletConfig, bridgeConfig);
  }

  /**
   * This is a method-override that provides specific behavior for Liferay Portal. Specifically,
   * since Liferay Portal does not implement the POST-REDIRECT-GET design pattern, not all instance
   * types listed in Section 5.1.2 of the Spec can be candidates for exclusion.
   */
  @Override
  protected boolean isExcludedRequestAttributeByInstance(
      String attributeName, Object attributeValue) {

    boolean excluded = false;

    if (attributeValue != null) {

      if ((attributeValue instanceof ExternalContext) || (attributeValue instanceof FacesContext)) {

        // Always safe to exclude when running under Liferay Portal.
        excluded = true;
      } else if (attributeValue instanceof PortletConfig) {

        // Liferay Portal includes request attribute named "javax.portlet.config" that must not be
        // excluded. It
        // also includes an attribute named "javax.portlet.portlet" that is the current
        // GenericFacesPortlet
        // (which extends GenericPortlet). But since GenericPortlet implements the PortletConfig
        // interface, need
        // to prevent it from being excluded as well.
        if (!JavaConstants.JAVAX_PORTLET_CONFIG.equals(attributeName)
            && !JavaConstants.JAVAX_PORTLET_PORTLET.equals(attributeName)) {
          excluded = true;
        }
      } else if (attributeValue instanceof PortletRequest) {

        // Liferay Portal includes request attribute named "javax.portlet.request" that must not be
        // excluded.
        if (!JavaConstants.JAVAX_PORTLET_REQUEST.equals(attributeName)) {
          excluded = true;
        }
      } else if (attributeValue instanceof PortletResponse) {

        // Liferay Portal includes request attribute named "javax.portlet.response" that must not be
        // excluded.
        if (!JavaConstants.JAVAX_PORTLET_RESPONSE.equals(attributeName)) {
          excluded = true;
        }
      } else if ((attributeValue instanceof PortalContext)
          || (attributeValue instanceof PortletContext)
          || (attributeValue instanceof PortletPreferences)
          || (attributeValue instanceof PortletSession)) {

        excluded = true;
      } else if ((attributeValue instanceof HttpSession)
          || (attributeValue instanceof ServletConfig)
          || (attributeValue instanceof ServletContext)
          || (attributeValue instanceof ServletRequest)
          || (attributeValue instanceof ServletResponse)) {

        // Can only exclude attributes that are not Liferay objects. For example, Liferay Portal
        // includes
        // a request attribute named "com.liferay.portal.kernel.servlet.PortletServletRequest" that
        // must not be
        // excluded.
        if (!attributeValue.getClass().getName().startsWith("com.liferay")) {
          excluded = true;
        }
      }
    }

    return excluded;
  }

  /**
   * This is a method-override that provides specific behavior for Liferay Portal. Specifically,
   * since Liferay Portal does not implement the POST-REDIRECT-GET design pattern, not all instance
   * types listed in Section 5.1.2 of the Spec can be candidates for exclusion.
   */
  @Override
  protected boolean isExcludedRequestAttributeByNamespace(String attributeName) {

    boolean excluded = false;

    if (isNamespaceMatch(attributeName, EXCLUDED_NAMESPACE_JAVAX_FACES)
        || isNamespaceMatch(attributeName, EXCLUCED_NAMESPACE_JAVAX_SERVLET)
        || isNamespaceMatch(attributeName, EXCLUCED_NAMESPACE_JAVAX_SERVLET_INCLUDE)) {

      // Always safe to exclude when running under Liferay Portal.
      excluded = true;
    } else if (isNamespaceMatch(attributeName, EXCLUDED_NAMESPACE_JAVAX_PORTLET_FACES)) {

      if (!Bridge.PORTLET_LIFECYCLE_PHASE.equals(attributeName)) {

        // The "javax.portlet.faces.phase" request attribute must never be excluded, as it is
        // required by {@link
        // BridgeUtil#getPortletRequestPhase()}.
        excluded = true;
      }
    } else if (isNamespaceMatch(attributeName, EXCLUDED_NAMESPACE_JAVAX_PORTLET)) {
      excluded = true;
    }

    if (excluded) {

      for (String liferayAttributeName : LIFERAY_ATTRIBUTE_NAMES) {

        if (liferayAttributeName.equals(attributeName)) {
          excluded = false;

          break;
        }
      }
    }

    if (excluded) {

      for (String portletRequestAttributeName : PORTLET_REQUEST_ATTRIBUTE_NAMES) {

        if (portletRequestAttributeName.equals(attributeName)) {
          excluded = false;

          break;
        }
      }
    }

    return excluded;
  }
}
// J-
@FacesRenderer(
    componentFamily = InputRichText.COMPONENT_FAMILY,
    rendererType = InputRichText.RENDERER_TYPE)
// J+
public class InputRichTextRenderer extends PortalTagRenderer<InputRichText, InputEditorTag>
    implements SystemEventListener {

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

  // Templates
  private static WYSIWYGTemplate wysiwygTemplate;

  @Override
  public InputRichText cast(UIComponent uiComponent) {
    return (InputRichText) uiComponent;
  }

  @Override
  public void copyFrameworkAttributes(
      FacesContext facesContext, InputRichText inputRichText, InputEditorTag inputEditorTag) {

    inputEditorTag.setCssClass(inputRichText.getStyleClass());

    // When ckeditor.jsp renders a hidden textarea, the name is rendered as the id and name
    // attributes of the
    // textarea element. Since this renderer creates its own textarea, it is necessary to set a name
    // that will
    // not interfere when decoding.
    String editorType = getEditorType(inputRichText);
    String escapedEditorName = inputRichText.getClientId();

    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
    escapedEditorName = escapedEditorName.replace(separatorChar, '_').concat("_jsptag");

    if ("bbcode".equals(editorType)) {
      inputEditorTag.setName(escapedEditorName + "_bbcodeInput");
    } else {
      inputEditorTag.setName(escapedEditorName + "_nonInput");
    }
  }

  @Override
  public void copyNonFrameworkAttributes(
      FacesContext facesContext, InputRichText inputRichText, InputEditorTag inputEditorTag) {

    inputEditorTag.setConfigParams(inputRichText.getConfigParams());
    inputEditorTag.setContentsLanguageId(inputRichText.getContentsLanguageId());
    inputEditorTag.setEditorImpl(inputRichText.getEditorKey());
    inputEditorTag.setFileBrowserParams(inputRichText.getFileBrowserParams());

    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
    String clientId = inputRichText.getClientId();
    String functionNamespace = clientId.replace(separatorChar, '_');
    inputEditorTag.setInitMethod(functionNamespace + "init");
    inputEditorTag.setOnBlurMethod(functionNamespace + "blur");
    inputEditorTag.setOnChangeMethod(functionNamespace + "change");
    inputEditorTag.setOnFocusMethod(functionNamespace + "focus");
    inputEditorTag.setResizable(inputRichText.isResizable());
    inputEditorTag.setSkipEditorLoading(inputRichText.isSkipEditorLoading());
    inputEditorTag.setToolbarSet(inputRichText.getToolbarSet());
  }

  @Override
  public void decode(FacesContext facesContext, UIComponent uiComponent) {

    ExternalContext externalContext = facesContext.getExternalContext();
    Map<String, String> requestParameterMap = externalContext.getRequestParameterMap();
    String clientId = uiComponent.getClientId();
    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
    String escapedEditorName = clientId.replace(separatorChar, '_').concat("_jsptag");

    String submittedValue = requestParameterMap.get(escapedEditorName + "_bbcodeInput");

    if (submittedValue == null) {
      submittedValue = requestParameterMap.get(escapedEditorName);
    }

    InputRichText inputRichText = (InputRichText) uiComponent;
    inputRichText.setSubmittedValue(submittedValue);
  }

  @Override
  public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    // Encode the starting <div> element that represents the rich text editor.
    ResponseWriter responseWriter = facesContext.getResponseWriter();
    responseWriter.startElement(StringPool.DIV, uiComponent);

    String clientId = uiComponent.getClientId();
    char separatorChar = UINamingContainer.getSeparatorChar(facesContext);
    String escapedEditorName = clientId.replace(separatorChar, '_').concat("_jsptag");
    responseWriter.writeAttribute(StringPool.ID, clientId, null);
    RendererUtil.encodeStyleable(responseWriter, (Styleable) uiComponent);

    // Encode the starting <textarea> element.
    InputRichText inputRichText = (InputRichText) uiComponent;

    responseWriter.startElement("textarea", uiComponent);
    responseWriter.writeAttribute(StringPool.ID, clientId + "_input", null);
    responseWriter.writeAttribute(StringPool.NAME, escapedEditorName, null);
    responseWriter.writeAttribute(Styleable.STYLE, "display:none;", null);

    // Encode the onblur/onchange/onfocus attributes and any associated client behavior scripts.
    String onblur = inputRichText.getOnblur();
    String onchange = inputRichText.getOnchange();
    String onfocus = inputRichText.getOnfocus();
    Map<String, List<ClientBehavior>> clientBehaviorMap = inputRichText.getClientBehaviors();

    for (String eventName : inputRichText.getEventNames()) {
      List<ClientBehavior> clientBehaviorsForEvent = clientBehaviorMap.get(eventName);

      if (clientBehaviorsForEvent != null) {

        for (ClientBehavior clientBehavior : clientBehaviorsForEvent) {

          ClientBehaviorContext clientBehaviorContext =
              ClientBehaviorContext.createClientBehaviorContext(
                  facesContext, inputRichText, eventName, clientId, null);
          String clientBehaviorScript = clientBehavior.getScript(clientBehaviorContext);

          if (clientBehaviorScript != null) {

            if ("valueChange".equals(eventName) || "change".equals(eventName)) {

              if (onchange != null) {
                clientBehaviorScript = onchange.concat(";").concat(clientBehaviorScript);
                onchange = null;
              }

              responseWriter.writeAttribute("onchange", clientBehaviorScript, null);
            } else if ("blur".equals(eventName)) {

              if (onblur != null) {
                clientBehaviorScript = onblur.concat(";").concat(clientBehaviorScript);
                onblur = null;
              }

              responseWriter.writeAttribute("onblur", clientBehaviorScript, null);
            } else if ("focus".equals(eventName)) {

              if (onfocus != null) {
                clientBehaviorScript = onfocus.concat(";").concat(clientBehaviorScript);
                onfocus = null;
              }

              responseWriter.writeAttribute("onfocus", clientBehaviorScript, null);
            }
          }
        }
      }
    }

    if (onblur != null) {
      responseWriter.writeAttribute("onblur", onblur, null);
    }

    if (onchange != null) {
      responseWriter.writeAttribute("onchange", onchange, null);
    }

    if (onfocus != null) {
      responseWriter.writeAttribute("onfocus", onfocus, null);
    }

    // Encode the value of the component as a child of the textarea element.
    Object value = inputRichText.getValue();

    if (value != null) {
      responseWriter.writeText(value, null);
    }

    // Encode the closing </textarea> element.
    responseWriter.endElement("textarea");

    // Encode the script that contains functions with names specific to this component, so that they
    // can be
    // invoked directly by the JavaScript generated by the JSP tag.
    String formattedTemplate = wysiwygTemplate.format(facesContext, inputRichText);
    responseWriter.startElement(StringPool.SCRIPT, uiComponent);
    responseWriter.writeAttribute(StringPool.TYPE, ContentTypes.TEXT_JAVASCRIPT, null);
    responseWriter.write(formattedTemplate);
    responseWriter.endElement(StringPool.SCRIPT);

    // Begin the JSP tag lifecycle and write the output to the response.
    super.encodeBegin(facesContext, uiComponent);
  }

  @Override
  public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    // End writing the output of the JSP tag lifecycle.
    super.encodeEnd(facesContext, uiComponent);

    // Encode the ending <div> element that represents the rich text editor.
    ResponseWriter responseWriter = facesContext.getResponseWriter();
    responseWriter.endElement(StringPool.DIV);
  }

  @Override
  public InputEditorTag newTag() {
    return new InputEditorTag();
  }

  @Override
  public void processEvent(SystemEvent postConstructApplicationEvent)
      throws AbortProcessingException {

    // Due to ClassLoader problems during static initialization, it is necessary to delay creation
    // of singleton
    // instances of template classes until the PostConstructApplicationEvent is sent.
    try {
      FacesContext startupFacesContext = FacesContext.getCurrentInstance();
      boolean minified = startupFacesContext.isProjectStage(ProjectStage.Production);
      wysiwygTemplate = new WYSIWYGTemplate(minified);
    } catch (Exception e) {
      logger.error(e);
    }
  }

  @Override
  public boolean isListenerForSource(Object source) {
    return ((source != null) && (source instanceof Application));
  }

  protected String getEditorType(InputRichText inputRichText) {

    String editorType = PropsUtil.get(PropsKeys.EDITOR_WYSIWYG_DEFAULT);
    String editorKey = inputRichText.getEditorKey();

    if (editorKey != null) {
      editorType = PropsUtil.get(editorKey);
    }

    return editorType;
  }
}
/**
 * Mojarra has a vendor-specific Service Provider Interface (SPI) for dependency injection called
 * the InjectionProvider. This class provides the ability to leverage the InjectionProvider instance
 * for invoking methods annotated with {@link javax.annotation.PreDestroy}.
 *
 * @author Neil Griffin
 */
public class PreDestroyInvokerMojarraImpl extends PreDestroyInvokerImpl {

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

  // Private Constants
  private static final String INVOKE_PRE_DESTROY = "invokePreDestroy";

  // Private Data Members
  private Method invokePreDestroyMethod;
  private Object mojarraInjectionProvider;

  public PreDestroyInvokerMojarraImpl(Map<String, Object> applicationMap) {

    this.mojarraInjectionProvider = getInjectionProvider(applicationMap);

    try {
      this.invokePreDestroyMethod =
          mojarraInjectionProvider
              .getClass()
              .getMethod(INVOKE_PRE_DESTROY, new Class[] {Object.class});
    } catch (Exception e) {
      logger.error(e);
    }
  }

  @Override
  public void invokeAnnotatedMethods(Object managedBean, boolean preferPreDestroy) {

    if (preferPreDestroy) {

      if (invokePreDestroyMethod != null) {

        try {
          logger.debug(
              "Invoking methods annotated with @PreDestroy: mojarraInjectionProvider=[{0}] managedBean=[{1}]",
              mojarraInjectionProvider, managedBean);
          invokePreDestroyMethod.invoke(mojarraInjectionProvider, managedBean);
        } catch (Exception e) {
          logger.error(e);
        }
      } else {
        super.invokeAnnotatedMethods(managedBean, preferPreDestroy);
      }
    } else {
      super.invokeAnnotatedMethods(managedBean, preferPreDestroy);
    }
  }

  @Override
  public String toString() {
    return mojarraInjectionProvider.toString();
  }

  protected Object getInjectionProvider(Map<String, Object> applicationMap) {

    try {

      Object applicationAssociate = applicationMap.get("com.sun.faces.ApplicationAssociate");

      // If the ApplicationAssociate instance is available, then return the InjectionProvider that
      // it knows about.
      if (applicationAssociate != null) {

        // Note that the ApplicationAssociate instance will be available during startup if the
        // Mojarra
        // ConfigureListener executes prior to the BridgeSessionListener. It will also be available
        // during
        // execution of the JSF lifecycle.
        Method getInjectionProviderMethod =
            applicationAssociate.getClass().getMethod("getInjectionProvider", new Class[] {});
        Object mojarraInjectionProvider =
            getInjectionProviderMethod.invoke(applicationAssociate, new Object[] {});

        logger.debug("mojarraInjectionProvider=[{0}]", mojarraInjectionProvider);

        return mojarraInjectionProvider;
      }

      // Otherwise, return null.
      else {

        // Note that the ApplicationAssociate instance will be null if this method is called during
        // startup and
        // the BridgeSessionListener executes prior to the Mojarra ConfigureListener. This can be
        // remedied by
        // explicitly specifying com.sun.faces.config.ConfigureListener as a listener in the
        // WEB-INF/web.xml
        // descriptor.
        return null;
      }
    } catch (Exception e) {
      logger.error(e);

      return null;
    }
  }
}
/** @author Neil Griffin */
public class BridgeRequestScopeManagerImpl implements BridgeRequestScopeManager {

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

  public void removeBridgeRequestScopesByPortlet(PortletConfig portletConfig) {
    String portletNameToRemove = portletConfig.getPortletName();
    PortletContext portletContext = portletConfig.getPortletContext();
    BridgeRequestScopeCache bridgeRequestScopeCache =
        BridgeRequestScopeCacheFactory.getBridgeRequestScopeCacheInstance(portletContext);
    Set<Map.Entry<String, BridgeRequestScope>> mapEntries = bridgeRequestScopeCache.entrySet();

    if (mapEntries != null) {

      List<String> keysToRemove = new ArrayList<String>();

      for (Map.Entry<String, BridgeRequestScope> mapEntry : mapEntries) {
        BridgeRequestScope bridgeRequestScope = mapEntry.getValue();
        String bridgeRequestScopeId = bridgeRequestScope.getId();
        String portletName = bridgeRequestScopeId.split("[:][:][:]")[0];

        if (portletNameToRemove.equals(portletName)) {
          keysToRemove.add(mapEntry.getKey());
        }
      }

      for (String key : keysToRemove) {
        bridgeRequestScopeCache.remove(key);
      }
    }
  }

  /**
   * This method is designed to be invoked from a {@link javax.servlet.http.HttpSessionListener}
   * like {@link BridgeSessionListener} when a session timeout/expiration occurs. The logic in this
   * method is a little awkward because we have to try and remove BridgeRequestScope instances from
   * {@link Map} instances in the {@link ServletContext} rather than the {@link PortletContext}
   * because we only have access to the Servlet-API when sessions expire.
   */
  public void removeBridgeRequestScopesBySession(HttpSession httpSession) {

    // For each ServletContext attribute name:
    String httpSessionId = httpSession.getId();
    ServletContext servletContext = httpSession.getServletContext();

    Enumeration<String> attributeNames = servletContext.getAttributeNames();

    if (attributeNames != null) {

      while (attributeNames.hasMoreElements()) {
        String attributeName = attributeNames.nextElement();

        // Get the value associated with the current attribute name.
        Object attributeValue = servletContext.getAttribute(attributeName);

        // If the value is a type of java.util.Map then it is possible that it contains
        // BridgeRequestScope
        // instances.
        if ((attributeValue != null) && (attributeValue instanceof Map)) {

          // Prepare to iterate over the map entries.
          Map<?, ?> map = (Map<?, ?>) attributeValue;

          Set<?> entrySet = null;

          try {
            entrySet = map.entrySet();
          } catch (Exception e) {
            // ignore -- some maps like Mojarra's Flash scope will throw a NullPointerException
          }

          if (entrySet != null) {

            // Iterate over the map entries, and build up a list of BridgeRequestScope keys that are
            // to be
            // removed. Doing it this way prevents ConcurrentModificationExceptions from being
            // thrown.
            List<Object> keysToRemove = new ArrayList<Object>();

            for (Object mapEntryAsObject : entrySet) {
              Map.Entry<?, ?> mapEntry = (Map.Entry<?, ?>) mapEntryAsObject;
              Object key = mapEntry.getKey();
              Object value = mapEntry.getValue();

              if ((value != null) && (value instanceof BridgeRequestScope)) {
                BridgeRequestScope bridgeRequestScope = (BridgeRequestScope) value;
                String bridgeRequestScopeSessionId =
                    bridgeRequestScope.getId().split("[:][:][:]")[1];

                if (httpSessionId.equals(bridgeRequestScopeSessionId)) {
                  keysToRemove.add(key);
                }
              }
            }

            // For each BridgeRequestScope key that is to be removed:
            for (Object bridgeRequestScopeId : keysToRemove) {

              // Remove it from the map.
              Object bridgeRequestScope = map.remove(bridgeRequestScopeId);
              logger.debug(
                  "Removed bridgeRequestScopeId=[{0}] bridgeRequestScope=[{1}] from cache due to session timeout",
                  bridgeRequestScopeId, bridgeRequestScope);
            }
          }
        }
      }
    }
  }
}
/** @author Neil Griffin */
public class ExtELResolver extends ELResolverBase {

  public static final String VAR_NAME_I18N = "i18n";

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

  static {

    // Initialize the list of static feature descriptors.
    addFeatureDescriptor(VAR_NAME_I18N, String.class);
  }

  private I18N i18n;

  @Override
  protected Object resolveProperty(ELContext elContext, Object base, String property) {

    return null;
  }

  @Override
  protected Object resolveVariable(ELContext elContext, String varName) {

    Object value = null;

    try {

      if (varName.equals(VAR_NAME_I18N)) {

        if (i18n == null) {
          i18n = new I18N();
        }

        value = i18n;
      }
    } catch (Exception e) {
      throw new ELException("Failed to resolve variable [" + varName + "]", e);
    }

    if (value == null) {

      if (logger.isDebugEnabled()) {
        logger.debug("Unable to resolve variable [" + varName + "] value=" + value);
      }
    } else {

      if (logger.isDebugEnabled()) {
        logger.debug("Resolved variable [" + varName + "] value=" + value);
      }
    }

    return value;
  }

  @Override
  public Class<?> getCommonPropertyType(ELContext elContext, Object base) {

    Class<?> commonPropertyType = null;

    return commonPropertyType;
  }

  @Override
  public void setValue(ELContext elContext, Object base, Object property, Object value) {

    if (elContext == null) {

      // Throw an exception as directed by the JavaDoc for ELContext.
      throw new NullPointerException("elContext may not be null");
    }

    if ((property != null) && (property instanceof String)) {
      String propertyAsString = (String) property;

      if (propertyAsString.equals(VAR_NAME_I18N)) {
        throw new PropertyNotWritableException(propertyAsString);
      }
    }
  }

  @Override
  public boolean isReadOnly(ELContext elContext, Object base, Object property) {

    return true;
  }
}
/** @author Neil Griffin */
@RequestScoped
@ManagedBean
public class BridgeInputFileBackingBean {

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

  @ManagedProperty(value = "#{bridgeInputFileModelBean}")
  private BridgeInputFileModelBean bridgeInputFileModelBean;

  public void deleteUploadedFile(ActionEvent actionEvent) {

    UICommand uiCommand = (UICommand) actionEvent.getComponent();
    String fileId = (String) uiCommand.getValue();

    try {
      List<UploadedFile> uploadedFiles = bridgeInputFileModelBean.getUploadedFiles();

      UploadedFile uploadedFileToDelete = null;

      for (UploadedFile uploadedFile : uploadedFiles) {

        if (uploadedFile.getId().equals(fileId)) {
          uploadedFileToDelete = uploadedFile;

          break;
        }
      }

      if (uploadedFileToDelete != null) {
        uploadedFileToDelete.delete();
        uploadedFiles.remove(uploadedFileToDelete);
        logger.debug("Deleted file=[{0}]", uploadedFileToDelete.getName());
      }
    } catch (Exception e) {
      logger.error(e);
    }
  }

  public void handleFileUpload(FileUploadEvent fileUploadEvent) {

    List<UploadedFile> uploadedFiles = bridgeInputFileModelBean.getUploadedFiles();
    UploadedFile uploadedFile = fileUploadEvent.getUploadedFile();

    if (uploadedFile.getStatus() == UploadedFile.Status.FILE_SAVED) {

      FacesContext facesContext = FacesContext.getCurrentInstance();
      FacesMessage facesMessage =
          new FacesMessage(
              "Received fileUploadEvent for file named '"
                  + uploadedFile.getName()
                  + "' in the "
                  + fileUploadEvent.getPhaseId().toString()
                  + " phase.");
      facesContext.addMessage(null, facesMessage);
      uploadedFiles.add(uploadedFile);
      logger.debug(
          "Received fileName=[{0}] absolutePath=[{1}]",
          uploadedFile.getName(), uploadedFile.getAbsolutePath());
    } else {
      logger.error(
          "Failed to receive uploaded file due to error status=[{0}] message=[{1}]",
          uploadedFile.getStatus(), uploadedFile.getMessage());
    }
  }

  public void setBridgeInputFileModelBean(BridgeInputFileModelBean bridgeInputFileModelBean) {

    // Injected via @ManagedProperty annotation
    this.bridgeInputFileModelBean = bridgeInputFileModelBean;
  }
}
Example #24
0
/**
 * This class is a portlet-specific implementation of the Faces Application. Its purpose is to
 * override the {@link createComponent(String)} and {@link getResourceHandler()} methods so that
 * additional portlet-specific instances can be introduced into the Faces lifecycle. Note that
 * instances of this class are generated by the custom {@link ApplicationFactoryImpl}.
 *
 * @author Neil Griffin
 */
public class ApplicationImpl extends ApplicationWrapper {

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

  // Private Data Members
  private Application wrappedApplication;
  private boolean wrapHandlerAtRuntime = true;

  public ApplicationImpl(Application application) {
    this.wrappedApplication = application;
  }

  /**
   * This method provides the ability to supply an instance of the bridge API's {@link
   * PortletNamingContainerUIViewRoot} class which properly handles namespacing of "id" attributes
   * for portlets.
   *
   * @see Application#createComponent(String)
   */
  @Override
  public UIComponent createComponent(String componentType) throws FacesException {

    if (componentType.equals(UIViewRoot.COMPONENT_TYPE) && BridgeUtil.isPortletRequest()) {
      return new UIViewRootBridgeImpl();
    } else {
      return wrappedApplication.createComponent(componentType);
    }
  }

  @Override
  public UIComponent createComponent(
      FacesContext facesContext, String componentType, String rendererType) {

    UIComponent wrappedUIComponent =
        wrappedApplication.createComponent(facesContext, componentType, rendererType);

    if (componentType.equals(DataPaginator.COMPONENT_TYPE)) {

      // Workaround for: http://jira.icesoft.org/browse/ICE-6398
      DataPaginator dataPaginator = new DataPaginatorBridgeImpl(wrappedUIComponent);

      try {
        dataPaginator.setUIData(dataPaginator.findUIData(facesContext));
        wrappedUIComponent = dataPaginator;
      } catch (Exception e) {
        logger.error(e);
      }
    }

    return wrappedUIComponent;
  }

  /**
   * The normal way of adding a {@link NavigationHandler} to a JSF application is to have a
   * navigation-handler element in the faces-config.xml descriptor. Unfortunately the bridge can't
   * use this mechanism, because it must ensure that the {@link BridgeNavigationHandler} is the
   * outermost instance in the chain-of-responsibility. While this could be done with
   * &lt;ordering&gt;&lt;after&gt;&lt;others/&gt;&lt;/after&gt;&lt;/others&gt; in the bridge's
   * META-INF/faces-config.xml file, the bridge must use
   * &lt;ordering&gt;&lt;before&gt;&lt;others/&gt;&lt;/before&gt;&lt;/others&gt; in order to
   * maintain compatibility with ICEfaces and other component libraries. So because of this, it is
   * necessary to provide this override of the {@link #getNavigationHandler()} method in order to
   * ensure that the {@link BridgeNavigationHandler} is the outermost instance.
   */
  @Override
  public NavigationHandler getNavigationHandler() {

    // NOTE: Mojarra uses a servlet context listener to pre-load all the faces-config.xml files in
    // the classpath.
    // During this initialization, it will call this method override for whatever reason. But we
    // can't ask the
    // BridgeFactoryFinder to find the BridgeNavigationHandler factory at that time because it
    // relies on the
    // PortletContext object which can only be retrieved at runtime. So for this reason, we have to
    // delay the
    // wrapping the Faces default NavigationHandler until a PortletRequest happens at runtime.
    if (wrapHandlerAtRuntime) {

      FacesContext facesContext = FacesContext.getCurrentInstance();

      if (facesContext != null) {

        try {

          PortletRequest portletRequest =
              (PortletRequest) facesContext.getExternalContext().getRequest();

          if (portletRequest != null) {
            BridgeNavigationHandler bridgeNavigationHandler =
                new BridgeNavigationHandlerImpl(super.getNavigationHandler());
            super.setNavigationHandler(bridgeNavigationHandler);
            wrapHandlerAtRuntime = false;
          }
        } catch (UnsupportedOperationException e) {
          // ignore -- MyFaces does not permit calling getRequest() during startup.
        }
      }
    }

    return super.getNavigationHandler();
  }

  @Override
  public ResourceHandler getResourceHandler() {

    ResourceHandler resourceHandler = super.getResourceHandler();
    if (resourceHandler != null) {
      resourceHandler = new ResourceHandlerOuterImpl(resourceHandler);
    }

    return resourceHandler;
  }

  /** @see ApplicationWrapper#getWrapped() */
  @Override
  public Application getWrapped() {
    return wrappedApplication;
  }
}
/** @author Neil Griffin */
public class BridgePhaseRenderImpl extends BridgePhaseCompat_2_2_Impl {

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

  // Private Data Members
  private RenderRequest renderRequest;
  private RenderResponse renderResponse;

  public BridgePhaseRenderImpl(
      RenderRequest renderRequest,
      RenderResponse renderResponse,
      PortletConfig portletConfig,
      BridgeConfig bridgeConfig) {

    super(portletConfig, bridgeConfig);

    this.renderRequest =
        BridgePortletRequestFactory.getRenderRequestInstance(
            renderRequest, renderResponse, portletConfig, bridgeConfig);

    this.renderResponse =
        BridgePortletResponseFactory.getRenderResponseInstance(
            renderRequest, renderResponse, portletConfig, bridgeConfig);
  }

  @Override
  public void execute() throws BridgeException {

    logger.debug(Logger.SEPARATOR);
    logger.debug(
        "execute(RenderRequest, RenderResponse) portletName=[{0}] portletMode=[{1}]",
        portletName, renderRequest.getPortletMode());

    Object renderPartAttribute = renderRequest.getAttribute(RenderRequest.RENDER_PART);

    if ((renderPartAttribute != null) && renderPartAttribute.equals(RenderRequest.RENDER_HEADERS)) {
      doFacesHeaders(renderRequest, renderResponse);
    } else {

      try {
        execute(null);
      } catch (BridgeException e) {
        throw e;
      } catch (Throwable t) {
        throw new BridgeException(t);
      } finally {
        cleanup(renderRequest);
      }

      logger.debug(Logger.SEPARATOR);
    }
  }

  @Override
  protected void cleanup(PortletRequest portletRequest) {

    // If required, cause the BridgeRequestScope to go out-of-scope.
    if (!bridgeRequestScopePreserved) {
      bridgeRequestScopeCache.remove(bridgeRequestScope.getId());
    }

    super.cleanup(portletRequest);
  }

  protected void doFacesHeaders(RenderRequest renderRequest, RenderResponse renderResponse) {
    logger.trace(
        "doFacesHeaders(RenderRequest, RenderResponse) this=[{0}], renderRequest=[{1}], renderResponse=[{2}]",
        this, renderRequest, renderResponse);
  }

  protected void execute(String renderRedirectViewId) throws BridgeException, IOException {

    init(renderRequest, renderResponse, Bridge.PortletPhase.RENDER_PHASE);

    // If the portlet mode has not changed, then restore the faces view root and messages that would
    // have been saved during the ACTION_PHASE of the portlet lifecycle. Section 5.4.1 requires that
    // the
    // BridgeRequestScope must not be restored if there is a change in portlet modes detected.
    boolean facesLifecycleExecuted = bridgeRequestScope.isFacesLifecycleExecuted();
    bridgeRequestScope.restoreState(facesContext);

    if (bridgeRequestScope.isPortletModeChanged()) {
      bridgeRequestScopeCache.remove(bridgeRequestScope.getId());
    }

    // If a render-redirect URL was specified, then it is necessary to create a new view from the
    // URL and place it
    // in the FacesContext.
    if (renderRedirectViewId != null) {
      renderRequest.setAttribute(BridgeExt.RENDER_REDIRECT_AFTER_DISPATCH, Boolean.TRUE);

      ViewHandler viewHandler = facesContext.getApplication().getViewHandler();
      UIViewRoot uiViewRoot = viewHandler.createView(facesContext, renderRedirectViewId);
      facesContext.setViewRoot(uiViewRoot);
      logger.debug("Performed render-redirect to viewId=[{0}]", renderRedirectViewId);
    }

    // NOTE: PROPOSE-FOR-BRIDGE3-API Actually, the proposal would be to REMOVE
    // Bridge.IS_POSTBACK_ATTRIBUTE from the Bridge API, because JSF 2.0 introduced the
    // FacesContext#isPostBack() method.
    // http://javaserverfaces.java.net/nonav/docs/2.0/javadocs/javax/faces/context/FacesContext.html#isPostback()
    if (bridgeRequestScope.getBeganInPhase() == Bridge.PortletPhase.ACTION_PHASE) {

      ExternalContext externalContext = facesContext.getExternalContext();
      externalContext.getRequestMap().put(Bridge.IS_POSTBACK_ATTRIBUTE, Boolean.TRUE);
    }

    logger.debug(
        "portletName=[{0}] facesLifecycleExecuted=[{1}]", portletName, facesLifecycleExecuted);

    // If the JSF lifecycle executed back in the ACTION_PHASE of the portlet lifecycle, then
    if (facesLifecycleExecuted) {

      // TCK TestPage054: prpUpdatedFromActionTest
      PhaseEvent restoreViewPhaseEvent =
          new PhaseEvent(facesContext, PhaseId.RESTORE_VIEW, facesLifecycle);
      PhaseListener[] phaseListeners = facesLifecycle.getPhaseListeners();

      for (PhaseListener phaseListener : phaseListeners) {

        if (phaseListener instanceof IPCPhaseListener) {
          phaseListener.afterPhase(restoreViewPhaseEvent);

          break;
        }
      }
    }

    // Otherwise, in accordance with Section 5.2.6 of the Spec, execute the JSF lifecycle so that
    // ONLY the
    // RESTORE_VIEW phase executes. Note that this is accomplished by the
    // RenderRequestPhaseListener.
    else {

      try {
        ExternalContext externalContext = facesContext.getExternalContext();
        String viewId = getFacesViewId(externalContext);
        logger.debug("Executing Faces lifecycle for viewId=[{0}]", viewId);
      } catch (BridgeException e) {
        logger.error("Unable to get viewId due to {0}", e.getClass().getSimpleName());
        throw e;
      }

      // Attach the JSF 2.2 client window to the JSF lifecycle so that Faces Flows can be utilized.
      attachClientWindowToLifecycle(facesContext, facesLifecycle);

      // Execute the JSF lifecycle.
      facesLifecycle.execute(facesContext);
    }

    // If there were any "handled" exceptions queued, then throw a BridgeException.
    Throwable handledException = getJSF2HandledException(facesContext);

    if (handledException != null) {
      throw new BridgeException(handledException);
    }

    // Otherwise, if there were any "unhandled" exceptions queued, then throw a BridgeException.
    Throwable unhandledException = getJSF2UnhandledException(facesContext);

    if (unhandledException != null) {
      throw new BridgeException(unhandledException);
    }

    // Otherwise, if the PortletMode has changed, and a navigation-rule hasn't yet fired (which
    // could have happened
    // in the EVENT_PHASE), then switch to the appropriate PortletMode and navigate to the current
    // viewId in the
    // UIViewRoot.
    if (bridgeRequestScope.isPortletModeChanged() && !bridgeRequestScope.isNavigationOccurred()) {
      BridgeNavigationHandler bridgeNavigationHandler = getBridgeNavigationHandler(facesContext);
      PortletMode fromPortletMode = bridgeRequestScope.getPortletMode();
      PortletMode toPortletMode = renderRequest.getPortletMode();
      bridgeNavigationHandler.handleNavigation(facesContext, fromPortletMode, toPortletMode);
    }

    // Determines whether or not lifecycle incongruities should be managed.
    boolean manageIncongruities =
        PortletConfigParam.ManageIncongruities.getBooleanValue(portletConfig);

    // Now that we're executing the RENDER_PHASE of the Portlet lifecycle, before the JSF
    // RENDER_RESPONSE phase is executed, we have to fix some incongruities between the Portlet
    // lifecycle and the JSF lifecycle that may have occurred during the ACTION_PHASE of the Portlet
    // lifecycle.
    if (manageIncongruities) {
      incongruityContext.makeCongruous(facesContext);
    }

    // Execute the RENDER_RESPONSE phase of the faces lifecycle.
    logger.debug("Executing Faces render");
    facesLifecycle.render(facesContext);

    // Set the view history according to Section 5.4.3 of the Bridge Spec.
    setViewHistory(facesContext.getViewRoot().getViewId());

    // Spec 6.6 (Namespacing)
    indicateNamespacingToConsumers(facesContext.getViewRoot(), renderResponse);

    // If a render-redirect occurred, then
    ExternalContext externalContext = facesContext.getExternalContext();
    Writer writer = getResponseOutputWriter(externalContext);

    Map<String, Object> requestMap = externalContext.getRequestMap();
    Boolean renderRedirect = (Boolean) requestMap.remove(BridgeExt.RENDER_REDIRECT);

    if ((renderRedirect != null) && renderRedirect) {

      // Cleanup the old FacesContext since a new one will be created in the recursive method call
      // below.
      facesContext.responseComplete();
      facesContext.release();

      // If the render-redirect standard feature is enabled in web.xml or portlet.xml, then the
      // ResponseOutputWriter has buffered up markup that must be discarded. This is because we
      // don't want the
      // markup from the original Faces view to be included with the markup of Faces view found in
      // the
      // redirect URL.
      if (writer instanceof RenderRedirectWriter) {
        RenderRedirectWriter responseOutputWriter = (RenderRedirectWriter) writer;
        responseOutputWriter.discard();
      }

      // Recursively call this method with the render-redirect URL so that the RENDER_RESPONSE phase
      // of the
      // JSF lifecycle will be re-executed according to the new Faces viewId found in the redirect
      // URL.
      renderRedirectViewId = (String) requestMap.remove(BridgeExt.RENDER_REDIRECT_VIEW_ID);

      execute(renderRedirectViewId);
    }

    // Otherwise,
    else {

      // In the case that a render-redirect took place, need to render the buffered markup to the
      // response.
      if (writer instanceof RenderRedirectWriter) {
        RenderRedirectWriter responseOutputWriter = (RenderRedirectWriter) writer;
        responseOutputWriter.render();
      }
    }
  }

  protected BridgeNavigationHandler getBridgeNavigationHandler(FacesContext facesContext) {
    BridgeNavigationHandler bridgeNavigationHandler;
    NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler();

    if (navigationHandler instanceof BridgeNavigationHandler) {
      bridgeNavigationHandler = (BridgeNavigationHandler) navigationHandler;
    } else {
      bridgeNavigationHandler = new BridgeNavigationHandlerImpl(navigationHandler);
    }

    return bridgeNavigationHandler;
  }

  @Override
  protected void initBridgeRequestScope(
      PortletRequest portletRequest, PortletResponse portletResponse, PortletPhase portletPhase) {

    super.initBridgeRequestScope(portletRequest, portletResponse, portletPhase);

    // If the portlet container does not support the POST-REDIRECT-GET design pattern, then the
    // ACTION_PHASE and
    // RENDER_PHASE are both part of a single HTTP POST request. In such cases, the excluded request
    // attributes must
    // be pro-actively removed here in the RENDER_PHASE (providing that the bridge request scope was
    // created in the
    // ACTION_PHASE). Note that this must take place prior to the FacesContext getting constructed.
    // This is because
    // the FacesContextFactory delegation chain might consult a request attribute that is supposed
    // to be excluded.
    // This is indeed the case with Apache Trinidad {@link
    // org.apache.myfaces.trinidadinternal.context.FacesContextFactoryImpl.CacheRenderKit}
    // constructor, which
    // consults a request attribute named "org.apache.myfaces.trinidad.util.RequestStateMap" that
    // must first be
    // excluded.
    PortalContext portalContext = portletRequest.getPortalContext();
    String postRedirectGetSupport =
        portalContext.getProperty(BridgePortalContext.POST_REDIRECT_GET_SUPPORT);

    if ((postRedirectGetSupport == null)
        && (bridgeRequestScope.getBeganInPhase() == Bridge.PortletPhase.ACTION_PHASE)) {
      bridgeRequestScope.removeExcludedAttributes(renderRequest);
    }
  }

  /**
   * Sets the "javax.portlet.faces.viewIdHistory.<code>portletMode</code>" session attribute
   * according to the requirements in Section 5.4.3 of the Bridge Spec. There is no corresponding
   * getter method, because the value is meant to be retrieved by developers via an EL expression.
   *
   * @param viewId The current Faces viewId.
   */
  protected void setViewHistory(String viewId) {

    String attributeName =
        Bridge.VIEWID_HISTORY.concat(".").concat(renderRequest.getPortletMode().toString());
    PortletSession portletSession = renderRequest.getPortletSession();
    portletSession.setAttribute(attributeName, viewId);
  }
}
// J-
@FacesRenderer(
    componentFamily = OutputTooltip.COMPONENT_FAMILY,
    rendererType = OutputTooltip.RENDERER_TYPE)
@ResourceDependencies({
  @ResourceDependency(
      library = "liferay-faces-alloy",
      name = "build/aui-css/css/bootstrap.min.css"),
  @ResourceDependency(library = "liferay-faces-alloy", name = "build/aui/aui-min.js"),
  @ResourceDependency(library = "liferay-faces-alloy", name = "liferay.js")
})
// J+
public class OutputTooltipRenderer extends OutputTooltipRendererBase {

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

  @Override
  public void encodeChildren(FacesContext facesContext, UIComponent uiComponent)
      throws IOException {
    List<UIComponent> children = uiComponent.getChildren();

    if (children != null) {

      for (UIComponent child : children) {
        child.encodeAll(facesContext);
      }
    }
  }

  @Override
  public void encodeJavaScriptCustom(FacesContext facesContext, UIComponent uiComponent)
      throws IOException {

    ResponseWriter responseWriter = facesContext.getResponseWriter();

    OutputTooltip tooltip = (OutputTooltip) uiComponent;

    // alloy's divs should be in place and hidden by now.
    // so we need to unhide the div we have hidden until now.
    // any chance for blinking should be over by now.
    responseWriter.write(
        "A.one('"
            + StringPool.POUND
            + ComponentUtil.escapeClientId(tooltip.getClientId(facesContext))
            + "')._node['style'].display = 'block';");
  }

  @Override
  public void encodeMarkupBegin(FacesContext facesContext, UIComponent uiComponent)
      throws IOException {

    ResponseWriter responseWriter = facesContext.getResponseWriter();
    OutputTooltipResponseWriter outputTooltipResponseWriter =
        new OutputTooltipResponseWriter(responseWriter, uiComponent);

    OutputTooltip outputTooltip = (OutputTooltip) uiComponent;

    if (outputTooltip.getFor() == null) {

      if (facesContext.isProjectStage(ProjectStage.Development)) {
        logger.error(
            "The outputTooltip needs to point to something. Try using its 'for' attribute to point to an 'id' in the component tree.");
      }
    }

    // Mojarra's HTML Basic calls encodeEnd for fun
    super.encodeMarkupEnd(facesContext, uiComponent, outputTooltipResponseWriter);
  }

  @Override
  public void encodeMarkupEnd(FacesContext facesContext, UIComponent uiComponent)
      throws IOException {
    ResponseWriter responseWriter = facesContext.getResponseWriter();
    responseWriter.endElement(StringPool.DIV);
  }

  @Override
  protected void encodeCssClass(
      ResponseWriter responseWriter, OutputTooltip outputTooltip, String styleClass, boolean first)
      throws IOException {
    encodeNonEscapedString(responseWriter, CSS_CLASS, styleClass, first);
  }

  @Override
  protected void encodeHiddenAttributes(
      ResponseWriter responseWriter, OutputTooltip tooltip, boolean first) throws IOException {

    FacesContext facesContext = FacesContext.getCurrentInstance();

    // contentBox
    String clientId = tooltip.getClientId(facesContext);
    String contentBox = StringPool.POUND + ComponentUtil.escapeClientId(clientId);
    encodeNonEscapedString(responseWriter, AlloyRendererUtil.CONTENT_BOX, contentBox, first);

    first = false;

    // render : true
    encodeWidgetRender(responseWriter, first);
  }

  @Override
  protected void encodeTrigger(
      ResponseWriter responseWriter, OutputTooltip outputTooltip, String for_, boolean first)
      throws IOException {

    UIComponent uiComponent = outputTooltip.findComponent(for_);

    if (uiComponent != null) {
      String forClientId = uiComponent.getClientId();
      for_ = StringPool.POUND + ComponentUtil.escapeClientId(forClientId);
    }

    encodeNonEscapedString(responseWriter, TRIGGER, for_, first);
  }

  @Override
  protected void encodeZIndex(
      ResponseWriter responseWriter, OutputTooltip outputTooltip, Integer zIndex, boolean first)
      throws IOException {

    if (zIndex == Integer.MIN_VALUE) {
      encodeNonEscapedObject(
          responseWriter, Z_INDEX, AlloyRendererUtil.LIFERAY_Z_INDEX_TOOLTIP, first);
    } else {
      super.encodeZIndex(responseWriter, outputTooltip, zIndex, first);
    }
  }

  @Override
  public String getDelegateComponentFamily() {
    return OutputTooltip.DELEGATE_COMPONENT_FAMILY;
  }

  @Override
  public String getDelegateRendererType() {
    return OutputTooltip.DELEGATE_RENDERER_TYPE;
  }
}
/**
 * This is a JSF backing managed-bean for the applicant.xhtml composition.
 *
 * @author "Neil Griffin"
 */
@ManagedBean(name = "applicantBackingBean")
@RequestScoped
public class ApplicantBackingBean implements Serializable {

  // serialVersionUID
  private static final long serialVersionUID = 2947548873495692163L;

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

  // Injections
  @ManagedProperty(value = "#{applicantModelBean}")
  private transient ApplicantModelBean applicantModelBean;

  @ManagedProperty(value = "#{applicantViewBean}")
  private transient ApplicantViewBean applicantViewBean;

  @ManagedProperty(value = "#{listModelBean}")
  private transient ListModelBean listModelBean;

  public void deleteUploadedFile(ActionEvent actionEvent) {

    try {
      List<UploadedFile> uploadedFiles = applicantModelBean.getUploadedFiles();

      String uploadedFileId = applicantViewBean.getUploadedFileId();

      UploadedFile uploadedFileToDelete = null;

      for (UploadedFile uploadedFile : uploadedFiles) {

        if (uploadedFile.getId().equals(uploadedFileId)) {
          uploadedFileToDelete = uploadedFile;

          break;
        }
      }

      if (uploadedFileToDelete != null) {
        uploadedFileToDelete.delete();
        uploadedFiles.remove(uploadedFileToDelete);
        logger.debug("Deleted file=[{0}]", uploadedFileToDelete.getName());
      }
    } catch (Exception e) {
      logger.error(e);
    }
  }

  public void handleFileUpload(FileUploadEvent event) {
    List<UploadedFile> uploadedFiles = applicantModelBean.getUploadedFiles();
    ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
    PortletSession portletSession = (PortletSession) externalContext.getSession(false);
    String uniqueFolderName = portletSession.getId();
    org.primefaces.model.UploadedFile uploadedFile = event.getFile();
    UploadedFileWrapper uploadedFileWrapper =
        new UploadedFileWrapper(uploadedFile, UploadedFile.Status.FILE_SAVED, uniqueFolderName);
    uploadedFiles.add(uploadedFileWrapper);
    logger.debug(
        "Received fileName=[{0}] absolutePath=[{1}]",
        uploadedFileWrapper.getName(), uploadedFileWrapper.getAbsolutePath());
  }

  public void postalCodeListener(ValueChangeEvent valueChangeEvent) {

    try {
      String newPostalCode = (String) valueChangeEvent.getNewValue();
      City city = listModelBean.getCityByPostalCode(newPostalCode);

      if (city != null) {
        applicantModelBean.setAutoFillCity(city.getCityName());
        applicantModelBean.setAutoFillProvinceId(city.getProvinceId());
      }
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
      FacesMessageUtil.addGlobalUnexpectedErrorMessage(FacesContext.getCurrentInstance());
    }
  }

  public String submit() {

    if (logger.isDebugEnabled()) {
      logger.debug("firstName=" + applicantModelBean.getFirstName());
      logger.debug("lastName=" + applicantModelBean.getLastName());
      logger.debug("emailAddress=" + applicantModelBean.getEmailAddress());
      logger.debug("phoneNumber=" + applicantModelBean.getPhoneNumber());
      logger.debug("dateOfBirth=" + applicantModelBean.getDateOfBirth());
      logger.debug("city=" + applicantModelBean.getCity());
      logger.debug("provinceId=" + applicantModelBean.getProvinceId());
      logger.debug("postalCode=" + applicantModelBean.getPostalCode());
      logger.debug("comments=" + applicantModelBean.getComments());

      List<UploadedFile> uploadedFiles = applicantModelBean.getUploadedFiles();

      for (UploadedFile uploadedFile : uploadedFiles) {
        logger.debug("uploadedFile=[{0}]", uploadedFile.getName());
      }
    }

    // Delete the uploaded files.
    try {
      List<UploadedFile> uploadedFiles = applicantModelBean.getUploadedFiles();

      for (UploadedFile uploadedFile : uploadedFiles) {
        uploadedFile.delete();
        logger.debug("Deleted file=[{0}]", uploadedFile.getName());
      }

      // Store the applicant's first name in JSF 2 Flash Scope so that it can be picked up
      // for use inside of confirmation.xhtml
      FacesContext facesContext = FacesContext.getCurrentInstance();
      facesContext
          .getExternalContext()
          .getFlash()
          .put("firstName", applicantModelBean.getFirstName());

      applicantModelBean.clearProperties();

      return "success";

    } catch (Exception e) {
      logger.error(e.getMessage(), e);
      FacesMessageUtil.addGlobalUnexpectedErrorMessage(FacesContext.getCurrentInstance());

      return "failure";
    }
  }

  public void setApplicantModelBean(ApplicantModelBean applicantModelBean) {

    // Injected via @ManagedProperty annotation
    this.applicantModelBean = applicantModelBean;
  }

  public void setApplicantViewBean(ApplicantViewBean applicantViewBean) {

    // Injected via @ManagedProperty annotation
    this.applicantViewBean = applicantViewBean;
  }

  public void setListModelBean(ListModelBean listModelBean) {

    // Injected via @ManagedProperty annotation
    this.listModelBean = listModelBean;
  }
}
/**
 * This is a renderer for the liferay-ui-internal:input-editor component.
 *
 * @author Neil Griffin
 */
public class InputEditorInternalRenderer extends Renderer implements CleanupRenderer {

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

  // Private Constants
  private static final String EDITOR_NAME_TOKEN = "%EDITOR_NAME%";
  private static final String ONBLUR_JS;
  private static final String ONBLUR_METHOD_NAME_TOKEN = "%ONBLUR_METHOD_NAME%";
  private static final String COMMENT_CDATA_CLOSE = "// " + StringPool.CDATA_CLOSE;
  private static final String CKEDITOR = "ckeditor";

  static {
    StringBuilder onBlurJS = new StringBuilder();
    onBlurJS.append("(function() {");
    onBlurJS.append("var ckEditor = CKEDITOR.instances['");
    onBlurJS.append(EDITOR_NAME_TOKEN);
    onBlurJS.append("'];");
    onBlurJS.append("ckEditor.on('blur',");
    onBlurJS.append("function () {");
    onBlurJS.append(ONBLUR_METHOD_NAME_TOKEN);
    onBlurJS.append("();");
    onBlurJS.append("});");
    onBlurJS.append("})();");
    ONBLUR_JS = onBlurJS.toString();
  }

  @Override
  public void encodeBegin(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    super.encodeBegin(facesContext, uiComponent);

    InputEditorInternal inputEditorInternal = (InputEditorInternal) uiComponent;
    ResponseWriter responseWriter = facesContext.getResponseWriter();
    ExternalContext externalContext = facesContext.getExternalContext();
    PortletRequest portletRequest = (PortletRequest) externalContext.getRequest();
    PortletResponse portletResponse = (PortletResponse) externalContext.getResponse();
    HttpServletRequest httpServletRequest = PortalUtil.getHttpServletRequest(portletRequest);
    httpServletRequest = new NonNamespacedHttpServletRequest(httpServletRequest);

    HttpServletResponse httpServletResponse = PortalUtil.getHttpServletResponse(portletResponse);
    PortletRequest liferayPortletRequest = getLiferayPortletRequest(portletRequest);
    boolean resourcePhase = (liferayPortletRequest instanceof ResourceRequest);
    Map<String, Object> attributes = inputEditorInternal.getAttributes();
    String onBlurMethod = (String) attributes.get("onBlurMethod");
    String editorImpl = (String) attributes.get("editorImpl");

    if (editorImpl == null) {
      editorImpl = CKEDITOR;
    }

    // Build up a URL that can be used to invoke the liferay-ui:input-editor JSP tag.
    String url = "/resources/liferay-ui/jsp/input-editor.jsp";
    StringBuilder queryString = new StringBuilder();
    queryString.append(StringPool.QUESTION);
    queryString.append("editorImpl");
    queryString.append(StringPool.EQUAL);
    queryString.append(editorImpl);
    queryString.append(StringPool.AMPERSAND);
    queryString.append("height");
    queryString.append(StringPool.EQUAL);
    queryString.append(attributes.get("height"));
    queryString.append(StringPool.AMPERSAND);
    queryString.append("initMethod");
    queryString.append(StringPool.EQUAL);
    queryString.append(attributes.get("initMethod"));
    queryString.append(StringPool.AMPERSAND);
    queryString.append("name");
    queryString.append(StringPool.EQUAL);

    String editorName = (String) attributes.get("name");
    queryString.append(editorName);
    queryString.append(StringPool.AMPERSAND);
    queryString.append("onChangeMethod");
    queryString.append(StringPool.EQUAL);
    queryString.append(attributes.get("onChangeMethod"));
    queryString.append(StringPool.AMPERSAND);
    queryString.append("skipEditorLoading");
    queryString.append(StringPool.EQUAL);

    if (resourcePhase) {

      // FACES-1439: Ensure that the <script src=".../ckeditor.js" /> element is not included in the
      // response by
      // specifying skipEditorLoading="true" during Ajax requests.
      queryString.append(Boolean.TRUE.toString());
    } else {
      queryString.append(Boolean.FALSE.toString());
    }

    queryString.append(StringPool.AMPERSAND);
    queryString.append("toolbarSet");
    queryString.append(StringPool.EQUAL);
    queryString.append(attributes.get("toolbarSet"));
    queryString.append(StringPool.AMPERSAND);
    queryString.append("width");
    queryString.append(StringPool.EQUAL);
    queryString.append(attributes.get("width"));
    url = url + queryString.toString();

    // Invoke the tag and capture it's output in a String, rather than having the output go directly
    // to the
    // response.
    RequestDispatcher requestDispatcher = httpServletRequest.getRequestDispatcher(url);
    JspIncludeResponse jspIncludeResponse = new JspIncludeResponse(httpServletResponse);

    try {
      requestDispatcher.include(httpServletRequest, jspIncludeResponse);
    } catch (ServletException e) {
      logger.error(e.getMessage());
      throw new IOException(e.getMessage());
    }

    String bufferedResponse = jspIncludeResponse.getBufferedResponse();

    if (bufferedResponse != null) {

      // Note: Trim the buffered response since there is typically over 100 newlines at the
      // beginning.
      bufferedResponse = bufferedResponse.trim();

      // If rendering an instance of the CKEditor, then
      String editorType = EditorUtil.getEditorValue(httpServletRequest, editorImpl);

      if (editorType.indexOf(CKEDITOR) >= 0) {

        String namespace = portletResponse.getNamespace();

        // FACES-1441: The liferay-ui:input-editor JSP tag (and associated ckeditor.jsp file) do not
        // provide a
        // way to hook-in to the "onblur" callback feature of the CKEditor. In order to overcome
        // this
        // limitation, it is necessary to append a <script>...</script> to the response that
        // provides this
        // ability.
        String onBlurScript = getOnBlurScript(editorName, onBlurMethod, namespace);

        // If running within an Ajax request, include the "onblur" callback script must be included
        // directly
        // to the response.
        if (resourcePhase) {

          StringBuilder scriptMarkup = new StringBuilder();
          scriptMarkup.append(StringPool.LESS_THAN);
          scriptMarkup.append(StringPool.SCRIPT);
          scriptMarkup.append(StringPool.GREATER_THAN);
          scriptMarkup.append(StringPool.CDATA_OPEN);
          scriptMarkup.append(onBlurScript);
          scriptMarkup.append(COMMENT_CDATA_CLOSE);
          scriptMarkup.append(StringPool.LESS_THAN);
          scriptMarkup.append(StringPool.FORWARD_SLASH);
          scriptMarkup.append(StringPool.SCRIPT);
          scriptMarkup.append(StringPool.GREATER_THAN);
          bufferedResponse = bufferedResponse.concat(scriptMarkup.toString());
        }

        // Otherwise, append the script to the "LIFERAY_SHARED_AUI_SCRIPT_DATA" request attribute,
        // which will
        // cause the script to be rendered at the bottom of the portal page.
        else {

          ScriptData scriptData =
              (ScriptData) externalContext.getRequestMap().get(WebKeys.AUI_SCRIPT_DATA);
          scriptData.append(getPortletId(portletRequest), onBlurScript, null);
        }

        // FACES-1439: If the component was rendered on the page on the previous JSF lifecycle, then
        // prevent it
        // from being re-initialized by removing all <script>...</script> elements.
        boolean scriptsRemoved = false;

        String clientId = inputEditorInternal.getClientId();

        if (resourcePhase && inputEditorInternal.isPreviouslyRendered()) {

          logger.debug("Preventing re-initialization of CKEditor for clientId=[{0}]", clientId);

          ParsedResponse parsedResponse = new ParsedResponse(bufferedResponse);
          bufferedResponse = parsedResponse.getNonScripts();
          scriptsRemoved = true;
        }

        // FACES-1422: Move the scripts to the <eval>...</eval> section of the partial-response so
        // that they
        // will execute properly. This has the added benefit of preempt a DOM-diff with ICEfaces.
        if (resourcePhase && !scriptsRemoved) {

          logger.debug(
              "Moving CKEditor scripts to <eval>...</eval> section of the partial-response for clientId=[{0}]",
              clientId);

          ParsedResponse parsedResponse = new ParsedResponse(bufferedResponse);
          bufferedResponse = parsedResponse.getNonScripts();

          String scripts = parsedResponse.getScripts();

          LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance();
          liferayFacesContext.getJavaScriptMap().put(clientId, scripts);
          logger.trace(scripts);
        }
      }

      // Write the captured output from the JSP tag to the Faces responseWriter.
      logger.trace(bufferedResponse);
      responseWriter.write(bufferedResponse);
    }
  }

  public void encodeCleanup(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    PortletResponse portletResponse =
        (PortletResponse) facesContext.getExternalContext().getResponse();
    String namespace = portletResponse.getNamespace();

    String editorName = uiComponent.getParent().getParent().getClientId();
    StringBuilder scriptBuilder = new StringBuilder();

    // Build up a JavaScript fragment that will cleanup the DOM.
    scriptBuilder.append("var oldEditor = CKEDITOR.instances['");
    scriptBuilder.append(namespace);
    scriptBuilder.append(editorName);
    scriptBuilder.append("']; if (oldEditor) {");
    scriptBuilder.append("oldEditor.destroy(true);");
    scriptBuilder.append("delete window['");
    scriptBuilder.append(namespace);
    scriptBuilder.append(editorName);
    scriptBuilder.append("'];");
    scriptBuilder.append("}");

    String script = scriptBuilder.toString();

    LiferayFacesContext liferayFacesContext = LiferayFacesContext.getInstance();
    liferayFacesContext.getJavaScriptMap().put(editorName, script);

    logger.trace(script);
  }

  protected PortletRequest getLiferayPortletRequest(PortletRequest portletRequest) {

    PortletRequest liferayPortletRequest = portletRequest;

    if (liferayPortletRequest instanceof PortletRequestWrapper) {
      PortletRequestWrapper portletRequestWrapper = (PortletRequestWrapper) portletRequest;
      liferayPortletRequest = getLiferayPortletRequest(portletRequestWrapper.getRequest());
    }

    return liferayPortletRequest;
  }

  protected String getOnBlurScript(String editorName, String onBlurMethod, String namespace) {
    String onBlurScript = ONBLUR_JS;

    // Replace %EDITOR_NAME% token with specified editor name.
    int editorNameTokenPos = onBlurScript.indexOf(EDITOR_NAME_TOKEN);

    if (editorNameTokenPos > 0) {
      onBlurScript =
          onBlurScript.substring(0, editorNameTokenPos)
              + namespace
              + editorName
              + onBlurScript.substring(editorNameTokenPos + EDITOR_NAME_TOKEN.length());
    }

    // Replace %ONBLUR_METHOD_NAME% token with specified onblur method name.
    int onBlurTokenPos = onBlurScript.indexOf(ONBLUR_METHOD_NAME_TOKEN);

    if (onBlurTokenPos > 0) {
      onBlurScript =
          onBlurScript.substring(0, onBlurTokenPos)
              + namespace
              + onBlurMethod
              + onBlurScript.substring(onBlurTokenPos + ONBLUR_METHOD_NAME_TOKEN.length());
    }

    return onBlurScript;
  }

  protected String getPortletId(PortletRequest portletRequest) {
    String portletId = StringPool.BLANK;
    Portlet portlet = (Portlet) portletRequest.getAttribute(WebKeys.RENDER_PORTLET);

    if (portlet != null) {
      portletId = portlet.getPortletId();
    }

    return portletId;
  }

  protected class ParsedResponse {

    private String scripts;
    private String nonScripts;

    public ParsedResponse(String response) {

      StringBuilder scriptBuilder = new StringBuilder();
      String beginScriptToken = StringPool.LESS_THAN + StringPool.SCRIPT;
      String endScriptToken =
          StringPool.FORWARD_SLASH + StringPool.SCRIPT + StringPool.GREATER_THAN;
      int endElementLength = endScriptToken.length();

      boolean done1 = false;

      while (!done1) {
        int beginPos = response.indexOf(beginScriptToken);
        int endPos = response.indexOf(endScriptToken, beginPos);

        if ((beginPos >= 0) && (endPos > beginPos)) {
          String script = response.substring(beginPos, endPos + endElementLength);
          boolean done2 = false;

          while (!done2) {
            int cdataOpenPos = script.indexOf(StringPool.CDATA_OPEN);

            if (cdataOpenPos > 0) {
              script = script.substring(cdataOpenPos + StringPool.CDATA_OPEN.length());

              int cdataClosePos = script.indexOf(COMMENT_CDATA_CLOSE);

              if (cdataClosePos > 0) {
                script = script.substring(0, cdataClosePos);
              }
            } else {
              done2 = true;
            }
          }

          scriptBuilder.append(script);
          response =
              response.substring(0, beginPos) + response.substring(endPos + endElementLength);
        } else {
          done1 = true;
        }
      }

      this.scripts = scriptBuilder.toString().trim();
      this.nonScripts = response.trim();
    }

    public String getNonScripts() {
      return nonScripts;
    }

    public String getScripts() {
      return scripts;
    }
  }
}
Example #29
0
/** @author Neil Griffin */
public class PDFUtil {

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

  public static byte[] TXT2PDF(
      String htmlFragment, String headMarkup, String pdfTitle, String description, String author)
      throws IOException {
    byte[] pdf = null;

    if (htmlFragment != null) {
      StringBuilder xhtml = new StringBuilder();
      xhtml.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
      xhtml.append(
          "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
      xhtml.append("<html>");

      if ((pdfTitle != null) || (description != null) || (author != null)) {
        xhtml.append("<head>");
      }

      if (description != null) {
        xhtml.append("<meta name=\"description\" content=\"");
        xhtml.append(description);
        xhtml.append("\" />");
      }

      if (description != null) {
        xhtml.append("<meta name=\"author\" content=\"");
        xhtml.append(author);
        xhtml.append("\" />");
      }

      if (pdfTitle != null) {
        xhtml.append("<title>");
        xhtml.append(pdfTitle);
        xhtml.append("</title>");
      }

      if (headMarkup != null) {
        xhtml.append(headMarkup);
      }

      if ((pdfTitle != null) || (description != null)) {
        xhtml.append("</head>");
      }

      xhtml.append("<body>");

      if (htmlFragment != null) {
        htmlFragment = htmlFragment.replace("\n", "<br />");
      }

      xhtml.append(htmlFragment);
      xhtml.append("</body>");
      xhtml.append("</html>");
      pdf = XHTML2PDF(xhtml.toString());
    }

    return pdf;
  }

  public static byte[] XHTML2PDF(String xhtml) throws IOException {
    byte[] pdf = null;
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

    try {
      ITextRenderer itextRenderer = new ITextRenderer();
      itextRenderer.setDocumentFromString(xhtml);
      itextRenderer.layout();
      itextRenderer.createPDF(byteArrayOutputStream);
      pdf = byteArrayOutputStream.toByteArray();
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
      logger.error("vvv--- Offending XHTML ---vvv");
      logger.error(xhtml);
      throw new IOException(e.getMessage());
    }

    return pdf;
  }
}
/** @author Neil Griffin */
public class BridgeResourceURLImpl extends BridgeResourceURLCompatImpl {

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

  // Private Pseudo-Constants
  private static Set<String> EXCLUDED_PARAMETER_NAMES = new HashSet<String>();

  static {
    EXCLUDED_PARAMETER_NAMES.add(Bridge.PORTLET_MODE_PARAMETER);
    EXCLUDED_PARAMETER_NAMES.add(Bridge.PORTLET_SECURE_PARAMETER);
    EXCLUDED_PARAMETER_NAMES.add(Bridge.PORTLET_WINDOWSTATE_PARAMETER);
  }

  // Private Data Members
  private boolean inProtocol;
  private PortletContainer portletContainer;
  private boolean viewLink;

  public BridgeResourceURLImpl(String url, String currentFacesViewId, BridgeContext bridgeContext) {
    super(url, currentFacesViewId, bridgeContext);
    this.portletContainer = bridgeContext.getPortletContainer();
  }

  public void replaceBackLinkParameter(FacesContext facesContext) {
    String backLinkViewId = facesContext.getViewRoot().getViewId();
    String backLinkURL =
        facesContext.getApplication().getViewHandler().getActionURL(facesContext, backLinkViewId);
    String backLinkEncodedActionURL = StringPool.BLANK;

    try {
      backLinkEncodedActionURL =
          URLEncoder.encode(
              facesContext.getExternalContext().encodeActionURL(backLinkURL), StringPool.UTF8);
    } catch (UnsupportedEncodingException e) {
      logger.error(e.getMessage());
    }

    String newParamName = removeParameter(Bridge.BACK_LINK);
    setParameter(newParamName, backLinkEncodedActionURL);
  }

  @Override
  protected BaseURL toBaseURL() throws MalformedURLException {

    BaseURL baseURL = null;

    // If the URL is opaque, meaning it starts with something like "portlet:" or "mailto:" and
    // doesn't have the double-forward-slash like "http://" does, then
    if (isOpaque()) {

      // If the specified URL starts with "portlet:", then return a BaseURL that contains the
      // modified
      // parameters. This will be a URL that represents navigation to a different viewId.
      if (isPortletScheme()) {

        // TCK TestPage005: modeViewIDTest
        // TCK TestPage042: requestRenderIgnoresScopeViaCreateViewTest
        // TCK TestPage043: requestRenderRedisplayTest
        // TCK TestPage044: requestRedisplayOutOfScopeTest
        // TCK TestPage049: renderRedirectTest
        // TCK TestPage050: ignoreCurrentViewIdModeChangeTest
        // TCK TestPage051: exceptionThrownWhenNoDefaultViewIdTest
        String portletMode = getParameter(Bridge.PORTLET_MODE_PARAMETER);
        boolean modeChanged = ((portletMode != null) && (portletMode.length() > 0));
        String security = getParameter(Bridge.PORTLET_SECURE_PARAMETER);
        String windowState = getParameter(Bridge.PORTLET_WINDOWSTATE_PARAMETER);
        String urlWithModifiedParameters = _toString(modeChanged);
        Bridge.PortletPhase urlPortletPhase = getPortletPhase();

        if (urlPortletPhase == Bridge.PortletPhase.ACTION_PHASE) {
          baseURL = portletContainer.createActionURL(urlWithModifiedParameters);
        } else if (urlPortletPhase == Bridge.PortletPhase.RENDER_PHASE) {
          baseURL = portletContainer.createRenderURL(urlWithModifiedParameters);
        } else {
          baseURL = portletContainer.createResourceURL(urlWithModifiedParameters);
        }

        // If the URL string is self-referencing, meaning, it targets the current Faces view, then
        // copy the
        // render parameters from the current PortletRequest to the BaseURL. NOTE: This has the
        // added benefit of
        // copying the bridgeRequestScopeId render parameter, which will preserve the
        // BridgeRequestScope if the
        // user clicks on the link (invokes the BaseURL).
        if (isSelfReferencing()) {
          setRenderParameters(baseURL);
        }

        // If the portlet container created a PortletURL, then apply the PortletMode and WindowState
        // to the
        // PortletURL.
        if (baseURL instanceof PortletURL) {

          PortletURL portletURL = (PortletURL) baseURL;
          setPortletModeParameter(portletMode, portletURL);
          setWindowStateParameter(windowState, portletURL);
        }

        // Apply the security.
        setSecureParameter(security, baseURL);
      }

      // Otherwise, return the a BaseURL string representation (unmodified value) as required by the
      // Bridge Spec.
      else {

        // TCK TestPage128: encodeResourceURLOpaqueTest
        baseURL = new BaseURLNonEncodedStringImpl(url, getParameterMap());
      }
    }

    // Otherwise, if the URL is external, then return an encoded BaseURL string representation of
    // the URL.
    else if (isExternal()) {

      // TCK TestPage130: encodeResourceURLForeignExternalURLBackLinkTest
      baseURL = new BaseURLEncodedExternalStringImpl(url, getParameterMap(), bridgeContext);
    }

    // Otherwise, if the URL is identified by the ResourceHandler as a JSF2 resource URL, then
    else if (isFaces2ResourceURL()) {

      // If the URL has already been encoded, then return the URL string unmodified.
      if (isEncodedFaces2ResourceURL()) {

        // FACES-63: Prevent double-encoding of resource URLs
        baseURL = new BaseURLNonEncodedStringImpl(url, getParameterMap());
      }

      // Otherwise, return a ResourceURL that can retrieve the JSF2 resource.
      else {
        baseURL = portletContainer.createResourceURL(url);
      }
    }

    // Otherwise, if the URL is relative, in that it starts with "../", then return a BaseURL string
    // representation
    // of the URL that contains the context-path.
    else if (isPathRelative()) {

      // TCK TestPage131: encodeResourceURLRelativeURLTest
      // TCK TestPage132: encodeResourceURLRelativeURLBackLinkTest
      baseURL = new BaseURLRelativeStringImpl(url, getParameterMap(), bridgeContext);
    }

    // Otherwise, if the URL originally contained the "javax.portlet.faces.ViewLink" which
    // represents navigation
    // to a different Faces view, then
    else if (viewLink) {

      String urlWithModifiedParameters = _toString(false, EXCLUDED_PARAMETER_NAMES);
      String portletMode = getParameter(Bridge.PORTLET_MODE_PARAMETER);
      String windowState = getParameter(Bridge.PORTLET_WINDOWSTATE_PARAMETER);
      boolean secure = BooleanHelper.toBoolean(getParameter(Bridge.PORTLET_SECURE_PARAMETER));

      // If the URL targets a Faces viewId, then return a PortletURL (Action URL) that targets the
      // view with the
      // appropriate PortletMode, WindowState, and Security settings built into the URL. For more
      // info, see
      // JavaDoc comments for {@link Bridge#VIEW_LINK}.
      if (isFacesViewTarget()) {

        // TCK TestPage135: encodeResourceURLViewLinkTest
        // TCK TestPage136: encodeResourceURLViewLinkWithBackLinkTest
        baseURL =
            new PortletURLFacesTargetActionImpl(
                bridgeContext, urlWithModifiedParameters, portletMode, windowState, secure);
      }

      // Otherwise, return a PortletURL (Render URL) that contains the "_jsfBridgeNonFacesView"
      // render parameter,
      // which is a signal to the GenericFacesPortlet to dispatch to this non-Faces target when the
      // URL is
      // requested. Note that this seems to be a use-case that is contradictory with the JavaDoc for
      // Brige#VIEW_LINK which claims navigation to a different view. But there are a number of
      // tests in the TCK
      // that utilize this (see below).
      else {

        // TCK TestPage097: encodeActionURLNonJSFViewRenderTest
        // TCK TestPage098: encodeActionURLNonJSFViewWithParamRenderTest
        // TCK TestPage099: encodeActionURLNonJSFViewWithModeRenderTest
        // TCK TestPage100: encodeActionURLNonJSFViewWithInvalidModeRenderTest
        // TCK TestPage101: encodeActionURLNonJSFViewWithWindowStateRenderTest
        // TCK TestPage102: encodeActionURLNonJSFViewWithInvalidWindowStateRenderTest
        // TCK TestPage103: encodeActionURLNonJSFViewResourceTest
        // TCK TestPage104: encodeActionURLNonJSFViewWithParamResourceTest
        // TCK TestPage105: encodeActionURLNonJSFViewWithModeResourceTest
        // TCK TestPage106: encodeActionURLNonJSFViewWithInvalidModeResourceTest
        // TCK TestPage107: encodeActionURLNonJSFViewWithWindowStateResourceTest
        // TCK TestPage108: encodeActionURLNonJSFViewWithInvalidWindowStateResourceTest
        baseURL =
            new PortletURLNonFacesTargetRenderImpl(
                bridgeContext,
                urlWithModifiedParameters,
                portletMode,
                windowState,
                secure,
                getURI().getPath());
      }
    }

    // Otherwise, if the URL targets a Faces viewId, then return a ResourceURL that targets the
    // view.
    else if (isFacesViewTarget()) {

      // TCK TestPage073: scopeAfterRedisplayResourcePPRTest
      // TCK TestPage121: encodeActionURLJSFViewResourceTest
      // TCK TestPage122: encodeActionURLWithParamResourceTest
      // TCK TestPage123: encodeActionURLWithModeResourceTest
      // TCK TestPage124: encodeActionURLWithInvalidModeResourceTest
      // TCK TestPage125: encodeActionURLWithWindowStateResourceTest
      // TCK TestPage126: encodeActionURLWithInvalidWindowStateResourceTest
      // TCK TestPage127: encodeURLEscapingTest
      // TCK TestPage137: encodeResourceURLWithModeTest
      String urlWithModifiedParameters = _toString(false, EXCLUDED_PARAMETER_NAMES);
      baseURL = portletContainer.createResourceURL(urlWithModifiedParameters);
    }

    // Otherwise, if the bridge must encode the URL to satisfy "in-protocol" resource serving, then
    // return a
    // an appropriate ResourceURL.
    else if (inProtocol) {

      // TCK TestPage071: nonFacesResourceTest
      String urlWithModifiedParameters = _toString(false);
      ResourceURL resourceURL = portletContainer.createResourceURL(urlWithModifiedParameters);
      resourceURL.setResourceID(getContextRelativePath());
      baseURL = resourceURL;
    }

    // Otherwise, assume that the URL is for an resource external to the portlet context like
    // "/portalcontext/resources/foo.png" and return a BaseURL string representation of it.
    else {

      // TCK TestPage133: encodeResourceURLTest
      baseURL = new BaseURLEncodedExternalStringImpl(url, getParameterMap(), bridgeContext);
    }

    return baseURL;
  }

  public void setInProtocol(boolean inProtocol) {
    this.inProtocol = inProtocol;
  }

  public void setViewLink(boolean viewLink) {
    this.viewLink = viewLink;
  }
}