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