KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javax > faces > webapp > UIComponentTag


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 javax.faces.FacesException;
19 import javax.faces.FactoryFinder;
20 import javax.faces.application.Application;
21 import javax.faces.component.UIComponent;
22 import javax.faces.component.UIViewRoot;
23 import javax.faces.context.FacesContext;
24 import javax.faces.context.ResponseWriter;
25 import javax.faces.el.ValueBinding;
26 import javax.faces.render.RenderKit;
27 import javax.faces.render.RenderKitFactory;
28 import javax.servlet.ServletRequest JavaDoc;
29 import javax.servlet.jsp.JspException JavaDoc;
30 import javax.servlet.jsp.PageContext JavaDoc;
31 import javax.servlet.jsp.tagext.Tag JavaDoc;
32 import java.io.IOException JavaDoc;
33 import java.util.*;
34
35 /**
36  * @author Manfred Geiler (latest modification by $Author: matzew $)
37  * @version $Revision: 1.26 $ $Date: 2005/03/15 18:43:42 $
38  * $Log: UIComponentTag.java,v $
39  * Revision 1.26 2005/03/15 18:43:42 matzew
40  * Patch from Stan Silver FOR MYFACES-123
41  *
42  * Revision 1.25 2005/03/12 02:17:52 mmarinschek
43  * ui component logging enhanced
44  *
45  * Revision 1.24 2005/03/12 02:15:18 mmarinschek
46  * jsvalueset now supports maps of maps; ui component logging enhanced
47  *
48  * Revision 1.23 2004/08/27 12:47:52 manolito
49  * automatically assign IDs to facets and children of components that where created by binding
50  *
51  * Revision 1.22 2004/07/05 23:43:36 o_rossmueller
52  * fix #985274: call setProperties for viewRoot
53  *
54  * Revision 1.21 2004/07/01 22:00:54 mwessendorf
55  * ASF switch
56  *
57  * Revision 1.20 2004/04/26 13:13:52 manolito
58  * always release facesContext
59  *
60  * Revision 1.19 2004/04/26 12:01:39 manolito
61  * more reluctant releasing of members for Resin compatibility
62  *
63  * Revision 1.18 2004/04/20 11:16:23 royalts
64  * no message
65  *
66  * Revision 1.17 2004/04/20 11:11:03 royalts
67  * no message
68  *
69  * Revision 1.16 2004/04/20 10:54:21 royalts
70  * added index check to findComponent
71  *
72  * Revision 1.15 2004/03/31 12:48:03 manolito
73  * bug: newly created children added always at end
74  *
75  * Revision 1.14 2004/03/31 02:29:41 dave0000
76  * avoid lastIndexOf scan if not needed
77  *
78  * Revision 1.13 2004/03/26 11:48:33 manolito
79  * additional NPE check
80  */

