View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package javax.faces.webapp;
20  
21  import java.io.IOException;
22  import java.util.ArrayList;
23  import java.util.HashMap;
24  import java.util.HashSet;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Set;
28  import java.util.Stack;
29  import java.util.concurrent.atomic.AtomicInteger;
30  import java.util.logging.Level;
31  
32  import javax.faces.component.NamingContainer;
33  import javax.faces.component.UIComponent;
34  import javax.faces.component.UIOutput;
35  import javax.faces.component.UIViewRoot;
36  import javax.faces.context.FacesContext;
37  import javax.faces.render.ResponseStateManager;
38  import javax.servlet.jsp.JspException;
39  import javax.servlet.jsp.JspWriter;
40  import javax.servlet.jsp.PageContext;
41  import javax.servlet.jsp.jstl.core.LoopTag;
42  import javax.servlet.jsp.tagext.BodyContent;
43  import javax.servlet.jsp.tagext.BodyTag;
44  import javax.servlet.jsp.tagext.JspIdConsumer;
45  import javax.servlet.jsp.tagext.Tag;
46  
47  /**
48   * @author Bruno Aranda (latest modification by $Author: baranda $)
49   * @author Manfred Geiler
50   * @author Dennis Byrne
51   * @version $Revision$ $Date$
52   *
53   * @since 1.2
54   */
55  
56  public abstract class UIComponentClassicTagBase extends UIComponentTagBase
57          implements BodyTag, JspIdConsumer
58  {
59      
60      //  do not change this w/out doing likewise in UIComponentTag
61      private static final String COMPONENT_STACK_ATTR = "org.apache.myfaces.COMPONENT_STACK";
62  
63      private static final String REQUEST_FACES_CONTEXT = "org.apache.myfaces.REQUEST_FACES_CONTEXT";
64  
65      private static final String VIEW_IDS = "org.apache.myfaces.VIEW_IDS";
66  
67      private static final String FORMER_CHILD_IDS_SET_ATTR = "org.apache.myfaces.FORMER_CHILD_IDS";
68      private static final String FORMER_FACET_NAMES_SET_ATTR = "org.apache.myfaces.FORMER_FACET_NAMES";
69  
70      private static final String PREVIOUS_JSP_IDS_SET = "org.apache.myfaces.PREVIOUS_JSP_IDS_SET";
71  
72      private static final String BOUND_VIEW_ROOT = "org.apache.myfaces.BOUND_VIEW_ROOT";
73      
74      private static final String LOGICAL_PAGE_ID = "org.apache.myfaces.LOGICAL_PAGE_ID";
75      
76      private static final String LOGICAL_PAGE_COUNTER = "org.apache.myfaces.LOGICAL_PAGE_COUNTER";
77  
78      protected static final String UNIQUE_ID_PREFIX = UIViewRoot.UNIQUE_ID_PREFIX + "_";
79  
80      protected PageContext pageContext = null;
81      protected BodyContent bodyContent = null;
82  
83      private boolean _created = false;
84  
85      private String _jspId = null;
86      private String _facesJspId = null;
87  
88      private List<String> _childrenAdded = null;
89      private List<String> _facetsAdded = null;
90  
91      private UIComponent _componentInstance = null;
92      private String _id = null;
93  
94      private boolean isInAnIterator;
95  
96      // the parent tag
97      private Tag _parent = null;
98  
99      // the enclosing "classic" parent tag
100     private UIComponentClassicTagBase _parentClassicTag = null;
101 
102     private FacesContext _facesContext = null;
103 
104     protected abstract void setProperties(UIComponent component);
105 
106     protected abstract UIComponent createComponent(FacesContext context,
107                                                    String newId) throws JspException;
108 
109     public void release()
110     {
111         internalRelease();
112 
113         //members, that must/need only be reset when there is no more risk, that the container
114         //wants to reuse this tag
115         pageContext = null;
116         _parent = null;
117         _jspId = null;
118         _id = null;
119         _facesJspId = null;
120         bodyContent = null;
121     }
122 
123 
124     /**
125      * Reset any members that apply to the according component instance and
126      * must not be reused if the container wants to reuse this tag instance.
127      * This method is called when rendering for this tag is finished
128      * ( doEndTag() ) or when released by the container.
129      */
130     private void internalRelease()
131     {
132         _facesContext = null;
133         _componentInstance = null;
134         _created = false;
135 
136          _childrenAdded = null;
137         _facetsAdded = null;
138     }
139 
140     /**
141      * @see http://java.sun.com/javaee/5/docs/api/javax/faces/webapp/UIComponentClassicTagBase.html#getCreated()
142      */
143     public boolean getCreated()
144     {
145         return _created;
146     }
147 
148      protected List<String> getCreatedComponents() {
149          return _childrenAdded;
150     }
151 
152     /**
153      * @see http://java.sun.com/javaee/5/docs/api/javax/faces/webapp/UIComponentClassicTagBase.html#getParentUIComponentClassicTagBase(javax.servlet.jsp.PageContext)
154      * @param pageContext
155      * @return
156      */
157     public static UIComponentClassicTagBase getParentUIComponentClassicTagBase(
158             PageContext pageContext)
159     {
160         Stack<UIComponentClassicTagBase> stack = getStack(pageContext);
161 
162         int size = stack.size();
163 
164         return size > 0 ? stack.get(size - 1) : null;
165     }
166 
167     /**
168      * @see http://java.sun.com/javaee/5/docs/api/javax/faces/webapp/UIComponentClassicTagBase.html#getFacesJspId()
169      * @return
170      */
171     public String getJspId()
172     {
173         return _jspId;
174     }
175 
176     public void setJspId(String jspId)
177     {
178         // -= Leonardo Uribe =- The javadoc says the following about this method:
179         //
180         // 1. This method is called by the container before doStartTag(). 
181         // 2. The argument is guaranteed to be unique within the page.
182         //
183         // Doing some tests it was found that the jspId generated in a
184         // jsp:include are "reset", so if before call it it was id10
185         // the tags inside jsp:include starts from id1 (really I suppose a
186         // different counter is used), so if we assign this one
187         // directly it is possible to cause duplicate id exceptions later.
188         //
189         // One problem is caused by f:view tag. This one is not included when
190         // we check for duplicate id, so it is possible to assign to a component
191         // in a jsp:include the id of the UIViewRoot instance and cause a 
192         // duplicate id exception when the view is saved.
193         //
194         // Checking the javadoc it was found the following note:
195         //
196         // "... IMPLEMENTATION NOTE: This method will detect where we are in an 
197         // include and assign a unique ID for each include in a particular 'logical page'. 
198         // This allows us to avoid possible duplicate ID situations for included pages 
199         // that have components without explicit IDs..."
200         //
201         // So we need to keep a counter per logical page or page context found. 
202         // It is assumed the first one should not be suffixed. The others needs to be
203         // suffixed, so all generated ids of those pages are different. The final result
204         // is that jsp:include works correctly.
205         //
206         // Note this implementation detail takes precedence over c:forEach tag. If a
207         // jsp:include is inside a c:forEach, jsp:include takes precedence and the 
208         // iteration prefix is ignored. If a custom id is provided for a component, 
209         // it will throw duplicate id exception, because this code is "override" 
210         // by the custom id, and the iteration suffix only applies on generated ids.
211         Integer logicalPageId = (Integer) pageContext.getAttribute(LOGICAL_PAGE_ID);
212         
213         if (logicalPageId != null)
214         {
215             if (logicalPageId.intValue() == 1)
216             {
217                 //Base case, just pass it unchanged
218                 _jspId = jspId;
219             }
220             else
221             {
222                 // We are on a different page context, suffix it with the logicalPageId
223                 _jspId = jspId + "pc" + logicalPageId;
224             }
225         }
226         else
227         {
228             Map<String,Object> requestMap = getFacesContext().getExternalContext().getRequestMap();
229             AtomicInteger logicalPageCounter = (AtomicInteger) requestMap.get(LOGICAL_PAGE_COUNTER);
230             
231             if (logicalPageCounter == null)
232             {
233                 //We are processing the first component tag. 
234                 logicalPageCounter = new AtomicInteger(1);
235                 logicalPageId = 1;
236                 requestMap.put(LOGICAL_PAGE_COUNTER, logicalPageCounter);
237                 pageContext.setAttribute(LOGICAL_PAGE_ID, logicalPageId);
238             }
239             else
240             {
241                 //We are on a different page context, so we need to assign and set.
242                 logicalPageId = logicalPageCounter.incrementAndGet();
243                 pageContext.setAttribute(LOGICAL_PAGE_ID, logicalPageId);
244                 _jspId = jspId + "pc" + logicalPageId;
245             }
246         }
247         _facesJspId = null;
248         checkIfItIsInAnIterator(_jspId);
249     }
250 
251 
252     /**
253      * @param child
254      * @see http://java.sun.com/javaee/5/docs/api/javax/faces/webapp/UIComponentTagBase.html#addChild(javax.faces._componentInstance.UIComponent)
255      */
256 
257     protected void addChild(UIComponent child)
258     {
259         if (_childrenAdded == null)
260         {
261             _childrenAdded = new ArrayList<String>();
262         }
263 
264         _childrenAdded.add(child.getId());
265     }
266 
267     /**
268      * @param name
269      * @see http://java.sun.com/javaee/5/docs/api/javax/faces/webapp/UIComponentTagBase.html#addFacet(java.lang.String)
270      */
271     protected void addFacet(String name)
272     {
273         if (_facetsAdded == null)
274         {
275             _facetsAdded = new ArrayList<String>();
276         }
277 
278         _facetsAdded.add(name);
279     }
280 
281     /**
282      * Return the UIComponent instance associated with this tag.
283      * @return a UIComponent, never null.
284      */
285     public UIComponent getComponentInstance()
286     {
287         return _componentInstance;
288     }
289 
290     /**
291      * @return
292      * @see http://java.sun.com/javaee/5/docs/api/javax/faces/webapp/UIComponentTagBase.html#getFacesContext()
293      */
294 
295     protected FacesContext getFacesContext()
296     {
297         if (_facesContext != null)
298         {
299             return _facesContext;
300         }
301 
302         _facesContext = pageContext == null ? null : (FacesContext) pageContext.getAttribute(REQUEST_FACES_CONTEXT);
303 
304         if (_facesContext != null)
305         {
306             return _facesContext;
307         }
308 
309         _facesContext = FacesContext.getCurrentInstance();
310 
311         if (_facesContext != null)
312         {
313             if(pageContext != null)
314             {
315                 pageContext.setAttribute(REQUEST_FACES_CONTEXT, _facesContext);
316             }
317             return _facesContext;
318         }
319 
320         // should never be reached
321         throw new RuntimeException("FacesContext not found");
322     }
323 
324     /**
325      * @return
326      * @see http://java.sun.com/javaee/5/docs/api/javax/faces/webapp/UIComponentTagBase.html#getIndexOfNextChildTag()
327      */
328 
329     protected int getIndexOfNextChildTag()
330     {
331         if (_childrenAdded == null)
332         {
333             return 0;
334         }
335 
336         return _childrenAdded.size();
337     }
338 
339     /**
340      * @param id
341      * @see http://java.sun.com/javaee/5/docs/api/javax/faces/webapp/UIComponentTagBase.html#setId(java.lang.String)
342      */
343     public void setId(String id)
344     {
345         if (id != null && id.startsWith(UIViewRoot.UNIQUE_ID_PREFIX))
346         {
347             throw new IllegalArgumentException("Id is non-null and starts with UIViewRoot.UNIQUE_ID_PREFIX: "+id);
348         }
349 
350         _id = id;
351     }
352 
353     /**
354      * Return the id (if any) specified as an xml attribute on this tag.
355      */
356     protected String getId()
357     {
358         return _id;
359     }
360 
361     protected String getFacesJspId() {
362         if (_facesJspId == null)
363         {
364             if (_jspId != null)
365             {
366                 _facesJspId = UNIQUE_ID_PREFIX + _jspId;
367 
368                 if (isIdDuplicated(_facesJspId)) {
369                     _facesJspId = createNextId(_facesJspId);
370                 }
371             }
372             else
373             {
374                 _facesJspId = _facesContext.getViewRoot().createUniqueId();
375             }
376         }
377 
378         return _facesJspId;
379     }
380 
381     public void setBodyContent(BodyContent bodyContent)
382     {
383         this.bodyContent = bodyContent;
384     }
385 
386     public void doInitBody() throws JspException
387     {
388         // nothing by default
389     }
390 
391     public int doAfterBody() throws JspException
392     {
393         UIComponentClassicTagBase parentTag = getParentUIComponentClassicTagBase(pageContext);
394 
395         if (isRootTag(parentTag) || isInRenderedChildrenComponent(parentTag))
396         {
397             UIComponent verbatimComp = createVerbatimComponentFromBodyContent();
398 
399             if (verbatimComp != null)
400             {
401                 List<String> childrenAddedIds = (List<String>)
402                   _componentInstance.getAttributes().get(FORMER_CHILD_IDS_SET_ATTR);
403 
404                 if (childrenAddedIds == null)
405                 {
406                     _componentInstance.getChildren().add(verbatimComp);
407                 }
408                 else
409                 {
410                     int index = _componentInstance.getChildCount();
411                     if (childrenAddedIds.size() == index)
412                     {
413                         // verbatim already present, replace it
414                         _componentInstance.getChildren().add(index-1, verbatimComp);
415                     }
416                     else
417                     {
418                         _componentInstance.getChildren().add(verbatimComp);
419                     }
420                 }
421 
422                 // also tell the parent-tag about the new component instance
423                 if(parentTag!=null) {
424                     parentTag.addChild(verbatimComp);
425                 }
426             }
427         }
428 
429         return getDoAfterBodyValue();
430     }
431 
432     /**
433      * Standard method invoked by the JSP framework to inform this tag
434      * of the PageContext associated with the jsp page currently being
435      * processed.
436      */
437     public void setPageContext(PageContext pageContext)
438     {
439         this.pageContext = pageContext;
440     }
441 
442     /**
443      * Returns the enclosing JSP tag object. Note that this is not
444      * necessarily a JSF tag.
445      */
446     public Tag getParent()
447     {
448         return _parent;
449     }
450 
451     /**
452      * Standard method invoked by the JSP framework to inform this tag
453      * of the enclosing JSP tag object.
454      */
455     public void setParent(Tag tag)
456     {
457         this._parent = tag;
458     }
459 
460     public BodyContent getBodyContent()
461     {
462         return bodyContent;
463     }
464 
465     public int doStartTag() throws JspException
466     {
467         this._facesContext = getFacesContext();
468 
469         if (_facesContext == null)
470         {
471             throw new JspException("FacesContext not found");
472         }
473 
474         _childrenAdded = null;
475         _facetsAdded = null;
476 
477         _parentClassicTag = getParentUIComponentClassicTagBase(pageContext);
478 
479         UIComponent verbatimComp = null;
480 
481         // create the verbatim component if not inside a facet (facets are rendered
482         // by their parents) and in a component that renders children
483         if (!isFacet())
484         {
485             Tag parent = getParent();
486 
487             // flush if in a loop tag and not in a jsp tag
488             if (parent != null && parent instanceof LoopTag)
489             {
490                 JspWriter outWriter = pageContext.getOut();
491                 boolean insideJspTag = (outWriter instanceof BodyContent);
492 
493                 if (!insideJspTag)
494                 {
495                     try
496                     {
497                         outWriter.flush();
498                     }
499                     catch (IOException e)
500                     {
501                         throw new JspException("Exception flushing when creating verbatim _componentInstance", e);
502                     }
503                 }
504             }
505 
506             // create the transient _componentInstance
507             if (_parentClassicTag != null)
508             {
509                 verbatimComp = _parentClassicTag.createVerbatimComponentFromBodyContent();
510             }
511         }
512 
513         // find the _componentInstance for this tag
514         _componentInstance = findComponent(_facesContext);
515 
516         // add the verbatim component
517         if (verbatimComp != null && _parentClassicTag != null)
518         {
519             addVerbatimBeforeComponent(_parentClassicTag, verbatimComp, _componentInstance);
520         }
521 
522         Map<String,Object> viewComponentIds = getViewComponentIds();
523 
524         // check that the instance returned by the client ID for the viewComponentIds
525         // is the same like this one, so we do not perform again the check for duplicated ids
526         Object tagInstance = null;
527         String clientId = null;
528         if (_id != null) {
529             clientId = _componentInstance.getClientId(_facesContext);
530             tagInstance = (viewComponentIds.get(clientId) == this) ? this : null;
531         }
532 
533         if (tagInstance == null)
534         {
535             // check for duplicated IDs
536             if (_id != null)
537             {
538                 if (clientId != null)
539                 {
540                     if (viewComponentIds.containsKey(clientId))
541                     {
542                         throw new JspException("Duplicated component Id: '"+clientId+"' " +
543                                 "for component: '"+getPathToComponent(_componentInstance)+"'.");
544                     }
545 
546                     viewComponentIds.put(clientId, this);
547                 }
548             }
549 
550             // add to the component or facet to parent
551             if (_parentClassicTag != null)
552             {
553                 if (isFacet())
554                 {
555                     _parentClassicTag.addFacet(getFacetName());
556                 }
557                 else
558                 {
559                      _parentClassicTag.addChild(_componentInstance);
560                 }
561             }
562         }
563 
564         // push this tag on the stack
565         pushTag();
566 
567         return getDoStartValue();
568     }
569 
570     public int doEndTag() throws JspException
571     {
572         popTag();
573         UIComponent component = getComponentInstance();
574 
575         removeFormerChildren(component);
576         removeFormerFacets(component);
577 
578         try
579         {
580             UIComponentClassicTagBase parentTag =
581                     getParentUIComponentClassicTagBase(pageContext);
582 
583             UIComponent verbatimComp = createVerbatimComponentFromBodyContent();
584 
585              if (verbatimComp != null)
586             {
587                 component.getChildren().add(verbatimComp);
588 
589                 if (parentTag != null)
590                 {
591                     parentTag.addChild(verbatimComp);
592                 }
593             }
594         }
595         catch (Throwable e)
596         {
597             throw new JspException(e);
598         }
599         finally
600         {
601             component = null;
602         }
603 
604         int retValue = getDoEndValue();
605 
606         internalRelease();
607 
608         return retValue;
609     }
610 
611     protected int getDoAfterBodyValue() throws javax.servlet.jsp.JspException
612     {
613         return SKIP_BODY;
614     }
615 
616     /**
617      * Get the value to be returned by the doStartTag method to the
618      * JSP framework. Subclasses which wish to use the inherited
619      * doStartTag but control whether the tag is permitted to contain
620      * nested tags or not can just override this method to return
621      * Tag.SOME_CONSTANT.
622      *
623      * @return BodyTag.EVAL_BODY_BUFFERED
624      */
625     protected int getDoStartValue()
626             throws JspException
627     {
628         return BodyTag.EVAL_BODY_BUFFERED;
629     }
630 
631     /**
632      * Get the value to be returned by the doEndTag method to the
633      * JSP framework. Subclasses which wish to use the inherited
634      * doEndTag but control whether the tag is permitted to contain
635      * nested tags or not can just override this method to return
636      * Tag.SOME_CONSTANT.
637      *
638      * @return Tag.EVAL_PAGE
639      */
640     protected int getDoEndValue()
641             throws JspException
642     {
643         return Tag.EVAL_PAGE;
644     }
645 
646     protected String getFacetName()
647     {
648         return isFacet() ? ((FacetTag)_parent).getName() : null;
649     }
650 
651 
652     /**
653      * Creates a UIComponent from the BodyContent
654      */
655     protected UIComponent createVerbatimComponentFromBodyContent()
656     {
657         UIOutput verbatimComp = null;
658 
659         if (bodyContent != null)
660         {
661             String strContent = bodyContent.getString();
662 
663             if (strContent != null)
664             {
665                 String trimmedContent = strContent.trim();
666                 if (trimmedContent.length() > 0 && !isComment(strContent))
667                 {
668                     verbatimComp = createVerbatimComponent();
669                     verbatimComp.setValue(strContent);
670                 }
671             }
672 
673             bodyContent.clearBody();
674         }
675 
676         return verbatimComp;
677     }
678 
679     private static boolean isComment(String bodyContent)
680     {
681         return (bodyContent.startsWith("<!--") && bodyContent.endsWith("-->"));
682     }
683 
684     /**
685      * <p>Creates a transient UIOutput using the Application, with the following characteristics:</p>
686      * <p/>
687      * <p><code>componentType</code> is
688      * <code>javax.faces.HtmlOutputText</code>.</p>
689      * <p/>
690      * <p><code>transient</code> is <code>true</code>.</p>
691      * <p/>
692      * <p><code>escape</code> is <code>false</code>.</p>
693      * <p/>
694      * <p><code>id</code> is
695      * <code>FacesContext.getViewRoot().createUniqueId()</code></p>
696      */
697     protected UIOutput createVerbatimComponent()
698     {
699         UIOutput verbatimComp = (UIOutput) getFacesContext().getApplication()
700                 .createComponent("javax.faces.HtmlOutputText");
701         verbatimComp.setTransient(true);
702         verbatimComp.getAttributes().put("escape", Boolean.FALSE);
703         verbatimComp.setId(getFacesContext().getViewRoot().createUniqueId());
704 
705         return verbatimComp;
706     }
707 
708     protected void addVerbatimBeforeComponent(
709             UIComponentClassicTagBase parentTag,
710             UIComponent verbatimComp,
711             UIComponent component)
712     {
713         UIComponent parent = component.getParent();
714 
715         if (parent == null)
716         {
717             return;
718         }
719 
720         List<UIComponent> children = parent.getChildren();
721         // EDGE CASE:
722         // Consider CASE 1 or 2 where the _componentInstance is provided via a
723         // _componentInstance binding in session or application scope.
724         // The automatically created UIOuput instances for the template text
725         // will already be present.  Check the JSP_CREATED_COMPONENT_IDS attribute,
726         // if present and the number of created components is the same
727         // as the number of children replace at a -1 offset from the current
728         // value of indexOfComponentInParent, otherwise, call add()
729 
730         List<String> childrenAddedIds = (List<String>)
731                 parent.getAttributes().get(FORMER_CHILD_IDS_SET_ATTR);
732 
733 
734         int parentIndex = children.indexOf(component);
735 
736          if (childrenAddedIds != null)
737          {
738              if (parentIndex > 0 && childrenAddedIds.size() == parentIndex)
739              {
740                  UIComponent formerVerbatim = children.get(parentIndex - 1);
741 
742                  if (formerVerbatim instanceof UIOutput && formerVerbatim.isTransient())
743                  {
744                      children.set(parentIndex - 1, verbatimComp);
745                  }
746              }
747          }
748 
749         children.add(parentIndex, verbatimComp);
750 
751         parentTag.addChild(verbatimComp);
752     }
753 
754     /**
755      * <p>Add <i>verbatim</i> as a sibling of <i>_componentInstance</i> in
756      * <i>_componentInstance</i> in the parent's child list.  <i>verbatim</i> is
757      * added to the list at the position immediatly following
758      * <i>_componentInstance</i>.</p>
759      */
760 
761     protected void addVerbatimAfterComponent(UIComponentClassicTagBase parentTag,
762                                              UIComponent verbatim,
763                                              UIComponent component)
764     {
765         int indexOfComponentInParent = 0;
766         UIComponent parent = component.getParent();
767 
768         // invert the order of this if and the assignment below.  Since this line is
769         // here, it appears an early return is acceptable/desired if parent is null,
770         // and, if it is null, we should probably check for that before we try to
771         // access it.  2006-03-15 jdl
772         if (null == parent)
773         {
774             return;
775         }
776         List<UIComponent> children = parent.getChildren();
777         indexOfComponentInParent = children.indexOf(component);
778         if (children.size() - 1 == indexOfComponentInParent)
779         {
780             children.add(verbatim);
781         }
782         else
783         {
784             children.add(indexOfComponentInParent + 1, verbatim);
785         }
786         parentTag.addChild(verbatim);
787     }
788 
789     /**
790      * @deprecated the ResponseWriter is now set by {@link
791      * javax.faces.application.ViewHandler#renderView}
792      */
793     protected void setupResponseWriter() {
794     }
795 
796     /**
797      * Invoke encodeBegin on the associated UIComponent. Subclasses can
798      * override this method to perform custom processing before or after
799      * the UIComponent method invocation.
800      */
801     protected void encodeBegin()
802             throws IOException
803     {
804         if (log.isLoggable(Level.FINE))
805             log.fine("Entered encodeBegin for client-Id: " + _componentInstance.getClientId(getFacesContext()));
806         _componentInstance.encodeBegin(getFacesContext());
807         if (log.isLoggable(Level.FINE))
808             log.fine("Exited encodeBegin");
809     }
810 
811     /**
812      * Invoke encodeChildren on the associated UIComponent. Subclasses can
813      * override this method to perform custom processing before or after
814      * the UIComponent method invocation. This is only invoked for components
815      * whose getRendersChildren method returns true.
816      */
817     protected void encodeChildren()
818             throws IOException
819     {
820         if (log.isLoggable(Level.FINE))
821             log.fine("Entered encodeChildren for client-Id: " + _componentInstance.getClientId(getFacesContext()));
822         _componentInstance.encodeChildren(getFacesContext());
823         if (log.isLoggable(Level.FINE))
824             log.fine("Exited encodeChildren for client-Id: " + _componentInstance.getClientId(getFacesContext()));
825     }
826 
827     /**
828      * Invoke encodeEnd on the associated UIComponent. Subclasses can override this
829      * method to perform custom processing before or after the UIComponent method
830      * invocation.
831      */
832     protected void encodeEnd()
833             throws IOException
834     {
835         if (log.isLoggable(Level.FINE))
836             log.fine("Entered encodeEnd for client-Id: " + _componentInstance.getClientId(getFacesContext()));
837         _componentInstance.encodeEnd(getFacesContext());
838         if (log.isLoggable(Level.FINE))
839             log.fine("Exited encodeEnd for client-Id: " + _componentInstance.getClientId(getFacesContext()));
840 
841     }
842 
843 
844 
845     private boolean isRootTag(UIComponentClassicTagBase parentTag)
846     {
847         return (parentTag == this);
848     }
849 
850     private boolean isInRenderedChildrenComponent (UIComponentClassicTagBase tag)
851     {
852         return (_parentClassicTag != null && tag.getComponentInstance().getRendersChildren());
853     }
854 
855     private boolean isFacet()
856     {
857         return _parent != null && _parent instanceof FacetTag;
858     }
859 
860     /** Map of <ID,Tag> in the view */
861     @SuppressWarnings("unchecked")
862     private Map<String, Object> getViewComponentIds()
863     {
864         Map<String, Object> requestMap = _facesContext.getExternalContext().getRequestMap();
865         Map<String, Object> viewComponentIds;
866 
867         if (_parent == null)
868         {
869             // top level _componentInstance
870             viewComponentIds = new HashMap<String, Object>();
871             requestMap.put(VIEW_IDS, viewComponentIds);
872         }
873         else
874         {
875             viewComponentIds = (Map<String, Object>)requestMap.get(VIEW_IDS);
876             
877             // Check if null, this can happen if someone programatically tries to do an include of a 
878             // JSP fragment. This code will prevent NullPointerException from happening in such cases.
879             if (viewComponentIds == null)
880             {
881                 viewComponentIds = new HashMap<String, Object>();
882                 requestMap.put(VIEW_IDS, viewComponentIds);
883             }
884         }
885 
886         return viewComponentIds;
887     }
888 
889 
890     private static final Stack<UIComponentClassicTagBase> getStack(PageContext pageContext)
891     {
892         Stack<UIComponentClassicTagBase> stack = (Stack<UIComponentClassicTagBase>) pageContext.getAttribute(COMPONENT_STACK_ATTR,
893                 PageContext.REQUEST_SCOPE);
894 
895         if (stack == null)
896         {
897             stack = new Stack<UIComponentClassicTagBase>();
898             pageContext.setAttribute(COMPONENT_STACK_ATTR,
899                     stack, PageContext.REQUEST_SCOPE);
900         }
901 
902         return stack;
903     }
904 
905     /**
906      * The pageContext's request scope map is used to hold a stack of
907      * JSP tag objects seen so far, so that a new tag can find the
908      * parent tag that encloses it. Access to the parent tag is used
909      * to find the parent UIComponent for the component associated
910      * with this tag plus some other uses.
911      */
912     private void popTag()
913     {
914         Stack<UIComponentClassicTagBase> stack = getStack(pageContext);
915 
916         int size = stack.size();
917         stack.remove(size -1);
918         if (size <= 1)
919             pageContext.removeAttribute(COMPONENT_STACK_ATTR,
920                                          PageContext.REQUEST_SCOPE);
921 
922     }
923 
924     private void pushTag()
925     {
926         getStack(pageContext).add(this);
927     }
928 
929     //private boolean isIncludedOrForwarded() {
930     //    return getFacesContext().getExternalContext().getRequestMap().
931     //            containsKey("javax.servlet.include.request_uri");
932     //}
933 
934      /** Generate diagnostic output. */
935     private String getPathToComponent(UIComponent component)
936     {
937         StringBuffer buf = new StringBuffer();
938 
939         if(component == null)
940         {
941             buf.append("{Component-Path : ");
942             buf.append("[null]}");
943             return buf.toString();
944         }
945 
946         getPathToComponent(component,buf);
947 
948         buf.insert(0,"{Component-Path : ");
949         buf.append("}");
950 
951         return buf.toString();
952     }
953 
954     /** Generate diagnostic output. */
955     private static void getPathToComponent(UIComponent component, StringBuffer buf)
956     {
957         if(component == null)
958             return;
959 
960         StringBuffer intBuf = new StringBuffer();
961 
962         intBuf.append("[Class: ");
963         intBuf.append(component.getClass().getName());
964         if(component instanceof UIViewRoot)
965         {
966             intBuf.append(",ViewId: ");
967             intBuf.append(((UIViewRoot) component).getViewId());
968         }
969         else
970         {
971             intBuf.append(",Id: ");
972             intBuf.append(component.getId());
973         }
974         intBuf.append("]");
975 
976         buf.insert(0,intBuf);
977 
978         getPathToComponent(component.getParent(),buf);
979     }
980 
981     /**
982      * Remove any child components of the associated components which do not
983      * have corresponding tags as children of this tag. This only happens
984      * when a view is being re-rendered and there are components in the view
985      * tree which don't have corresponding JSP tags. Wrapping JSF tags in
986      * JSTL "c:if" statements is one way this can happen.
987      * <br />
988      * Attention: programmatically added components are are not affected by this:
989      * they will not be on the old list of created components nor on the new list
990      * of created components, so nothing will happen to them.
991      */
992     private void removeFormerChildren(UIComponent component)
993     {
994         List<String> formerChildIds = (List<String>)component.getAttributes().get(FORMER_CHILD_IDS_SET_ATTR);
995         if (formerChildIds != null)
996         {
997             for (String childId : formerChildIds)
998             {
999                 if (_childrenAdded == null || !_childrenAdded.contains(childId))
1000                 {
1001                     UIComponent childToRemove = component.findComponent(childId);
1002                     if (childToRemove != null)
1003                     {
1004                         component.getChildren().remove(childToRemove);
1005                     }
1006                 }
1007             }
1008             if (_childrenAdded == null)
1009             {
1010                 component.getAttributes().remove(FORMER_CHILD_IDS_SET_ATTR);
1011             }
1012             else
1013             {
1014                 component.getAttributes().put(FORMER_CHILD_IDS_SET_ATTR, _childrenAdded);
1015             }
1016         }
1017         else
1018         {
1019             if (_childrenAdded != null)
1020             {
1021                 component.getAttributes().put(FORMER_CHILD_IDS_SET_ATTR, _childrenAdded);
1022             }
1023         }
1024     }
1025 
1026     /** See removeFormerChildren. */
1027     private void removeFormerFacets(UIComponent component)
1028     {
1029         List<String> formerFacetNames = (List<String>)component.getAttributes().get(FORMER_FACET_NAMES_SET_ATTR);
1030         if (formerFacetNames != null)
1031         {
1032             for (String facetName : formerFacetNames)
1033             {
1034                 if (_facetsAdded == null || !_facetsAdded.contains(facetName)) {
1035                     component.getFacets().remove(facetName);
1036                 }
1037             }
1038             if (_facetsAdded == null)
1039             {
1040                 component.getAttributes().remove(FORMER_FACET_NAMES_SET_ATTR);
1041             }
1042             else
1043             {
1044                 component.getAttributes().put(FORMER_FACET_NAMES_SET_ATTR, _facetsAdded);
1045             }
1046         }
1047         else
1048         {
1049             if (_facetsAdded != null)
1050             {
1051                 component.getAttributes().put(FORMER_FACET_NAMES_SET_ATTR, _facetsAdded);
1052             }
1053         }
1054     }
1055 
1056     /**
1057      * Return the corresponding UIComponent for this tag, creating it
1058      * if necessary.
1059      * <p>
1060      * If this is not the first time this method has been called, then
1061      * return the cached _componentInstance instance found last time.
1062      * <p>
1063      * If this is not the first time this view has been seen, then
1064      * locate the existing _componentInstance using the id attribute assigned
1065      * to this tag and return it. Note that this is simple for
1066      * components with user-assigned ids. For components with
1067      * generated ids, the "reattachment" relies on the fact that
1068      * UIViewRoot will generate the same id values for tags in
1069      * this page as it did when first generating the view. For this
1070      * reason all JSF tags within a JSTL "c:if" are required to have
1071      * explicitly-assigned ids.
1072      * <p>
1073      * Otherwise create the _componentInstance, populate its properties from
1074      * the xml attributes on this JSP tag and attach it to its parent.
1075      * <p>
1076      * When a _componentInstance is found or created the parent JSP tag is also
1077      * told that the _componentInstance has been "seen". When the parent tag
1078      * ends it will delete any components which were in the view
1079      * previously but have not been seen this time; see doEndTag for
1080      * more details.
1081      */
1082     protected UIComponent findComponent(FacesContext context)
1083             throws JspException
1084     {
1085         // 1. If we have previously located this component, return it.
1086         if (_componentInstance != null)
1087         {
1088             return _componentInstance;
1089         }
1090 
1091         // 2. Locate the parent component by looking for a parent UIComponentTag instance,
1092         // and ask it for its component. If there is no parent UIComponentTag instance,
1093         // this tag represents the root component, so get it from the current Tree and return it.
1094         UIComponentClassicTagBase parentTag = getParentUIComponentClassicTagBase(pageContext);
1095 
1096         if (parentTag == null)
1097         {
1098             // This is the root
1099             _componentInstance = context.getViewRoot();
1100 
1101             // check if the view root is already bound to the tag
1102             Object alreadyBoundViewRootFlag = _componentInstance.getAttributes().get(BOUND_VIEW_ROOT);
1103 
1104             if (alreadyBoundViewRootFlag == null)
1105             {
1106                 try
1107                 {
1108                     setProperties(_componentInstance);
1109                 }
1110                 catch (Throwable e)
1111                 {
1112                     throw new JspException(e);
1113                 }
1114 
1115                 if (_id != null)
1116                 {
1117                     _componentInstance.setId(_id);
1118                 }
1119                 else
1120                 {
1121                     _componentInstance.setId(getFacesJspId());
1122                 }
1123                 _componentInstance.getAttributes().put(BOUND_VIEW_ROOT, true);
1124                 _created = true;
1125 
1126             }
1127             else if (hasBinding())
1128             {
1129                 setProperties(_componentInstance);
1130             }
1131 
1132             return _componentInstance;
1133         }
1134 
1135         UIComponent parent = parentTag.getComponentInstance();
1136 
1137         if (parent == null)
1138         {
1139             throw new IllegalStateException("parent is null?");
1140         }
1141 
1142         String facetName = getFacetName();
1143         if (facetName != null)
1144         {
1145             //Facet
1146             String id = createUniqueId(context, parent);
1147             _componentInstance = parent.getFacet(facetName);
1148             if (_componentInstance == null)
1149             {
1150                 _componentInstance = createComponent(context, id);
1151                 _created = true;
1152                 parent.getFacets().put(facetName, _componentInstance);
1153             }
1154             else
1155             {
1156                 if (checkFacetNameOnParentExists(parentTag, facetName))
1157                 {
1158                     throw new IllegalStateException("facet '" + facetName + "' already has a child associated. current associated _componentInstance id: "
1159                             + _componentInstance.getClientId(context) + " class: " + _componentInstance.getClass().getName());
1160                 }
1161             }
1162 
1163             addFacetNameToParentTag(parentTag, facetName);
1164             return _componentInstance;
1165         }
1166 
1167         //Child
1168         //
1169         // Note that setProperties is called only when we create the
1170         // _componentInstance; on later passes, the attributes defined on the
1171         // JSP tag are set on this Tag object, but then completely
1172         // ignored.
1173 
1174         String id = createUniqueId(context, parent);
1175 
1176         // Warn users that this tag is about to find/steal the UIComponent
1177         // that has already been created for a sibling tag with the same id value .
1178         // _childrenAdded is a Set, and we will stomp over a past id when calling
1179         // addChildIdToParentTag.
1180         //
1181         // It would also be reasonable to throw an exception here rather than
1182         // just issue a warning as this is a pretty serious problem. However the
1183         // Sun RI just issues a warning...
1184         if(parentTag._childrenAdded != null && parentTag._childrenAdded.contains(id))
1185         {
1186             if(log.isLoggable(Level.WARNING))
1187                 log.warning("There is more than one JSF tag with an id : " + id);
1188         }
1189 
1190         _componentInstance = findComponent(parent,id);
1191         if (_componentInstance == null)
1192         {
1193             _componentInstance = createComponent(context, id);
1194             if (id.equals(_componentInstance.getId()) )
1195             {
1196                 _created = true;
1197                 int index = parentTag.getIndexOfNextChildTag();
1198                 if (index > parent.getChildCount())
1199                 {
1200                     index = parent.getChildCount();
1201                 }
1202 
1203                 List<UIComponent> children = parent.getChildren();
1204                 children.add(index, _componentInstance);
1205             }
1206             // On weblogic portal using faces-adapter, the id set and the retrieved 
1207             // one for <netuix:namingContainer> is different. The reason is 
1208             // this custom solution for integrate jsf changes the id of the parent
1209             // component to allow the same native portlet to be allocated multiple
1210             // times in the same page
1211             else if (null == findComponent(parent,_componentInstance.getId()))
1212             {
1213                 _created = true;
1214                 int index = parentTag.getIndexOfNextChildTag();
1215                 if (index > parent.getChildCount())
1216                 {
1217                     index = parent.getChildCount();
1218                 }
1219 
1220                 List<UIComponent> children = parent.getChildren();
1221                 children.add(index, _componentInstance);
1222             }
1223         }
1224 
1225         return _componentInstance;
1226 
1227     }
1228 
1229     private UIComponent findComponent(UIComponent parent, String id)
1230     {
1231         List li = parent.getChildren();
1232 
1233         for (int i = 0; i < li.size(); i++)
1234         {
1235             UIComponent uiComponent = (UIComponent) li.get(i);
1236             if(uiComponent.getId()!=null && uiComponent.getId().equals(id))
1237             {
1238                 return uiComponent;
1239             }
1240         }
1241 
1242         return null;
1243     }
1244 
1245 
1246     private String createUniqueId(FacesContext context, UIComponent parent)
1247             throws JspException
1248     {
1249         String id = getId();
1250         if (id == null)
1251         {
1252             id = getFacesJspId();
1253         }
1254         else if (isIdDuplicated(id))
1255         {
1256             if (isInAnIterator)
1257             {
1258                 setId(createNextId(id));              
1259                 id = getId();
1260             }
1261             else
1262             {
1263                 if (parent != null)
1264                 {
1265 
1266                     UIComponent namingContainer;
1267 
1268                     if (parent instanceof NamingContainer)
1269                     {
1270                         namingContainer = parent;
1271                     }
1272                     else
1273                     {
1274                         namingContainer = parent.getParent();
1275                     }
1276 
1277                     if (namingContainer != null)
1278                     {
1279                         UIComponent component = namingContainer.findComponent(id);
1280 
1281                         if (component == null || isPostBack(context))
1282                         {
1283                             return id;
1284                         }
1285                     }
1286                 }
1287 
1288                 throw new JspException("Duplicated Id found in the view: " + id);
1289             }
1290         }
1291 
1292         return id;
1293     }
1294 
1295     private String createNextId(String componentId)
1296     {
1297         Integer currentCounter = (Integer) getFacesContext().getExternalContext().getRequestMap().get(componentId);
1298 
1299         int iCurrentCounter = 1;
1300 
1301         if (currentCounter != null)
1302         {
1303             iCurrentCounter = currentCounter.intValue();
1304             iCurrentCounter++;
1305         }
1306 
1307         getFacesContext().getExternalContext().getRequestMap().put(componentId, new Integer(iCurrentCounter));
1308 
1309         //if (isIncludedOrForwarded())
1310         //{
1311         //    componentId = componentId + "pc" + iCurrentCounter;
1312         //}
1313         //else
1314         //{
1315         componentId = componentId + UNIQUE_ID_PREFIX + iCurrentCounter;            
1316         //}
1317 
1318         return componentId;
1319     }
1320         
1321     private void checkIfItIsInAnIterator(String jspId)
1322     {
1323         Set<String> previousJspIdsSet = getPreviousJspIdsSet();
1324 
1325         if (previousJspIdsSet.contains(jspId))
1326         {
1327             isInAnIterator = true;
1328         }
1329         else
1330         {
1331             previousJspIdsSet.add(jspId);
1332             isInAnIterator = false;
1333         }
1334     }
1335 
1336     private Set<String> getPreviousJspIdsSet()
1337     {
1338         Set<String> previousJspIdsSet = (Set<String>) getFacesContext().getExternalContext()
1339                 .getRequestMap().get(PREVIOUS_JSP_IDS_SET);
1340 
1341         if (previousJspIdsSet == null)
1342         {
1343             previousJspIdsSet = new HashSet<String>();
1344             //Add it to the context! The next time is called
1345             //this method it takes the ref from the RequestContext
1346             getFacesContext().getExternalContext().getRequestMap()
1347                 .put(PREVIOUS_JSP_IDS_SET, previousJspIdsSet);
1348         }
1349 
1350         return previousJspIdsSet;
1351     }
1352 
1353     private boolean isIdDuplicated(String componentId)
1354     {
1355         boolean result = false;
1356         if (_parentClassicTag != null)
1357         {
1358             if (_parentClassicTag.isInAnIterator)
1359             {
1360                 return true;
1361             }
1362             List childComponents = _parentClassicTag.getCreatedComponents();
1363 
1364             if (childComponents != null)
1365             {
1366                 result = childComponents.contains(componentId);
1367                 if (result && (!isInAnIterator))
1368                 {
1369                     return true;
1370                 }
1371             }
1372         }
1373 
1374         return result;
1375     }
1376 
1377     private boolean isPostBack(FacesContext facesContext)
1378     {
1379         return facesContext.getExternalContext().getRequestParameterMap().
1380               containsKey(ResponseStateManager.VIEW_STATE_PARAM);
1381     }
1382 
1383 
1384     /**
1385      * check if the facet is already added to the parent
1386      */
1387     private boolean checkFacetNameOnParentExists(UIComponentClassicTagBase parentTag, String facetName)
1388     {
1389         return parentTag._facetsAdded != null && parentTag._facetsAdded.contains(facetName);
1390     }
1391 
1392     /**
1393      * Notify the enclosing JSP tag of the id of this facet's id. The parent
1394      * tag will later delete any existing view facets that were not seen
1395      * during this rendering phase; see doEndTag for details.
1396      */
1397     private void addFacetNameToParentTag(UIComponentClassicTagBase parentTag, String facetName)
1398     {
1399         if (parentTag._facetsAdded == null)
1400         {
1401             parentTag._facetsAdded = new ArrayList<String>();
1402         }
1403         parentTag._facetsAdded.add(facetName);
1404     }
1405 
1406     protected abstract boolean hasBinding();
1407 
1408     public JspWriter getPreviousOut() {
1409         return bodyContent.getEnclosingWriter();
1410     }
1411 }