Package org.apache.myfaces.trinidad.component

Source Code of org.apache.myfaces.trinidad.component.UIXComponent

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
*/
package org.apache.myfaces.trinidad.component;

import java.io.IOException;

import java.util.Collection;
import java.util.Iterator;

import javax.faces.component.UIComponent;

import javax.el.MethodExpression;

import javax.faces.component.NamingContainer;
import javax.faces.component.UINamingContainer;
import javax.faces.context.FacesContext;

import javax.faces.event.PhaseId;
import javax.faces.render.Renderer;

import org.apache.myfaces.trinidad.bean.FacesBean;
import org.apache.myfaces.trinidad.component.visit.VisitCallback;
import org.apache.myfaces.trinidad.component.visit.VisitContext;
import org.apache.myfaces.trinidad.component.visit.VisitHint;
import org.apache.myfaces.trinidad.component.visit.VisitResult;
import org.apache.myfaces.trinidad.context.PartialPageContext;
import org.apache.myfaces.trinidad.context.RenderingContext;
import org.apache.myfaces.trinidad.event.AttributeChangeListener;
import org.apache.myfaces.trinidad.render.CoreRenderer;

/**
* Pure abstract base class for all UIX components.
*/
abstract public class UIXComponent extends UIComponent
{
  /**
   * Helper function called by Renderers to iterate over a flattened view of a group of
   * potentially FlattenedComponent instances rooted at a single child of the component that
   * the Renderer is encoding, invoking the <code>childProcessor</code> with its
   * <code>callbackContext</code> on each renderable instance.
   * <p>
   * If the child is a FlattenedComponent, the <code>childProcessor</code> will
   * be called on each of that FlattenedComponent's children, recursing if those children are
   * themselves FlattenedComponents, otherwise, the <code>childProcessor</code> will be called on
   * the child itself.
   * <p>
   * This method is typically used to flatten the contents of a facet on the FlattenedComponent to
   * be encoded.  If the Renderer accidentally passes in the component to be encoded instead of one
   * of its children, the result will almost certainly be an infinite recursion and stack overflow.
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, Iterable, Object)
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, UIComponent, Object)
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, Iterable, Object)
   * @see FlattenedComponent
   */
  public static <S> boolean processFlattenedChildren(
    FacesContext context,
    ComponentProcessor<S> childProcessor,
    UIComponent child,
    S callbackContext) throws IOException
  {
    return processFlattenedChildren(context,
                                    new ComponentProcessingContext(),
                                    childProcessor,
                                    child,
                                    callbackContext);
  }

  /**
   * Helper function called by FlattenedComponent to iterate over a flattened view of a group of
   * potentially FlattenedComponent instances rooted at a single child of the FlattenedComponent,
   * invoking the <code>childProcessor</code> with its
   * <code>callbackContext</code> on each renderable instance.
   * <p>
   * If the child is a FlattenedComponent, the <code>childProcessor</code> will
   * be called on each of that FlattenedComponent's children, recursing if those children are
   * themselves FlattenedComponents, otherwise, the <code>childProcessor</code> will be called on
   * the child itself.
   * <p>
   * This method is typically used to flatten the contents of a facet of the FlattenedComponent.
   * If the FlattenedComponent accidentally passes in itself instead of one
   * of its children, the result will almost certainly be an infinite recursion and stack overflow.
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, UIComponent, Object)
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, Iterable, Object)
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, Iterable, Object)
   * @see FlattenedComponent
   */
    public static <S> boolean processFlattenedChildren(
    FacesContext context,
    ComponentProcessingContext cpContext,
    ComponentProcessor<S> childProcessor,
    UIComponent child,
    S callbackContext) throws IOException
  {
    if (child.isRendered())
    {     
       // component is an action FlattenedComponent.  Ask it to flatten its children
      if ((child instanceof FlattenedComponent) &&
          ((FlattenedComponent)child).isFlatteningChildren(context))
      {
        return ((FlattenedComponent)child).processFlattenedChildren(context,
                                                                    cpContext,
                                                                    childProcessor,
                                                                    callbackContext);
      }
      else
      {
        // not a FlattenedComponent, pass the component directly to the ComponentProcessor
        try
        {
          childProcessor.processComponent(context, cpContext, child, callbackContext);
        }
        finally
        {
          // if startDepth is > 0, only the first visible child will be marked as starting a group
          cpContext.resetStartDepth();
        }
       
        return true;
      }
    }
    else
    {
      // component not rendered
      return false;
    }
  }

