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