001 package org.apache.myfaces.tobago.util;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 import org.apache.commons.lang.ArrayUtils;
021 import org.apache.commons.lang.StringUtils;
022 import org.apache.myfaces.tobago.component.Attributes;
023 import org.apache.myfaces.tobago.component.Facets;
024 import org.apache.myfaces.tobago.component.RendererTypes;
025 import org.apache.myfaces.tobago.component.SupportsMarkup;
026 import org.apache.myfaces.tobago.context.Markup;
027 import org.apache.myfaces.tobago.context.TransientStateHolder;
028 import org.apache.myfaces.tobago.el.ConstantMethodBinding;
029 import org.apache.myfaces.tobago.event.AbstractPopupActionListener;
030 import org.apache.myfaces.tobago.internal.component.AbstractUIForm;
031 import org.apache.myfaces.tobago.internal.component.AbstractUIInput;
032 import org.apache.myfaces.tobago.internal.component.AbstractUIPage;
033 import org.apache.myfaces.tobago.internal.component.AbstractUIPopup;
034 import org.apache.myfaces.tobago.internal.util.FindComponentUtils;
035 import org.apache.myfaces.tobago.renderkit.RendererBase;
036 import org.apache.myfaces.tobago.renderkit.html.StyleClasses;
037 import org.slf4j.Logger;
038 import org.slf4j.LoggerFactory;
039
040 import javax.faces.FactoryFinder;
041 import javax.faces.application.Application;
042 import javax.faces.application.FacesMessage;
043 import javax.faces.component.ActionSource;
044 import javax.faces.component.EditableValueHolder;
045 import javax.faces.component.NamingContainer;
046 import javax.faces.component.UICommand;
047 import javax.faces.component.UIComponent;
048 import javax.faces.component.UIGraphic;
049 import javax.faces.component.UIInput;
050 import javax.faces.component.UIOutput;
051 import javax.faces.component.UIParameter;
052 import javax.faces.component.UISelectMany;
053 import javax.faces.component.ValueHolder;
054 import javax.faces.context.FacesContext;
055 import javax.faces.convert.Converter;
056 import javax.faces.el.MethodBinding;
057 import javax.faces.el.ValueBinding;
058 import javax.faces.event.ActionEvent;
059 import javax.faces.event.ActionListener;
060 import javax.faces.event.ValueChangeEvent;
061 import javax.faces.model.SelectItem;
062 import javax.faces.render.RenderKit;
063 import javax.faces.render.RenderKitFactory;
064 import javax.faces.render.Renderer;
065 import javax.faces.webapp.UIComponentTag;
066 import javax.servlet.jsp.JspException;
067 import java.util.ArrayList;
068 import java.util.Iterator;
069 import java.util.List;
070 import java.util.Map;
071
072 public class ComponentUtils {
073
074 private static final Logger LOG = LoggerFactory.getLogger(ComponentUtils.class);
075
076 public static final String SUB_SEPARATOR = "::";
077
078 private static final String RENDER_KEY_PREFIX
079 = "org.apache.myfaces.tobago.util.ComponentUtils.RendererKeyPrefix_";
080
081 private static final String PAGE_KEY = "org.apache.myfaces.tobago.Page.Key";
082
083 public static final Class[] ACTION_ARGS = {};
084 public static final Class[] ACTION_LISTENER_ARGS = {ActionEvent.class};
085 public static final Class[] VALUE_CHANGE_LISTENER_ARGS = {ValueChangeEvent.class};
086 public static final Class[] VALIDATOR_ARGS = {FacesContext.class, UIComponent.class, Object.class};
087 public static final String LIST_SEPARATOR_CHARS = ", ";
088
089 private ComponentUtils() {
090 }
091
092 public static boolean hasErrorMessages(FacesContext context) {
093 for (Iterator iter = context.getMessages(); iter.hasNext();) {
094 FacesMessage message = (FacesMessage) iter.next();
095 if (FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0) {
096 return true;
097 }
098 }
099 return false;
100 }
101
102 public static boolean containsPopupActionListener(UICommand command) {
103 ActionListener[] actionListeners = command.getActionListeners();
104 for (ActionListener actionListener : actionListeners) {
105 if (actionListener instanceof AbstractPopupActionListener) {
106 return true;
107 }
108 }
109 return false;
110 }
111
112 public static String getFacesMessageAsString(FacesContext facesContext, UIComponent component) {
113 Iterator messages = facesContext.getMessages(
114 component.getClientId(facesContext));
115 StringBuilder stringBuffer = new StringBuilder();
116 while (messages.hasNext()) {
117 FacesMessage message = (FacesMessage) messages.next();
118 stringBuffer.append(message.getDetail());
119 }
120 if (stringBuffer.length() > 0) {
121 return stringBuffer.toString();
122 } else {
123 return null;
124 }
125 }
126
127 public static boolean isInPopup(UIComponent component) {
128 while (component != null) {
129 if (component instanceof AbstractUIPopup) {
130 return true;
131 }
132 component = component.getParent();
133 }
134 return false;
135 }
136
137 public static void resetPage(FacesContext context) {
138 javax.faces.component.UIViewRoot view = context.getViewRoot();
139 if (view != null) {
140 view.getAttributes().remove(PAGE_KEY);
141 }
142 }
143
144 @SuppressWarnings("unchecked")
145 public static AbstractUIPage findPage(FacesContext context, UIComponent component) {
146 javax.faces.component.UIViewRoot view = context.getViewRoot();
147 if (view != null) {
148 TransientStateHolder stateHolder = (TransientStateHolder) view.getAttributes().get(PAGE_KEY);
149 if (stateHolder == null || stateHolder.isEmpty()) {
150 AbstractUIPage page = findPage(component);
151 stateHolder = new TransientStateHolder(page);
152 context.getViewRoot().getAttributes().put(PAGE_KEY, stateHolder);
153 }
154 return (AbstractUIPage) stateHolder.get();
155 } else {
156 return findPage(component);
157 }
158 }
159
160 public static AbstractUIPage findPage(UIComponent component) {
161 while (component != null) {
162 if (component instanceof AbstractUIPage) {
163 return (AbstractUIPage) component;
164 }
165 component = component.getParent();
166 }
167 return null;
168 }
169
170 public static AbstractUIPage findPage(FacesContext facesContext) {
171 return findPageBreadthFirst(facesContext.getViewRoot());
172 }
173
174 private static AbstractUIPage findPageBreadthFirst(UIComponent component) {
175 for (Object o : component.getChildren()) {
176 UIComponent child = (UIComponent) o;
177 if (child instanceof AbstractUIPage) {
178 return (AbstractUIPage) child;
179 }
180 }
181 for (Object o : component.getChildren()) {
182 UIComponent child = (UIComponent) o;
183 AbstractUIPage result = findPageBreadthFirst(child);
184 if (result != null) {
185 return result;
186 }
187 }
188 return null;
189 }
190
191
192 public static AbstractUIForm findForm(UIComponent component) {
193 while (component != null) {
194 if (component instanceof AbstractUIForm) {
195 return (AbstractUIForm) component;
196 }
197 component = component.getParent();
198 }
199 return null;
200 }
201
202 public static <T> T findAncestor(UIComponent component, Class<T> type) {
203
204 while (component != null) {
205 if (type.isAssignableFrom(component.getClass())) {
206 return (T) component;
207 }
208 component = component.getParent();
209 }
210 return null;
211 }
212
213 /**
214 * Find all sub forms of a component, and collects it.
215 * It does not find sub forms of sub forms.
216 */
217 public static List<AbstractUIForm> findSubForms(UIComponent component) {
218 List<AbstractUIForm> collect = new ArrayList<AbstractUIForm>();
219 findSubForms(collect, component);
220 return collect;
221 }
222
223 @SuppressWarnings("unchecked")
224 private static void findSubForms(List<AbstractUIForm> collect, UIComponent component) {
225 Iterator<UIComponent> kids = component.getFacetsAndChildren();
226 while (kids.hasNext()) {
227 UIComponent child = kids.next();
228 if (child instanceof AbstractUIForm) {
229 collect.add((AbstractUIForm) child);
230 } else {
231 findSubForms(collect, child);
232 }
233 }
234 }
235
236 /**
237 * Searches the component tree beneath the component and return the first component matching the type.
238 */
239 public static <T extends UIComponent> T findDescendant(UIComponent component, Class<T> type) {
240
241 for (UIComponent child : (List<UIComponent>) component.getChildren()) {
242 if (type.isAssignableFrom(child.getClass())) {
243 return (T) child;
244 }
245 final T descendant = findDescendant(child, type);
246 if (descendant != null) {
247 return descendant;
248 }
249 }
250 return null;
251 }
252
253 /**
254 * Looks for the attribute "for" in the component. If there is any
255 * search for the component which is referenced by the "for" attribute,
256 * and return their clientId.
257 * If there is no "for" attribute, return the "clientId" of the parent
258 * (if it has a parent). This is useful for labels.
259 */
260 public static String findClientIdFor(UIComponent component, FacesContext facesContext) {
261 UIComponent forComponent = findFor(component);
262 if (forComponent != null) {
263 String clientId = forComponent.getClientId(facesContext);
264 if (LOG.isDebugEnabled()) {
265 LOG.debug("found clientId: '" + clientId + "'");
266 }
267 return clientId;
268 }
269 if (LOG.isDebugEnabled()) {
270 LOG.debug("found no clientId");
271 }
272 return null;
273 }
274
275 public static UIComponent findFor(UIComponent component) {
276 String forValue = (String) component.getAttributes().get(Attributes.FOR);
277 if (forValue == null) {
278 return component.getParent();
279 }
280 return component.findComponent(forValue);
281 }
282
283 /**
284 * Looks for the attribute "for" of the component.
285 * In case that the value is equals to "@auto" the children of the parent will be
286 * checked if they are a UIInput. The "id" of the first one will be used to reset the "for"
287 * attribute of the component.
288 */
289 public static void evaluateAutoFor(UIComponent component) {
290 String forComponent = (String) component.getAttributes().get(Attributes.FOR);
291 if (LOG.isDebugEnabled()) {
292 LOG.debug("for = '" + forComponent + "'");
293 }
294 if ("@auto".equals(forComponent)) {
295 for (Object object : component.getParent().getChildren()) {
296 UIComponent child = (UIComponent) object;
297 if (child instanceof UIInput) {
298 forComponent = child.getId();
299 component.getAttributes().put(Attributes.FOR, forComponent);
300 break;
301 }
302 }
303 }
304 }
305
306 public static boolean isInActiveForm(UIComponent component) {
307 while (component != null) {
308 if (component instanceof AbstractUIForm) {
309 AbstractUIForm form = (AbstractUIForm) component;
310 if (form.isSubmitted()) {
311 return true;
312 }
313 }
314 component = component.getParent();
315 }
316 return false;
317 }
318
319 public static FacesMessage.Severity getMaximumSeverity(UIComponent component) {
320 final boolean invalid = component instanceof javax.faces.component.UIInput
321 && !((javax.faces.component.UIInput) component).isValid();
322 FacesMessage.Severity max = invalid ? FacesMessage.SEVERITY_ERROR : null;
323 FacesContext facesContext = FacesContext.getCurrentInstance();
324 final Iterator messages = facesContext.getMessages(component.getClientId(facesContext));
325 while (messages.hasNext()) {
326 FacesMessage message = (FacesMessage) messages.next();
327 if (max == null || message.getSeverity().getOrdinal() > max.getOrdinal()) {
328 max = message.getSeverity();
329 }
330 }
331 return max;
332 }
333
334 public static boolean isError(javax.faces.component.UIInput uiInput) {
335 FacesContext facesContext = FacesContext.getCurrentInstance();
336 return !uiInput.isValid()
337 || facesContext.getMessages(uiInput.getClientId(facesContext)).hasNext();
338 }
339
340 public static boolean isError(UIComponent component) {
341 if (component instanceof AbstractUIInput) {
342 return isError((AbstractUIInput) component);
343 }
344 return false;
345 }
346
347 public static boolean isOutputOnly(UIComponent component) {
348 return getBooleanAttribute(component, Attributes.DISABLED)
349 || getBooleanAttribute(component, Attributes.READONLY);
350 }
351
352 public static boolean mayValidate(UIComponent component) {
353 return !isOutputOnly(component)
354 && ComponentUtils.isInActiveForm(component);
355 }
356
357 public static boolean mayUpdateModel(UIComponent component) {
358 return mayValidate(component);
359 }
360
361 public static boolean getBooleanAttribute(UIComponent component, String name) {
362
363 Object bool = component.getAttributes().get(name);
364 if (bool == null) {
365 return false;
366 }
367 if (bool instanceof ValueBinding) {
368 bool = ((ValueBinding) bool).getValue(FacesContext.getCurrentInstance());
369 }
370 if (bool instanceof Boolean) {
371 return (Boolean) bool;
372 } else if (bool instanceof String) {
373 LOG.warn("Searching for a boolean, but find a String. Should not happen. "
374 + "attribute: '" + name + "' id: '" + component.getClientId(FacesContext.getCurrentInstance())
375 + "' comp: '" + component + "'");
376 return Boolean.valueOf((String) bool);
377 } else {
378 LOG.warn("Unknown type '" + bool.getClass().getName()
379 + "' for boolean attribute: " + name + " id: " + component.getClientId(FacesContext.getCurrentInstance())
380 + " comp: " + component);
381 return false;
382 }
383 }
384
385
386
387 public static ValueBinding createValueBinding(String value) {
388 return FacesContext.getCurrentInstance().getApplication().createValueBinding(value);
389 }
390
391 /**
392 * @deprecated Please define a {@link Markup} and set it to the component with
393 * {@link SupportsMarkup#setMarkup(Markup markup)} before the rendering phase.
394 */
395 @Deprecated
396 public static void setStyleClasses(UIComponent component, String styleClasses) {
397 if (styleClasses != null) {
398 if (UIComponentTag.isValueReference(styleClasses)) {
399 component.setValueBinding(Attributes.STYLE_CLASS, createValueBinding(styleClasses));
400 } else {
401 String[] classes = splitList(styleClasses);
402 if (classes.length > 0) {
403 StyleClasses styles = StyleClasses.ensureStyleClasses(component);
404 for (String clazz : classes) {
405 styles.addFullQualifiedClass(clazz);
406 }
407 }
408 }
409 }
410 }
411
412 /**
413 * @deprecated since 1.5.0
414 */
415 @Deprecated
416 public static void setMarkup(UIComponent markupComponent, String markup) {
417 if (markup != null) {
418 if (markupComponent instanceof SupportsMarkup) {
419 if (UIComponentTag.isValueReference(markup)) {
420 markupComponent.setValueBinding(Attributes.MARKUP, createValueBinding(markup));
421 } else {
422 ((SupportsMarkup) markupComponent).setMarkup(Markup.valueOf(markup));
423 }
424 } else {
425 LOG.error("Component did not support Markup " + markupComponent.getClass().getName());
426 }
427 }
428 }
429
430 public static Object getAttribute(UIComponent component, String name) {
431 Object value = component.getAttributes().get(name);
432 if (value instanceof ValueBinding) {
433 value = ((ValueBinding) value).getValue(FacesContext.getCurrentInstance());
434 }
435 return value;
436 }
437
438 public static Object getObjectAttribute(UIComponent component, String name) {
439 return getAttribute(component, name);
440 }
441
442 public static String getStringAttribute(UIComponent component, String name) {
443 return (String) getAttribute(component, name);
444 }
445
446 public static int getIntAttribute(UIComponent component, String name) {
447 return getIntAttribute(component, name, 0);
448 }
449
450 public static int getIntAttribute(UIComponent component, String name,
451 int defaultValue) {
452 Object integer = component.getAttributes().get(name);
453 if (integer instanceof Number) {
454 return ((Number) integer).intValue();
455 } else if (integer instanceof String) {
456 try {
457 return Integer.parseInt((String) integer);
458 } catch (NumberFormatException e) {
459 LOG.warn("Can't parse number from string : \"" + integer + "\"!");
460 return defaultValue;
461 }
462 } else if (integer == null) {
463 return defaultValue;
464 } else {
465 LOG.warn("Unknown type '" + integer.getClass().getName()
466 + "' for integer attribute: " + name + " comp: " + component);
467 return defaultValue;
468 }
469 }
470
471 public static Character getCharacterAttribute(UIComponent component, String name) {
472 Object character = component.getAttributes().get(name);
473 if (character == null) {
474 return null;
475 } else if (character instanceof Character) {
476 return ((Character) character);
477 } else if (character instanceof String) {
478 String asString = ((String) character);
479 return asString.length() > 0 ? asString.charAt(0) : null;
480 } else {
481 LOG.warn("Unknown type '" + character.getClass().getName()
482 + "' for integer attribute: " + name + " comp: " + component);
483 return null;
484 }
485 }
486
487 public static boolean isFacetOf(UIComponent component, UIComponent parent) {
488 for (Object o : parent.getFacets().keySet()) {
489 UIComponent facet = parent.getFacet((String) o);
490 if (component.equals(facet)) {
491 return true;
492 }
493 }
494 return false;
495 }
496
497 public static RendererBase getRenderer(FacesContext facesContext, UIComponent component) {
498 return getRenderer(facesContext, component.getFamily(), component.getRendererType());
499 }
500
501 public static RendererBase getRenderer(FacesContext facesContext, String family, String rendererType) {
502 if (rendererType == null) {
503 return null;
504 }
505
506 Map<String, Object> requestMap = (Map<String, Object>) facesContext.getExternalContext().getRequestMap();
507 StringBuilder key = new StringBuilder(RENDER_KEY_PREFIX);
508 key.append(rendererType);
509 RendererBase renderer = (RendererBase) requestMap.get(key.toString());
510
511 if (renderer == null) {
512 Renderer myRenderer = getRendererInternal(facesContext, family, rendererType);
513 if (myRenderer instanceof RendererBase) {
514 requestMap.put(key.toString(), myRenderer);
515 renderer = (RendererBase) myRenderer;
516 } else {
517 return null;
518 }
519 }
520 return renderer;
521 }
522
523
524 private static Renderer getRendererInternal(FacesContext facesContext, String family, String rendererType) {
525 RenderKitFactory rkFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
526 RenderKit renderKit = rkFactory.getRenderKit(facesContext, facesContext.getViewRoot().getRenderKitId());
527 Renderer myRenderer = renderKit.getRenderer(family, rendererType);
528 return myRenderer;
529 }
530
531 public static Object findParameter(UIComponent component, String name) {
532 for (Object o : component.getChildren()) {
533 UIComponent child = (UIComponent) o;
534 if (child instanceof UIParameter) {
535 UIParameter parameter = (UIParameter) child;
536 if (LOG.isDebugEnabled()) {
537 LOG.debug("Select name='" + parameter.getName() + "'");
538 LOG.debug("Select value='" + parameter.getValue() + "'");
539 }
540 if (name.equals(parameter.getName())) {
541 return parameter.getValue();
542 }
543 }
544 }
545 return null;
546 }
547
548 public static ActionListener createActionListener(String type)
549 throws JspException {
550 try {
551 ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
552 if (classLoader == null) {
553 classLoader = type.getClass().getClassLoader();
554 }
555 Class clazz = classLoader.loadClass(type);
556 return (ActionListener) clazz.newInstance();
557 } catch (Exception e) {
558 if (LOG.isDebugEnabled()) {
559 LOG.debug("type=" + type, e);
560 }
561 throw new JspException(e);
562 }
563 }
564
565 public static UIGraphic getFirstGraphicChild(UIComponent component) {
566 UIGraphic graphic = null;
567 for (Object o : component.getChildren()) {
568 UIComponent uiComponent = (UIComponent) o;
569 if (uiComponent instanceof UIGraphic) {
570 graphic = (UIGraphic) uiComponent;
571 break;
572 }
573 }
574 return graphic;
575 }
576
577 public static boolean isHoverEnabled(UIComponent component) {
578 return ComponentUtils.getBooleanAttribute(component, Attributes.HOVER);
579 }
580
581 public static UIOutput getFirstNonGraphicChild(UIComponent component) {
582 for (UIComponent child : (List<UIComponent>) component.getChildren()) {
583 if (child instanceof UIOutput) {
584 return (UIOutput) child;
585 }
586 }
587 return null;
588 }
589
590 /**
591 * @deprecated since 1.5.0
592 */
593 @Deprecated
594 public static void setIntegerSizeProperty(UIComponent component, String name, String value) {
595 if (value != null) {
596 if (UIComponentTag.isValueReference(value)) {
597 component.setValueBinding(name, createValueBinding(value));
598 } else {
599 value = removePx(value);
600 component.getAttributes().put(name, new Integer(value));
601 }
602 }
603 }
604
605 public static String removePx(String value) {
606 if (value != null && value.endsWith("px")) {
607 value = value.substring(0, value.length() - 2);
608 }
609 return value;
610 }
611
612 public static void setValueForValueBinding(String name, Object value) {
613 FacesContext context = FacesContext.getCurrentInstance();
614 ValueBinding valueBinding = context.getApplication().createValueBinding(name);
615 valueBinding.setValue(context, value);
616 }
617
618
619 public static boolean hasSelectedValue(List<SelectItem> items, Object value) {
620 for (SelectItem item : items) {
621 if (item.getValue().equals(value)) {
622 return true;
623 }
624 }
625 return false;
626 }
627
628 public static int getIntValue(ValueBinding valueBinding) {
629 return getAsInt(valueBinding.getValue(FacesContext.getCurrentInstance()));
630 }
631
632 private static int getAsInt(Object value) {
633 int result;
634 if (value instanceof Number) {
635 result = ((Number) value).intValue();
636 } else if (value instanceof String) {
637 result = Integer.parseInt((String) value);
638 } else {
639 throw new IllegalArgumentException("Can't convert " + value + " to int!");
640 }
641 return result;
642 }
643
644
645 public static String createPickerId(FacesContext facesContext, UIComponent component, String postfix) {
646 //String id = component.getId();
647 String id = getComponentId(facesContext, component);
648 return id + "_picker" + postfix;
649 }
650
651 public static String getComponentId(FacesContext facesContext, UIComponent component) {
652 String id = component.getId();
653 //if (id == null) {
654 // XXX What is this?
655 // id = component.getClientId(facesContext).substring(id.lastIndexOf('_'));
656 //}
657 return id;
658 }
659
660 /**
661 * Checks if the Component has a label facet and if not creates one with the label attribute.
662 *
663 * Todo: check if this method should be set to deprecated.
664 */
665 public static UIComponent provideLabel(FacesContext facesContext, UIComponent component) {
666 UIComponent label = component.getFacet(Facets.LABEL);
667
668
669 if (label == null) {
670 final Map attributes = component.getAttributes();
671 Object labelText = component.getValueBinding(Attributes.LABEL);
672 if (labelText == null) {
673 labelText = attributes.get(Attributes.LABEL);
674 }
675
676 if (labelText != null) {
677 Application application = FacesContext.getCurrentInstance().getApplication();
678 label = application.createComponent(UIOutput.COMPONENT_TYPE);
679 label.setRendererType(RendererTypes.LABEL);
680 String idprefix = ComponentUtils.getComponentId(facesContext, component);
681 label.setId(idprefix + "_" + Facets.LABEL);
682 label.setRendered(true);
683
684 if (labelText instanceof ValueBinding) {
685 label.setValueBinding(Attributes.VALUE, (ValueBinding) labelText);
686 } else {
687 label.getAttributes().put(Attributes.VALUE, labelText);
688 }
689
690 component.getFacets().put(Facets.LABEL, label);
691 }
692 }
693 return label;
694 }
695
696 /**
697 * @deprecated since 1.5.0
698 */
699 @Deprecated
700 public static void setValidator(EditableValueHolder editableValueHolder, String validator) {
701 if (validator != null && editableValueHolder.getValidator() == null) {
702 if (UIComponentTag.isValueReference(validator)) {
703 MethodBinding methodBinding =
704 FacesContext.getCurrentInstance().getApplication().createMethodBinding(validator, VALIDATOR_ARGS);
705 editableValueHolder.setValidator(methodBinding);
706 }
707 }
708 }
709
710 /**
711 * @deprecated since 1.5.0
712 */
713 @Deprecated
714 public static void setConverter(ValueHolder valueHolder, String converterId) {
715 if (converterId != null && valueHolder.getConverter() == null) {
716 final FacesContext facesContext = FacesContext.getCurrentInstance();
717 final Application application = facesContext.getApplication();
718 if (UIComponentTag.isValueReference(converterId)) {
719 ValueBinding valueBinding = application.createValueBinding(converterId);
720 if (valueHolder instanceof UIComponent) {
721 ((UIComponent) valueHolder).setValueBinding(Attributes.CONVERTER, valueBinding);
722 }
723 } else {
724 Converter converter = application.createConverter(converterId);
725 valueHolder.setConverter(converter);
726 }
727 }
728 }
729
730 /**
731 * @deprecated since 1.5.0
732 */
733 @Deprecated
734 public static void setAction(ActionSource component, String action) {
735 if (action != null) {
736 if (UIComponentTag.isValueReference(action)) {
737 final FacesContext facesContext = FacesContext.getCurrentInstance();
738 final Application application = facesContext.getApplication();
739 MethodBinding binding = application.createMethodBinding(action, null);
740 component.setAction(binding);
741 } else {
742 component.setAction(new ConstantMethodBinding(action));
743 }
744 }
745 }
746
747 /**
748 * @deprecated since 1.5.0
749 */
750 @Deprecated
751 public static void setActionListener(ActionSource command, String actionListener) {
752 final FacesContext facesContext = FacesContext.getCurrentInstance();
753 final Application application = facesContext.getApplication();
754 if (actionListener != null) {
755 if (UIComponentTag.isValueReference(actionListener)) {
756 MethodBinding binding
757 = application.createMethodBinding(actionListener, ACTION_LISTENER_ARGS);
758 command.setActionListener(binding);
759 } else {
760 throw new IllegalArgumentException(
761 "Must be a valueReference (actionListener): " + actionListener);
762 }
763 }
764 }
765
766 /**
767 * @deprecated since 1.5.0
768 */
769 @Deprecated
770 public static void setValueChangeListener(EditableValueHolder valueHolder, String valueChangeListener) {
771 final FacesContext facesContext = FacesContext.getCurrentInstance();
772 final Application application = facesContext.getApplication();
773 if (valueChangeListener != null) {
774 if (UIComponentTag.isValueReference(valueChangeListener)) {
775 MethodBinding binding
776 = application.createMethodBinding(valueChangeListener, VALUE_CHANGE_LISTENER_ARGS);
777 valueHolder.setValueChangeListener(binding);
778 } else {
779 throw new IllegalArgumentException(
780 "Must be a valueReference (valueChangeListener): " + valueChangeListener);
781 }
782 }
783 }
784
785 /**
786 * @deprecated since 1.5.0
787 */
788 @Deprecated
789 public static void setValueBinding(UIComponent component, String name, String state) {
790 // TODO: check, if it is an writeable object
791 if (state != null && UIComponentTag.isValueReference(state)) {
792 ValueBinding valueBinding = createValueBinding(state);
793 component.setValueBinding(name, valueBinding);
794 }
795 }
796
797 /**
798 * @deprecated since 1.5
799 */
800 @Deprecated
801 public static String[] getMarkupBinding(FacesContext facesContext, SupportsMarkup component) {
802 ValueBinding vb = ((UIComponent) component).getValueBinding(Attributes.MARKUP);
803 if (vb != null) {
804 Object markups = vb.getValue(facesContext);
805 if (markups instanceof String[]) {
806 return (String[]) markups;
807 } else if (markups instanceof String) {
808 String[] strings = StringUtils.split((String) markups, ", ");
809 List<String> result = new ArrayList<String>(strings.length);
810 for (String string : strings) {
811 if (string.trim().length() != 0) {
812 result.add(string.trim());
813 }
814 }
815 return result.toArray(new String[result.size()]);
816 } else if (markups == null) {
817 return ArrayUtils.EMPTY_STRING_ARRAY;
818 } else {
819 return new String[]{markups.toString()};
820 }
821 }
822
823 return ArrayUtils.EMPTY_STRING_ARRAY;
824 }
825
826 /**
827 * The search depends on the number of colons in the relativeId:
828 * <dl>
829 * <dd>colonCount == 0</dd>
830 * <dt>fully relative</dt>
831 * <dd>colonCount == 1</dd>
832 * <dt>absolute (still normal findComponent syntax)</dt>
833 * <dd>colonCount > 1</dd>
834 * <dt>for each extra colon after 1, go up a naming container</dt>
835 * </dl>
836 * (to the view root, if naming containers run out)
837 */
838 public static UIComponent findComponent(UIComponent from, String relativeId) {
839 return FindComponentUtils.findComponent(from, relativeId);
840 }
841
842 public static String[] splitList(String renderers) {
843 return StringUtils.split(renderers, LIST_SEPARATOR_CHARS);
844 }
845
846 public static Object getConvertedValue(
847 FacesContext facesContext, UIComponent component, String stringValue) {
848 try {
849 Renderer renderer = getRenderer(facesContext, component);
850 if (renderer != null) {
851 if (component instanceof UISelectMany) {
852 final Object converted = renderer.getConvertedValue(facesContext, component, new String[]{stringValue});
853 return ((Object[]) converted)[0];
854 } else {
855 return renderer.getConvertedValue(facesContext, component, stringValue);
856 }
857 } else if (component instanceof ValueHolder) {
858 Converter converter = ((ValueHolder) component).getConverter();
859 if (converter == null) {
860 //Try to find out by value binding
861 ValueBinding vb = component.getValueBinding("value");
862 if (vb != null) {
863 Class valueType = vb.getType(facesContext);
864 if (valueType != null) {
865 converter = facesContext.getApplication().createConverter(valueType);
866 }
867 }
868 }
869 if (converter != null) {
870 converter.getAsObject(facesContext, component, stringValue);
871 }
872 }
873 } catch (Exception e) {
874 LOG.warn("Can't convert string value '" + stringValue + "'", e);
875 }
876 return stringValue;
877 }
878
879 public static Markup updateMarkup(UIComponent component, Markup markup) {
880 if (markup == null) {
881 markup = Markup.NULL;
882 }
883 if (ComponentUtils.getBooleanAttribute(component, Attributes.DISABLED)) {
884 markup = markup.add(Markup.DISABLED);
885 }
886 if (ComponentUtils.getBooleanAttribute(component, Attributes.READONLY)) {
887 markup = markup.add(Markup.READONLY);
888 }
889 if (component instanceof UIInput) {
890 UIInput input = (UIInput) component;
891
892 final FacesMessage.Severity maximumSeverity = ComponentUtils.getMaximumSeverity(input);
893 markup = markup.add(markupOfSeverity(maximumSeverity));
894
895 if (input.isRequired()) {
896 markup = markup.add(Markup.REQUIRED);
897 }
898 }
899 return markup;
900 }
901
902 public static Markup markupOfSeverity(FacesMessage.Severity maximumSeverity) {
903 if (FacesMessage.SEVERITY_FATAL.equals(maximumSeverity)) {
904 return Markup.FATAL;
905 } else if (FacesMessage.SEVERITY_ERROR.equals(maximumSeverity)) {
906 return Markup.ERROR;
907 } else if (FacesMessage.SEVERITY_WARN.equals(maximumSeverity)) {
908 return Markup.WARN;
909 } else if (FacesMessage.SEVERITY_INFO.equals(maximumSeverity)) {
910 return Markup.INFO;
911 }
912 return null;
913 }
914
915 public static boolean hasChildrenWithMessages(FacesContext facesContext, NamingContainer container) {
916 if (container instanceof UIComponent) {
917 String clientId = ((UIComponent) container).getClientId(facesContext);
918 for (Iterator ids = facesContext.getClientIdsWithMessages(); ids.hasNext();) {
919 String id = (String) ids.next();
920 if (id.startsWith(clientId)) {
921 return true;
922 }
923 }
924 }
925 return false;
926 }
927
928 public static FacesMessage.Severity getMaximumSeverityOfChildrenMessages(
929 FacesContext facesContext, NamingContainer container) {
930 if (container instanceof UIComponent) {
931 String clientId = ((UIComponent) container).getClientId(facesContext);
932 FacesMessage.Severity max = null;
933 for (Iterator ids = facesContext.getClientIdsWithMessages(); ids.hasNext();) {
934 String id = (String) ids.next();
935 if (id != null && id.startsWith(clientId)) {
936 final Iterator messages = facesContext.getMessages(id);
937 while (messages.hasNext()) {
938 FacesMessage message = (FacesMessage) messages.next();
939 if (max == null || message.getSeverity().getOrdinal() > max.getOrdinal()) {
940 max = message.getSeverity();
941 }
942 }
943 }
944 }
945 return max;
946 }
947 return null;
948 }
949
950 public static String[] getChildrenWithMessages(FacesContext facesContext, NamingContainer container) {
951 if (container instanceof UIComponent) {
952 List<String> clientIds = new ArrayList<String>();
953 String clientId = ((UIComponent) container).getClientId(facesContext);
954 for (Iterator ids = facesContext.getClientIdsWithMessages(); ids.hasNext();) {
955 String id = (String) ids.next();
956 if (id.startsWith(clientId)) {
957 clientIds.add(id);
958 }
959 }
960 return clientIds.toArray(new String[clientIds.size()]);
961 }
962 return ArrayUtils.EMPTY_STRING_ARRAY;
963 }
964 }