  /**
   * Helper function called by Renderers to iterate over a flattened view of the
   * children, potentially containing FlattenedComponents, of the component the Renderer is
   * encoding, invoking the <code>childProcessor</code> with its
   * <code>callbackContext</code> on each renderable instance.
   * <p>
   * For each FlattenedComponent child, the <code>childProcessor</code> will
   * be called on each of that FlattenedComponent's children, recursing if those children are
   * themselves FlattenedComponents, otherwise, the <code>childProcessor</code> will be called on
   * the child itself.
   * <p>
   * This method is typically used to flatten the children of the FlattenedComponent to
   * be encoded.
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, UIComponent, Object)
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, UIComponent, Object)
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, Iterable, Object)
   * @see FlattenedComponent
   */
  public static <S> boolean processFlattenedChildren(
    FacesContext context,
    ComponentProcessor<S> childProcessor,
    Iterable<UIComponent> children,
    S callbackContext) throws IOException
  {
    return processFlattenedChildren(context,
                                    new ComponentProcessingContext(),
                                    childProcessor,
                                    children,
                                    callbackContext);
  }

  /**
   * Helper function called by FlattenedComponents to iterate over a flattened view of their
   * children, potentially themselves FlattenedComponents, invoking the <code>childProcessor</code>
   * with its <code>callbackContext</code> on each renderable instance.
   * <p>
   * For each FlattenedComponent child, the <code>childProcessor</code> will
   * be called on each of that FlattenedComponent's children, recursing if those children are
   * themselves FlattenedComponents, otherwise, the <code>childProcessor</code> will be called on
   * the child itself.
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, UIComponent, Object)
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessor, Iterable, Object)
   * @see UIXComponent#processFlattenedChildren(FacesContext, ComponentProcessingContext, ComponentProcessor, UIComponent, Object)
   * @see FlattenedComponent
   */
  public static <S> boolean processFlattenedChildren(
    FacesContext context,
    ComponentProcessingContext cpContext,
    ComponentProcessor<S> childProcessor,
    Iterable<UIComponent> children,
    S callbackContext) throws IOException
  {
    // we haven't processed a child yet
    boolean processedChild = false;
   
    for (UIComponent currChild : children)
    {
      // latch processed child to the first child processed
      processedChild |= processFlattenedChildren(context,
                                                 cpContext, childProcessor,
                                                 currChild,
                                                 callbackContext);
    }
   
    return processedChild;
  }

  /**
  * <p>Perform a tree visit starting at
  * this node in the tree.</p>
  *
  * <p>UIXComponent.visitTree() implementations do not invoke the
  * {@code VisitCallback} directly, but instead call
  * {@code VisitContext.invokeVisitCallback()} to invoke the
  * callback.  This allows {@code VisitContext} implementations
  * to provide optimized tree traversals, for example by only
  * calling the {@code VisitCallback} for a subset of components.</p>
  *
  * @param visitContext the <code>VisitContext</code> for this visit
  * @param callback the <code>VisitCallback</code> instance
  * whose <code>visit</code> method will be called
  * for each node visited.
  * @return component implementations may return <code>true</code>
  *   to indicate that the tree visit is complete (eg. all components
  *   that need to be visited have been visited).  This results in
  *   the tree visit being short-circuited such that no more components
  *   are visited.
  *
  * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
  */
  public boolean visitTree(
    VisitContext visitContext,
    VisitCallback callback)
  {
    return visitTree(visitContext, this, callback);
  }
 
