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