81 public abstract class UIComponentTag
82         implements Tag JavaDoc
83 {
84     private static final String JavaDoc FORMER_CHILD_IDS_SET_ATTR = UIComponentTag.class.getName() + ".FORMER_CHILD_IDS";
85     private static final String JavaDoc FORMER_FACET_NAMES_SET_ATTR = UIComponentTag.class.getName() + ".FORMER_FACET_NAMES";
86     private static final String JavaDoc COMPONENT_STACK_ATTR = UIComponentTag.class.getName() + ".COMPONENT_STACK";
87
88     protected PageContext JavaDoc pageContext = null;
89     private Tag JavaDoc _parent = null;
90
91     //tag attributes
92
private String JavaDoc _binding = null;
93     private String JavaDoc _id = null;
94     private String JavaDoc _rendered = null;
95
96     private FacesContext _facesContext = null;
97     private UIComponent _componentInstance = null;
98     private boolean _created = false;
99     private Boolean JavaDoc _suppressed = null;
100     private ResponseWriter _writer = null;
101     private Set _childrenAdded = null;
102     private Set _facetsAdded = null;
103
104
105     public UIComponentTag()
106     {
107
108     }
109
110     public void release()
111     {
112         internalRelease();
113
114         //members, that must/need only be reset when there is no more risk, that the container
115
//wants to reuse this tag
116
pageContext = null;
117         _parent = null;
118
119         //reset tag attribute members
120
_binding = null;
121         _id = null;
122         _rendered = null;
123     }
124
125
126     /**
127      * Reset any members that apply to the according component instance and
128      * must not be reused if the container wants to reuse this tag instance.
129      * This method is called when rendering for this tag is finished ( doEndTag() )
130      * or when released by the container.
131      */

132     private void internalRelease()
133     {
134         _facesContext = null;
135         _componentInstance = null;
136         _created = false;
137         _suppressed = null;
138         _writer = null;
139         _childrenAdded = null;
140         _facetsAdded = null;
141     }
142
143
144     public void setBinding(String JavaDoc binding)
145             throws JspException JavaDoc
146     {
147         if (!isValueReference(binding))
148         {
149             throw new IllegalArgumentException JavaDoc("not a valid binding: " + binding);
150         }
151         _binding = binding;
152     }
153
154     public void setId(String JavaDoc id)
155     {
156         _id = id;
157     }
158
159     public String JavaDoc getId()
160     {
161         return _id;
162     }
163
164     public void setRendered(String JavaDoc rendered)
165     {
166         _rendered = rendered;
167     }
168
169     public abstract String JavaDoc getComponentType();
170
171     public UIComponent getComponentInstance()
172     {
173         return _componentInstance;
174     }
175
176     public boolean getCreated()
177     {
178         return _created;
179     }
180
181     public static UIComponentTag getParentUIComponentTag(PageContext JavaDoc pageContext)
182     {
183         List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
184                                                    PageContext.REQUEST_SCOPE);
185         if (list != null)
186         {
187             return (UIComponentTag)list.get(list.size() - 1);
188         }
189         return null;
190     }
191
192     private void popTag()
193     {
194         List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
195                                                     PageContext.REQUEST_SCOPE);
196         if (list != null)
197         {
198             int size = list.size();
199             list.remove(size -1);
200             if (size <= 1)
201             {
202                 pageContext.removeAttribute(COMPONENT_STACK_ATTR,
203                                              PageContext.REQUEST_SCOPE);
204             }
205         }
206     }
207
208     private void pushTag()
209     {
210         List list = (List)pageContext.getAttribute(COMPONENT_STACK_ATTR,
211                                                     PageContext.REQUEST_SCOPE);
212         if (list == null)
213         {
214             list = new ArrayList();
215             pageContext.setAttribute(COMPONENT_STACK_ATTR,
216                                       list,
217                                       PageContext.REQUEST_SCOPE);
218         }
219         list.add(this);
220     }
221
222
223     public abstract String JavaDoc getRendererType();
224
225     public static boolean isValueReference(String JavaDoc value)
226     {
227         if (value == null) throw new NullPointerException JavaDoc("value");
228         
229         int start = value.indexOf("#{");
230         if (start < 0) return false;
231         
232         int end = value.lastIndexOf('}');
233         return (end >=0 && start < end);
234     }
235
236     public void setPageContext(PageContext JavaDoc pageContext)
237     {
238         this.pageContext = pageContext;
239     }
240
241     public Tag JavaDoc getParent()
242     {
243         return _parent;
244     }
245
246     public void setParent(Tag JavaDoc parent)
247     {
248         _parent = parent;
249     }
250
251     public int doStartTag()
252             throws JspException JavaDoc
253     {
254         setupResponseWriter();
255         FacesContext facesContext = getFacesContext();
256         UIComponent component = findComponent(facesContext);
257         if (!component.getRendersChildren() && !isSuppressed())
258         {
259             try
260             {
261                 encodeBegin();
262                 _writer.flush();
263             }
264             catch (IOException JavaDoc e)
265             {
266                 throw new JspException JavaDoc(e.getMessage(), e);
267             }
268         }
269         pushTag();
270         return getDoStartValue();
271     }
272
273     public int doEndTag()
274             throws JspException JavaDoc
275     {
276         popTag();
277         UIComponent component = getComponentInstance();
278         removeFormerChildren(component);
279         removeFormerFacets(component);
280
281         try
282         {
283             if (!isSuppressed())
284             {
285                 if (component.getRendersChildren())
286                 {
287                     encodeBegin();
288                     encodeChildren();
289                 }
290                 encodeEnd();
291             }
292         }
293         catch (IOException JavaDoc e)
294         {
295             throw new JspException JavaDoc(e.getMessage(), e);
296         }
297
298         int retValue = getDoEndValue();
299         internalRelease();
300         return retValue;
301     }
302
303     private void removeFormerChildren(UIComponent component)
304     {
305         Set formerChildIdsSet = (Set)component.getAttributes().get(FORMER_CHILD_IDS_SET_ATTR);
306         if (formerChildIdsSet != null)
307         {
308             for (Iterator iterator = formerChildIdsSet.iterator(); iterator.hasNext();)
309             {
310                 String JavaDoc childId = (String JavaDoc)iterator.next();
311                 if (_childrenAdded == null || !_childrenAdded.contains(childId))
312                 {
313                     UIComponent childToRemove = component.findComponent(childId);
314                     if (childToRemove != null)
315                     {
316                         component.getChildren().remove(childToRemove);
317                     }
318                 }
319             }
320             if (_childrenAdded == null)
321             {
322                 component.getAttributes().remove(FORMER_CHILD_IDS_SET_ATTR);
323             }
324             else
325             {
326                 component.getAttributes().put(FORMER_CHILD_IDS_SET_ATTR, _childrenAdded);
327             }
328         }
329         else
330         {
331             if (_childrenAdded != null)
332             {
333                 component.getAttributes().put(FORMER_CHILD_IDS_SET_ATTR, _childrenAdded);
334             }
335         }
336     }
337
338     private void removeFormerFacets(UIComponent component)
339     {
340         Set formerFacetNamesSet = (Set)component.getAttributes().get(FORMER_FACET_NAMES_SET_ATTR);
341         if (formerFacetNamesSet != null)
342         {
343             for (Iterator iterator = formerFacetNamesSet.iterator(); iterator.hasNext();)
344             {
345                 String JavaDoc facetName = (String JavaDoc)iterator.next();
346                 if (_facetsAdded == null || !_facetsAdded.contains(facetName))
347                 {
348                     component.getFacets().remove(facetName);
349                 }
350             }
351             if (_facetsAdded == null)
352             {
353                 component.getAttributes().remove(FORMER_FACET_NAMES_SET_ATTR);
354             }
355             else
356             {
357                 component.getAttributes().put(FORMER_FACET_NAMES_SET_ATTR, _facetsAdded);
358             }
359         }
360         else
361         {
362             if (_facetsAdded != null)
363             {
364                 component.getAttributes().put(FORMER_FACET_NAMES_SET_ATTR, _facetsAdded);
365             }
366         }
367     }
368
369
370
371     protected void encodeBegin()
372             throws IOException JavaDoc
373     {
374         _componentInstance.encodeBegin(getFacesContext());
375     }
376
377     protected void encodeChildren()
378             throws IOException JavaDoc
379     {
380         _componentInstance.encodeChildren(getFacesContext());
381     }
382
383     protected void encodeEnd()
384             throws IOException JavaDoc
385     {
386         _componentInstance.encodeEnd(getFacesContext());
387     }
388
389     protected UIComponent findComponent(FacesContext context)
390             throws JspException JavaDoc
391     {
392         if (_componentInstance != null) return _componentInstance;
393         UIComponentTag parentTag = getParentUIComponentTag(pageContext);
394         if (parentTag == null)
395         {
396             //This is the root
397
_componentInstance = context.getViewRoot();
398             setProperties(_componentInstance);
399             return _componentInstance;
400         }
401
402         UIComponent parent = parentTag.getComponentInstance();
403         //TODO: what if parent == null?
404
if (parent == null) throw new IllegalStateException JavaDoc("parent is null?");
405
406         String JavaDoc facetName = getFacetName();
407         if (facetName != null)
408         {
409             //Facet
410
String JavaDoc id = getOrCreateUniqueId(context);
411             _componentInstance = parent.getFacet(facetName);
412             if (_componentInstance == null)
413             {
414                 _componentInstance = createComponentInstance(context, id);
415                 setProperties(_componentInstance);
416                 parent.getFacets().put(facetName, _componentInstance);
417             }
418             addFacetNameToParentTag(parentTag, facetName);
419             return _componentInstance;
420         }
421         else
422         {
423             //Child
424
String JavaDoc id = getOrCreateUniqueId(context);
425             _componentInstance = parent.findComponent(id);
426             if (_componentInstance == null)
427             {
428                 _componentInstance = createComponentInstance(context, id);
429                 setProperties(_componentInstance);
430                 int index = getAddedChildrenCount(parentTag);
431                 List children = parent.getChildren();
432                 if (index <= children.size())
433                 {
434                     children.add(index, _componentInstance);
435                 }
436                 else
437                 {
438                     throw new FacesException("cannot add component with id '" +
439                             _componentInstance.getId() + "' and path : "
440                             +getPathToComponent(_componentInstance)+" to its parent component. This might be a problem due to duplicate ids.");
441                 }
442             }
443             addChildIdToParentTag(parentTag, id);
444             return _componentInstance;
445         }
446     }
447
448
449     private String JavaDoc getOrCreateUniqueId(FacesContext context)
450     {
451         String JavaDoc id = getId();
452         if (id != null)
453         {
454             return id;
455         }
456         else
457         {
458             return context.getViewRoot().createUniqueId();
459         }
460     }
461
462     private UIComponent createComponentInstance(FacesContext context, String JavaDoc id)
463     {
464         String JavaDoc componentType = getComponentType();
465         if (componentType == null)
466         {
467             throw new NullPointerException JavaDoc("componentType");
468         }
469
470         if (_binding != null)
471         {
472             Application application = context.getApplication();
473             ValueBinding componentBinding = application.createValueBinding(_binding);
474             UIComponent component = application.createComponent(componentBinding,
475                                                                 context,
476                                                                 componentType);
477             component.setId(id);
478             component.setValueBinding("binding", componentBinding);
479             recurseFacetsAndChildrenForId(context, component.getFacetsAndChildren(), id + "_", 0);
480             _created = true;
481             return component;
482         }
483         else
484         {
485             UIComponent component = context.getApplication().createComponent(componentType);
486             component.setId(id);
487             _created = true;
488             return component;
489         }
490     }
491
492     /**
493      * Recurse all facets and children and assign them an unique ID if necessary.
494      * We must *not* use UIViewRoot#createUniqueId here, because this would affect the
495      * order of the created ids upon rerendering the page!
496      */

