1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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.Visual;
26 import org.apache.myfaces.tobago.context.Markup;
27 import org.apache.myfaces.tobago.context.TransientStateHolder;
28 import org.apache.myfaces.tobago.internal.component.AbstractUIForm;
29 import org.apache.myfaces.tobago.internal.component.AbstractUIFormBase;
30 import org.apache.myfaces.tobago.internal.component.AbstractUIInput;
31 import org.apache.myfaces.tobago.internal.component.AbstractUIPage;
32 import org.apache.myfaces.tobago.internal.component.AbstractUIPopup;
33 import org.apache.myfaces.tobago.internal.component.AbstractUIReload;
34 import org.apache.myfaces.tobago.internal.component.AbstractUISheet;
35 import org.apache.myfaces.tobago.internal.util.StringUtils;
36 import org.apache.myfaces.tobago.renderkit.RendererBase;
37 import org.apache.myfaces.tobago.renderkit.html.DataAttributes;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import javax.el.ValueExpression;
42 import javax.faces.FactoryFinder;
43 import javax.faces.application.FacesMessage;
44 import javax.faces.component.NamingContainer;
45 import javax.faces.component.UIComponent;
46 import javax.faces.component.UIInput;
47 import javax.faces.component.UINamingContainer;
48 import javax.faces.component.UIParameter;
49 import javax.faces.component.UISelectMany;
50 import javax.faces.component.UIViewRoot;
51 import javax.faces.component.ValueHolder;
52 import javax.faces.context.FacesContext;
53 import javax.faces.convert.Converter;
54 import javax.faces.convert.ConverterException;
55 import javax.faces.event.ActionEvent;
56 import javax.faces.event.ValueChangeEvent;
57 import javax.faces.render.RenderKit;
58 import javax.faces.render.RenderKitFactory;
59 import javax.faces.render.Renderer;
60 import javax.faces.view.facelets.FaceletContext;
61 import java.lang.invoke.MethodHandles;
62 import java.util.ArrayList;
63 import java.util.Collection;
64 import java.util.HashMap;
65 import java.util.Iterator;
66 import java.util.List;
67 import java.util.Map;
68
69 public final class ComponentUtils {
70
71 private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
72
73 public static final String SUB_SEPARATOR = "::";
74
75 private static final String RENDER_KEY_PREFIX
76 = "org.apache.myfaces.tobago.util.ComponentUtils.RendererKeyPrefix_";
77
78 private static final String PAGE_KEY = "org.apache.myfaces.tobago.Page.Key";
79
80 public static final Class[] ACTION_ARGS = {};
81 public static final Class[] ACTION_LISTENER_ARGS = {ActionEvent.class};
82 public static final Class[] VALUE_CHANGE_LISTENER_ARGS = {ValueChangeEvent.class};
83 public static final Class[] VALIDATOR_ARGS = {FacesContext.class, UIComponent.class, Object.class};
84 public static final String LIST_SEPARATOR_CHARS = ", ";
85
86
87
88
89
90
91 public static final String DATA_ATTRIBUTES_KEY = "javax.faces.component.DATA_ATTRIBUTES_KEY";
92
93 private ComponentUtils() {
94 }
95
96
97
98
99 @Deprecated
100 public static boolean hasErrorMessages(final FacesContext context) {
101 for (final FacesMessage message : (Iterable<FacesMessage>) context::getMessages) {
102 if (FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0) {
103 return true;
104 }
105 }
106 return false;
107 }
108
109 public static String getFacesMessageAsString(final FacesContext facesContext, final UIComponent component) {
110 final Iterator messages = facesContext.getMessages(
111 component.getClientId(facesContext));
112 final StringBuilder stringBuffer = new StringBuilder();
113 while (messages.hasNext()) {
114 final FacesMessage message = (FacesMessage) messages.next();
115 stringBuffer.append(message.getDetail());
116 }
117 if (stringBuffer.length() > 0) {
118 return stringBuffer.toString();
119 } else {
120 return null;
121 }
122 }
123
124
125
126
127 @Deprecated
128 public static boolean isInPopup(final UIComponent component) {
129 UIComponent c = component;
130 while (c != null) {
131 if (c instanceof AbstractUIPopup) {
132 return true;
133 }
134 c = c.getParent();
135 }
136 return false;
137 }
138
139
140
141
142 @Deprecated
143 public static void resetPage(final FacesContext context) {
144 final UIViewRoot view = context.getViewRoot();
145 if (view != null) {
146 view.getAttributes().remove(PAGE_KEY);
147 }
148 }
149
150
151
152
153
154 public static UIViewRoot findViewRoot(final FaceletContext faceletContext, final UIComponent component) {
155 final UIViewRoot viewRoot = findAncestor(component, UIViewRoot.class);
156 if (viewRoot != null) {
157 return viewRoot;
158 } else {
159 return faceletContext.getFacesContext().getViewRoot();
160 }
161 }
162
163 public static AbstractUIPage findPage(final FacesContext context, final UIComponent component) {
164 final UIViewRoot view = context.getViewRoot();
165 if (view != null) {
166 TransientStateHolder stateHolder = (TransientStateHolder) view.getAttributes().get(PAGE_KEY);
167 if (stateHolder == null || stateHolder.isEmpty()) {
168 final AbstractUIPage page = findPage(component);
169 stateHolder = new TransientStateHolder(page);
170 context.getViewRoot().getAttributes().put(PAGE_KEY, stateHolder);
171 }
172 return (AbstractUIPage) stateHolder.get();
173 } else {
174 return findPage(component);
175 }
176 }
177
178 public static AbstractUIPage findPage(final UIComponent component) {
179 UIComponent c = component;
180 if (c instanceof UIViewRoot) {
181 return findPageBreadthFirst(c);
182 } else {
183 while (c != null) {
184 if (c instanceof AbstractUIPage) {
185 return (AbstractUIPage) c;
186 }
187 c = c.getParent();
188 }
189 return null;
190 }
191 }
192
193 public static AbstractUIPage findPage(final FacesContext facesContext) {
194 return findPageBreadthFirst(facesContext.getViewRoot());
195 }
196
197 private static AbstractUIPage findPageBreadthFirst(final UIComponent component) {
198 for (final UIComponent child : component.getChildren()) {
199 if (child instanceof AbstractUIPage) {
200 return (AbstractUIPage) child;
201 }
202 }
203 for (final UIComponent child : component.getChildren()) {
204 final AbstractUIPage result = findPageBreadthFirst(child);
205 if (result != null) {
206 return result;
207 }
208 }
209 return null;
210 }
211
212 public static AbstractUIFormBase findForm(final UIComponent component) {
213 UIComponent c = component;
214 while (c != null) {
215 if (c instanceof AbstractUIFormBase) {
216 return (AbstractUIFormBase) c;
217 }
218 c = c.getParent();
219 }
220 return null;
221 }
222
223 public static <T> T findAncestor(final UIComponent component, final Class<T> type) {
224 UIComponent c = component;
225 while (c != null) {
226 if (type.isAssignableFrom(c.getClass())) {
227 return (T) c;
228 }
229 c = c.getParent();
230 }
231 return null;
232 }
233
234
235
236
237 public static List<AbstractUIForm> findSubForms(final UIComponent component) {
238 final List<AbstractUIForm> collect = new ArrayList<>();
239 findSubForms(collect, component);
240 return collect;
241 }
242
243 @SuppressWarnings("unchecked")
244 private static void findSubForms(final List<AbstractUIForm> collect, final UIComponent component) {
245 final Iterator<UIComponent> kids = component.getFacetsAndChildren();
246 while (kids.hasNext()) {
247 final UIComponent child = kids.next();
248 if (child instanceof AbstractUIForm) {
249 collect.add((AbstractUIForm) child);
250 } else {
251 findSubForms(collect, child);
252 }
253 }
254 }
255
256
257
258
259 public static <T extends UIComponent> T findDescendant(final UIComponent component, final Class<T> type) {
260
261 for (final UIComponent child : component.getChildren()) {
262 if (type.isAssignableFrom(child.getClass())) {
263 return (T) child;
264 }
265 final T descendant = findDescendant(child, type);
266 if (descendant != null) {
267 return descendant;
268 }
269 }
270 return null;
271 }
272
273
274
275
276 public static <T extends UIComponent> T findFacetDescendant(
277 final UIComponent component, final Facets facet, final Class<T> type) {
278
279 final UIComponent facetComponent = component.getFacet(facet.name());
280 if (facetComponent != null) {
281 if (type.isAssignableFrom(facetComponent.getClass())) {
282 return (T) facetComponent;
283 } else {
284 return findDescendant(facetComponent, type);
285 }
286 } else {
287 return null;
288 }
289 }
290
291
292
293
294 public static <T extends UIComponent> T findChild(final UIComponent component, final Class<T> type) {
295
296 for (final UIComponent child : component.getChildren()) {
297 if (type.isAssignableFrom(child.getClass())) {
298 return (T) child;
299 }
300 }
301 return null;
302 }
303
304
305
306
307 public static <T extends UIComponent> List<T> findDescendantList(final UIComponent component, final Class<T> type) {
308
309 final List<T> result = new ArrayList<>();
310
311 for (final UIComponent child : component.getChildren()) {
312 if (type.isAssignableFrom(child.getClass())) {
313 result.add((T) child);
314 }
315 result.addAll(findDescendantList(child, type));
316 }
317 return result;
318 }
319
320
321
322
323
324
325 public static String findClientIdFor(final UIComponent component, final FacesContext facesContext) {
326 final UIComponent forComponent = findFor(component);
327 if (forComponent != null) {
328 final String clientId = forComponent.getClientId(facesContext);
329 if (LOG.isDebugEnabled()) {
330 LOG.debug("found clientId: '" + clientId + "'");
331 }
332 return clientId;
333 }
334 if (LOG.isDebugEnabled()) {
335 LOG.debug("found no clientId");
336 }
337 return null;
338 }
339
340 public static UIComponent findFor(final UIComponent component) {
341 final String forValue = getStringAttribute(component, Attributes.forValue);
342 if (forValue == null) {
343 return component.getParent();
344 }
345 return ComponentUtils.findComponent(component, forValue);
346 }
347
348
349
350
351
352
353 public static void evaluateAutoFor(final UIComponent component, final Class<? extends UIComponent> clazz) {
354 final String forComponent = getStringAttribute(component, Attributes.forValue);
355 if (LOG.isDebugEnabled()) {
356 LOG.debug("for = '" + forComponent + "'");
357 }
358 if ("@auto".equals(forComponent)) {
359
360 for (final UIComponent child : component.getParent().getChildren()) {
361 if (setForToInput(component, child, clazz, component instanceof NamingContainer)) {
362 return;
363 }
364 }
365
366 for (final UIComponent child : component.getParent().getParent().getChildren()) {
367 if (setForToInput(component, child, clazz, component.getParent() instanceof NamingContainer)) {
368 return;
369 }
370 }
371 }
372 }
373
374 private static boolean setForToInput(
375 final UIComponent component, final UIComponent child, final Class<? extends UIComponent> clazz,
376 final boolean namingContainer) {
377 if (clazz.isAssignableFrom(child.getClass())) {
378 final String forComponent;
379 if (namingContainer) {
380 forComponent = ":::" + child.getId();
381 } else {
382 forComponent = child.getId();
383 }
384 ComponentUtils.setAttribute(component, Attributes.forValue, forComponent);
385 return true;
386 }
387 return false;
388 }
389
390
391
392
393 @Deprecated
394 public static boolean isInActiveForm(final UIComponent component) {
395 UIComponent c = component;
396 while (c != null) {
397 if (c instanceof AbstractUIFormBase) {
398 final AbstractUIFormBase form = (AbstractUIFormBase) c;
399 if (form.isSubmitted()) {
400 return true;
401 }
402 }
403 c = c.getParent();
404 }
405 return false;
406 }
407
408 public static FacesMessage.Severity getMaximumSeverity(final UIComponent component) {
409 final FacesContext facesContext = FacesContext.getCurrentInstance();
410 final List<FacesMessage> messages = facesContext.getMessageList(component.getClientId(facesContext));
411 final FacesMessage.Severity maximumSeverity = getMaximumSeverity(messages);
412
413 final boolean invalid = component instanceof UIInput && !((UIInput) component).isValid();
414
415 return invalid
416 && (maximumSeverity == null || FacesMessage.SEVERITY_ERROR.getOrdinal() > maximumSeverity.getOrdinal())
417 ? FacesMessage.SEVERITY_ERROR : maximumSeverity;
418 }
419
420 public static FacesMessage.Severity getMaximumSeverity(final List<FacesMessage> messages) {
421 FacesMessage.Severity max = null;
422 for (final FacesMessage message : messages) {
423 if (max == null || message.getSeverity().getOrdinal() > max.getOrdinal()) {
424 max = message.getSeverity();
425 }
426 }
427 return max;
428 }
429
430
431
432
433 @Deprecated
434 public static boolean isError(final UIInput uiInput) {
435 final FacesContext facesContext = FacesContext.getCurrentInstance();
436 return !uiInput.isValid()
437 || facesContext.getMessages(uiInput.getClientId(facesContext)).hasNext();
438 }
439
440
441
442
443 @Deprecated
444 public static boolean isError(final UIComponent component) {
445 if (component instanceof AbstractUIInput) {
446 return isError((AbstractUIInput) component);
447 }
448 return false;
449 }
450
451
452
453
454 @Deprecated
455 public static boolean isOutputOnly(final UIComponent component) {
456 return getBooleanAttribute(component, Attributes.disabled)
457 || getBooleanAttribute(component, Attributes.readonly);
458 }
459
460 public static Object getAttribute(final UIComponent component, final Attributes name) {
461 return component.getAttributes().get(name.getName());
462 }
463
464 public static boolean getBooleanAttribute(final UIComponent component, final Attributes name) {
465 return getBooleanAttribute(component, name, false);
466 }
467
468 public static boolean getBooleanAttribute(
469 final UIComponent component, final Attributes name, final boolean defaultValue) {
470
471 final Object bool = component.getAttributes().get(name.getName());
472 if (bool == null) {
473 return defaultValue;
474 } else if (bool instanceof Boolean) {
475 return (Boolean) bool;
476 } else {
477 return Boolean.valueOf(bool.toString());
478 }
479 }
480
481 public static String getStringAttribute(final UIComponent component, final Attributes name) {
482 return getStringAttribute(component, name, null);
483 }
484
485 public static String getStringAttribute(
486 final UIComponent component, final Attributes name, final String defaultValue) {
487 final String result = (String) getAttribute(component, name);
488 return result != null ? result : defaultValue;
489 }
490
491 public static int getIntAttribute(final UIComponent component, final Attributes name) {
492 return getIntAttribute(component, name, 0);
493 }
494
495 public static int getIntAttribute(final UIComponent component, final Attributes name, final int defaultValue) {
496 final Object integer = component.getAttributes().get(name.getName());
497 if (integer instanceof Number) {
498 return ((Number) integer).intValue();
499 } else if (integer instanceof String) {
500 try {
501 return Integer.parseInt((String) integer);
502 } catch (final NumberFormatException e) {
503 LOG.warn("Can't parse number from string : \"" + integer + "\"!");
504 return defaultValue;
505 }
506 } else if (integer == null) {
507 return defaultValue;
508 } else {
509 LOG.warn("Unknown type '" + integer.getClass().getName()
510 + "' for integer attribute: " + name + " comp: " + component);
511 return defaultValue;
512 }
513 }
514
515 public static Character getCharacterAttribute(final UIComponent component, final Attributes name) {
516 final Object character = getAttribute(component, name);
517 if (character == null) {
518 return null;
519 } else if (character instanceof Character) {
520 return (Character) character;
521 } else if (character instanceof String) {
522 final String asString = (String) character;
523 return asString.length() > 0 ? asString.charAt(0) : null;
524 } else {
525 LOG.warn("Unknown type '" + character.getClass().getName()
526 + "' for integer attribute: " + name + " comp: " + component);
527 return null;
528 }
529 }
530
531 public static void setAttribute(final UIComponent component, final Attributes name, final Object value) {
532 component.getAttributes().put(name.getName(), value);
533 }
534
535 public static void removeAttribute(final UIComponent component, final Attributes name) {
536 component.getAttributes().remove(name.getName());
537 }
538
539 public static UIComponent getFacet(final UIComponent component, final Facets facet) {
540 return component.getFacet(facet.name());
541 }
542
543 public static void setFacet(final UIComponent component, final Facets facet, final UIComponent child) {
544 component.getFacets().put(facet.name(), child);
545 }
546
547 public static void removeFacet(final UIComponent component, final Facets facet) {
548 component.getFacets().remove(facet.name());
549 }
550
551 public static AbstractUIReload getReloadFacet(final UIComponent component) {
552 final UIComponent facet = getFacet(component, Facets.reload);
553 if (facet == null) {
554 return null;
555 } else if (facet instanceof AbstractUIReload) {
556 return (AbstractUIReload) facet;
557 } else {
558 LOG.warn("Content of a reload facet must be {} but found {} in component with id '{}'",
559 AbstractUIReload.class.getName(), facet.getClass().getName(), component.getClientId());
560 return null;
561 }
562 }
563
564 public static boolean isFacetOf(final UIComponent component, final UIComponent parent) {
565 for (final Object o : parent.getFacets().keySet()) {
566 final UIComponent facet = parent.getFacet((String) o);
567 if (component.equals(facet)) {
568 return true;
569 }
570 }
571 return false;
572 }
573
574 public static RendererBase getRenderer(final FacesContext facesContext, final UIComponent component) {
575 return getRenderer(facesContext, component.getFamily(), component.getRendererType());
576 }
577
578 public static RendererBase getRenderer(final FacesContext facesContext, final String family,
579 final String rendererType) {
580 if (rendererType == null) {
581 return null;
582 }
583
584 final Map<String, Object> requestMap = facesContext.getExternalContext().getRequestMap();
585 final StringBuilder key = new StringBuilder(RENDER_KEY_PREFIX);
586 key.append(rendererType);
587 RendererBase renderer = (RendererBase) requestMap.get(key.toString());
588
589 if (renderer == null) {
590 final Renderer myRenderer = getRendererInternal(facesContext, family, rendererType);
591 if (myRenderer instanceof RendererBase) {
592 requestMap.put(key.toString(), myRenderer);
593 renderer = (RendererBase) myRenderer;
594 } else {
595 return null;
596 }
597 }
598 return renderer;
599 }
600
601
602 private static Renderer getRendererInternal(
603 final FacesContext facesContext, final String family, final String rendererType) {
604 final RenderKitFactory rkFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
605 final RenderKit renderKit = rkFactory.getRenderKit(facesContext, facesContext.getViewRoot().getRenderKitId());
606 final Renderer myRenderer = renderKit.getRenderer(family, rendererType);
607 return myRenderer;
608 }
609
610 public static Object findParameter(final UIComponent component, final String name) {
611 for (final UIComponent child : component.getChildren()) {
612 if (child instanceof UIParameter) {
613 final UIParameter parameter = (UIParameter) child;
614 if (LOG.isDebugEnabled()) {
615 LOG.debug("Select name='" + parameter.getName() + "'");
616 LOG.debug("Select value='" + parameter.getValue() + "'");
617 }
618 if (name.equals(parameter.getName())) {
619 return parameter.getValue();
620 }
621 }
622 }
623 return null;
624 }
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646 public static UIComponent findComponent(final UIComponent from, final String relativeId) {
647 UIComponent from1 = from;
648 String relativeId1 = relativeId;
649 final int idLength = relativeId1.length();
650 if (idLength > 0
651 && relativeId1.charAt(0) == '@'
652 && "@this".equals(relativeId1)) {
653 return from1;
654 }
655
656
657 int colonCount = 0;
658 while (colonCount < idLength) {
659 if (relativeId1.charAt(colonCount) != UINamingContainer.getSeparatorChar(FacesContext.getCurrentInstance())) {
660 break;
661 }
662 colonCount++;
663 }
664
665
666
667
668
669 if (colonCount > 1) {
670 relativeId1 = relativeId1.substring(colonCount);
671 for (int j = 1; j < colonCount; j++) {
672 while (from1.getParent() != null) {
673 from1 = from1.getParent();
674 if (from1 instanceof NamingContainer) {
675 break;
676 }
677 }
678 }
679 }
680 return from1.findComponent(relativeId1);
681 }
682
683
684
685
686 public static String evaluateClientIds(
687 final FacesContext context, final UIComponent component, final String[] componentIds) {
688 final List<String> result = new ArrayList<>(componentIds.length);
689 for (final String id : componentIds) {
690 if (!StringUtils.isBlank(id)) {
691 final String clientId = evaluateClientId(context, component, id);
692 if (clientId != null) {
693 result.add(clientId);
694 }
695 }
696 }
697 if (result.isEmpty()) {
698 return null;
699 } else {
700 return StringUtils.join(result, ' ');
701 }
702 }
703
704
705
706
707 public static String evaluateClientId(
708 final FacesContext context, final UIComponent component, final String componentId) {
709 final UIComponent partiallyComponent = ComponentUtils.findComponent(component, componentId);
710 if (partiallyComponent != null) {
711 final String clientId = partiallyComponent.getClientId(context);
712 if (partiallyComponent instanceof AbstractUISheet) {
713 final int rowIndex = ((AbstractUISheet) partiallyComponent).getRowIndex();
714 if (rowIndex >= 0 && clientId.endsWith(Integer.toString(rowIndex))) {
715 return clientId.substring(0, clientId.lastIndexOf(UINamingContainer.getSeparatorChar(context)));
716 }
717 }
718 return clientId;
719 }
720 LOG.error("No component found for id='{}', search base component is '{}'",
721 componentId, component != null ? component.getClientId(context) : "<null>");
722 return null;
723 }
724
725 public static String[] splitList(final String renderers) {
726 return StringUtils.split(renderers, LIST_SEPARATOR_CHARS);
727 }
728
729 public static Object getConvertedValue(
730 final FacesContext facesContext, final UIComponent component, final String stringValue) {
731 try {
732 final Renderer renderer = getRenderer(facesContext, component);
733 if (renderer != null) {
734 if (component instanceof UISelectMany) {
735 final Object converted = renderer.getConvertedValue(facesContext, component, new String[]{stringValue});
736 if (converted instanceof Object[]) {
737 return ((Object[]) converted)[0];
738 } else if (converted instanceof List) {
739 return ((List) converted).get(0);
740 } else if (converted instanceof Collection) {
741 return ((Collection) converted).iterator().next();
742 } else {
743 return null;
744 }
745 } else {
746 return renderer.getConvertedValue(facesContext, component, stringValue);
747 }
748 } else if (component instanceof ValueHolder) {
749 Converter converter = ((ValueHolder) component).getConverter();
750 if (converter == null) {
751
752 final ValueExpression expression = component.getValueExpression("value");
753 if (expression != null) {
754 final Class valueType = expression.getType(facesContext.getELContext());
755 if (valueType != null) {
756 converter = facesContext.getApplication().createConverter(valueType);
757 }
758 }
759 }
760 if (converter != null) {
761 converter.getAsObject(facesContext, component, stringValue);
762 }
763 }
764 } catch (final Exception e) {
765 LOG.warn("Can't convert string value '" + stringValue + "'", e);
766 }
767 return stringValue;
768 }
769
770 public static Markup markupOfSeverity(final FacesMessage.Severity maximumSeverity) {
771 if (FacesMessage.SEVERITY_FATAL.equals(maximumSeverity)) {
772 return Markup.FATAL;
773 } else if (FacesMessage.SEVERITY_ERROR.equals(maximumSeverity)) {
774 return Markup.ERROR;
775 } else if (FacesMessage.SEVERITY_WARN.equals(maximumSeverity)) {
776 return Markup.WARN;
777 } else if (FacesMessage.SEVERITY_INFO.equals(maximumSeverity)) {
778 return Markup.INFO;
779 }
780 return null;
781 }
782
783 public static FacesMessage.Severity getMaximumSeverityOfChildrenMessages(
784 final FacesContext facesContext, final NamingContainer container) {
785 if (container instanceof UIComponent) {
786 final String clientId = ((UIComponent) container).getClientId(facesContext);
787 FacesMessage.Severity max = null;
788 for (final String id : (Iterable<String>) facesContext::getClientIdsWithMessages) {
789 if (id != null && id.startsWith(clientId)) {
790 final Iterator messages = facesContext.getMessages(id);
791 while (messages.hasNext()) {
792 final FacesMessage message = (FacesMessage) messages.next();
793 if (max == null || message.getSeverity().getOrdinal() > max.getOrdinal()) {
794 max = message.getSeverity();
795 }
796 }
797 }
798 }
799 return max;
800 }
801 return null;
802 }
803
804
805
806
807 public static void putDataAttributeWithPrefix(
808 final UIComponent component, final DataAttributes name, final Object value) {
809 if (name.getValue().startsWith("data-")) {
810 putDataAttribute(component, name.getValue().substring(5), value);
811 } else {
812 LOG.error("The name must start with 'data-' but it doesn't: '" + name + "'");
813 }
814 }
815
816
817
818
819 public static void putDataAttribute(final UIComponent component, final Object name, final Object value) {
820 Map<Object, Object> map = getDataAttributes(component);
821 if (map == null) {
822 map = new HashMap<>();
823 component.getAttributes().put(DATA_ATTRIBUTES_KEY, map);
824 }
825 if (map.containsKey(name)) {
826 LOG.warn("Data attribute '{}' is already set for component '{}' (old value='{}', new value='{}')!",
827 name, component.getClientId(), map.get(name), value);
828 }
829 map.put(name, value);
830 }
831
832 @SuppressWarnings("unchecked")
833 public static Map<Object, Object> getDataAttributes(final UIComponent component) {
834 return (Map<Object, Object>) component.getAttributes().get(DATA_ATTRIBUTES_KEY);
835 }
836
837 public static Object getDataAttribute(final UIComponent component, final String name) {
838 final Map<Object, Object> map = getDataAttributes(component);
839 return map != null ? map.get(name) : null;
840 }
841
842
843
844
845 public static Converter getConverter(
846 final FacesContext facesContext, final UIComponent component, final Object value) {
847
848 Converter converter = null;
849 if (component instanceof ValueHolder) {
850 converter = ((ValueHolder) component).getConverter();
851 }
852
853 if (converter == null) {
854 final ValueExpression valueExpression = component.getValueExpression("value");
855 if (valueExpression != null) {
856 Class converterType = null;
857 try {
858 converterType = valueExpression.getType(facesContext.getELContext());
859 } catch (final Exception e) {
860
861 }
862 if (converterType == null) {
863 if (value != null) {
864 converterType = value.getClass();
865 }
866 }
867 if (converterType != null && converterType != Object.class) {
868 converter = facesContext.getApplication().createConverter(converterType);
869 }
870 }
871 }
872
873 return converter;
874 }
875
876 public static String getFormattedValue(
877 final FacesContext facesContext, final UIComponent component, final Object currentValue)
878 throws ConverterException {
879
880 if (currentValue == null) {
881 return "";
882 }
883
884 final Converter converter = ComponentUtils.getConverter(facesContext, component, currentValue);
885 if (converter != null) {
886 return converter.getAsString(facesContext, component, currentValue);
887 } else {
888 return currentValue.toString();
889 }
890 }
891
892 public static UIComponent createComponent(
893 final FacesContext facesContext, final String componentType, final RendererTypes rendererType,
894 final String clientId) {
895 final UIComponent component = facesContext.getApplication().createComponent(componentType);
896 if (rendererType != null) {
897 component.setRendererType(rendererType.name());
898 }
899 component.setId(clientId);
900 return component;
901 }
902
903 public static List<UIComponent> findLayoutChildren(final UIComponent container) {
904 final List<UIComponent> result = new ArrayList<>();
905 addLayoutChildren(container, result);
906 return result;
907 }
908
909 private static void addLayoutChildren(final UIComponent component, final List<UIComponent> result) {
910 for (final UIComponent child : component.getChildren()) {
911 if (child instanceof Visual && !((Visual) child).isPlain()
912 || (UIComponent.isCompositeComponent(child) && !child.isRendered())) {
913 result.add(child);
914 } else {
915
916
917 addLayoutChildren(child, result);
918 }
919 }
920
921 final UIComponent child = component.getFacet(UIComponent.COMPOSITE_FACET_NAME);
922 if (child instanceof Visual && !((Visual) child).isPlain()) {
923 result.add(child);
924 } else if (child != null) {
925
926
927 addLayoutChildren(child, result);
928 }
929 }
930
931
932
933
934
935
936 public static String getConfirmation(final UIComponent component) {
937 final String confirmation = getStringAttribute(component, Attributes.confirmation, null);
938 if (confirmation != null) {
939 return confirmation;
940 }
941 final UIComponent facet = ComponentUtils.getFacet(component, Facets.confirmation);
942 if (facet instanceof ValueHolder && ((UIComponent) facet).isRendered()) {
943 final ValueHolder valueHolder = (ValueHolder) facet;
944 return "" + valueHolder.getValue();
945 } else if (facet != null && !(facet instanceof ValueHolder)) {
946 LOG.warn("The content of a confirmation facet must be a ValueHolder. Use e. g. <tc:out>.");
947 }
948 return null;
949 }
950 }