Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /*
    * $Id: UIComponentClassicTagBase.java,v 1.32 2007/02/05 15:18:33 rlubke Exp $
    */
   
   /*
    * The contents of this file are subject to the terms
    * of the Common Development and Distribution License
    * (the License). You may not use this file except in
    * compliance with the License.
   * 
   * You can obtain a copy of the License at
   * https://javaserverfaces.dev.java.net/CDDL.html or
   * legal/CDDLv1.0.txt. 
   * See the License for the specific language governing
   * permission and limitations under the License.
   * 
   * When distributing Covered Code, include this CDDL
   * Header Notice in each file and include the License file
   * at legal/CDDLv1.0.txt.    
   * If applicable, add the following below the CDDL Header,
   * with the fields enclosed by brackets [] replaced by
   * your own identifying information:
   * "Portions Copyrighted [year] [name of copyright owner]"
   * 
   * [Name of File] [ver.__] [Date]
   * 
   * Copyright 2005 Sun Microsystems Inc. All Rights Reserved
   */
  
  package javax.faces.webapp;
  import  javax.servlet.jsp.jstl.core.LoopTag;
  
  import java.io.Writer;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;

UIComponentTagBase is the base class for all JSP tags that use the "classic" JSP tag interface that correspond to a javax.faces.component.UIComponent instance in the view. In Faces 1.2, all component tags are BodyTag instances to allow for the execution of the page to build the component tree, but not render it. Rendering happens only after the component tree is completely built.

UIComponentTag extends UIComponentClassicTagBase to add support for properties that conform to the Faces 1.1 EL.

UIComponentELTag extends UIComponentClassicTagBase class to add support for properties that conform to the EL API.

The default implementation allows the proper interweaving of template text, non-Faces JSP tag output, and Faces component tag output in the same page, as expected by the page author.

The CASE markers in the following example will be cited in the method descriptions of this class.

  • CASE 1 describes template text and/or non-component custom tag output occurring as the child of a component tag, but before the first component tag child of that component tag.

  • CASE 2 describes template text and/or non-component custom tag output occurring between two sibling component tags.

  • CASE 3 describes template text and/or non-component custom tag output occurring as the child content of an <f:verbatim> tag at any point in the page.

  • CASE 4 describes template text and/or non-component custom tag output occurring between the last child component tag and its enclosing parent component tag's end tag.


<h:panelGrid style="color:red" border="4" columns="2">
CASE 1
<h:outputText value="component 1"/>
CASE 2
<h:outputText value="component 2"/>
<f:verbatim>CASE 3</f:verbatim>
<c:out value="${pageScope.CASE4}" />
</h:panelGrid>

 

The preceding arrangement of faces component tags, must yield markup that will render identically to the following (assuming that ${pageScope.CASE4} evaluates to "CASE 4" without the quotes).


<table border="4" style="color:red">

<tbody>

<tr><td>CASE 1</td></tr> <tr><td>component 1</td></tr> 

<tr><td>CASE 2</td> <tr><td>component 2</td></tr> 

<tr><td>CASE 3</td> <td>CASE 4</td></tr>

</tbody>

