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.component;
20  
21  import javax.el.ValueExpression;
22  import javax.faces.application.FacesMessage;
23  import javax.faces.context.FacesContext;
24  import javax.faces.el.EvaluationException;
25  import javax.faces.el.MethodBinding;
26  import javax.faces.el.ValueBinding;
27  import javax.faces.validator.Validator;
28  import javax.faces.validator.ValidatorException;
29  import java.util.Collection;
30  import java.util.Iterator;
31  
32  /**
33   * A collection of static helper methods for locating UIComponents.
34   * 
35   * @author Manfred Geiler (latest modification by $Author: bommel $)
36   * @version $Revision: 1187700 $ $Date: 2011-10-22 07:19:37 -0500 (Sat, 22 Oct 2011) $
37   */
38  class _ComponentUtils
39  {
40      private _ComponentUtils()
41      {
42      }
43  
44      static UIComponent findParentNamingContainer(UIComponent component, boolean returnRootIfNotFound)
45      {
46          UIComponent parent = component.getParent();
47          if (returnRootIfNotFound && parent == null)
48          {
49              return component;
50          }
51          while (parent != null)
52          {
53              if (parent instanceof NamingContainer)
54                  return parent;
55              if (returnRootIfNotFound)
56              {
57                  UIComponent nextParent = parent.getParent();
58                  if (nextParent == null)
59                  {
60                      return parent; // Root
61                  }
62                  parent = nextParent;
63              }
64              else
65              {
66                  parent = parent.getParent();
67              }
68          }
69          return null;
70      }
71  
72      static UniqueIdVendor findParentUniqueIdVendor(UIComponent component)
73      {
74          UIComponent parent = component.getParent();
75  
76          while (parent != null)
77          {
78              if (parent instanceof UniqueIdVendor)
79              {
80                  return (UniqueIdVendor) parent;
81              }
82              parent = parent.getParent();
83          }
84          return null;
85      }
86      
87      static UIComponent getRootComponent(UIComponent component)
88      {
89          UIComponent parent;
90          for (;;)
91          {
92              parent = component.getParent();
93              if (parent == null)
94                  return component;
95              component = parent;
96          }
97      }
98  
99      /**
100      * Find the component with the specified id starting from the specified component.
101      * <p>
102      * Param id must not contain any NamingContainer.SEPARATOR_CHAR characters (ie ":"). This method explicitly does
103      * <i>not</i> search into any child naming container components; this is expected to be handled by the caller of
104      * this method.
105      * <p>
106      * For an implementation of findComponent which does descend into child naming components, see
107      * org.apache.myfaces.custom.util.ComponentUtils.
108      * 
109      * @return findBase, a descendant of findBase, or null.
110      */
111     static UIComponent findComponent(UIComponent findBase, String id, final char separatorChar)
112     {
113 
114         if (!(findBase instanceof NamingContainer) && idsAreEqual(id, findBase, separatorChar))
115         {
116             return findBase;
117         }
118 
119         int facetCount = findBase.getFacetCount();
120         if (facetCount > 0)
121         {
122             for (UIComponent facet : findBase.getFacets().values())
123             {
124                 if (!(facet instanceof NamingContainer))
125                 {
126                     UIComponent find = findComponent(facet, id, separatorChar);
127                     if (find != null)
128                         return find;
129                 }
130                 else if (idsAreEqual(id, facet, separatorChar))
131                 {
132                     return facet;
133                 }
134             }
135         }
136         
137         for (int i = 0, childCount = findBase.getChildCount(); i < childCount; i++)
138         {
139             UIComponent child = findBase.getChildren().get(i);
140             if (!(child instanceof NamingContainer))
141             {
142                 UIComponent find = findComponent(child, id, separatorChar);
143                 if (find != null)
144                     return find;
145             }
146             else if (idsAreEqual(id, child, separatorChar))
147             {
148                 return child;
149             }
150         }
151 
152         if (findBase instanceof NamingContainer && idsAreEqual(id, findBase, separatorChar))
153         {
154             return findBase;
155         }
156 
157         return null;
158     }
159     
160     static UIComponent findComponentChildOrFacetFrom(UIComponent parent, String id, String innerExpr)
161     {
162         if (parent.getFacetCount() > 0)
163         {
164             for (UIComponent facet : parent.getFacets().values())
165             {
166                 if (id.equals(facet.getId()))
167                 {
168                     if (innerExpr == null)
169                     {
170                         return facet;
171                     }
172                     else if (facet instanceof NamingContainer)
173                     {
174                         UIComponent find = facet.findComponent(innerExpr);
175                         if (find != null)
176                         {
177                             return find;
178                         }
179                     }
180                 }
181                 else if (!(facet instanceof NamingContainer))
182                 {
183                     UIComponent find = findComponentChildOrFacetFrom(facet, id, innerExpr);
184                     if (find != null)
185                     {
186                         return find;
187                     }
188                 }
189             }
190         }
191         if (parent.getChildCount() > 0)
192         {
193             for (int i = 0, childCount = parent.getChildCount(); i < childCount; i++)
194             {
195                 UIComponent child = parent.getChildren().get(i);
196                 if (id.equals(child.getId()))
197                 {
198                     if (innerExpr == null)
199                     {
200                         return child;
201                     }
202                     else if (child instanceof NamingContainer)
203                     {
204                         UIComponent find = child.findComponent(innerExpr);
205                         if (find != null)
206                         {
207                             return find;
208                         }
209                     }
210                 }
211                 else if (!(child instanceof NamingContainer))
212                 {
213                     UIComponent find = findComponentChildOrFacetFrom(child, id, innerExpr);
214                     if (find != null)
215                     {
216                         return find;
217                     }
218                 }
219             }
220         }
221         return null;
222     }
223 
224     /*
225      * Return true if the specified component matches the provided id. This needs some quirks to handle components whose
226      * id value gets dynamically "tweaked", eg a UIData component whose id gets the current row index appended to it.
227      */
228     private static boolean idsAreEqual(String id, UIComponent cmp, final char separatorChar)
229     {
230         if (id.equals(cmp.getId()))
231             return true;
232 
233         /* By the spec, findComponent algorithm does not take into account UIData.rowIndex() property,
234          * because it just scan over nested plain ids. 
235         if (cmp instanceof UIData)
236         {
237             UIData uiData = ((UIData)cmp);
238 
239             if (uiData.getRowIndex() == -1)
240             {
241                 return dynamicIdIsEqual(id, cmp.getId());
242             }
243             return id.equals(cmp.getId() + separatorChar + uiData.getRowIndex());
244         }
245         */
246 
247         return false;
248     }
249 
250     private static boolean dynamicIdIsEqual(String dynamicId, String id)
251     {
252         return dynamicId.matches(id + ":[0-9]*");
253     }
254 
255     static void callValidators(FacesContext context, UIInput input, Object convertedValue)
256     {
257         // first invoke the list of validator components
258         Validator[] validators = input.getValidators();
259         for (int i = 0; i < validators.length; i++)
260         {
261             Validator validator = validators[i];
262             try
263             {
264                 validator.validate(context, input, convertedValue);
265             }
266             catch (ValidatorException e)
267             {
268                 input.setValid(false);
269 
270                 String validatorMessage = input.getValidatorMessage();
271                 if (validatorMessage != null)
272                 {
273                     context.addMessage(input.getClientId(context), new FacesMessage(FacesMessage.SEVERITY_ERROR,
274                         validatorMessage, validatorMessage));
275                 }
276                 else
277                 {
278                     FacesMessage facesMessage = e.getFacesMessage();
279                     if (facesMessage != null)
280                     {
281                         facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
282                         context.addMessage(input.getClientId(context), facesMessage);
283                     }
284                     Collection<FacesMessage> facesMessages = e.getFacesMessages();
285                     if (facesMessages != null)
286                     {
287                         for (FacesMessage message : facesMessages)
288                         {
289                             message.setSeverity(FacesMessage.SEVERITY_ERROR);
290                             context.addMessage(input.getClientId(context), message);
291                         }
292                     }
293                 }
294             }
295         }
296 
297         // now invoke the validator method defined as a method-binding attribute
298         // on the component
299         MethodBinding validatorBinding = input.getValidator();
300         if (validatorBinding != null)
301         {
302             try
303             {
304                 validatorBinding.invoke(context, new Object[] { context, input, convertedValue });
305             }
306             catch (EvaluationException e)
307             {
308                 input.setValid(false);
309                 Throwable cause = e.getCause();
310                 if (cause instanceof ValidatorException)
311                 {
312                     String validatorMessage = input.getValidatorMessage();
313                     if (validatorMessage != null)
314                     {
315                         context.addMessage(input.getClientId(context), new FacesMessage(FacesMessage.SEVERITY_ERROR,
316                             validatorMessage, validatorMessage));
317                     }
318                     else
319                     {
320                         FacesMessage facesMessage = ((ValidatorException)cause).getFacesMessage();
321                         if (facesMessage != null)
322                         {
323                             facesMessage.setSeverity(FacesMessage.SEVERITY_ERROR);
324                             context.addMessage(input.getClientId(context), facesMessage);
325                         }
326                         Collection<FacesMessage> facesMessages = ((ValidatorException)cause).getFacesMessages();
327                         if (facesMessages != null)
328                         {
329                             for (FacesMessage message : facesMessages)
330                             {
331                                 message.setSeverity(FacesMessage.SEVERITY_ERROR);
332                                 context.addMessage(input.getClientId(context), message);
333                             }
334                         }
335                     }
336                 }
337                 else
338                 {
339                     throw e;
340                 }
341             }
342         }
343     }
344 
345     static String getStringValue(FacesContext context, ValueBinding vb)
346     {
347         Object value = vb.getValue(context);
348         if (value == null)
349         {
350             return null;
351         }
352         return value.toString();
353     }
354 
355     @SuppressWarnings("unchecked")
356     static <T> T getExpressionValue(UIComponent component, String attribute, T overrideValue, T defaultValue)
357     {
358         if (overrideValue != null)
359         {
360             return overrideValue;
361         }
362         ValueExpression ve = component.getValueExpression(attribute);
363         if (ve != null)
364         {
365             return (T)ve.getValue(component.getFacesContext().getELContext());
366         }
367         return defaultValue;
368     }
369 
370     static String getPathToComponent(UIComponent component)
371     {
372         StringBuffer buf = new StringBuffer();
373 
374         if (component == null)
375         {
376             buf.append("{Component-Path : ");
377             buf.append("[null]}");
378             return buf.toString();
379         }
380 
381         getPathToComponent(component, buf);
382 
383         buf.insert(0, "{Component-Path : ");
384         buf.append("}");
385 
386         return buf.toString();
387     }
388     
389     /**
390      * Call {@link #pushComponentToEL(javax.faces.context.FacesContext,javax.faces.component.UIComponent)}, 
391      * reads the isRendered property, call {@link
392      * UIComponent#popComponentFromEL} and returns the value of isRendered.
393      */
394     static boolean isRendered(FacesContext facesContext, UIComponent uiComponent) {
395         // We must call pushComponentToEL here because ValueExpression may have 
396         // implicit object "component" used. 
397         try
398         {
399             uiComponent.pushComponentToEL(facesContext, uiComponent);
400             return uiComponent.isRendered();
401         }
402         finally
403         {       
404             uiComponent.popComponentFromEL(facesContext);
405         }
406     }
407 
408     private static void getPathToComponent(UIComponent component, StringBuffer buf)
409     {
410         if (component == null)
411             return;
412 
413         StringBuffer intBuf = new StringBuffer();
414 
415         intBuf.append("[Class: ");
416         intBuf.append(component.getClass().getName());
417         if (component instanceof UIViewRoot)
418         {
419             intBuf.append(",ViewId: ");
420             intBuf.append(((UIViewRoot)component).getViewId());
421         }
422         else
423         {
424             intBuf.append(",Id: ");
425             intBuf.append(component.getId());
426         }
427         intBuf.append("]");
428 
429         buf.insert(0, intBuf.toString());
430 
431         getPathToComponent(component.getParent(), buf);
432     }
433 }