497     private int recurseFacetsAndChildrenForId(FacesContext context,
498                                               Iterator facetsAndChildren,
499                                               String JavaDoc idPrefix,
500                                               int cnt)
501     {
502         while (facetsAndChildren.hasNext())
503         {
504             UIComponent comp = (UIComponent)facetsAndChildren.next();
505             if (comp.getId() == null)
506             {
507                 ++cnt;
508                 comp.setId(idPrefix + cnt);
509             }
510             cnt = recurseFacetsAndChildrenForId(context, comp.getFacetsAndChildren(), idPrefix, cnt);
511         }
512         return cnt;
513     }
514
515
516
517     private void addChildIdToParentTag(UIComponentTag parentTag, String JavaDoc id)
518     {
519         if (parentTag._childrenAdded == null)
520         {
521             parentTag._childrenAdded = new HashSet();
522         }
523         parentTag._childrenAdded.add(id);
524     }
525
526     private void addFacetNameToParentTag(UIComponentTag parentTag, String JavaDoc facetName)
527     {
528         if (parentTag._facetsAdded == null)
529         {
530             parentTag._facetsAdded = new HashSet();
531         }
532         parentTag._facetsAdded.add(facetName);
533     }
534                              
535     private int getAddedChildrenCount(UIComponentTag parentTag)
536     {
537         return parentTag._childrenAdded != null ?
538                parentTag._childrenAdded.size() :
539                0;
540     }
541
542
543
544
545     protected int getDoStartValue()
546             throws JspException JavaDoc
547     {
548         return Tag.EVAL_BODY_INCLUDE;
549     }
550
551     protected int getDoEndValue()
552             throws JspException JavaDoc
553     {
554         return Tag.EVAL_PAGE;
555     }
556
557     protected FacesContext getFacesContext()
558     {
559         if (_facesContext == null)
560         {
561             _facesContext = FacesContext.getCurrentInstance();
562         }
563         return _facesContext;
564     }
565
566
567     private boolean isFacet()
568     {
569         return _parent != null && _parent instanceof FacetTag;
570     }
571
572     protected String JavaDoc getFacetName()
573     {
574         return isFacet() ? ((FacetTag)_parent).getName() : null;
575     }
576
577
578     protected boolean isSuppressed()
579     {
580         if (_suppressed == null)
581         {
582             if (isFacet())
583             {
584                 // facets are always rendered by their parents --> suppressed
585
return (_suppressed = Boolean.TRUE).booleanValue();
586             }
587
588             UIComponent component = getComponentInstance();
589
590             // Does any parent render its children?
591
// (We must determine this first, before calling any isRendered method
592
// because rendered properties might reference a data var of a nesting UIData,
593
// which is not set at this time, and would cause a VariableResolver error!)
594
UIComponent parent = component.getParent();
595             while (parent != null)
596             {
597                 if (parent.getRendersChildren())
598                 {
599                     //Yes, parent found, that renders children --> suppressed
600
return (_suppressed = Boolean.TRUE).booleanValue();
601                 }
602                 parent = parent.getParent();
603             }
604
605             // does component or any parent has a false rendered attribute?
606
while (component != null)
607             {
608                 if (!component.isRendered())
609                 {
610                     //Yes, component or any parent must not be rendered --> suppressed
611
return (_suppressed = Boolean.TRUE).booleanValue();
612                 }
613                 component = component.getParent();
614             }
615
616             // else --> not suppressed
617
_suppressed = Boolean.FALSE;
618         }
619         return _suppressed.booleanValue();
620     }
621
622     protected void setProperties(UIComponent component)
623     {
624         if (getRendererType() != null)
625         {
626             _componentInstance.setRendererType(getRendererType());
627         }
628
629         if (_rendered != null)
630         {
631             if (isValueReference(_rendered))
632             {
633                 ValueBinding vb = getFacesContext().getApplication().createValueBinding(_rendered);
634                 component.setValueBinding("rendered", vb);
635             } else
636             {
637                 boolean b = Boolean.valueOf(_rendered).booleanValue();
638                 component.setRendered(b);
639             }
640         }
641     }
642
643     protected void setupResponseWriter()
644     {
645         FacesContext facesContext = getFacesContext();
646         _writer = facesContext.getResponseWriter();
647         if (_writer == null)
648         {
649             RenderKitFactory renderFactory = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
650             RenderKit renderKit = renderFactory.getRenderKit(facesContext,
651                                                              facesContext.getViewRoot().getRenderKitId());
652             
653             _writer = renderKit.createResponseWriter(new _PageContextOutWriter(pageContext),
654                                                      pageContext.getRequest().getContentType(), //TODO: is this the correct content type?
655
pageContext.getRequest().getCharacterEncoding());
656             facesContext.setResponseWriter(_writer);
657         }
658     }
659
660     public static String JavaDoc getPathToComponent(UIComponent component)
661     {
662         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
663
664         if(component == null)
665         {
666             buf.append("{Component-Path : ");
667             buf.append("[null]}");
668             return buf.toString();
669         }
670
671         getPathToComponent(component,buf);
672
673         buf.insert(0,"{Component-Path : ");
674         buf.append("}");
675
676         return buf.toString();
677     }
678
679     private static void getPathToComponent(UIComponent component, StringBuffer JavaDoc buf)
680     {
681         if(component == null)
682             return;
683
684         StringBuffer JavaDoc intBuf = new StringBuffer JavaDoc();
685
686         intBuf.append("[Class: ");
687         intBuf.append(component.getClass().getName());
688         if(component instanceof UIViewRoot)
689         {
690             intBuf.append(",ViewId: ");
691             intBuf.append(((UIViewRoot) component).getViewId());
692         }
693         else
694         {
695             intBuf.append(",Id: ");
696             intBuf.append(component.getId());
697         }
698         intBuf.append("]");
699
700         buf.insert(0,intBuf);
701
702         if(component!=null)
703         {
704             getPathToComponent(component.getParent(),buf);
705         }
706     }
707
708 }
709
Popular Tags