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 javax.faces.application.Application;
22  import javax.faces.component.UIComponent;
23  import javax.faces.context.FacesContext;
24  import javax.faces.el.ValueBinding;
25  import javax.servlet.jsp.JspException;
26  import javax.servlet.jsp.PageContext;
27  import javax.servlet.jsp.tagext.Tag;
28  
29  /**
30   * Base class for all JSP tags that represent a JSF UIComponent.
31   * <p>
32   * <i>Disclaimer</i>: The official definition for the behaviour of
33   * this class is the JSF specification but for legal reasons the
34   * specification cannot be replicated here. Any javadoc present on this
35   * class therefore describes the current implementation rather than the
36   * officially required behaviour, though it is believed that this class
37   * does comply with the specification.
38   * 
39   * see Javadoc of <a href="http://java.sun.com/j2ee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a> for more.
40   * 
41   * @author Manfred Geiler (latest modification by $Author: skitching $)
42   * @author Bruno Aranda
43   * @version $Revision: 676298 $ $Date: 2008-07-13 05:31:48 -0500 (Sun, 13 Jul 2008) $
44   *
45   * @deprecated replaced by {@link UIComponentELTag}
46   */
47  public abstract class UIComponentTag extends UIComponentClassicTagBase
48  {
49  
50      //tag attributes
51      private String _binding = null;
52      private String _rendered = null;
53  
54      private Boolean _suppressed = null;
55  
56      public UIComponentTag()
57      {
58  
59      }
60  
61      public void release()
62      {
63          super.release();
64  
65          _binding = null;
66          _rendered = null;
67      }
68  
69      /** Setter for common JSF xml attribute "binding". */
70      public void setBinding(String binding)
71              throws JspException
72      {
73          if (!isValueReference(binding))
74          {
75              throw new IllegalArgumentException("not a valid binding: " + binding);
76          }
77          _binding = binding;
78      }
79  
80  
81      /** Setter for common JSF xml attribute "rendered". */
82      public void setRendered(String rendered)
83      {
84          _rendered = rendered;
85      }
86  
87  
88      /**
89       * Return the nearest JSF tag that encloses this tag.
90       * @deprecated
91       */
92      public static UIComponentTag getParentUIComponentTag(PageContext pageContext)
93      {
94          UIComponentClassicTagBase parentTag = getParentUIComponentClassicTagBase(pageContext);
95  
96          return parentTag instanceof UIComponentTag ? (UIComponentTag) parentTag : new UIComponentTagWrapper(parentTag);
97          
98      }
99  
100     /**
101      * Return true if the specified string contains an EL expression.
102      * <p>
103      * UIComponent properties are often required to be value-binding
104      * expressions; this method allows code to check whether that is
105      * the case or not.
106      */
107     public static boolean isValueReference(String value)
108     {
109         if (value == null) throw new NullPointerException("value");
110 
111         int start = value.indexOf("#{");
112         if (start < 0) return false;
113 
114         int end = value.lastIndexOf('}');
115         return (end >=0 && start < end);
116     }
117 
118     /**
119      * Create a UIComponent. Abstract method getComponentType is invoked to
120      * determine the actual type name for the component to be created.
121      *
122      * If this tag has a "binding" attribute, then that is immediately
123      * evaluated to store the created component in the specified property.
124      */
125     protected UIComponent createComponent(FacesContext context, String id) 
126     {
127         String componentType = getComponentType();
128         if (componentType == null)
129         {
130             throw new NullPointerException("componentType");
131         }
132 
133         if (_binding != null)
134         {
135             Application application = context.getApplication();
136             ValueBinding componentBinding = application.createValueBinding(_binding);
137             UIComponent component = application.createComponent(componentBinding,
138                                                                 context,
139                                                                 componentType);
140             
141             component.setId(id);
142             component.setValueBinding("binding", componentBinding);
143             setProperties(component);
144             
145             return component;
146         }
147 
148         UIComponent component = context.getApplication().createComponent(componentType);
149         component.setId(id);
150         setProperties(component);
151 
152         return component;
153         
154     }
155 
156 
157     private boolean isFacet()
158     {
159         return getParent() != null && getParent() instanceof FacetTag;
160     }
161 
162     /**
163      * Determine whether this component renders itself. A component
164      * is "suppressed" when it is either not rendered, or when it is
165      * rendered by its parent component at a time of the parent's choosing.
166      */
167     protected boolean isSuppressed()
168     {
169         if (_suppressed == null)
170         {
171             // we haven't called this method before, so determine the suppressed
172             // value and cache it for later calls to this method.
173 
174             if (isFacet())
175             {
176                 // facets are always rendered by their parents --> suppressed
177                 _suppressed = Boolean.TRUE;
178                 return true;
179             }
180 
181             UIComponent component = getComponentInstance();
182 
183             // Does any parent render its children?
184             // (We must determine this first, before calling any isRendered method
185             //  because rendered properties might reference a data var of a nesting UIData,
186             //  which is not set at this time, and would cause a VariableResolver error!)
187             UIComponent parent = component.getParent();
188             while (parent != null)
189             {
190                 if (parent.getRendersChildren())
191                 {
192                     //Yes, parent found, that renders children --> suppressed
193                     _suppressed = Boolean.TRUE;
194                     return true;
195                 }
196                 parent = parent.getParent();
197             }
198 
199             // does component or any parent has a false rendered attribute?
200             while (component != null)
201             {
202                 if (!component.isRendered())
203                 {
204                     //Yes, component or any parent must not be rendered --> suppressed
205                     _suppressed = Boolean.TRUE;
206                     return true;
207                 }
208                 component = component.getParent();
209             }
210 
211             // else --> not suppressed
212             _suppressed = Boolean.FALSE;
213         }
214         return _suppressed.booleanValue();
215     }
216 
217     protected void setProperties(UIComponent component)
218     {
219         if (getRendererType() != null)
220         {
221             component.setRendererType(getRendererType());
222         }
223 
224         if (_rendered != null)
225         {
226             if (isValueReference(_rendered))
227             {
228                 ValueBinding vb = getFacesContext().getApplication().createValueBinding(_rendered);
229                 component.setValueBinding("rendered", vb);
230             } else
231             {
232                 boolean b = Boolean.valueOf(_rendered).booleanValue();
233                 component.setRendered(b);
234             }
235         }
236     }
237 
238     /**
239      * Class used to create an UIComponentTag from a UIComponentClassicTagBase.
240      * <p>
241      * This is a standard use of the decorator pattern, to make the logic of the JSF12
242      * UIComponentClassicTagBase class available via the old JSF11 UIComponentTag
243      * api.
244      */
245     private static class UIComponentTagWrapper extends UIComponentTag
246     {
247         private UIComponentClassicTagBase target;
248 
249         public UIComponentTagWrapper(UIComponentClassicTagBase classicTag)
250         {
251             target = classicTag;
252         }
253 
254         // -----------------------------------------------------------
255         // Methods that can reasonably be called on a parent tag object
256         // -----------------------------------------------------------
257 
258         @Override
259         public String getComponentType()
260         {
261             return target.getComponentType();
262         }
263 
264         @Override
265         public String getRendererType()
266         {
267             return target.getRendererType();
268         }
269 
270         @Override
271         public boolean getCreated()
272         {
273             return target.getCreated();
274         }
275 
276         @Override
277         public String getId()
278         {
279             return target.getId();
280         }
281 
282         @Override
283         public UIComponent getComponentInstance()
284         {
285             return target.getComponentInstance();
286         }
287 
288         @Override
289         public Tag getParent()
290         {
291             return target.getParent();
292         }
293 
294         // -----------------------------------------------------------
295         // Methods that should never be called on a parent tag object
296         // -----------------------------------------------------------
297 
298         @Override
299         public void release()
300         {
301             throw new UnsupportedOperationException();
302         }
303 
304         @Override
305         public void setBinding(String binding) throws JspException
306         {
307             throw new UnsupportedOperationException();
308         }
309 
310         @Override
311         public void setId(String id)
312         {
313             throw new UnsupportedOperationException();
314         }
315 
316         @Override
317         public void setRendered(String state)
318         {
319             throw new UnsupportedOperationException();
320         }
321 
322         @Override
323         protected UIComponent createComponent(FacesContext context, String newId)
324         {
325             throw new UnsupportedOperationException();
326         }
327 
328         @Override
329         public void setPageContext(PageContext context)
330         {
331             throw new UnsupportedOperationException();
332         }
333 
334         @Override
335         public void setParent(Tag parent)
336         {
337             throw new UnsupportedOperationException();
338         }
339 
340         @Override
341         protected UIComponent findComponent(FacesContext context) throws JspException
342         {
343             throw new UnsupportedOperationException();
344         }
345 
346         @Override
347         protected FacesContext getFacesContext()
348         {
349             throw new UnsupportedOperationException();
350         }
351 
352         // Methods that no sane user of this class would call, so we do not need to override here:
353         //   doStartTag, doEndTag, getDoStartValue, getDoEndValue, isSupressed
354         //   encodeBegin, encodeChildren, encodeEnd, getFacetName
355         //   setProperties, setupResponseWriter
356     }
357 
358     @Override
359     protected boolean hasBinding()
360     {
361         return _binding != null;
362     }
363 }