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