  /**
  * <p>Perform a tree visit starting at the specified node in the tree.</p>
  *
  * <p>UIXComponent.visitTree() implementations do not invoke the
  * {@code VisitCallback} directly, but instead call
  * {@code VisitContext.invokeVisitCallback()} to invoke the
  * callback.  This allows {@code VisitContext} implementations
  * to provide optimized tree traversals, for example by only
  * calling the {@code VisitCallback} for a subset of components.</p>
  *
  * @param visitContext the <code>VisitContext</code> for this visit
  * @param component the <code>UIComponent</code> to start the visit from
  * @param callback the <code>VisitCallback</code> instance
  * whose <code>visit</code> method will be called
  * for each node visited.
  * @return component implementations may return <code>true</code>
  *   to indicate that the tree visit is complete (eg. all components
  *   that need to be visited have been visited).  This results in
  *   the tree visit being short-circuited such that no more components
  *   are visited.
  *
  * @see VisitContext#invokeVisitCallback VisitContext.invokeVisitCallback()
  */
  public static boolean visitTree(
    VisitContext visitContext,
    UIComponent   component,
    VisitCallback callback)
  {
    UIXComponent uixComponent;

    // determine if we should even visit this component subtree
    if (component instanceof UIXComponent)
    {
      uixComponent = (UIXComponent)component;
     
      // delegate to the UIXComponent
      if (!uixComponent.isVisitable(visitContext))
        return false;
    }
    else
    {
      // use generic isVisitable implemetation
      if (!_isVisitable(visitContext, component))
        return false;
     
      uixComponent = null;
    }
   
    // invoke the callback for this component
    VisitResult result = visitContext.invokeVisitCallback(component, callback);

    if (result == VisitResult.COMPLETE)
      return true;
    else if (result == VisitResult.ACCEPT)
    {
      // now visit the children
      FacesContext context = visitContext.getFacesContext();
      PhaseId phaseId = visitContext.getPhaseId();
      RenderingContext rc = (PhaseId.RENDER_RESPONSE == phaseId)
                              ? RenderingContext.getCurrentInstance()
                              : null;
     
      if (uixComponent != null)
      {
        // assume that all UIXComponent NamingContainers always act as NamingContainers,
        // (unlike <h:form>) and this it is OK to put the optimization where we
        // don't visit the children if we know that we don't have any ids in this
        // subtree to visit
        if (uixComponent instanceof NamingContainer)
        {
          if (visitContext.getSubtreeIdsToVisit(uixComponent).isEmpty())
            return false;
        }
       
        // UIXComponents are allowed to set up their context differently for encoding
        // than normal processing, so behave differently if this is the RenderResponse
        // phase
        if (PhaseId.RENDER_RESPONSE == phaseId)
        {
          uixComponent.setUpEncodingContext(context, rc);
        }
        else
        {
          uixComponent.setupVisitingContext(context);
        }
      }
      else
      {
        // we only optimize walking into non-UIXComponent NamingContainers
        // if they are UINamingConainer (which is used by <f:subview>
        if (UINamingContainer.class == component.getClass())
        {
          if (visitContext.getSubtreeIdsToVisit(component).isEmpty())
            return false;
        }
      }
     
      // visit the children of the component
      try
      {
        Iterator<UIComponent> kids = component.getFacetsAndChildren();
             
        while(kids.hasNext())
        {
          boolean done;
         
          UIComponent currChild = kids.next();
         
          if (currChild instanceof UIXComponent)
          {
            UIXComponent uixChild = (UIXComponent)currChild;
           
            // delegate to UIXComponent's visitTree implementation to allow
            // subclassses to modify the behavior
            done = uixChild.visitTree(visitContext, callback);
          }
          else
          {
            // use generic visit implementation
            done = visitTree(visitContext, currChild, callback);
          }
         
          // If any kid visit returns true, we are done.
          if (done)
          {
            return true;
          }
        }
      }
      finally
      {
        // tear down the context we set up in order to visit our children
        if (uixComponent != null)
        {
          if (PhaseId.RENDER_RESPONSE == phaseId)
          {
            uixComponent.tearDownEncodingContext(context, rc);
          }
          else
          {
            uixComponent.tearDownVisitingContext(context);
          }
        }
      }
    }
    else
    {
      assert(result == VisitResult.REJECT);     
    }

    // if we got this far, we're not done
    return false;
  }

 
 
