Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: javax/faces/webapp/UIComponentTag.java


1   /*
2    * Copyright 2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package javax.faces.webapp;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  
21  import javax.faces.FacesException;
22  import javax.faces.FactoryFinder;
23  import javax.faces.application.Application;
24  import javax.faces.component.UIComponent;
25  import javax.faces.component.UIViewRoot;
26  import javax.faces.context.FacesContext;
27  import javax.faces.context.ResponseWriter;
28  import javax.faces.el.ValueBinding;
29  import javax.faces.render.RenderKit;
30  import javax.faces.render.RenderKitFactory;
31  
32  import javax.servlet.jsp.JspException;
33  import javax.servlet.jsp.PageContext;
34  import javax.servlet.jsp.tagext.Tag;
35  import java.io.IOException;
36  import java.util.*;
37  
38  /**
39   * @author Manfred Geiler (latest modification by $Author: oros $)
40   * @version $Revision: 265611 $ $Date: 2005-08-31 21:05:16 -0400 (Wed, 31 Aug 2005) $
41   */
42  public abstract class UIComponentTag
43          implements Tag
44  {
45      private static final String FORMER_CHILD_IDS_SET_ATTR = UIComponentTag.class.getName() + ".FORMER_CHILD_IDS";
46      private static final String FORMER_FACET_NAMES_SET_ATTR = UIComponentTag.class.getName() + ".FORMER_FACET_NAMES";
47      private static final String COMPONENT_STACK_ATTR =  UIComponentTag.class.getName() + ".COMPONENT_STACK";
48  
49      protected PageContext pageContext = null;
50      private Tag _parent = null;
51  
52      //tag attributes
53      private String _binding = null;
54      private String _id = null;
55      private String _rendered = null;
56  
57      private FacesContext _facesContext = null;
58      private UIComponent _componentInstance = null;
59      private boolean _created = false;
60      private Boolean _suppressed = null;
61      private ResponseWriter _writer = null;
62      private Set _childrenAdded = null;
63      private Set _facetsAdded = null;
64  
65      private static Log log = LogFactory.getLog(UIComponentTag.class);
66  
67  
68      public UIComponentTag()
69      {
70  
71      }
72  
73      public void release()
74      {
75          internalRelease();
76  
77          //members, that must/need only be reset when there is no more risk, that the container
78          //wants to reuse this tag
79          pageContext = null;
80          _parent = null;
81  
82          //reset tag attribute members
83          _binding = null;
84          _id = null;
85          _rendered = null;
86      }
87  
88  
89      /**
90       * Reset any members that apply to the according component instance and
91       * must not be reused if the container wants to reuse this tag instance.
92       * This method is called when rendering for this tag is finished ( doEndTag() )
93       * or when released by the container.
94       */
95      private void internalRelease()
96      {
97          _facesContext = null;
98          _componentInstance = null;
99          _created = false;
100         _suppressed = null;
101         _writer = null;
102         _childrenAdded = null;
103         _facetsAdded = null;
104     }
105 
106 
107     public void setBinding(String binding)
108             throws JspException
109     {
110         if (!isValueReference(binding))
111         {
112             throw new IllegalArgumentException("not a valid binding: " + binding);
113         }
114         _binding = binding;
115     }
116 
117     public void setId(String id)
118     {
119         _id = id;
120     }
121 
122     protected String getId()
123     {
124         return _id;
125     }
126 
127     public void setRendered(String rendered)
128     {
129         _rendered = rendered;
130     }
131 
132     public abstract String getComponentType();
133 
134     public UIComponent getComponentInstance()
135     {
136         return _componentInstance;
137     }
138 
139     public boolean getCreated()
140     {
141         return _created;
142     }
143 
144     public static UIComponentTag getParentUIComponentTag(PageContext pageContext)
145     {
146         List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
147                                                    PageContext.REQUEST_SCOPE);
148         if (list != null)
149         {
150             return (UIComponentTag)list.get(list.size() - 1);
151         }
152         return null;
153     }
154 
155     private void popTag()
156     {
157         List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
158                                                     PageContext.REQUEST_SCOPE);
159         if (list != null)
160         {
161             int size = list.size();
162             list.remove(size -1);
163             if (size <= 1)
164             {
165                 pageContext.removeAttribute(COMPONENT_STACK_ATTR,
166                                              PageContext.REQUEST_SCOPE);
167             }
168         }
169     }
170 
171     private void pushTag()
172     {
173         List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
174                                                     PageContext.REQUEST_SCOPE);
175         if (list == null)
176         {
177             list = new ArrayList();
178             pageContext.setAttribute(COMPONENT_STACK_ATTR,
179                                       list,
180                                       PageContext.REQUEST_SCOPE);
181         }
182         list.add(this);
183     }
184 
185 
186     public abstract String getRendererType();
187 
188     public static boolean isValueReference(String value)
189     {
190         if (value == null) throw new NullPointerException("value");
191 
192         int start = value.indexOf("#{");
193         if (start < 0) return false;
194 
195         int end = value.lastIndexOf('}');
196         return (end >=0 && start < end);
197     }
198 
199     public void setPageContext(PageContext pageContext)
200     {
201         this.pageContext = pageContext;
202     }
203 
204     public Tag getParent()
205     {
206         return _parent;
207     }
208 
209     public void setParent(Tag parent)
210     {
211         _parent = parent;
212     }
213 
214     public int doStartTag()
215             throws JspException
216     {
217         setupResponseWriter();
218         FacesContext facesContext = getFacesContext();
219         UIComponent component = findComponent(facesContext);
220         if (!component.getRendersChildren() && !isSuppressed())
221         {
222             try
223             {
224                 encodeBegin();
225                 _writer.flush();
226             }
227             catch (IOException e)
228             {
229                 throw new JspException(e.getMessage(), e);
230             }
231         }
232         pushTag();
233         return getDoStartValue();
234     }
235 
236     public int doEndTag()
237             throws JspException
238     {
239         popTag();
240         UIComponent component = getComponentInstance();
241         removeFormerChildren(component);
242         removeFormerFacets(component);
243 
244         try
245         {
246             if (!isSuppressed())
247             {
248                 if (component.getRendersChildren())
249                 {
250                     encodeBegin();
251                     encodeChildren();
252                 }
253                 encodeEnd();
254             }
255         }
256         catch (IOException e)
257         {
258             throw new JspException(e.getMessage(), e);
259         }
260 
261         int retValue = getDoEndValue();
262         internalRelease();
263         return retValue;
264     }
265 
266     private void removeFormerChildren(UIComponent component)
267     {
268         Set formerChildIdsSet = (Set)component.getAttributes().get(FORMER_CHILD_IDS_SET_ATTR);
269         if (formerChildIdsSet != null)
270         {
271             for (Iterator iterator = formerChildIdsSet.iterator(); iterator.hasNext();)
272             {
273                 String childId = (String)iterator.next();
274                 if (_childrenAdded == null || !_childrenAdded.contains(childId))
275                 {
276                     UIComponent childToRemove = component.findComponent(childId);
277                     if (childToRemove != null)
278                     {
279                         component.getChildren().remove(childToRemove);
280                     }
281                 }
282             }
283             if (_childrenAdded == null)
284             {
285                 component.getAttributes().remove(FORMER_CHILD_IDS_SET_ATTR);
286             }
287             else
288             {
289                 component.getAttributes().put(FORMER_CHILD_IDS_SET_ATTR, _childrenAdded);
290             }
291         }
292         else
293         {
294             if (_childrenAdded != null)
295             {
296                 component.getAttributes().put(FORMER_CHILD_IDS_SET_ATTR, _childrenAdded);
297             }
298         }
299     }
300 
301     private void removeFormerFacets(UIComponent component)
302     {
303         Set formerFacetNamesSet = (Set)component.getAttributes().get(FORMER_FACET_NAMES_SET_ATTR);
304         if (formerFacetNamesSet != null)
305         {
306             for (Iterator iterator = formerFacetNamesSet.iterator(); iterator.hasNext();)
307             {
308                 String facetName = (String)iterator.next();
309                 if (_facetsAdded == null || !_facetsAdded.contains(facetName))
310                 {
311                     component.getFacets().remove(facetName);
312                 }
313             }
314             if (_facetsAdded == null)
315             {
316                 component.getAttributes().remove(FORMER_FACET_NAMES_SET_ATTR);
317             }
318             else
319             {
320                 component.getAttributes().put(FORMER_FACET_NAMES_SET_ATTR, _facetsAdded);
321             }
322         }
323         else
324         {
325             if (_facetsAdded != null)
326             {
327                 component.getAttributes().put(FORMER_FACET_NAMES_SET_ATTR, _facetsAdded);
328             }
329         }
330     }
331 
332 
333 
334     protected void encodeBegin()
335             throws IOException
336     {
337         _componentInstance.encodeBegin(getFacesContext());
338     }
339 
340     protected void encodeChildren()
341             throws IOException
342     {
343         _componentInstance.encodeChildren(getFacesContext());
344     }
345 
346     protected void encodeEnd()
347             throws IOException
348     {
349         _componentInstance.encodeEnd(getFacesContext());
350     }
351 
352     protected UIComponent findComponent(FacesContext context)
353             throws JspException
354     {
355         if (_componentInstance != null) return _componentInstance;
356         UIComponentTag parentTag = getParentUIComponentTag(pageContext);
357         if (parentTag == null)
358         {
359             //This is the root
360             _componentInstance = context.getViewRoot();
361             setProperties(_componentInstance);
362             return _componentInstance;
363         }
364 
365         UIComponent parent = parentTag.getComponentInstance();
366         //TODO: what if parent == null?
367         if (parent == null) throw new IllegalStateException("parent is null?");
368 
369         String facetName = getFacetName();
370         if (facetName != null)
371         {
372             //Facet
373             String id = getOrCreateUniqueId(context);
374             _componentInstance = parent.getFacet(facetName);
375             if (_componentInstance == null)
376             {
377                 _componentInstance = createComponentInstance(context, id);
378                 setProperties(_componentInstance);
379                 parent.getFacets().put(facetName, _componentInstance);
380             }
381             addFacetNameToParentTag(parentTag, facetName);
382             return _componentInstance;
383         }
384         else
385         {
386             //Child
387             String id = getOrCreateUniqueId(context);
388             _componentInstance = parent.findComponent(id);
389             if (_componentInstance == null)
390             {
391                 _componentInstance = createComponentInstance(context, id);
392                 setProperties(_componentInstance);
393                 int index = getAddedChildrenCount(parentTag);
394                 List children = parent.getChildren();
395                 if (index <= children.size())
396                 {
397                     children.add(index, _componentInstance);
398                 }
399                 else
400                 {
401                     throw new FacesException("cannot add component with id '" +
402                             _componentInstance.getId() + "' and path : "
403                             +getPathToComponent(_componentInstance)+" to its parent component. This might be a problem due to duplicate ids.");
404                 }
405             }
406             addChildIdToParentTag(parentTag, id);
407             return _componentInstance;
408         }
409     }
410 
411 
412     private String getOrCreateUniqueId(FacesContext context)
413     {
414         String id = getId();
415         if (id != null)
416         {
417             return id;
418         }
419         else
420         {
421             return context.getViewRoot().createUniqueId();
422         }
423     }
424 
425     private UIComponent createComponentInstance(FacesContext context, String id)
426     {
427         String componentType = getComponentType();
428         if (componentType == null)
429         {
430             throw new NullPointerException("componentType");
431         }
432 
433         if (_binding != null)
434         {
435             Application application = context.getApplication();
436             ValueBinding componentBinding = application.createValueBinding(_binding);
437             UIComponent component = application.createComponent(componentBinding,
438                                                                 context,
439                                                                 componentType);
440             component.setId(id);
441             component.setValueBinding("binding", componentBinding);
442             recurseFacetsAndChildrenForId(context, component.getFacetsAndChildren(), id + "_", 0);
443             _created = true;
444             return component;
445         }
446         else
447         {
448             UIComponent component = context.getApplication().createComponent(componentType);
449             component.setId(id);
450             _created = true;
451             return component;
452         }
453     }
454 
455     /**
456      * Recurse all facets and children and assign them an unique ID if necessary.
457      * We must *not* use UIViewRoot#createUniqueId here, because this would affect the
458      * order of the created ids upon rerendering the page!
459      */
460     private int recurseFacetsAndChildrenForId(FacesContext context,
461                                               Iterator facetsAndChildren,
462                                               String idPrefix,
463                                               int cnt)
464     {
465         while (facetsAndChildren.hasNext())
466         {
467             UIComponent comp = (UIComponent)facetsAndChildren.next();
468             if (comp.getId() == null)
469             {
470                 ++cnt;
471                 comp.setId(idPrefix + cnt);
472             }
473             cnt = recurseFacetsAndChildrenForId(context, comp.getFacetsAndChildren(), idPrefix, cnt);
474         }
475         return cnt;
476     }
477 
478 
479 
480     private void addChildIdToParentTag(UIComponentTag parentTag, String id)
481     {
482         if (parentTag._childrenAdded == null)
483         {
484             parentTag._childrenAdded = new HashSet();
485         }
486         parentTag._childrenAdded.add(id);
487     }
488 
489     private void addFacetNameToParentTag(UIComponentTag parentTag, String facetName)
490     {
491         if (parentTag._facetsAdded == null)
492         {
493             parentTag._facetsAdded = new HashSet();
494         }
495         parentTag._facetsAdded.add(facetName);
496     }
497 
498     private int getAddedChildrenCount(UIComponentTag parentTag)
499     {
500         return parentTag._childrenAdded != null ?
501                parentTag._childrenAdded.size() :
502                0;
503     }
504 
505 
506 
507 
508     protected int getDoStartValue()
509             throws JspException
510     {
511         return Tag.EVAL_BODY_INCLUDE;
512     }
513 
514     protected int getDoEndValue()
515             throws JspException
516     {
517         return Tag.EVAL_PAGE;
518     }
519 
520     protected FacesContext getFacesContext()
521     {
522         if (_facesContext == null)
523         {
524             _facesContext = FacesContext.getCurrentInstance();
525         }
526         return _facesContext;
527     }
528 
529 
530     private boolean isFacet()
531     {
532         return _parent != null && _parent instanceof FacetTag;
533     }
534 
535     protected String getFacetName()
536     {
537         return isFacet() ? ((FacetTag)_parent).getName() : null;
538     }
539 
540 
541     protected boolean isSuppressed()
542     {
543         if (_suppressed == null)
544         {
545             if (isFacet())
546             {
547                 // facets are always rendered by their parents --> suppressed
548                 return (_suppressed = Boolean.TRUE).booleanValue();
549             }
550 
551             UIComponent component = getComponentInstance();
552 
553             // Does any parent render its children?
554             // (We must determine this first, before calling any isRendered method
555             //  because rendered properties might reference a data var of a nesting UIData,
556             //  which is not set at this time, and would cause a VariableResolver error!)
557             UIComponent parent = component.getParent();
558             while (parent != null)
559             {
560                 if (parent.getRendersChildren())
561                 {
562                     //Yes, parent found, that renders children --> suppressed
563                     return (_suppressed = Boolean.TRUE).booleanValue();
564                 }
565                 parent = parent.getParent();
566             }
567 
568             // does component or any parent has a false rendered attribute?
569             while (component != null)
570             {
571                 if (!component.isRendered())
572                 {
573                     //Yes, component or any parent must not be rendered --> suppressed
574                     return (_suppressed = Boolean.TRUE).booleanValue();
575                 }
576                 component = component.getParent();
577             }
578 
579             // else --> not suppressed
580             _suppressed = Boolean.FALSE;
581         }
582         return _suppressed.booleanValue();
583     }
584 
585     protected void setProperties(UIComponent component)
586     {
587         if (getRendererType() != null)
588         {
589             _componentInstance.setRendererType(getRendererType());
590         }
591 
592         if (_rendered != null)
593         {
594             if (isValueReference(_rendered))
595             {
596                 ValueBinding vb = getFacesContext().getApplication().createValueBinding(_rendered);
597                 component.setValueBinding("rendered", vb);
598             } else
599             {
600                 boolean b = Boolean.valueOf(_rendered).booleanValue();
601                 component.setRendered(b);
602             }
603         }
604     }
605 
606     protected void setupResponseWriter()
607     {
608         FacesContext facesContext = getFacesContext();
609 
610         if(facesContext == null)
611         {
612             log.error("Faces context not found. getResponseWriter will fail. Check if the FacesServlet has been initialized at all in your web.xml.");
613         }
614 
615         _writer = facesContext.getResponseWriter();
616         if (_writer == null)
617         {
618             RenderKitFactory renderFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
619             RenderKit renderKit = renderFactory.getRenderKit(facesContext,
620                                                              facesContext.getViewRoot().getRenderKitId());
621 
622             _writer = renderKit.createResponseWriter(new _PageContextOutWriter(pageContext),
623                                                      null /*Default: get the allowed content-types from the accept-header*/,
624                                                      pageContext.getRequest().getCharacterEncoding());
625             facesContext.setResponseWriter(_writer);
626         }
627     }
628 
629     private String getPathToComponent(UIComponent component)
630     {
631         StringBuffer buf = new StringBuffer();
632 
633         if(component == null)
634         {
635             buf.append("{Component-Path : ");
636             buf.append("[null]}");
637             return buf.toString();
638         }
639 
640         getPathToComponent(component,buf);
641 
642         buf.insert(0,"{Component-Path : ");
643         buf.append("}");
644 
645         return buf.toString();
646     }
647 
648     private static void getPathToComponent(UIComponent component, StringBuffer buf)
649     {
650         if(component == null)
651             return;
652 
653         StringBuffer intBuf = new StringBuffer();
654 
655         intBuf.append("[Class: ");
656         intBuf.append(component.getClass().getName());
657         if(component instanceof UIViewRoot)
658         {
659             intBuf.append(",ViewId: ");
660             intBuf.append(((UIViewRoot) component).getViewId());
661         }
662         else
663         {
664             intBuf.append(",Id: ");
665             intBuf.append(component.getId());
666         }
667         intBuf.append("]");
668 
669         buf.insert(0,intBuf);
670 
671         if(component!=null)
672         {
673             getPathToComponent(component.getParent(),buf);
674         }
675     }
676 
677 }