Package com.liferay.faces.util.context

Source Code of com.liferay.faces.util.context.PartialViewContextCleanupImpl$VisitCallbackCleanupImpl

/**
* Copyright (c) 2000-2014 Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.faces.util.context;

import java.io.IOException;
import java.util.Collection;
import java.util.EnumSet;
import java.util.Iterator;

import javax.faces.FactoryFinder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitContextFactory;
import javax.faces.component.visit.VisitHint;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialViewContext;
import javax.faces.context.PartialViewContextWrapper;
import javax.faces.event.PhaseId;

import com.liferay.faces.util.component.UICleanup;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;


/**
* <p>This class is a wrapper around the {@link PartialViewContext}. Its purpose is to provide a way to provide a way
* for components to handle the situation of moving from rendered="true" to rendered="false", since JSF does not provide
* a way for components to handle this special "cleanup" case during the RENDER_RESPONSE phase.</p>
*
* @author  Neil Griffin
*/
public class PartialViewContextCleanupImpl extends PartialViewContextWrapper {

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

  // Private Data Members
  private FacesContext facesContext;
  private PartialViewContext wrappedPartialViewContext;

  public PartialViewContextCleanupImpl(PartialViewContext partialViewContext, FacesContext facesContext) {
    this.wrappedPartialViewContext = partialViewContext;
    this.facesContext = facesContext;
  }

  @Override
  public void processPartial(PhaseId phaseId) {

    if (phaseId == PhaseId.RENDER_RESPONSE) {

      try {

        // Render the cleanup prior to delegating to the wrapped processPartial(PhaseId) method. Since rendered
        // cleanup is JavaScript (rather than markup), components that implement {@link UICleanup} need to
        // "render" all of their JavaScript into the {@link ExtFacesContext#getJavaScriptMap} ahead of time.
        // This allows the {@link PartialResponseWriterCleanupImpl} or the ICEfaces {@link
        // DOMPartialViewContext} to place the JavaScript at the end of the partial-response.
        if (isRenderAll()) {
          cleanupAll(facesContext);
        }
        else {
          cleanupPartial(facesContext, wrappedPartialViewContext.getRenderIds());
        }

        wrappedPartialViewContext.processPartial(phaseId);
      }
      catch (IOException e) {

        // Unfortunately the signature for {@link PartialViewContext#processPartial(PhaseId)} does throw
        // IOException
        logger.error(e);
        throw new RuntimeException(e);
      }
    }
    else {
      wrappedPartialViewContext.processPartial(phaseId);
    }
  }

  protected void cleanupAll(FacesContext facesContext) throws IOException {
    encodeCleanup(facesContext, facesContext.getViewRoot(), true);
  }

  protected void cleanupPartial(FacesContext facesContext, Collection<String> renderIds) {

    if ((renderIds != null) && (renderIds.size() > 0)) {

      VisitContextFactory visitContextFactory = (VisitContextFactory) FactoryFinder.getFactory(
          FactoryFinder.VISIT_CONTEXT_FACTORY);

      EnumSet<VisitHint> visitHints = EnumSet.of(VisitHint.EXECUTE_LIFECYCLE);
      VisitContext visitContext = visitContextFactory.getVisitContext(facesContext, renderIds, visitHints);
      VisitCallback visitCallback = new VisitCallbackCleanupImpl();
      facesContext.getViewRoot().visitTree(visitContext, visitCallback);
    }
  }

  protected void encodeCleanup(FacesContext facesContext, UIComponent uiComponent, boolean parentRendered)
    throws IOException {

    // FACES-1497: Push the specified UIComponent to the EL in order to ensure that EL expressions like
    // "#{component}" and "{cc}" resolve to the specified UIComponent before attempting to call
    // UIComponent.isRendered() below.
    uiComponent.pushComponentToEL(facesContext, uiComponent);

    // Determine whether or not the specified UIComponent is rendered, taking into consideration the
    // specified flag that indicates whether or not the parent UIComponent is rendered.
    boolean rendered = (parentRendered && uiComponent.isRendered());

    // If the specified UIComponent has cleanup abilities and it is not rendered, then instruct it to encode its
    // cleanup markup to the response.
    if (uiComponent instanceof UICleanup) {
      UICleanup uiCleanup = (UICleanup) uiComponent;

      if (!rendered) {
        uiCleanup.encodeCleanup(facesContext);
      }
    }

    // Otherwise, recurse through all of the children.
    else {

      // FACES-1956: If the parent component is data-iterator type of component then its children cannot undergo
      // cleanup since they may have EL-expressions that depend on the current iteration variable.
      if (!(uiComponent instanceof UIData)) {

        Iterator<UIComponent> itr = uiComponent.getFacetsAndChildren();

        while (itr.hasNext()) {
          UIComponent childUIComponent = itr.next();
          encodeCleanup(facesContext, childUIComponent, rendered);
        }
      }
    }

    // FACES-1497: Pop the specified UIComponent from the EL.
    uiComponent.popComponentFromEL(facesContext);
  }

  /**
   * This method is missing from the {@link PartialViewContextWrapper} class so it must be implemented here.
   */
  @Override
  public void setPartialRequest(boolean isPartialRequest) {
    wrappedPartialViewContext.setPartialRequest(isPartialRequest);
  }

  @Override
  public PartialViewContext getWrapped() {
    return wrappedPartialViewContext;
  }

  protected class VisitCallbackCleanupImpl implements VisitCallback {

    public VisitResult visit(VisitContext visitContext, UIComponent uiComponent) {

      boolean parentRendered = true;
      UIComponent parentUIComponent = uiComponent.getParent();

      if (parentUIComponent != null) {

        // FACES-1497: Push the parent UIComponent to the EL in order to ensure that EL expressions like
        // "#{component}" and "{cc}" resolve to the specified UIComponent before attempting to call
        // parent.isRendered() below.
        parentUIComponent.pushComponentToEL(facesContext, parentUIComponent);

        parentRendered = parentUIComponent.isRendered();
      }

      try {
        encodeCleanup(facesContext, uiComponent, parentRendered);
      }
      catch (IOException e) {
        logger.error(e);
      }

      if (parentUIComponent != null) {

        // FACES-1497: Pop the parent UIComponent from the EL.
        parentUIComponent.popComponentFromEL(facesContext);
      }

      return VisitResult.REJECT;
    }

  }
}
TOP

Related Classes of com.liferay.faces.util.context.PartialViewContextCleanupImpl$VisitCallbackCleanupImpl

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