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