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  
20  package org.apache.myfaces.tobago.util;
21  
22  import org.apache.myfaces.tobago.component.Attributes;
23  import org.apache.myfaces.tobago.component.Facets;
24  import org.apache.myfaces.tobago.component.RendererTypes;
25  import org.apache.myfaces.tobago.component.SupportsMarkup;
26  import org.apache.myfaces.tobago.context.Markup;
27  import org.apache.myfaces.tobago.context.TransientStateHolder;
28  import org.apache.myfaces.tobago.event.AbstractPopupActionListener;
29  import org.apache.myfaces.tobago.internal.component.AbstractUIForm;
30  import org.apache.myfaces.tobago.internal.component.AbstractUIInput;
31  import org.apache.myfaces.tobago.internal.component.AbstractUIPage;
32  import org.apache.myfaces.tobago.internal.component.AbstractUIPopup;
33  import org.apache.myfaces.tobago.internal.util.ArrayUtils;
34  import org.apache.myfaces.tobago.internal.util.Deprecation;
35  import org.apache.myfaces.tobago.internal.util.FindComponentUtils;
36  import org.apache.myfaces.tobago.internal.util.ObjectUtils;
37  import org.apache.myfaces.tobago.internal.util.StringUtils;
38  import org.apache.myfaces.tobago.renderkit.RendererBase;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  
42  import javax.faces.FactoryFinder;
43  import javax.faces.application.Application;
44  import javax.faces.application.FacesMessage;
45  import javax.faces.component.ActionSource;
46  import javax.faces.component.ContextCallback;
47  import javax.faces.component.EditableValueHolder;
48  import javax.faces.component.NamingContainer;
49  import javax.faces.component.UICommand;
50  import javax.faces.component.UIComponent;
51  import javax.faces.component.UIGraphic;
52  import javax.faces.component.UIInput;
53  import javax.faces.component.UIOutput;
54  import javax.faces.component.UIParameter;
55  import javax.faces.component.UISelectMany;
56  import javax.faces.component.UIViewRoot;
57  import javax.faces.component.ValueHolder;
58  import javax.faces.context.FacesContext;
59  import javax.faces.convert.Converter;
60  import javax.faces.el.ValueBinding;
61  import javax.faces.event.ActionEvent;
62  import javax.faces.event.ActionListener;
63  import javax.faces.event.ValueChangeEvent;
64  import javax.faces.model.SelectItem;
65  import javax.faces.render.RenderKit;
66  import javax.faces.render.RenderKitFactory;
67  import javax.faces.render.Renderer;
68  import javax.faces.view.facelets.FaceletContext;
69  import javax.servlet.jsp.JspException;
70  import java.util.ArrayList;
71  import java.util.HashMap;
72  import java.util.Iterator;
73  import java.util.List;
74  import java.util.Map;
75  
76  public final class ComponentUtils {
77  
78    private static final Logger LOG = LoggerFactory.getLogger(ComponentUtils.class);
79  
80    public static final String SUB_SEPARATOR = "::";
81    
82    private static final String RENDER_KEY_PREFIX
83        = "org.apache.myfaces.tobago.util.ComponentUtils.RendererKeyPrefix_";
84  
85    private static final String PAGE_KEY = "org.apache.myfaces.tobago.Page.Key";
86  
87    public static final Class[] ACTION_ARGS = {};
88    public static final Class[] ACTION_LISTENER_ARGS = {ActionEvent.class};
89    public static final Class[] VALUE_CHANGE_LISTENER_ARGS = {ValueChangeEvent.class};
90    public static final Class[] VALIDATOR_ARGS = {FacesContext.class, UIComponent.class, Object.class};
91    public static final String LIST_SEPARATOR_CHARS = ", ";
92  
93    /**
94     * Name of the map for data attributes in components. New in JSF 2.2.
95     * @since 2.0.0
96     */
97    public static final String DATA_ATTRIBUTES_KEY = "javax.faces.component.DATA_ATTRIBUTES_KEY";
98  
99    private ComponentUtils() {
100   }
101 
102   public static boolean hasErrorMessages(final FacesContext context) {
103     for (final Iterator iter = context.getMessages(); iter.hasNext();) {
104       final FacesMessage message = (FacesMessage) iter.next();
105       if (FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0) {
106         return true;
107       }
108     }
109     return false;
110   }
111 
112   public static boolean containsPopupActionListener(final UICommand command) {
113     final ActionListener[] actionListeners = command.getActionListeners();
114     for (final ActionListener actionListener : actionListeners) {
115       if (actionListener instanceof AbstractPopupActionListener) {
116         return true;
117       }
118     }
119     return false;
120   }
121 
122   public static String getFacesMessageAsString(final FacesContext facesContext, final UIComponent component) {
123     final Iterator messages = facesContext.getMessages(
124         component.getClientId(facesContext));
125     final StringBuilder stringBuffer = new StringBuilder();
126     while (messages.hasNext()) {
127       final FacesMessage message = (FacesMessage) messages.next();
128       stringBuffer.append(message.getDetail());
129     }
130     if (stringBuffer.length() > 0) {
131       return stringBuffer.toString();
132     } else {
133       return null;
134     }
135   }
136 
137   public static boolean isInPopup(UIComponent component) {
138     while (component != null) {
139       if (component instanceof AbstractUIPopup) {
140         return true;
141       }
142       component = component.getParent();
143     }
144     return false;
145   }
146 
147   public static void resetPage(final FacesContext context) {
148     final UIViewRoot view = context.getViewRoot();
149     if (view != null) {
150       view.getAttributes().remove(PAGE_KEY);
151     }
152   }
153 
154   /**
155    * Tries to walk up the parents to find the UIViewRoot, if not found, then go to FaceletContext's FacesContext for
156    * the view root.
157    */
158   public static UIViewRoot findViewRoot(final FaceletContext faceletContext, final UIComponent component) {
159     final UIViewRoot viewRoot = findAncestor(component, UIViewRoot.class);
160     if (viewRoot != null) {
161       return viewRoot;
162     } else {
163       return faceletContext.getFacesContext().getViewRoot();
164     }
165   }
166 
167   public static AbstractUIPage findPage(final FacesContext context, final UIComponent component) {
168     final UIViewRoot view = context.getViewRoot();
169     if (view != null) {
170       TransientStateHolder stateHolder = (TransientStateHolder) view.getAttributes().get(PAGE_KEY);
171       if (stateHolder == null || stateHolder.isEmpty()) {
172         final AbstractUIPage page = findPage(component);
173         stateHolder = new TransientStateHolder(page);
174         context.getViewRoot().getAttributes().put(PAGE_KEY, stateHolder);
175       }
176       return (AbstractUIPage) stateHolder.get();
177     } else {
178       return findPage(component);
179     }
180   }
181 
182   public static AbstractUIPage findPage(UIComponent component) {
183     if (component instanceof UIViewRoot) {
184       return findPageBreadthFirst(component);
185     } else {
186       while (component != null) {
187         if (component instanceof AbstractUIPage) {
188           return (AbstractUIPage) component;
189         }
190         component = component.getParent();
191       }
192       return null;
193     }
194   }
195 
196   public static AbstractUIPage findPage(final FacesContext facesContext) {
197     return findPageBreadthFirst(facesContext.getViewRoot());
198   }
199 
200   private static AbstractUIPage findPageBreadthFirst(final UIComponent component) {
201     for (final UIComponent child : component.getChildren()) {
202       if (child instanceof AbstractUIPage) {
203         return (AbstractUIPage) child;
204       }
205     }
206     for (final UIComponent child : component.getChildren()) {
207       final AbstractUIPage result = findPageBreadthFirst(child);
208       if (result != null) {
209         return result;
210       }
211     }
212     return null;
213   }
214 
215 
216   public static AbstractUIForm findForm(UIComponent component) {
217     while (component != null) {
218       if (component instanceof AbstractUIForm) {
219         return (AbstractUIForm) component;
220       }
221       component = component.getParent();
222     }
223     return null;
224   }
225 
226   public static <T> T findAncestor(UIComponent component, final Class<T> type) {
227 
228     while (component != null) {
229       if (type.isAssignableFrom(component.getClass())) {
230         return (T) component;
231       }
232       component = component.getParent();
233     }
234     return null;
235   }
236 
237   /**
238    * Find all sub forms of a component, and collects it.
239    * It does not find sub forms of sub forms.
240    */
241   public static List<AbstractUIForm> findSubForms(final UIComponent component) {
242     final List<AbstractUIForm> collect = new ArrayList<AbstractUIForm>();
243     findSubForms(collect, component);
244     return collect;
245   }
246 
247   @SuppressWarnings("unchecked")
248   private static void findSubForms(final List<AbstractUIForm> collect, final UIComponent component) {
249     final Iterator<UIComponent> kids = component.getFacetsAndChildren();
250     while (kids.hasNext()) {
251       final UIComponent child = kids.next();
252       if (child instanceof AbstractUIForm) {
253         collect.add((AbstractUIForm) child);
254       } else {
255         findSubForms(collect, child);
256       }
257     }
258   }
259 
260   /**
261    * Searches the component tree beneath the component and return the first component matching the type.
262    */
263   public static <T extends UIComponent> T findDescendant(final UIComponent component, final Class<T> type) {
264 
265     for (final UIComponent child : component.getChildren()) {
266       if (type.isAssignableFrom(child.getClass())) {
267         return (T) child;
268       }
269       final T descendant = findDescendant(child, type);
270       if (descendant != null) {
271         return descendant;
272       }
273     }
274     return null;
275   }
276 
277   /**
278    * Searches the children beneath the component and return the first component matching the type.
279    */
280   public static <T extends UIComponent> T findChild(final UIComponent component, final Class<T> type) {
281 
282     for (final UIComponent child : component.getChildren()) {
283       if (type.isAssignableFrom(child.getClass())) {
284         return (T) child;
285       }
286     }
287     return null;
288   }
289 
290   /**
291    * Searches the component tree beneath the component and return all component matching the type.
292    */
293   public static <T extends UIComponent> List<T> findDescendantList(final UIComponent component, final Class<T> type) {
294 
295     final List<T> result = new ArrayList<T>();
296     
297     for (final UIComponent child : component.getChildren()) {
298       if (type.isAssignableFrom(child.getClass())) {
299         result.add((T) child);
300       }
301       result.addAll(findDescendantList(child, type));
302     }
303     return result;
304   }
305 
306   /**
307    * Looks for the attribute "for" in the component. If there is any
308    * search for the component which is referenced by the "for" attribute,
309    * and return their clientId.
310    * If there is no "for" attribute, return the "clientId" of the parent
311    * (if it has a parent). This is useful for labels.
312    */
313   public static String findClientIdFor(final UIComponent component, final FacesContext facesContext) {
314     final UIComponent forComponent = findFor(component);
315     if (forComponent != null) {
316       final String clientId = forComponent.getClientId(facesContext);
317       if (LOG.isDebugEnabled()) {
318         LOG.debug("found clientId: '" + clientId + "'");
319       }
320       return clientId;
321     }
322     if (LOG.isDebugEnabled()) {
323       LOG.debug("found no clientId");
324     }
325     return null;
326   }
327 
328   public static UIComponent findFor(final UIComponent component) {
329     final String forValue = (String) component.getAttributes().get(Attributes.FOR);
330     if (forValue == null) {
331       return component.getParent();
332     }
333     return ComponentUtils.findComponent(component, forValue);
334   }
335 
336   /**
337    * Looks for the attribute "for" of the component.
338    * In case that the value is equals to "@auto" the children of the parent will be
339    * checked if they are a UIInput. The "id" of the first one will be used to reset the "for"
340    * attribute of the component.
341    * @deprecated
342    */
343   @Deprecated
344   public static void evaluateAutoFor(final UIComponent component) {
345     final String forComponent = (String) component.getAttributes().get(Attributes.FOR);
346     if (LOG.isDebugEnabled()) {
347       LOG.debug("for = '" + forComponent + "'");
348     }
349     if ("@auto".equals(forComponent)) {
350       for (final UIComponent child : component.getParent().getChildren()) {
351         if (setForToInput(component, child, AbstractUIInput.class, false)) {
352           break;
353         }
354       }
355     }
356   }
357 
358   /**
359    * Looks for the attribute "for" of the component.
360    * In case that the value is equals to "@auto" the children of the parent will be
361    * checked if they are of the type of the parameter clazz. The "id" of the first one will be used to reset the "for"
362    * attribute of the component.
363    */
364   public static void evaluateAutoFor(final UIComponent component, final Class<? extends UIComponent> clazz) {
365     final String forComponent = (String) component.getAttributes().get(Attributes.FOR);
366     if (LOG.isDebugEnabled()) {
367       LOG.debug("for = '" + forComponent + "'");
368     }
369     if ("@auto".equals(forComponent)) {
370       // parent
371       for (final UIComponent child : component.getParent().getChildren()) {
372         if (setForToInput(component, child, clazz, component instanceof NamingContainer)) {
373           return;
374         }
375       }
376       // grand parent
377       for (final UIComponent child : component.getParent().getParent().getChildren()) {
378         if (setForToInput(component, child, clazz, component.getParent() instanceof NamingContainer)) {
379           return;
380         }
381       }
382     }
383   }
384 
385   private static boolean setForToInput(
386       final UIComponent component, final UIComponent child, final Class<? extends UIComponent> clazz,
387       final boolean namingContainer) {
388     if (clazz.isAssignableFrom(child.getClass())) { // find the matching component
389       final String forComponent;
390       if (namingContainer) {
391         forComponent = ":::" + child.getId();
392       } else {
393         forComponent = child.getId();
394       }
395       component.getAttributes().put(Attributes.FOR, forComponent);
396       return true;
397     }
398     return false;
399   }
400 
401   public static boolean isInActiveForm(UIComponent component) {
402     while (component != null) {
403       if (component instanceof AbstractUIForm) {
404         final AbstractUIForm form = (AbstractUIForm) component;
405         if (form.isSubmitted()) {
406           return true;
407         }
408       }
409       component = component.getParent();
410     }
411     return false;
412   }
413 
414   public static FacesMessage.Severity getMaximumSeverity(final UIComponent component) {
415     final boolean invalid = component instanceof UIInput && !((UIInput) component).isValid();
416     FacesMessage.Severity max = invalid ? FacesMessage.SEVERITY_ERROR : null;
417     final FacesContext facesContext = FacesContext.getCurrentInstance();
418     final Iterator messages = facesContext.getMessages(component.getClientId(facesContext));
419     while (messages.hasNext()) {
420       final FacesMessage message = (FacesMessage) messages.next();
421       if (max == null || message.getSeverity().getOrdinal() > max.getOrdinal()) {
422         max = message.getSeverity();
423       }
424     }
425     return max;
426   }
427 
428   public static boolean isError(final UIInput uiInput) {
429     final FacesContext facesContext = FacesContext.getCurrentInstance();
430     return !uiInput.isValid()
431         || facesContext.getMessages(uiInput.getClientId(facesContext)).hasNext();
432   }
433 
434   public static boolean isError(final UIComponent component) {
435     if (component instanceof AbstractUIInput) {
436       return isError((AbstractUIInput) component);
437     }
438     return false;
439   }
440 
441   public static boolean isOutputOnly(final UIComponent component) {
442     return getBooleanAttribute(component, Attributes.DISABLED)
443         || getBooleanAttribute(component, Attributes.READONLY);
444   }
445 
446   public static boolean mayValidate(final UIComponent component) {
447     return !isOutputOnly(component)
448         && ComponentUtils.isInActiveForm(component);
449   }
450 
451   public static boolean mayUpdateModel(final UIComponent component) {
452     return mayValidate(component);
453   }
454 
455   public static boolean getBooleanAttribute(final UIComponent component, final String name) {
456 
457     Object bool = component.getAttributes().get(name);
458     if (bool == null) {
459       return false;
460     }
461     if (bool instanceof ValueBinding) {
462       bool = ((ValueBinding) bool).getValue(FacesContext.getCurrentInstance());
463     }
464     if (bool instanceof Boolean) {
465       return (Boolean) bool;
466     } else if (bool instanceof String) {
467       LOG.warn("Searching for a boolean, but find a String. Should not happen. "
468           + "attribute: '" + name + "' id: '" + component.getClientId(FacesContext.getCurrentInstance())
469           + "' comp: '" + component + "'");
470       return Boolean.valueOf((String) bool);
471     } else {
472       LOG.warn("Unknown type '" + bool.getClass().getName()
473           + "' for boolean attribute: " + name + " id: " + component.getClientId(FacesContext.getCurrentInstance())
474           + " comp: " + component);
475       return false;
476     }
477   }
478 
479   /**
480    * @deprecated since 2.0.0
481    */
482   @Deprecated
483   public static ValueBinding createValueBinding(final String value) {
484     return FacesContext.getCurrentInstance().getApplication().createValueBinding(value);
485   }
486 
487   /**
488    * @deprecated since 1.5.0
489    * Please define a {@link Markup} and set it to the component with
490    * {@link SupportsMarkup#setMarkup(Markup markup)} before the rendering phase.
491    */
492   @Deprecated
493   public static void setStyleClasses(final UIComponent component, final String styleClasses) {
494     Deprecation.LOG.warn("style class " + styleClasses);
495   }
496 
497   /**
498    * @deprecated since 1.5.0
499    */
500   @Deprecated
501   public static void setMarkup(final UIComponent markupComponent, final String markup) {
502     Deprecation.LOG.error("markup=" + markup);
503   }
504 
505   public static Object getAttribute(final UIComponent component, final String name) {
506     Object value = component.getAttributes().get(name);
507     if (value instanceof ValueBinding) {
508       value = ((ValueBinding) value).getValue(FacesContext.getCurrentInstance());
509     }
510     return value;
511   }
512 
513   public static Object getObjectAttribute(final UIComponent component, final String name) {
514     return getAttribute(component, name);
515   }
516 
517   public static String getStringAttribute(final UIComponent component, final String name) {
518     return (String) getAttribute(component, name);
519   }
520 
521   public static int getIntAttribute(final UIComponent component, final String name) {
522     return getIntAttribute(component, name, 0);
523   }
524 
525   public static int getIntAttribute(final UIComponent component, final String name,
526       final int defaultValue) {
527     final Object integer = component.getAttributes().get(name);
528     if (integer instanceof Number) {
529       return ((Number) integer).intValue();
530     } else if (integer instanceof String) {
531       try {
532         return Integer.parseInt((String) integer);
533       } catch (final NumberFormatException e) {
534         LOG.warn("Can't parse number from string : \"" + integer + "\"!");
535         return defaultValue;
536       }
537     } else if (integer == null) {
538       return defaultValue;
539     } else {
540       LOG.warn("Unknown type '" + integer.getClass().getName()
541           + "' for integer attribute: " + name + " comp: " + component);
542       return defaultValue;
543     }
544   }
545 
546   public static Character getCharacterAttribute(final UIComponent component, final String name) {
547     final Object character = component.getAttributes().get(name);
548     if (character == null) {
549       return null;
550     } else if (character instanceof Character) {
551       return ((Character) character);
552     } else if (character instanceof String) {
553       final String asString = ((String) character);
554       return asString.length() > 0 ? asString.charAt(0) : null;
555     } else {
556       LOG.warn("Unknown type '" + character.getClass().getName()
557           + "' for integer attribute: " + name + " comp: " + component);
558       return null;
559     }
560   }
561 
562   public static boolean isFacetOf(final UIComponent component, final UIComponent parent) {
563     for (final Object o : parent.getFacets().keySet()) {
564       final UIComponent facet = parent.getFacet((String) o);
565       if (component.equals(facet)) {
566         return true;
567       }
568     }
569     return false;
570   }
571 
572   public static RendererBase getRenderer(final FacesContext facesContext, final UIComponent component) {
573     return getRenderer(facesContext, component.getFamily(), component.getRendererType());
574   }
575 
576   public static RendererBase getRenderer(final FacesContext facesContext, final String family,
577                                          final String rendererType) {
578     if (rendererType == null) {
579       return null;
580     }
581 
582     final Map<String, Object> requestMap = (Map<String, Object>) facesContext.getExternalContext().getRequestMap();
583     final StringBuilder key = new StringBuilder(RENDER_KEY_PREFIX);
584     key.append(rendererType);
585     RendererBase renderer = (RendererBase) requestMap.get(key.toString());
586 
587     if (renderer == null) {
588       final Renderer myRenderer = getRendererInternal(facesContext, family, rendererType);
589       if (myRenderer instanceof RendererBase) {
590         requestMap.put(key.toString(), myRenderer);
591         renderer = (RendererBase) myRenderer;
592       } else {
593         return null;
594       }
595     }
596     return renderer;
597   }
598 
599 
600   private static Renderer getRendererInternal(
601       final FacesContext facesContext, final String family, final String rendererType) {
602     final RenderKitFactory rkFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
603     final RenderKit renderKit = rkFactory.getRenderKit(facesContext, facesContext.getViewRoot().getRenderKitId());
604     final Renderer myRenderer = renderKit.getRenderer(family, rendererType);
605     return myRenderer;
606   }
607 
608   public static Object findParameter(final UIComponent component, final String name) {
609     for (final UIComponent child : component.getChildren()) {
610       if (child instanceof UIParameter) {
611         final UIParameter parameter = (UIParameter) child;
612         if (LOG.isDebugEnabled()) {
613           LOG.debug("Select name='" + parameter.getName() + "'");
614           LOG.debug("Select value='" + parameter.getValue() + "'");
615         }
616         if (name.equals(parameter.getName())) {
617           return parameter.getValue();
618         }
619       }
620     }
621     return null;
622   }
623 
624   /**
625    * @deprecated since 2.0.0
626    */
627   @Deprecated
628   public static ActionListener createActionListener(final String type)
629       throws JspException {
630     try {
631       ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
632       if (classLoader == null) {
633         classLoader = type.getClass().getClassLoader();
634       }
635       final Class clazz = classLoader.loadClass(type);
636       return (ActionListener) clazz.newInstance();
637     } catch (final Exception e) {
638       if (LOG.isDebugEnabled()) {
639         LOG.debug("type=" + type, e);
640       }
641       throw new JspException(e);
642     }
643   }
644 
645   /**
646    * @deprecated since 2.0.0
647    */
648   @Deprecated
649   public static UIGraphic getFirstGraphicChild(final UIComponent component) {
650     UIGraphic graphic = null;
651     for (final UIComponent child : component.getChildren()) {
652       if (child instanceof UIGraphic) {
653         graphic = (UIGraphic) child;
654         break;
655       }
656     }
657     return graphic;
658   }
659 
660   /**
661    * @deprecated since 2.0.0
662    */
663   @Deprecated
664   public static boolean isHoverEnabled(final UIComponent component) {
665     return ComponentUtils.getBooleanAttribute(component, Attributes.HOVER);
666   }
667 
668   /**
669    * @deprecated since 2.0.0
670    */
671   @Deprecated
672   public static UIOutput getFirstNonGraphicChild(final UIComponent component) {
673     for (final UIComponent child : component.getChildren()) {
674       if (child instanceof UIOutput) {
675         return (UIOutput) child;
676       }
677     }
678     return null;
679   }
680 
681   /**
682    * @deprecated since 1.5.0
683    */
684   @Deprecated
685   public static void setIntegerSizeProperty(final UIComponent component, final String name, final String value) {
686     Deprecation.LOG.error("name=" + name + " value=" + value);
687   }
688 
689   /**
690    * @deprecated since 2.0.0
691    */
692   @Deprecated
693   public static String removePx(String value) {
694     if (value != null && value.endsWith("px")) {
695       value = value.substring(0, value.length() - 2);
696     }
697     return value;
698   }
699 
700   /**
701    * @deprecated since 2.0.0
702    */
703   @Deprecated
704   public static void setValueForValueBinding(final String name, final Object value) {
705     final FacesContext context = FacesContext.getCurrentInstance();
706     final ValueBinding valueBinding = context.getApplication().createValueBinding(name);
707     valueBinding.setValue(context, value);
708   }
709 
710   /**
711    * @deprecated Since Tobago 2.0
712    */
713   @Deprecated
714   public static boolean hasSelectedValue(final List<SelectItem> items, final Object value) {
715     for (final SelectItem item : items) {
716       if (ObjectUtils.equals(item.getValue(), value)) {
717         return true;
718       }
719     }
720     return false;
721   }
722 
723   /**
724    * @deprecated since 2.0.0
725    */
726   @Deprecated
727   public static int getIntValue(final ValueBinding valueBinding) {
728     return getAsInt(valueBinding.getValue(FacesContext.getCurrentInstance()));
729   }
730 
731   /**
732    * @deprecated since 2.0.0
733    */
734   @Deprecated
735   private static int getAsInt(final Object value) {
736     final int result;
737     if (value instanceof Number) {
738       result = ((Number) value).intValue();
739     } else if (value instanceof String) {
740       result = Integer.parseInt((String) value);
741     } else {
742       throw new IllegalArgumentException("Can't convert " + value + " to int!");
743     }
744     return result;
745   }
746 
747   /**
748    * @deprecated since 2.0.0
749    */
750   @Deprecated
751   public static String createPickerId(
752       final FacesContext facesContext, final UIComponent component, final String postfix) {
753     //String id = component.getId();
754     final String id = getComponentId(facesContext, component);
755     return id + "_picker" + postfix;
756   }
757 
758   /**
759    * @deprecated since 2.0.0
760    */
761   @Deprecated
762   public static String getComponentId(final FacesContext facesContext, final UIComponent component) {
763     final String id = component.getId();
764     //if (id == null) {
765     // XXX What is this?
766     //  id = component.getClientId(facesContext).substring(id.lastIndexOf('_'));
767     //}
768     return id;
769   }
770 
771   /**
772    * Checks if the Component has a label facet and if not creates one with the label attribute.
773    * @deprecated since 2.0.0
774    */
775   @Deprecated
776   public static UIComponent provideLabel(final FacesContext facesContext, final UIComponent component) {
777     UIComponent label = component.getFacet(Facets.LABEL);
778 
779     if (label == null) {
780       final Map attributes = component.getAttributes();
781       Object labelText = component.getValueBinding(Attributes.LABEL);
782       if (labelText == null) {
783         labelText = attributes.get(Attributes.LABEL);
784       }
785 
786       if (labelText != null) {
787         final Application application = FacesContext.getCurrentInstance().getApplication();
788         label = application.createComponent(UIOutput.COMPONENT_TYPE);
789         label.setRendererType(RendererTypes.LABEL);
790         final String idprefix = ComponentUtils.getComponentId(facesContext, component);
791         label.setId(idprefix + "_" + Facets.LABEL);
792         label.setRendered(true);
793 
794         if (labelText instanceof ValueBinding) {
795           label.setValueBinding(Attributes.VALUE, (ValueBinding) labelText);
796         } else {
797           label.getAttributes().put(Attributes.VALUE, labelText);
798         }
799 
800         component.getFacets().put(Facets.LABEL, label);
801       }
802     }
803     return label;
804   }
805 
806   /**
807    * @deprecated since 1.5.0
808    */
809   @Deprecated
810   public static void setValidator(final EditableValueHolder editableValueHolder, final String validator) {
811     Deprecation.LOG.error("validator=" + validator);
812   }
813 
814   /**
815    * @deprecated since 1.5.0
816    */
817   @Deprecated
818   public static void setConverter(final ValueHolder valueHolder, final String converterId) {
819     Deprecation.LOG.error("converterId=" + converterId);
820   }
821 
822   /**
823    * @deprecated since 1.5.0
824    */
825   @Deprecated
826   public static void setAction(final ActionSource component, final String action) {
827     Deprecation.LOG.error("action=" + action);
828   }
829 
830   /**
831    * @deprecated since 1.5.0
832    */
833   @Deprecated
834   public static void setActionListener(final ActionSource command, final String actionListener) {
835     Deprecation.LOG.error("actionListener=" + actionListener);
836   }
837 
838   /**
839    * @deprecated since 1.5.0
840    */
841   @Deprecated
842   public static void setValueChangeListener(final EditableValueHolder valueHolder, final String valueChangeListener) {
843     Deprecation.LOG.error("valueChangeListener=" + valueChangeListener);
844   }
845 
846   /**
847    * @deprecated since 1.5.0
848    */
849   @Deprecated
850   public static void setValueBinding(final UIComponent component, final String name, final String state) {
851     Deprecation.LOG.error("name=" + name + " state=" + state);
852   }
853 
854   /**
855    * @deprecated since 1.5
856    */
857   @Deprecated
858   public static String[] getMarkupBinding(final FacesContext facesContext, final SupportsMarkup component) {
859     final ValueBinding vb = ((UIComponent) component).getValueBinding(Attributes.MARKUP);
860     if (vb != null) {
861       final Object markups = vb.getValue(facesContext);
862       if (markups instanceof String[]) {
863         return (String[]) markups;
864       } else if (markups instanceof String) {
865         final String[] strings = StringUtils.split((String) markups, ", ");
866         final List<String> result = new ArrayList<String>(strings.length);
867         for (final String string : strings) {
868           if (string.trim().length() != 0) {
869             result.add(string.trim());
870           }
871         }
872         return result.toArray(new String[result.size()]);
873       } else if (markups == null) {
874         return ArrayUtils.EMPTY_STRING_ARRAY;
875       } else {
876         return new String[]{markups.toString()};
877       }
878     }
879 
880     return ArrayUtils.EMPTY_STRING_ARRAY;
881   }
882 
883   /**
884    * The search depends on the number of colons in the relativeId:
885    * <dl>
886    *   <dd>colonCount == 0</dd>
887    *   <dt>fully relative</dt>
888    *   <dd>colonCount == 1</dd>
889    *   <dt>absolute (still normal findComponent syntax)</dt>
890    *   <dd>colonCount > 1</dd>
891    *   <dt>for each extra colon after 1, go up a naming container</dt>
892    * </dl>
893    * (to the view root, if naming containers run out)
894    */
895   public static UIComponent findComponent(final UIComponent from, final String relativeId) {
896     return FindComponentUtils.findComponent(from, relativeId);
897   }
898 
899   public static String[] splitList(final String renderers) {
900     return StringUtils.split(renderers, LIST_SEPARATOR_CHARS);
901   }
902 
903   public static Object getConvertedValue(
904       final FacesContext facesContext, final UIComponent component, final String stringValue) {
905     try {
906       final Renderer renderer = getRenderer(facesContext, component);
907       if (renderer != null) {
908         if (component instanceof UISelectMany) {
909           final Object converted = renderer.getConvertedValue(facesContext, component, new String[]{stringValue});
910           return converted instanceof List ? ((List) converted).get(0) : ((Object[]) converted)[0];
911         } else {
912           return renderer.getConvertedValue(facesContext, component, stringValue);
913         }
914       } else if (component instanceof ValueHolder) {
915         Converter converter = ((ValueHolder) component).getConverter();
916         if (converter == null) {
917           //Try to find out by value binding
918           final ValueBinding vb = component.getValueBinding("value");
919           if (vb != null) {
920             final Class valueType = vb.getType(facesContext);
921             if (valueType != null) {
922               converter = facesContext.getApplication().createConverter(valueType);
923             }
924           }
925         }
926         if (converter != null) {
927           converter.getAsObject(facesContext, component, stringValue);
928         }
929       }
930     } catch (final Exception e) {
931       LOG.warn("Can't convert string value '" + stringValue + "'", e);
932     }
933     return stringValue;
934   }
935 
936   public static Markup updateMarkup(final UIComponent component, Markup markup) {
937     if (markup == null) {
938       markup = Markup.NULL;
939     }
940     if (ComponentUtils.getBooleanAttribute(component, Attributes.DISABLED)) {
941       markup = markup.add(Markup.DISABLED);
942     }
943     if (ComponentUtils.getBooleanAttribute(component, Attributes.READONLY)) {
944       markup = markup.add(Markup.READONLY);
945     }
946     if (component instanceof UIInput) {
947       final UIInput input = (UIInput) component;
948 
949       final FacesMessage.Severity maximumSeverity = ComponentUtils.getMaximumSeverity(input);
950       markup = markup.add(markupOfSeverity(maximumSeverity));
951 
952       if (input.isRequired()) {
953         markup = markup.add(Markup.REQUIRED);
954       }
955     }
956     return markup;
957   }
958 
959   public static Markup markupOfSeverity(final FacesMessage.Severity maximumSeverity) {
960     if (FacesMessage.SEVERITY_FATAL.equals(maximumSeverity)) {
961       return Markup.FATAL;
962     } else if (FacesMessage.SEVERITY_ERROR.equals(maximumSeverity)) {
963       return Markup.ERROR;
964     } else if (FacesMessage.SEVERITY_WARN.equals(maximumSeverity)) {
965       return Markup.WARN;
966     } else if (FacesMessage.SEVERITY_INFO.equals(maximumSeverity)) {
967       return Markup.INFO;
968     }
969     return null;
970   }
971 
972   public static void addCurrentMarkup(final SupportsMarkup component, final Markup markup) {
973     component.setCurrentMarkup(markup.add(component.getCurrentMarkup()));
974   }
975 
976   /**
977    * @deprecated since 2.0.0
978    */
979   @Deprecated
980   public static boolean hasChildrenWithMessages(final FacesContext facesContext, final NamingContainer  container) {
981     if (container instanceof UIComponent) {
982       final String clientId = ((UIComponent) container).getClientId(facesContext);
983       for (final Iterator ids = facesContext.getClientIdsWithMessages(); ids.hasNext();) {
984         final String id = (String) ids.next();
985         if (id.startsWith(clientId)) {
986           return true;
987         }
988       }
989     }
990     return false;
991   }
992 
993   public static FacesMessage.Severity getMaximumSeverityOfChildrenMessages(
994       final FacesContext facesContext, final NamingContainer container) {
995     if (container instanceof UIComponent) {
996       final String clientId = ((UIComponent) container).getClientId(facesContext);
997       FacesMessage.Severity max = null;
998       for (final Iterator ids = facesContext.getClientIdsWithMessages(); ids.hasNext();) {
999         final String id = (String) ids.next();
1000         if (id != null && id.startsWith(clientId)) {
1001           final Iterator messages = facesContext.getMessages(id);
1002           while (messages.hasNext()) {
1003             final FacesMessage message = (FacesMessage) messages.next();
1004             if (max == null || message.getSeverity().getOrdinal() > max.getOrdinal()) {
1005               max = message.getSeverity();
1006             }
1007           }
1008         }
1009       }
1010       return max;
1011     }
1012     return null;
1013   }
1014 
1015   /**
1016    * @deprecated since 2.0.0
1017    */
1018   @Deprecated
1019   public static String[] getChildrenWithMessages(final FacesContext facesContext, final NamingContainer container) {
1020     if (container instanceof UIComponent) {
1021       final List<String> clientIds = new ArrayList<String>();
1022       final String clientId = ((UIComponent) container).getClientId(facesContext);
1023       for (final Iterator ids = facesContext.getClientIdsWithMessages(); ids.hasNext();) {
1024         final String id = (String) ids.next();
1025         if (id.startsWith(clientId)) {
1026           clientIds.add(id);
1027         }
1028       }
1029       return clientIds.toArray(new String[clientIds.size()]);
1030     }
1031     return ArrayUtils.EMPTY_STRING_ARRAY;
1032   }
1033 
1034   /**
1035    * Adding a data attribute to the component. 
1036    * The name must start with "data-", e. g. "data-tobago-foo" or "data-bar"
1037    */
1038   public static void putDataAttributeWithPrefix(final UIComponent component, final String name, final Object value) {
1039     if (name.startsWith("data-")) {
1040       putDataAttribute(component, name.substring(5), value);
1041     } else {
1042       LOG.error("The name must start with 'data-' but it doesn't: '" + name + "'");
1043     }
1044   }
1045 
1046   /**
1047    * Adding a data attribute to the component.
1048    * The name should not start with "data-", e. g. "tobago-foo" or "bar"
1049    */
1050   public static void putDataAttribute(final UIComponent component, final Object name, final Object value) {
1051     Map<Object, Object> map = getDataAttributes(component);
1052     if (map == null) {
1053       map = new HashMap<Object, Object>();
1054       component.getAttributes().put(DATA_ATTRIBUTES_KEY, map);
1055     }
1056     map.put(name, value);
1057   }
1058 
1059   @SuppressWarnings("unchecked")
1060   public static Map<Object, Object> getDataAttributes(final UIComponent component) {
1061     return (Map<Object, Object>) component.getAttributes().get(DATA_ATTRIBUTES_KEY);
1062   }
1063 
1064   public static Object getDataAttribute(final UIComponent component, final String name) {
1065     Map<Object, Object> map = getDataAttributes(component);
1066     return map != null ? map.get(name) : null;
1067   }
1068 
1069   /**
1070    * @deprecated since 2.0.0, please use
1071    * {@link javax.faces.component.UIComponent#invokeOnComponent(javax.faces.context.FacesContext, java.lang.String,
1072       javax.faces.component.ContextCallback) }
1073    */
1074   public static boolean invokeOnComponent(
1075       final FacesContext context, final UIComponent component, final String clientId, final ContextCallback callback) {
1076     return component.invokeOnComponent(context, clientId, callback);
1077   }
1078 }