  /**
   * <p>Called by
   * {@link UIXComponent#visitTree UIXComponent.visitTree()} to determine
   * whether this component is "visitable" - ie. whether this component
   * satisfies the {@link org.apache.myfaces.trinidad.component.visit.VisitHints} returned by
   * {@link VisitContext#getHints VisitContext.getHints()}.</p>
   * <p>If this component is not visitable (ie. if this method returns
   * false), the tree visited is short-circuited such that neither the
   * component nor any of its descendents will be visited></p>
   * <p>Custom {@code treeVisit()} implementations may call this method
   * to determine whether the component is visitable before performing
   * any visit-related processing.</p>
   *
   * @return true if this component should be visited, false otherwise.
   */
  protected boolean isVisitable(VisitContext visitContext)
  {
    return _isVisitable(visitContext, this);
  }
 
  /**
   * default implementation checking the <code>VisitHint.SKIP_TRANSIENT</code> and
   * <code>VisitHint.SKIP_UNRENDERED</code> hints.
   */
  private static boolean _isVisitable(VisitContext visitContext, UIComponent component)
  {
    Collection<VisitHint> hints = visitContext.getHints();
   
    if (hints.contains(VisitHint.SKIP_TRANSIENT) && component.isTransient())
      return false;
   
    if (hints.contains(VisitHint.SKIP_UNRENDERED) && !component.isRendered())
      return false;
   
    return true;
  }
 
  /**
   * <p>
   * Called when visiting the component during optimized partial page encoding so that the
   * component can modify what is actually encoded.  For example tab controls often
   * render the tabs for the ShowDetailItems in the tab bar before delegating to the
   * disclosed ShowDetailItem to render the tab content.  As a result, the tab control
   * needs to encode its tab bar if any of its ShowDetailItems are partial targets so that
   * the tab labels, for example, are up-to-date.
   * </p>
   * <p>
   * The default implementation delegates to the CoreRenderer if this component has one, otherwise
   * it calls the VisitCallback and returns its result if this UIXComponent is a partial
   * target of the current encoding.
   * </p>
   * @param visitContext VisitContext to pass to the VisitCallback
   * @param partialContext PartialPageContext for the current partial encoding
   * @param callback VisitCallback to call if this component is a partial target
   * @return The VisitResult controlling continued iteration of the visit.
   */
  public VisitResult partialEncodeVisit(
    VisitContext visitContext,
    PartialPageContext partialContext,
    VisitCallback callback)
  {
    FacesContext context  = visitContext.getFacesContext();
    Renderer     renderer = getRenderer(context);
   
    if (renderer instanceof CoreRenderer)
    {
      // delegate to the CoreRenderer
      return ((CoreRenderer)renderer).partialEncodeVisit(visitContext,
                                                         partialContext,
                                                         this,
                                                         callback);
    }
    else
    {
      // check that this is a component instance that should be encoded
      if (partialContext.isPossiblePartialTarget(getId()) &&
          partialContext.isPartialTarget(getClientId(context)))
      {
        // visit the component instance
        return callback.visit(visitContext, this);
      }
      else
      {
        // Not visiting this component, but allow visit to
        // continue into this subtree in case we've got
        // visit targets there.
        return VisitResult.ACCEPT;
      }
    }
  }

  /**
   * <p>Sets up the context necessary to visit or invoke the component for all phases.</p>
   * <p>The default implementation does nothing.</p>
   * <p>If a subclass overrides this method, it should override
   * <code>tearDownVisitingContext</code> as well.</p>
   * <p>It is guaranteed that if <code>setupVisitingContext</code> completes
   * <code>tearDownVisitingContext</code> will be called for this component</p>
   * @see #tearDownVisitingContext
   * @see #setUpEncodingContext
   * @see #tearDownEncodingContext
   */
  protected void setupVisitingContext(FacesContext context)
  {
    // do nothing
  }
 
  /**
   * <p>Tears down context created in order to visit or invoke the component
   * for all phases.</p>
   * <p>The default implementation does nothing.</p>
   * <p>A subclass should only override this method if it overrode
   * <code>setupVisitingContext</code> as well</p>
   * <p>It is guaranteed that <code>tearDownVisitingContext</code> will be called only after
   * <code>setupVisitingContext</code> has been called for this component</p>
   * @see #setupVisitingContext
   * @see #setUpEncodingContext
   * @see #tearDownEncodingContext
   */
  protected void tearDownVisitingContext(FacesContext context)
  {
    // do nothing
  }
 