</table>

 
 
 
 public abstract class UIComponentClassicTagBase extends UIComponentTagBase implements JspIdConsumerBodyTag {
 
     // ------------------------------------------------------ Manifest Constants
     

The request scope attribute under which a component tag stack for the current request will be maintained.

 
     private static final String COMPONENT_TAG_STACK_ATTR =
         "javax.faces.webapp.COMPONENT_TAG_STACK";

    

The UIComponent attribute under which we will store a List of the component identifiers of child components created on the previous generation of this page (if any).

 
     private static final String JSP_CREATED_COMPONENT_IDS =
         "javax.faces.webapp.COMPONENT_IDS";


    

The UIComponent attribute under which we will store a List of the facet names of facets created on the previous generation of this page (if any).

 
     private static final String JSP_CREATED_FACET_NAMES =
         "javax.faces.webapp.FACET_NAMES";
    

    

The attribute name under which we will store all UIComponent IDs of the current translation unit.

  
     private static final String GLOBAL_ID_VIEW = 
         "javax.faces.webapp.GLOBAL_ID_VIEW";

    

The attribute name under which we will store the FacesContext for this request.

  
     private static final String CURRENT_FACES_CONTEXT =
         "javax.faces.webapp.CURRENT_FACES_CONTEXT";

    

The attribute name under which we will store the UIViewRoot for this request.

  
     private static final String CURRENT_VIEW_ROOT =
         "javax.faces.webapp.CURRENT_VIEW_ROOT";
    
    
Used as the prefix for ids. This is necessary to avoid uniqueness conflicts with the transient verbatim components.
 
     protected static final String UNIQUE_ID_PREFIX = 
 	. + '_';

    
Used to store the previousJspId Map in requestScope
 
     private static final String PREVIOUS_JSP_ID_SET = 
 	"javax.faces.webapp.PREVIOUS_JSP_ID_SET";

    
This is a Page scoped marker to help us keep track of the different execution context we could be operating within, e.g. an include, or a tag file. The value of the attribute is an Integer that is unqiue to this page context.
 
     private static final String JAVAX_FACES_PAGECONTEXT_MARKER =
          "javax.faces.webapp.PAGECONTEXT_MARKER";

    
This is a request scoped attribute which contains an AtomicInteger which we use to increment the PageContext count.
 
     private static final String JAVAX_FACES_PAGECONTEXT_COUNTER =
          "javax.faces.webapp.PAGECONTEXT_COUNTER";
     
     // ------------------------------------------------------ Instance Variables
     

The bodyContent for this tag handler.

 
     protected BodyContent bodyContent = null;

    

The UIComponent that is being encoded by this tag, if any.

 
     private UIComponent component = null;


    

The FacesContext for the request being processed, if any.

 
     private FacesContext context = null;


    

Was a new component instance dynamically created when our findComponent() method was called.

 
     private boolean created = false;


    

The Lst of UIComponent ids created or located by nested UIComponentTags while processing the current request.

 
     private List<StringcreatedComponents = null;


    

The List of facet names created or located by nested UIComponentTags while processing the current request.

 
     private List<StringcreatedFacets = null;


    

The JSP PageContext for the page we are embedded in.

 
     protected PageContext pageContext = null;


    

The JSP Tag that is the parent of this tag.

 
     private Tag parent = null;

    
setJspId
  
 
     private String jspId = null;
    
    
Only consulted in setJspId to detect the iterator case. Set in release. Never cleared.
 
     
     //private String oldJspId = null;
 
    
This is simply the jspId prefixed by UNIQUE_ID_PREFIX.
 
 
     private String facesJspId = null;

    

The component identifier for the associated component.

 
     private String id = null;

    
Caches the nearest enclosing UIComponentClassicTagBase of this tag. This is used for duplicate id detection.
 
     private UIComponentClassicTagBase parentTag = null;
    
    
Set to true if this component is nested inside of an iterating tag
 
     private boolean isNestedInIterator = false;
 
     // --------------------------------------------- Support Methods for Tag
 
     //
     // Simple methods to be overridden by subclasses if necessary
     // 
 
    

Return the flag value that should be returned from the doStart() method when it is called. Subclasses may override this method to return the appropriate value.

Throws:
JspException to cause doStart() to throw an exception
 
     protected int getDoStartValue() throws JspException {
 
 	int result = ;
 
 	return result;
     }

    

Return the flag value that should be returned from the doEnd() method when it is called. Subclasses may override this method to return the appropriate value.

Throws:
JspException to cause doEnd() to throw an exception
 
     protected int getDoEndValue() throws JspException {
 
         return ();
 
     }

    

Delegate to the encodeBegin() method of our corresponding UIComponent. This method is called from doStartTag(). Normally, delegation occurs unconditionally; however, this method is abstracted out so that advanced tags can conditionally perform this call.

Deprecated:
No encoding is done during JSP page execution. Encoding is deferred until the page has completed executing to allow the entire tree to be built before any encoding occurs.
Throws:
IOException if an input/output error occurs
 
     protected void encodeBegin() throws IOException {
 
         .encodeBegin();
 
     }


    

Delegate to the encodeChildren() method of our corresponding UIComponent. This method is called from doStartTag(). Normally, delegation occurs unconditionally; however, this method is abstracted out so that advanced tags can conditionally perform this call.

Deprecated:
No encoding is done during JSP page execution. Encoding is deferred until the page has completed executing to allow the entire tree to be built before any encoding occurs.
Throws:
IOException if an input/output error occurs
 
     protected void encodeChildren() throws IOException {
 
         .encodeChildren();
 
     }


    

Delegate to the encodeEnd() method of our corresponding UIComponent. This method is called from doStartTag(). Normally, delegation occurs unconditionally; however, this method is abstracted out so that advanced tags can conditionally perform this call.

Deprecated:
No encoding is done during JSP page execution. Encoding is deferred until the page has completed executing to allow the entire tree to be built before any encoding occurs.
Throws:
IOException if an input/output error occurs
 
     protected void encodeEnd() throws IOException {
 
         .encodeEnd();
 
     }
 
     // --------------------------------------------------------- Tag Properties
 

    

Set the PageContext of the page containing this tag instance.

Parameters:
pageContext The enclosing PageContext
 
     public void setPageContext(PageContext pageContext) {
 
         this. = pageContext;
 
     }


    

Return the Tag that is the parent of this instance.

 
     public Tag getParent() {
 
         return (this.);
 
     }


    

Set the Tag that is the parent of this instance.

Parameters:
parent The new parent Tag
 
     public void setParent(Tag parent) {
 
         this. = parent;
 
     }
 
 
 
 
     //
     // Complex methods to support Tag
     // 
 
    

Set up the javax.faces.context.ResponseWriter for the current response, if this has not been done already.

@deprecated. javax.faces.application.ViewHandler.renderView is now responsible for setting up the response writer. This method is now a no-op.

 
     protected void setupResponseWriter() {
     }


    

Create a new child component using createComponent, initialize its properties, and add it to its parent as a child.

Parameters:
context FacesContext for the current request
parent Parent UIComponent for the new child
componentId Component identifier for the new child, or null for no explicit identifier
 
     private UIComponent createChild(FacesContext contextUIComponent parent,
                                     String componentIdthrows JspException {
 
         UIComponent component = createComponent(contextcomponentId);
         int indexOfNextChildTag = parentTag.getIndexOfNextChildTag();
         if (indexOfNextChildTag > parent.getChildCount()) {
             indexOfNextChildTag = parent.getChildCount();
         }
         parent.getChildren().add(indexOfNextChildTagcomponent);
          = true;
         return (component);
 
     }

    

Create a new child component using createComponent, initialize its properties, and add it to its parent as a facet.

Parameters:
context FacesContext for the current request
parent Parent UIComponent of the new facet
name Name of the new facet
newId id of the new facet
 
     private UIComponent createFacet(FacesContext contextUIComponent parent,
                                     String nameString newIdthrows JspException {
 
         UIComponent component = createComponent(contextnewId);
         parent.getFacets().put(namecomponent);
          = true;
         return (component);
 
     }

    

Return a child with the specified component id from the specified component, if any; otherwise, return null.

Parameters:
component UIComponent to be searched
componentId Component id to search for
 
     private static UIComponent getChild(UIComponent componentString componentId) {
 
         Iterator<UIComponentkids = component.getChildren().iterator();
         while (kids.hasNext()) {
             UIComponent kid = kids.next();
             if (componentId.equals(kid.getId())) {
                 return (kid);
             }
         }
         return (null);
 
     }

    

Find and return the UIComponent, from the component tree, that corresponds to this tag handler instance. If there is no such UIComponent, create one and add it as a child or facet of the UIComponent associated with our nearest enclosing UIComponentTag. The process for locating or creating the component is:

  1. If we have previously located this component, return it.
  2. Locate the parent component by looking for a parent UIComponentTag instance, and ask it for its component. If there is no parent UIComponentTag instance, this tag represents the root component, so get it from the current Tree and return it.
  3. If this UIComponentTag instance has the facetName attribute set, ask the parent UIComponent for a facet with this name. If not found, create one, call setProperties() with the new component as a parameter, and register it under this name. Return the found or created facet UIComponent.
  4. Determine the component id to be assigned to the new component, as follows: if this UIComponentTag has an id attribute set, use that value; otherwise, generate an identifier that is guaranteed to be the same for this UIComponent every time this page is processed (i.e. one based on the location of all UIComponentTag instances without an id attribute set).
  5. Ask the parent UIComponent for a child with this identifier. If not found, create one, call setProperties() with the new component as a parameter, and register it as a child with this identifier. Return the found or created child UIComponent.

When creating a component, the process is:

  1. Retrieve the component type by calling UIComponentTag.getComponentType
  2. If the component has a binding attribute, create an expression from it, and call Application.createComponent with that expression, the FacesContext, and the component type. Store the expression using the key "binding".
  3. Otherwise, call Application.createComponent with only the component type.
  4. Call setProperties().
  5. Add the new component as a child or facet of its parent
 
     protected UIComponent findComponent(FacesContext context)
 	throws JspException {
 
         // Step 1 -- Have we already found the relevant component?
         if ( != null) {
             return ();
         }
 
         // Step 2 -- Identify the component that is, or will be, our parent
         UIComponentClassicTagBase parentTag = 
         UIComponent parentComponent;
         if (parentTag != null) {
             parentComponent = parentTag.getComponentInstance();
         } else {
 	    // Special case.  The component to be found is the
 	    // UIViewRoot.
 	    // see if this is the first time this tag instance is trying
 	    // to be bound to the UIViewRoot
 	    parentComponent = context.getViewRoot();
             // Has this UIViewRoot instance had a tag bound to it
             // before?
             if (null == 
                 parentComponent.getAttributes().get()) {
                 // No it hasn't.
 
                 // make sure setProperties() and setId() are called
                 // once per UIViewRoot instance.
 		try {
 		    setProperties(parentComponent);
 		}
 		catch (FacesException e) {
 		    if (e.getCause() instanceof JspException) {
 			throw ((JspException)e.getCause());
 		    }
 		    throw e;
 		}
 
                 if (null != this.) {
                     parentComponent.setId(this.);
                 }
 		else {
 		    assert(null != getFacesJspId());
 		    parentComponent.setId(getFacesJspId());
 		}
                 parentComponent.getAttributes().put(
                                                     );
                  = true;
             }
             else if (hasBinding()) {
 		try {
 		    setProperties(parentComponent);
 		}
 		catch (FacesException e) {
 		    if (e.getCause() instanceof JspException) {
 			throw ((JspException)e.getCause());
 		    }
 		    throw e;
 		}
             }
 
 	    // this is not the first time this tag instance is trying to
 	    // be bound to this UIViewRoot, take no extra action.
 		
              = parentComponent;
             return ();
         }
 
         // Step 3 -- Calculate the component identifier for this component
         String newId = createId(contextparentComponent);
         
         // Step 4 -- Create or return a facet with the specified name (if any)
         String facetName = getFacetName();
         if (facetName != null) {
              = parentComponent.getFacets().get(facetName);
             if ( == null) {
                  = createFacet(contextparentComponentfacetName,
                         newId);
             }
             return ();
         }
 
         // Step 5 -- Create or return a child with the specified id
          = getChild(parentComponentnewId);
         if ( == null) {
              = createChild(contextparentComponentnewId);
         }
         return ();
 
     }
 
     //
     // Tag tree navigation
     // 
 
    

Locate and return the nearest enclosing UIComponentClassicTagBase if any; otherwise, return null.

Parameters:
context PageContext for the current page
 
 
         FacesContext facesContext = getFacesContext(context);
         List list = (ListfacesContext.getExternalContext().getRequestMap()
               .get();
        
         if (list != null) {
             return ((UIComponentClassicTagBaselist.get(list.size() - 1));
         } else {
             return (null);
         }
 
     }
 
     //
     // Methods related to the createdComponents and createdFacets lists.
     // 
 
     protected int getIndexOfNextChildTag() {
 
         if ( != null) {
             return (.size());
         } else {
             return (0);
         }
 
     }
 
     protected void addChild(UIComponent child) {
 
         if ( == null) {
              = new ArrayList<String>(32);
         }
         .add(child.getId());
     }
 
     protected void addFacet(String name) {
 
         if ( == null) {
             //noinspection CollectionWithoutInitialCapacity
              = new ArrayList<String>();
         }
         .add(name);
 
     }

    

Pop the top UIComponentTag instance off of our component tag stack, deleting the stack if this was the last entry.

 
     private void popUIComponentClassicTagBase() {
         Map<String,ObjectrequestMap = 
               .getExternalContext().getRequestMap();
         List list = (ListrequestMap.get();
         if (list != null) {
             list.remove(list.size() - 1);
             if (list.size() < 1) {
                 requestMap.remove();
             }
         }
 
     }


    

Push the specified UIComponentTag instance onto our component tag stack, creating a stack if necessary.

 
     private void pushUIComponentClassicTagBase() {
 
         Map<String,ObjectrequestMap = 
               .getExternalContext().getRequestMap();
         List<UIComponentClassicTagBaselist = TypedCollections.dynamicallyCastList((List
               requestMap.get(), UIComponentClassicTagBase.class);
         if (list == null) {
             //noinspection CollectionWithoutInitialCapacity
             list = new ArrayList<UIComponentClassicTagBase>();
             requestMap.put(list);
         }
         list.add(this);
 
     }


    

Retrieve from the UIComponent corresponding to this tag handler the list of all child component ids created by UIComponentTag instances the previous time this tree was rendered. Compare it to the list of children created during this page processing pass, and remove all children present on the old list but not in the new list. Save the list as a UIComponent attribute so that it gets saved as part of the component's state.

 
     private void removeOldChildren() {
 
         // Remove old children that are no longer present
         List<StringoldList = TypedCollections.dynamicallyCastList(
             (List.getAttributes().get(), String.class);
         if (oldList != null && !oldList.isEmpty()) {
 
             if ( != null) {
 
                 // Components not in the new list need to be removed
                 Iterator<Stringolds = oldList.iterator();
                 while (olds.hasNext()) {
                     String old = olds.next();
                     if (!.contains(old)) {
                         UIComponent child = .findComponent(old);
                         // if a component is marked transient, it would have 
                         // been already removed from the child list, but the
                         // oldList would still have it.  In addition, the component
                         // might have manually been removed.  So, if findComponent
                         // isn't successful, don't call remove child (it will NPE)
                         if ( child != null) {
                             .getChildren().remove(child);
                         }
                     }
                 }
 
             } else {
 
                 // All old components need to be removed
                 Iterator<Stringolds = oldList.iterator();
                 while (olds.hasNext()) {
                     String old = olds.next();
                     UIComponent child = .findComponent(old);
                     if (child != null) {
                         .getChildren().remove(child);
                     }
                 }
 
             }
 
         }
 
         // Save the current list as a component attribute
         if ( != null) {
                                           );
         } else {
         }
          = null;
 
     }


    

Retrieve from the UIComponent corresponding to this tag handler the list of all facet names created by UIComponentTag instances the previous time this tree was rendered. Compare it to the list of facets created during this page processing pass, and remove all facets present on the old list but not in the new list. Save the list as a UIComponent attribute so that it gets saved as part of the component's state.

 
     private void removeOldFacets() {
 
         // Remove old facets that are no longer present
         List<StringoldList = TypedCollections.dynamicallyCastList(
             (List.getAttributes().get(), String.class);
         if (oldList != null) {
 
             if ( != null) {
 
                 // Facets not in the new list need to be removed
                 Iterator<Stringolds = oldList.iterator();
                 while (olds.hasNext()) {
                     String old = olds.next();
                     if (!.contains(old)) {
                         .getFacets().remove(old);
                     }
                 }
 
             } else {
 
                 // All old facets need to be removed
                 Iterator<Stringolds = oldList.iterator();
                 while (olds.hasNext()) {
                     String old = olds.next();
                     .getFacets().remove(old);
                 }
 
             }
 
         }
 
         // Save the current list as a component attribute
         if ( != null) {
                                           );
         } else {
         }
          = null;
 
     }
 
     //
     // Methods to support content interweaving
     //
 
    

Create a transient UIOutput component from the body content, of this tag instance or return null if there is no body content, the body content is whitespace, or the body content is a comment.

 
 
         UIOutput verbatim = null;
         String bodyContentString;
         String trimString;
         if (null !=  &&
              null != (bodyContentString = .getString()) &&
              0 < (trimString = .getString().trim()).length()) {
             if (!(trimString.startsWith("<!--") &&
                  trimString.endsWith("-->"))) {
                 verbatim = createVerbatimComponent();
                 verbatim.setValue(bodyContentString);
                 .clearBody();
             } else {
                 StringBuilder content = new StringBuilder(trimString.length());
                 int sIdx = trimString.indexOf("<!--");
                 int eIdx = trimString.indexOf("-->"sIdx);
                 while (sIdx >= 0 && eIdx >= 0) {
                     if (sIdx == 0) {
                         trimString = trimString.substring(eIdx + 3);
                     } else {
                         content.append(trimString.substring(0, sIdx));
                         trimString = trimString.substring(eIdx + 3);
                     }
                     sIdx = trimString.indexOf("<!--");
                     eIdx = trimString.indexOf("-->"sIdx);
                 }
                 content.append(trimString);
                 String result = content.toString();
                 if (result.trim().length() > 0) {
                     verbatim = createVerbatimComponent();
                     verbatim.setValue(content.toString());
                 }             
                 .clearBody();
             }
         }
         return verbatim;
     }

    

Use the Application instance to create a new component with the following characteristics.

componentType is javax.faces.HtmlOutputText.

transient is true.

escape is false.

id is FacesContext.getViewRoot().createUniqueId()

 
 
     protected UIOutput createVerbatimComponent() {
 	assert(null != getFacesContext());
 	UIOutput verbatim;
 	verbatim = (UIOutput)
 	    application.createComponent("javax.faces.HtmlOutputText");
 	verbatim.setTransient(true);
 	verbatim.getAttributes().put("escape".);
 	return verbatim;
     }

    

Add verbatim as a sibling of component in component in the parent's child list. verbatim is added to the list at the position immediatly preceding component.

 
 
     protected void addVerbatimBeforeComponent(
           UIComponentClassicTagBase parentTag,
           UIComponent verbatim,
           UIComponent component) {        
        
         UIComponent parent = component.getParent();
         if (null == parent) {
             return;
         }
         
         List<UIComponentchildren = parent.getChildren();   
         // EDGE CASE:
             // Consider CASE 1 or 2 where the component is provided via a
             // component binding in session or application scope.
             // The automatically created UIOuput instances for the template text
             // will already be present.  Check the JSP_CREATED_COMPONENT_IDS attribute, 
             // if present and the number of created components is the same
             // as the number of children replace at a -1 offset from the current
             // value of indexOfComponentInParent, otherwise, call add()
         List createdIds = (List
               parent.getAttributes().get();
         int indexOfComponentInParent = children.indexOf(component);
         boolean replace =
               (indexOfComponentInParent > 0 && createdIds != null &&
               createdIds.size() == children.size());
         if (replace) {
             UIComponent oldVerbatim = children.get(indexOfComponentInParent - 1);
             if (oldVerbatim instanceof UIOutput && oldVerbatim.isTransient()) {
                 children.set((indexOfComponentInParent - 1), verbatim);
             } else {
                 children.add(indexOfComponentInParentverbatim);
             }
         } else {
             children.add(indexOfComponentInParentverbatim);
         }
         parentTag.addChild(verbatim);
     }

    

Add verbatim as a sibling of component in component in the parent's child list. verbatim is added to the list at the position immediatly following component.

					   
    protected void addVerbatimAfterComponent(UIComponentClassicTagBase parentTag,
					   UIComponent verbatim,
					   UIComponent component) {
	int indexOfComponentInParent;
	UIComponent parent = component.getParent();
	// invert the order of this if and the assignment below.  Since this line is
	// here, it appears an early return is acceptable/desired if parent is null,
	// and, if it is null, we should probably check for that before we try to 
	// access it.  2006-03-15 jdl
	if (null == parent) {
	    return;
	List<UIComponentchildren = parent.getChildren();
	indexOfComponentInParent = children.indexOf(component);
	if (children.size() - 1 == indexOfComponentInParent) {
	    children.add(verbatim);
	else {
	    children.add(indexOfComponentInParent + 1, verbatim);
	parentTag.addChild(verbatim);
    }
    // ------------------------------------------------------------ Tag Methods

    

Perform any processing necessary to find (or create) the UIComponent instance in the view corresponding to this tag instance in the page and, if and only if a component was created, insert it into the tree at the proper location as expected by the page author. Secondarily, cause a transient UIOutput component to be created and placed in the tree before the UIComponent instance for this tag. The value of this UIOutput component must include anything covered by CASE 1 or CASE 2 in the class description.

The default implementation, which is intended to be sufficient for most components, implements this secondary requirement by calling getParentUIComponentClassicTagBase, and calling createVerbatimComponentFromBodyContent on the result. It then adds the returned component to the tree before the actual component for this tag instance instance by calling addVerbatimBeforeComponent.

Before returning, the component is pushed onto the component stack for this response to enable the getParentUIComponentClassicTagBase method to work properly.

The flag value to be returned is acquired by calling the getDoStartValue() method, which tag subclasses may override if they do not want the default value.

Throws:
JspException if an error occurs
    public int doStartTag() throws JspException {
	// make sure that these ivars are reset at the beginning of the
	// lifecycle for this tag.
	UIComponent verbatim = null;
        
         = getFacesContext();
	if (null == ) {
	    // PENDING(edburns): I18N
	    throw new JspException("Can't find FacesContext");
        Map<String,ObjectrequestMap = .getExternalContext().getRequestMap();
        Map<String,UIComponentTagBasecomponentIds;
        if ( == null) {
            // create the map if we're the top level UIComponentTag
            //noinspection CollectionWithoutInitialCapacity
            componentIds = new HashMap<String,UIComponentTagBase>();
            requestMap.put(componentIds); 
        } else {
            componentIds = TypedCollections.dynamicallyCastMap((Map)
        	requestMap.get(), String.classUIComponentTagBase.class);
        }
        // If we're not inside of a facet, and if we are inside of a
        // rendersChildren==true component, stuff any template text or
        // custom tag output into a transient component.
        if (null == getFacetName() &&
            null != ) {
            Tag p = this.getParent();
            // If we're not inside a JSP tag or we're inside a LoopTag, 
            // flush the buffer to our wrapped response
            if (null == p || p instanceof LoopTag) {
                JspWriter out = .getOut();                                
                if (!(out instanceof BodyContent)) {
                    try {
                        out.flush();
                    }
                    catch (IOException ioe) {
                        throw new JspException(ioe);
                    }
                }
            }
            verbatim = .createVerbatimComponentFromBodyContent();
        }
        // Locate the UIComponent associated with this UIComponentTag,
        // creating one if necessary
         = findComponent();
        
	// if we have a verbatim component, add it after this component.
	if (null != verbatim) {
				       verbatim);
        Object tagInstance = null;
        String clientId = null;
        if (this. != null) {
            clientId = .getClientId();
              UIComponentClassicTagBase temp = (UIComponentClassicTagBase)
                 componentIds.get(clientId);
            // According to the JavaDocs for JspIdConsumer tag handlers
            // that implement this interface are not to be pooled, however
            // due to a bug in Jasper this is not the case.
            // Because of this, two tags with the same ID within the same
            // naming container will not be detected as duplicates.  So
            // in order to ensure we detect it, if the instance is the same,
            // verify the JSP IDs are different.  If they are, then continue,
            // if they aren't, then we're dealing with EVAL_BODY_AGAIN (see
            // below)
            //noinspection ObjectEquality
            if (temp == this
                 && !this.getFacesJspId().equals(temp.getFacesJspId())) {
                tagInstance = this;
            }
        }
        // If we have a tag instance, then, most likely, a tag handler
        // returned EVAL_BODY_AGAIN somewhere.  Make sure the instance
        // returned is the same as the current instance and if this is the case,
        // do not perform ID validation as it has already been done.
        if (tagInstance == null) {
            // only check for id uniqueness if the author has manually given
            // us an id.
            if (null != this.) {
                // assert component ID uniqueness
                if (clientId != null) {
                    if (componentIds.containsKey(clientId)) {
                        // PENDING i18n
                        StringWriter writer = new StringWriter(128);
                        printTree(.getViewRoot(), clientIdwriter, 0);
                        String msg = "Duplicate component id: '" 
                                     + clientId 
                                     + "', first used in tag: '" 
                                     + componentIds.get(clientId).getClass().getName()
                                     + "'\n"
                                     + writer.toString();                                     
                        throw new JspException(new IllegalStateException(msg));
                    } else {                        
                        componentIds.put(clientIdthis);
                    }
                }
            }
            // Add to parent's list of created components or facets if needed
            if ( != null) {
                if (getFacetName() == null) {
                    .addChild();
                } else {
                    .addFacet(getFacetName());
                }
            }
        }
	// Rendering is deferred until after the tree is completely
	// created
        // Return the appropriate control value
        return (getDoStartValue());
    }


    

Perform any processing necessary to handle the content implications of CASE 3 in the class description.

The default implementation, which is intended to be sufficient for most components, calls createVerbatimComponentFromBodyContent on this instance and adds it as a child of the component for this tag's component at the end of the child list. In addition, the following housekeeping steps are taken.

  • Retrieve from the UIComponent the set of component ids of child components created by UIComponentTag instances the last time this page was processed (if any). Compare it to the list of children created during this page processing pass, and remove all children present in the old list but not the new. Save the new list as a component attribute so that it gets saved as part of the component's state.
  • Retrieve from the UIComponent the set of facet names of facets created by UIComponentTag instances the last time this page was processed (if any). Compare it to the list of facets created during this page processing pass, and remove all facets present in the old list but not the new. Save the new list as a component attribute so that it gets saved as part of the component's state.
  • Release all references to the component, and pop it from the component stack for this response, removing the stack if this was the outermost component.

The flag value to be returned is acquired by calling the getDoEndValue() method, which tag subclasses may override if they do not want the default value.

Throws:
JspException if an error occurs
    public int doEndTag() throws JspException {
        // Remove old children and facets as needed
        removeOldChildren();
        removeOldFacets();
        // Render the children (if needed) and  end of the component
        // associated with this tag
        try {
	    UIComponent verbatim;
	    UIComponentClassicTagBase parentTag = 
	    if (null != (verbatim = this.createVerbatimComponentFromBodyContent())) {
                .getChildren().add(verbatim);
		if (null != parentTag) {
		    parentTag.addChild(verbatim);
	    }
	    // else, we don't render rendersChildren==true
	    // components here
        } catch (Throwable e) {
            throw new JspException(e);
        } finally {
             = null;
             = null;
        }
        // Return the appropriate control value
         = false;
	this.release();
        return (getDoEndValue());
    }

    

Release any resources allocated during the execution of this tag handler.

    public void release() {
        
        this. = null;
        this. = null;
        this. = null;
        this. = null;
        this. = false;
	this. = null;
        this. = false;
    }
    // -------------------------------------------- Support methods for BodyTag

    

Return the flag value that should be returned from the doAfterBody() method when it is called. Subclasses may override this method to return the appropriate value.

    protected int getDoAfterBodyValue() throws JspException {
        return ();
    }
    // -------------------------------------------------------- BodyTag Methods

    

Set the bodyContent for this tag handler. This method is invoked by the JSP page implementation object at most once per action invocation, before doInitiBody(). This method will not be invoked for empty tags or for non-empty tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE.

Parameters:
bodyContent The new BodyContent for this tag
    public void setBodyContent(BodyContent bodyContent) {
        this. = bodyContent;
    }

    

Get the JspWriter from our BodyContent.

    public JspWriter getPreviousOut() {
        return (this..getEnclosingWriter());
    }
    public BodyContent getBodyContent() {
        return (this.);
    }



    

Prepare for evaluation of the body. This method is invoked by the JSP page implementation object after setBodyContent() and before the first time the body is to be evaluated. This method will not be invoked for empty tags or for non-empty tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE.

Throws:
JspException if an error is encountered
    public void doInitBody() throws JspException {
        ; // Default implementation does nothing
    }

    

Perform any processing necessary to handle the content implications of CASE 4 in the class description.

Return result from getDoAfterBodyValue

Throws:
JspException if an error is encountered
    public int doAfterBody() throws JspException {
	UIComponent verbatim;
	// if we are the root tag, or if we are inside of a
	// rendersChildren==true component
        //noinspection ObjectEquality
        if (this == parentTag ||
	    (null != parentTag && 
	     parentTag.getComponentInstance().getRendersChildren())) {
	    // stuff the template text or custom tag output into a
	    // transient component
	    if (null != (verbatim = this.createVerbatimComponentFromBodyContent())) {
            // EDGE CASE:
            // Consider CASE 4 where the component is provided via a
            // component binding in session or application scope.
            // The verbatim instance will already be present.  If we
            // add again, the user will get duplicate component ID
            // errors.  Check the JSP_CREATED_COMPONENT_IDS attribute.  If it is not present, we
            // need to add the new verbatim child.  If it is present, assume it is a
            // List and check its size.  If the size of the list is equal to the
            // number of children currently in the component, replace the replace
            // the child of this component at the index derived as follows.  If
            // indexOfChildInParent is 0, replace the child at the 0th index with
            // the new verbatim child.  Otherwise, replace the child at the
            // (indexOfChildInParent - 1)th index with the new verbatim child.
            List createdIds = (List
                  .getAttributes().get();
            if (createdIds != null) {
                int listIdx = .getChildCount();
                if (createdIds.size() == listIdx) {
                    .getChildren().set((listIdx - 1), verbatim);                    
                } else {
                    .getChildren().add(verbatim);                   
                }
            } else {
                .getChildren().add(verbatim);                
            }
            parentTag.addChild(verbatim);
        }
        return (getDoAfterBodyValue());
    }
    // ----------------------------------------------- Methods relating to Id

    

Set the component identifier for our component. If the argument begins with UIViewRoot.UNIQUE_ID_PREFIX throw an IllegalArgumentException

Parameters:
id The new component identifier. This may not start with UIViewRoot.UNIQUE_ID_PREFIX.
Throws:
IllegalArgumentException if the argument is non-null and starts with UIViewRoot.UNIQUE_ID_PREFIX.
    public void setId(String id) {
	if (null != id && id.startsWith(.)) {
	    throw new IllegalArgumentException();
        this. = id;
    }

    

Return the id value assigned by the page author.

    protected String getId() {
	return ();
    }

    

If this method has been called before on this tag's useful lifetime (before release was called), return the previously returned value. Otherwise, if getJspId returns non-null, prepend UNIQUE_ID_PREFIX to the jspId and return the result.

    protected String getFacesJspId() {
        if (null == ) {
            if (null != ) {
                 =  + ;
                // if this tag happens to be nested within <c:forEach>,
                //  jspId will be the same for each iteration. So it is 
                // transformed into a unique "id" by appending a counter which 
                // gets stored in request scope with jspId as the key for use 
                // during the next iteration.  
                if (isDuplicateId()) {
                     = generateIncrementedId();
                } 
            } else {
                // jspId will be null if we're running in a container
                // that doesn't support JspIdConsumer
                 = .getViewRoot().createUniqueId();
            }
        }
        return ;
    }
    
    
Returns true if a component already exists with the same id. This will be the case if this tag is nested within <c:forEach> tag or any other JSTL loop tag or if the page has components with the same Id.

Parameters:
componentId id to be looked up for possible duplication.
Returns:
true if this nested with facesJspId is duplicate.
    private boolean isDuplicateId(String componentId) {
        boolean result = false;
        if ( != null) {
           
            if (.) {
                return true;
            } 
             List childComponents = .;
            // PENDING: Need to analyze the impact of this look up on pages
            // with several levels of nesting.            
            if (childComponents != null) {
                result = childComponents.contains(componentId);
                if (result && (!)) {
                    return true;
                }
            }           
        }
       
        return result;
    }
    
    /*
     * Appends a counter to the passed in <code>id</code> and stores the 
     * <code>id</code> and counter information in request scope.
     *
     * @return String <code>id</code> with a counter appended to it.
     */
    private String generateIncrementedId (String componentId) {
        Map<String,ObjectrequestMap = getFacesContext().getExternalContext().getRequestMap();
        Integer serialNum = (IntegerrequestMap.get(componentId);
        if (null == serialNum) {
            serialNum = new Integer(1);
        } else {
            serialNum = new Integer(serialNum.intValue() + 1);            
        }   
        requestMap.put(componentIdserialNum);
        componentId = componentId +  + serialNum.intValue();
        return componentId;
    }
    
    
Returns the List of UIComponent ids created or located by nested UIComponentTags while processing the current request.
    protected List<StringgetCreatedComponents() {
        return ;
    }
    
    

Create the component identifier to be used for this component.

    private String createId(FacesContext contextUIComponent parent
    throws JspException {
	if (this. == null) {
	    return getFacesJspId();
else {
            // if this tag happens to be nested within <c:forEach>, jspId
            // will be the same for each iteration. So it is
            // transformed into a unique "id" by appending a counter which gets
            // stored in request scope with jspId as the key for use during next
            // iteration.
            if (isDuplicateId(this.)) {
                if () {
                    this. = generateIncrementedId(this.);
                } else {
                    // verify whether or not this ID is unique within
                    // it's closest naming container to prevent false
                    // positives.
                    if (parent != null) {
                        UIComponent container = getNamingContainer(parent);                        
                        if (container != null) { 
                            UIComponent comp = container.findComponent(this.);
                            // This is somewhat of a HACK, but I don't see any
                            // other way around it.  This logic works fine
                            // when the view is first rendered, however, on a
                            // post back, findComponent() will return true
                            // since the tree was restored.  So check for the
                            // saved state request parameter to determine if
                            // this was a post-back or not.
                            if (comp == null || isPostBack(context)) {
                                return (this.);
                            }
                        }
                    }
                    StringWriter writer = new StringWriter(128);
                    printTree(context.getViewRoot(), this.writer, 0);
                    String msg = "Component ID '"
                                 + this.
                                 + "' has already been used" 
                                 + " in the view.\n"
                                 + "See below for the view up to the point of" 
                                 + " the detected error.\n"
                                 + writer.toString();
                    throw new JspException(msg);
                }
            }
	    return (this.);
        }
    }


    
Determine if the request is a postback or not.

Parameters:
context the FacesContext for the current request
Returns:
true if the request is a postback otherwise, return false
    private static boolean isPostBack(FacesContext context) {
        return context.getRenderKit().getResponseStateManager().isPostback(context);
    }
    // ------------------------------------------------   JspIdConsumer Methods


    

Defined on JspIdConsumer. This method is called by the container before doStartTag. The argument is guaranteed to be unique within the page.

IMPLEMENTATION NOTE: This method will detect where we are in an include and assign a unique ID for each include in a particular 'logical page'. This allows us to avoid possible duplicate ID situations for included pages that have components without explicit IDs.

Parameters:
id the container generated id for this tag, guaranteed to be unique within the page.
    public void setJspId(String id) {
        Map<String,ObjectreqMap =
             getFacesContext().getExternalContext().getRequestMap();
        if (aInt == null) {
            aInt = new AtomicInteger();
            reqMap.put(aInt);
        }
        Integer pcId = (Integer)
                                      .);
        if (pcId == null) {
            pcId = aInt.incrementAndGet();
        }
        if (pcId.intValue() > 1) {
            StringBuilder builder = new StringBuilder(id.length() + 3);
            builder.append(id).append("pc").append(pcId);
             = builder.toString();
        } else {
             = id;
        }
         = null;
        updatePreviousJspIdAndIteratorStatus();        
    }

    

Called from setJspId to update the value saved for the previous call to setJspId for this component on this request. If this method is presented with the same argument id for the same tag instance more than once on the same request, then we know that the tag instance lies inside an iterator tag, such as c:forEach. If so, we set the isNestedInIterator ivar to true otherwise, we set it to false.

The implementation for this method stores a Map from tag instance to id String as a request scoped attribute. This map contains the value used as the previousJspId and compared with the argument id.

Parameters:
id the id to be compared with the previous id, if any, for this tag instance on this request.
    
    private void updatePreviousJspIdAndIteratorStatus(String id) {
      &n