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