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