  /**
   * <p>Sets up the context necessary to encode the component.</p>
   * <p>The default implementation delegates to
   * <code>CoreRenderer.setupEncodingContext</code> and then calls
   * <code>setupVisitingContext</code></p>
   * <p>If a subclass overrides this method, it should override
   * <code>tearDownEncodingContext</code> as well.</p>
   * <p>It is guaranteed that if <code>setUpEncodingContext</code> completes
   * <code>tearDownEncodingContext</code> will be called for this component</p>
   * @see #setupVisitingContext
   * @see #tearDownVisitingContext
   * @see #tearDownEncodingContext
   * @see CoreRenderer#setupEncodingContext
   */
  protected void setUpEncodingContext(FacesContext context, RenderingContext rc)
  {
    setupVisitingContext(context);
   
    Renderer renderer = getRenderer(context);
   
    if (renderer instanceof CoreRenderer)
    {
      CoreRenderer coreRenderer = (CoreRenderer)renderer;
     
      coreRenderer.setupEncodingContext(context, rc, this);
    }
  }

  /**
   * <p>Tears down the context created in order to encode the component</p>
   * <p>The default implementation delegates to
   * <code>CoreRenderer.tearDownEncodingContext</code> and then calls
   * <code>tearDownVisitingContext</code></p>
   * <p>A subclass should only override this method if it overrode
   * <code>setUpEncodingContext</code> as well</p>
   * <p>It is guaranteed that <code>tearDownEncodingContext</code> will be called only after
   * <code>setUpEncodingContext</code> has been called for this component</p>
   * @see #setUpEncodingContext
   * @see #tearDownVisitingContext
   * @see #setUpEncodingContext
   * @see CoreRenderer#tearDownEncodingContext
   */
  protected void tearDownEncodingContext(
    FacesContext context,
    RenderingContext rc)
  {
    Renderer renderer = getRenderer(context);
   
    try
    {
      if (renderer instanceof CoreRenderer)
      {
        CoreRenderer coreRenderer = (CoreRenderer)renderer;
     
        coreRenderer.tearDownEncodingContext(context, rc, this);
      }
    }
    finally
    {
      tearDownVisitingContext(context);
    }
  }

  /**
   * Returns the FacesBean used for storing the component's state.
   */
  abstract public FacesBean getFacesBean();

  /**
   * Adds an AttributeChangeListener.  Attribute change events are not
   * delivered for any programmatic change to a property.  They are only
   * delivered when a renderer changes a property without the application's
   * specific request.  An example of an attribute change events might
   * include the width of a column that supported client-side resizing.
   */
  abstract public void addAttributeChangeListener(AttributeChangeListener acl);

  /**
   * Removes an AttributeChangeListener.  Attribute change events are not
   * delivered for any programmatic change to a property.  They are only
   * delivered when a renderer changes a property without the application's
   * specific request.  An example of an attribute change events might
   * include the width of a column that supported client-side resizing.
   */
  abstract public void removeAttributeChangeListener(AttributeChangeListener acl);

  /**
   * Gets the registered AttributeChangeListeners.
   */
  abstract public AttributeChangeListener[] getAttributeChangeListeners();

  /**
   * Sets a method binding to an AttributeChangeListener.  Attribute
   * change events are not
   * delivered for any programmatic change to a property.  They are only
   * delivered when a renderer changes a property without the application's
   * specific request.  An example of an attribute change events might
   * include the width of a column that supported client-side resizing.
   */
  abstract public void setAttributeChangeListener(MethodExpression me);

  /**
   * Gets the method binding to an AttributeChangeListener.  Attribute
   * change events are not
   * delivered for any programmatic change to a property.  They are only
   * delivered when a renderer changes a property without the application's
   * specific request.  An example of an attribute change events might
   * include the width of a column that supported client-side resizing.
   */
  abstract public MethodExpression getAttributeChangeListener();

  abstract public void markInitialState();
 
  /**
   * Provides additional context (the target child component for which the container
   * client ID is requested) to a naming container for constructing a client ID.
   * This is useful for components such as @link UIXTable and @link UIXTreeTable which need
   * to return different container client IDs for stamped and non-stamped child components.
   * @see UIXComponentBase#getClientId(FacesContext context)
   */
  abstract public String getContainerClientId(FacesContext context, UIComponent child);
}
TOP

Related Classes of org.apache.myfaces.trinidad.component.UIXComponent

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.