001 package org.apache.myfaces.tobago.component; 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.StringUtils; 021 import org.apache.commons.lang.math.NumberUtils; 022 import org.apache.commons.logging.Log; 023 import org.apache.commons.logging.LogFactory; 024 import org.apache.myfaces.tobago.TobagoConstants; 025 import org.apache.myfaces.tobago.context.TransientStateHolder; 026 import org.apache.myfaces.tobago.el.ConstantMethodBinding; 027 import org.apache.myfaces.tobago.event.PopupActionListener; 028 import org.apache.myfaces.tobago.event.SheetStateChangeEvent; 029 import org.apache.myfaces.tobago.renderkit.LayoutableRendererBase; 030 import org.apache.myfaces.tobago.renderkit.html.StyleClasses; 031 import org.apache.myfaces.tobago.util.Callback; 032 import org.apache.myfaces.tobago.util.RangeParser; 033 import org.apache.myfaces.tobago.util.TobagoCallback; 034 035 import javax.faces.FactoryFinder; 036 import javax.faces.application.Application; 037 import javax.faces.application.FacesMessage; 038 import javax.faces.component.ActionSource; 039 import javax.faces.component.EditableValueHolder; 040 import javax.faces.component.NamingContainer; 041 import javax.faces.component.UICommand; 042 import javax.faces.component.UIComponent; 043 import javax.faces.component.UIGraphic; 044 import javax.faces.component.UIOutput; 045 import javax.faces.component.UIParameter; 046 import javax.faces.component.UISelectItem; 047 import javax.faces.component.UISelectItems; 048 import javax.faces.component.ValueHolder; 049 import javax.faces.context.FacesContext; 050 import javax.faces.convert.Converter; 051 import javax.faces.el.MethodBinding; 052 import javax.faces.el.ValueBinding; 053 import javax.faces.event.ActionEvent; 054 import javax.faces.event.ActionListener; 055 import javax.faces.event.PhaseId; 056 import javax.faces.event.ValueChangeEvent; 057 import javax.faces.model.SelectItem; 058 import javax.faces.render.RenderKit; 059 import javax.faces.render.RenderKitFactory; 060 import javax.faces.render.Renderer; 061 import javax.faces.webapp.UIComponentTag; 062 import javax.servlet.jsp.JspException; 063 import java.util.ArrayList; 064 import java.util.Arrays; 065 import java.util.Collection; 066 import java.util.Collections; 067 import java.util.Iterator; 068 import java.util.List; 069 import java.util.Map; 070 import java.util.Set; 071 072 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ACTION_LINK; 073 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ACTION_ONCLICK; 074 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ALIGN; 075 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_CONVERTER; 076 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_CREATE_SPAN; 077 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_DISABLED; 078 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_ESCAPE; 079 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_FOR; 080 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_HOVER; 081 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_LABEL; 082 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_MARKUP; 083 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_READONLY; 084 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_RENDERED_PARTIALLY; 085 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_RENDER_RANGE; 086 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_RENDER_RANGE_EXTERN; 087 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_SORTABLE; 088 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_STYLE_CLASS; 089 import static org.apache.myfaces.tobago.TobagoConstants.ATTR_VALUE; 090 import static org.apache.myfaces.tobago.TobagoConstants.COMMAND_TYPE_NAVIGATE; 091 import static org.apache.myfaces.tobago.TobagoConstants.COMMAND_TYPE_RESET; 092 import static org.apache.myfaces.tobago.TobagoConstants.COMMAND_TYPE_SCRIPT; 093 import static org.apache.myfaces.tobago.TobagoConstants.FACET_ITEMS; 094 import static org.apache.myfaces.tobago.TobagoConstants.FACET_LABEL; 095 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_LABEL; 096 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_OUT; 097 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_SELECT_BOOLEAN_CHECKBOX; 098 import static org.apache.myfaces.tobago.TobagoConstants.RENDERER_TYPE_SELECT_ONE_RADIO; 099 100 public class ComponentUtil { 101 102 private static final Log LOG = LogFactory.getLog(ComponentUtil.class); 103 104 private static final String RENDER_KEY_PREFIX 105 = "org.apache.myfaces.tobago.component.ComponentUtil.RendererKeyPrefix_"; 106 107 public static final Class[] ACTION_ARGS = {}; 108 public static final Class[] ACTION_LISTENER_ARGS = {ActionEvent.class}; 109 public static final Class[] VALUE_CHANGE_LISTENER_ARGS = {ValueChangeEvent.class}; 110 public static final Class[] VALIDATOR_ARGS = {FacesContext.class, UIComponent.class, Object.class}; 111 112 private ComponentUtil() { 113 } 114 115 116 public static boolean hasErrorMessages(FacesContext context) { 117 for (Iterator iter = context.getMessages(); iter.hasNext();) { 118 FacesMessage message = (FacesMessage) iter.next(); 119 if (FacesMessage.SEVERITY_ERROR.compareTo(message.getSeverity()) <= 0) { 120 return true; 121 } 122 } 123 return false; 124 } 125 126 public static boolean containsPopupActionListener(UICommand command) { 127 ActionListener[] actionListeners = command.getActionListeners(); 128 for (ActionListener actionListener : actionListeners) { 129 if (actionListener instanceof PopupActionListener) { 130 return true; 131 } 132 } 133 return false; 134 } 135 136 public static String getFacesMessageAsString(FacesContext facesContext, UIComponent component) { 137 Iterator messages = facesContext.getMessages( 138 component.getClientId(facesContext)); 139 StringBuilder stringBuffer = new StringBuilder(); 140 while (messages.hasNext()) { 141 FacesMessage message = (FacesMessage) messages.next(); 142 stringBuffer.append(message.getDetail()); 143 } 144 if (stringBuffer.length() > 0) { 145 return stringBuffer.toString(); 146 } else { 147 return null; 148 } 149 } 150 151 public static boolean isInPopup(UIComponent component) { 152 while (component != null) { 153 if (component instanceof UIPopup) { 154 return true; 155 } 156 component = component.getParent(); 157 } 158 return false; 159 } 160 161 public static void resetPage(FacesContext context) { 162 javax.faces.component.UIViewRoot view = context.getViewRoot(); 163 if (view != null) { 164 view.getAttributes().remove(UIPage.COMPONENT_TYPE); 165 } 166 } 167 168 @SuppressWarnings(value = "unchecked") 169 public static UIPage findPage(FacesContext context, UIComponent component) { 170 javax.faces.component.UIViewRoot view = context.getViewRoot(); 171 if (view != null) { 172 TransientStateHolder stateHolder = (TransientStateHolder) view.getAttributes().get(UIPage.COMPONENT_TYPE); 173 if (stateHolder == null || stateHolder.isEmpty()) { 174 UIPage page = findPage(component); 175 stateHolder = new TransientStateHolder(page); 176 context.getViewRoot().getAttributes().put(UIPage.COMPONENT_TYPE, stateHolder); 177 } 178 return (UIPage) stateHolder.get(); 179 } else { 180 return findPage(component); 181 } 182 } 183 184 public static UIPage findPage(UIComponent component) { 185 while (component != null) { 186 if (component instanceof UIPage) { 187 return (UIPage) component; 188 } 189 component = component.getParent(); 190 } 191 return null; 192 } 193 194 public static void addStyles(UIComponent component, String[] styles) { 195 UIPage uiPage = ComponentUtil.findPage(component); 196 uiPage.getStyleFiles().addAll(Arrays.asList(styles)); 197 } 198 199 public static void addScripts(UIComponent component, String[] scripts) { 200 UIPage uiPage = ComponentUtil.findPage(component); 201 uiPage.getScriptFiles().addAll(Arrays.asList(scripts)); 202 } 203 204 public static void addOnloadCommands(UIComponent component, String[] cmds) { 205 UIPage uiPage = ComponentUtil.findPage(component); 206 uiPage.getOnloadScripts().addAll(Arrays.asList(cmds)); 207 } 208 209 public static UIPage findPage(FacesContext facesContext) { 210 return findPageBreadthFirst(facesContext.getViewRoot()); 211 } 212 213 private static UIPage findPageBreadthFirst(UIComponent component) { 214 for (Object o : component.getChildren()) { 215 UIComponent child = (UIComponent) o; 216 if (child instanceof UIPage) { 217 return (UIPage) child; 218 } 219 } 220 for (Object o : component.getChildren()) { 221 UIComponent child = (UIComponent) o; 222 UIPage result = findPageBreadthFirst(child); 223 if (result != null) { 224 return result; 225 } 226 } 227 return null; 228 } 229 230 231 public static UIForm findForm(UIComponent component) { 232 while (component != null) { 233 if (component instanceof UIForm) { 234 return (UIForm) component; 235 } 236 component = component.getParent(); 237 } 238 return null; 239 } 240 241 /** 242 * Find all subforms of a component, and collects it. 243 * It does not find subforms of subforms. 244 */ 245 public static List<UIForm> findSubForms(UIComponent component) { 246 List<UIForm> collect = new ArrayList<UIForm>(); 247 findSubForms(collect, component); 248 return collect; 249 } 250 251 @SuppressWarnings(value = "unchecked") 252 private static void findSubForms(List<UIForm> collect, UIComponent component) { 253 Iterator<UIComponent> kids = component.getFacetsAndChildren(); 254 while (kids.hasNext()) { 255 UIComponent child = kids.next(); 256 if (child instanceof UIForm) { 257 collect.add((UIForm) child); 258 } else { 259 findSubForms(collect, child); 260 } 261 } 262 } 263 264 /** 265 * Searches the component tree beneath the component and return the first component matching the type. 266 */ 267 public static <T extends UIComponent> T findDescendant(UIComponent component, Class<T> type) { 268 269 for (UIComponent child : (List<UIComponent>) component.getChildren()) { 270 if (child.getClass().equals(type)) { 271 return (T) child; 272 } 273 final T descendant = findDescendant(child, type); 274 if (descendant != null) { 275 return descendant; 276 } 277 } 278 return null; 279 } 280 281 /** 282 * Looks for the attribute "for" in the component. If there is any 283 * search for the component which is referenced by the "for" attribute, 284 * and return their clientId. 285 * If there is no "for" attribute, return the "clientId" of the parent 286 * (if it has a parent). This is useful for labels. 287 */ 288 public static String findClientIdFor(UIComponent component, 289 FacesContext facesContext) { 290 UIComponent forComponent = findFor(component); 291 if (forComponent != null) { 292 String clientId = forComponent.getClientId(facesContext); 293 if (LOG.isDebugEnabled()) { 294 LOG.debug("found clientId: '" + clientId + "'"); 295 } 296 return clientId; 297 } 298 if (LOG.isDebugEnabled()) { 299 LOG.debug("found no clientId"); 300 } 301 return null; 302 } 303 304 public static UIComponent findFor(UIComponent component) { 305 String forValue = (String) component.getAttributes().get(ATTR_FOR); 306 if (forValue == null) { 307 return component.getParent(); 308 } 309 return component.findComponent(forValue); 310 } 311 312 public static boolean isInActiveForm(UIComponent component) { 313 while (component != null) { 314 //log.debug("compoent= " + component.getClientId(FacesContext.getCurrentInstance()) 315 // + " " + component.getRendererType()); 316 if (component instanceof UIForm) { 317 UIForm form = (UIForm) component; 318 if (form.isSubmitted()) { 319 //log.debug("in active form = " + form.getClientId(FacesContext.getCurrentInstance())); 320 return true; 321 } /*else { 322 log.debug("form found but not active = " + form.getClientId(FacesContext.getCurrentInstance())); 323 } */ 324 } 325 component = component.getParent(); 326 } 327 //log.debug("not in an active form"); 328 return false; 329 } 330 331 public static FacesMessage.Severity getMaximumSeverity(UIComponent component) { 332 final boolean invalid = component instanceof javax.faces.component.UIInput 333 && !((javax.faces.component.UIInput) component).isValid(); 334 FacesMessage.Severity max = invalid ? FacesMessage.SEVERITY_ERROR : null; 335 FacesContext facesContext = FacesContext.getCurrentInstance(); 336 final Iterator messages = facesContext.getMessages(component.getClientId(facesContext)); 337 while (messages.hasNext()) { 338 FacesMessage message = (FacesMessage) messages.next(); 339 if (max == null || message.getSeverity().getOrdinal() > max.getOrdinal()) { 340 max = message.getSeverity(); 341 } 342 } 343 return max; 344 } 345 346 public static boolean isError(javax.faces.component.UIInput uiInput) { 347 FacesContext facesContext = FacesContext.getCurrentInstance(); 348 return !uiInput.isValid() 349 || facesContext.getMessages(uiInput.getClientId(facesContext)).hasNext(); 350 } 351 352 public static boolean isError(UIComponent component) { 353 if (component instanceof UIInput) { 354 return isError((UIInput) component); 355 } 356 return false; 357 } 358 359 public static boolean isOutputOnly(UIComponent component) { 360 return getBooleanAttribute(component, ATTR_DISABLED) 361 || getBooleanAttribute(component, ATTR_READONLY); 362 } 363 364 public static boolean mayValidate(UIComponent component) { 365 return !isOutputOnly(component) 366 && ComponentUtil.isInActiveForm(component); 367 } 368 369 public static boolean mayUpdateModel(UIComponent component) { 370 return mayValidate(component); 371 } 372 373 public static boolean getBooleanAttribute(UIComponent component, String name) { 374 375 Object bool = component.getAttributes().get(name); 376 if (bool == null) { 377 return false; 378 } 379 if (bool instanceof ValueBinding) { 380 bool = ((ValueBinding) bool).getValue(FacesContext.getCurrentInstance()); 381 } 382 if (bool instanceof Boolean) { 383 return (Boolean) bool; 384 } else if (bool instanceof String) { 385 if (LOG.isInfoEnabled()) { 386 LOG.info("Searching for a boolean, but find a String. Should not happen. " 387 + "attribute: '" + name + "' id: '" + component.getClientId(FacesContext.getCurrentInstance()) 388 + "' comp: '" + component + "'"); 389 } 390 return Boolean.valueOf((String) bool); 391 } else { 392 LOG.warn("Unknown type '" + bool.getClass().getName() 393 + "' for boolean attribute: " + name + " id: " + component.getClientId(FacesContext.getCurrentInstance()) 394 + " comp: " + component); 395 return false; 396 } 397 } 398 399 public static void setRenderedPartially(org.apache.myfaces.tobago.component.UICommand command, 400 String renderers) { 401 if (renderers != null) { 402 if (UIComponentTag.isValueReference(renderers)) { 403 command.setValueBinding(ATTR_RENDERED_PARTIALLY, createValueBinding(renderers)); 404 } else { 405 String[] components = StringUtils.split(renderers, ","); 406 command.setRenderedPartially(components); 407 } 408 } 409 } 410 411 public static void setStyleClasses(UIComponent component, String styleClasses) { 412 if (styleClasses != null) { 413 if (UIComponentTag.isValueReference(styleClasses)) { 414 component.setValueBinding(ATTR_STYLE_CLASS, createValueBinding(styleClasses)); 415 } else { 416 String[] classes = StringUtils.split(styleClasses, ", "); 417 if (classes.length > 0) { 418 StyleClasses styles = StyleClasses.ensureStyleClasses(component); 419 for (String clazz : classes) { 420 styles.addFullQualifiedClass(clazz); 421 } 422 } 423 } 424 } 425 } 426 427 public static void setMarkup(UIComponent markupComponent, String markup) { 428 if (markup != null) { 429 if (markupComponent instanceof SupportsMarkup) { 430 if (UIComponentTag.isValueReference(markup)) { 431 markupComponent.setValueBinding(ATTR_MARKUP, createValueBinding(markup)); 432 } else { 433 String[] markups = StringUtils.split(markup, ","); 434 ((SupportsMarkup) markupComponent).setMarkup(markups); 435 } 436 } else { 437 LOG.error("Component did not support Markup " + markupComponent.getClass().getName()); 438 } 439 } 440 } 441 442 public static Object getAttribute(UIComponent component, String name) { 443 Object value = component.getAttributes().get(name); 444 if (value instanceof ValueBinding) { 445 value = ((ValueBinding) value).getValue(FacesContext.getCurrentInstance()); 446 } 447 return value; 448 } 449 450 public static String getStringAttribute(UIComponent component, String name) { 451 return (String) getAttribute(component, name); 452 } 453 454 public static int getIntAttribute(UIComponent component, String name) { 455 return getIntAttribute(component, name, 0); 456 } 457 458 public static int getIntAttribute(UIComponent component, String name, 459 int defaultValue) { 460 Object integer = component.getAttributes().get(name); 461 if (integer instanceof Number) { 462 return ((Number) integer).intValue(); 463 } else if (integer instanceof String) { 464 try { 465 return Integer.parseInt((String) integer); 466 } catch (NumberFormatException e) { 467 LOG.warn("Can't parse number from string : \"" + integer + "\"!"); 468 return defaultValue; 469 } 470 } else if (integer == null) { 471 return defaultValue; 472 } else { 473 LOG.warn("Unknown type '" + integer.getClass().getName() 474 + "' for integer attribute: " + name + " comp: " + component); 475 return defaultValue; 476 } 477 } 478 479 /** 480 * @param component 481 * @param name 482 * @deprecated please use the method {@link #getCharacterAttribute(javax.faces.component.UIComponent, String)} 483 */ 484 @Deprecated 485 public static Character getCharakterAttribute(UIComponent component, String name) { 486 return getCharacterAttribute(component, name); 487 } 488 489 public static Character getCharacterAttribute(UIComponent component, String name) { 490 Object character = component.getAttributes().get(name); 491 if (character == null) { 492 return null; 493 } else if (character instanceof Character) { 494 return ((Character) character); 495 } else if (character instanceof String) { 496 String asString = ((String) character); 497 return asString.length() > 0 ? asString.charAt(0) : null; 498 } else { 499 LOG.warn("Unknown type '" + character.getClass().getName() 500 + "' for integer attribute: " + name + " comp: " + component); 501 return null; 502 } 503 } 504 505 public static boolean isFacetOf(UIComponent component, UIComponent parent) { 506 for (Object o : parent.getFacets().keySet()) { 507 UIComponent facet = parent.getFacet((String) o); 508 if (component.equals(facet)) { 509 return true; 510 } 511 } 512 return false; 513 } 514 515 // TODO This should not be neseccary, but UIComponentBase.getRenderer() is protected 516 public static LayoutableRendererBase getRenderer(FacesContext facesContext, UIComponent component) { 517 return getRenderer(facesContext, component.getFamily(), component.getRendererType()); 518 519 } 520 521 public static LayoutableRendererBase getRenderer(FacesContext facesContext, String family, String rendererType) { 522 if (rendererType == null) { 523 return null; 524 } 525 526 LayoutableRendererBase renderer; 527 528 Map requestMap = facesContext.getExternalContext().getRequestMap(); 529 renderer = (LayoutableRendererBase) requestMap.get(RENDER_KEY_PREFIX + rendererType); 530 531 if (renderer == null) { 532 RenderKitFactory rkFactory = (RenderKitFactory) 533 FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); 534 RenderKit renderKit = rkFactory.getRenderKit(facesContext, facesContext.getViewRoot().getRenderKitId()); 535 Renderer myRenderer = renderKit.getRenderer(family, rendererType); 536 if (myRenderer instanceof LayoutableRendererBase) { 537 requestMap.put(RENDER_KEY_PREFIX + rendererType, myRenderer); 538 renderer = (LayoutableRendererBase) myRenderer; 539 } else { 540 return null; 541 } 542 } 543 return renderer; 544 } 545 546 public static String currentValue(UIComponent component) { 547 String currentValue = null; 548 if (component instanceof ValueHolder) { 549 Object value; 550 if (component instanceof EditableValueHolder) { 551 value = ((EditableValueHolder) component).getSubmittedValue(); 552 if (value != null) { 553 return (String) value; 554 } 555 } 556 557 value = ((ValueHolder) component).getValue(); 558 if (value != null) { 559 Converter converter = ((ValueHolder) component).getConverter(); 560 if (converter == null) { 561 FacesContext context = FacesContext.getCurrentInstance(); 562 converter = context.getApplication().createConverter(value.getClass()); 563 } 564 if (converter != null) { 565 currentValue = 566 converter.getAsString(FacesContext.getCurrentInstance(), 567 component, value); 568 } else { 569 currentValue = value.toString(); 570 } 571 } 572 } 573 return currentValue; 574 } 575 576 public static List<SelectItem> getSelectItems(UIComponent component) { 577 578 ArrayList<SelectItem> list = new ArrayList<SelectItem>(); 579 580 for (Object o1 : component.getChildren()) { 581 UIComponent kid = (UIComponent) o1; 582 if (LOG.isDebugEnabled()) { 583 LOG.debug("kid " + kid); 584 LOG.debug("kid " + kid.getClass().getName()); 585 } 586 if (kid instanceof UISelectItem) { 587 Object value = ((UISelectItem) kid).getValue(); 588 if (value == null) { 589 UISelectItem item = (UISelectItem) kid; 590 if (kid instanceof org.apache.myfaces.tobago.component.UISelectItem) { 591 list.add(new org.apache.myfaces.tobago.model.SelectItem( 592 (org.apache.myfaces.tobago.component.UISelectItem) kid)); 593 } else { 594 list.add(new SelectItem(item.getItemValue() == null ? "" : item.getItemValue(), 595 item.getItemLabel() != null ? item.getItemLabel() : item.getItemValue().toString(), 596 item.getItemDescription())); 597 } 598 } else if (value instanceof SelectItem) { 599 list.add((SelectItem) value); 600 } else { 601 throw new IllegalArgumentException("TYPE ERROR: value NOT instanceof SelectItem. type=" 602 + value.getClass().getName()); 603 } 604 } else if (kid instanceof UISelectItems) { 605 Object value = ((UISelectItems) kid).getValue(); 606 if (LOG.isDebugEnabled()) { 607 LOG.debug("value " + value); 608 if (value != null) { 609 LOG.debug("value " + value.getClass().getName()); 610 } 611 } 612 if (value == null) { 613 if (LOG.isDebugEnabled()) { 614 LOG.debug("value is null"); 615 } 616 } else if (value instanceof SelectItem) { 617 list.add((SelectItem) value); 618 } else if (value instanceof SelectItem[]) { 619 SelectItem[] items = (SelectItem[]) value; 620 list.addAll(Arrays.asList(items)); 621 } else if (value instanceof Collection) { 622 for (Object o : ((Collection) value)) { 623 list.add((SelectItem) o); 624 } 625 } else if (value instanceof Map) { 626 for (Object key : ((Map) value).keySet()) { 627 if (key != null) { 628 Object val = ((Map) value).get(key); 629 if (val != null) { 630 list.add(new SelectItem(val.toString(), key.toString(), null)); 631 } 632 } 633 } 634 } else { 635 throw new IllegalArgumentException("TYPE ERROR: value NOT instanceof " 636 + "SelectItem, SelectItem[], Collection, Map. type=" 637 + value.getClass().getName()); 638 } 639 } 640 } 641 642 return list; 643 } 644 645 public static Object findParameter(UIComponent component, String name) { 646 for (Object o : component.getChildren()) { 647 UIComponent child = (UIComponent) o; 648 if (child instanceof UIParameter) { 649 UIParameter parameter = (UIParameter) child; 650 if (LOG.isDebugEnabled()) { 651 LOG.debug("Select name='" + parameter.getName() + "'"); 652 LOG.debug("Select value='" + parameter.getValue() + "'"); 653 } 654 if (name.equals(parameter.getName())) { 655 return parameter.getValue(); 656 } 657 } 658 } 659 return null; 660 } 661 662 public static String toString(UIComponent component, int offset) { 663 return toString(component, offset, false); 664 } 665 666 private static String toString(UIComponent component, int offset, boolean asFacet) { 667 StringBuilder result = new StringBuilder(); 668 if (component == null) { 669 result.append("null"); 670 } else { 671 result.append('\n'); 672 if (!asFacet) { 673 result.append(spaces(offset)); 674 result.append(toString(component)); 675 } 676 Map facets = component.getFacets(); 677 if (facets.size() > 0) { 678 for (Map.Entry<String, UIComponent> entry : (Set<Map.Entry<String, UIComponent>>) facets.entrySet()) { 679 UIComponent facet = entry.getValue(); 680 result.append('\n'); 681 result.append(spaces(offset + 1)); 682 result.append('\"'); 683 result.append(entry.getKey()); 684 result.append("\" = "); 685 result.append(toString(facet)); 686 result.append(toString(facet, offset + 1, true)); 687 } 688 } 689 for (Object o : component.getChildren()) { 690 result.append(toString((UIComponent) o, offset + 1, false)); 691 } 692 } 693 return result.toString(); 694 } 695 696 private static String toString(UIComponent component) { 697 StringBuilder buf = new StringBuilder(component.getClass().getName()); 698 buf.append('@'); 699 buf.append(Integer.toHexString(component.hashCode())); 700 buf.append(" "); 701 buf.append(component.getRendererType()); 702 buf.append(" "); 703 if (component instanceof javax.faces.component.UIViewRoot) { 704 buf.append(((javax.faces.component.UIViewRoot) component).getViewId()); 705 } else { 706 buf.append(component.getId()); 707 buf.append(" "); 708 buf.append(component.getClientId(FacesContext.getCurrentInstance())); 709 } 710 return buf.toString(); 711 } 712 713 private static String spaces(int n) { 714 StringBuilder buffer = new StringBuilder(n * 2); 715 for (int i = 0; i < n; i++) { 716 buffer.append(" "); 717 } 718 return buffer.toString(); 719 } 720 721 public static ActionListener createActionListener(String type) 722 throws JspException { 723 try { 724 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 725 if (classLoader == null) { 726 classLoader = type.getClass().getClassLoader(); 727 } 728 Class clazz = classLoader.loadClass(type); 729 return (ActionListener) clazz.newInstance(); 730 } catch (Exception e) { 731 if (LOG.isDebugEnabled()) { 732 LOG.debug("type=" + type, e); 733 } 734 throw new JspException(e); 735 } 736 } 737 738 public static UIGraphic getFirstGraphicChild(UIComponent component) { 739 UIGraphic graphic = null; 740 for (Object o : component.getChildren()) { 741 UIComponent uiComponent = (UIComponent) o; 742 if (uiComponent instanceof UIGraphic) { 743 graphic = (UIGraphic) uiComponent; 744 break; 745 } 746 } 747 return graphic; 748 } 749 750 public static boolean isHoverEnabled(UIComponent component) { 751 return ComponentUtil.getBooleanAttribute(component, ATTR_HOVER); 752 } 753 754 public static UIOutput getFirstNonGraphicChild(UIComponent component) { 755 UIOutput output = null; 756 for (Object o : component.getChildren()) { 757 UIComponent uiComponent = (UIComponent) o; 758 if ((uiComponent instanceof UIOutput) 759 && !(uiComponent instanceof UIGraphic)) { 760 output = (UIOutput) uiComponent; 761 break; 762 } 763 } 764 return output; 765 } 766 767 public static void setIntegerSizeProperty(UIComponent component, 768 String name, String value) { 769 if (value != null) { 770 if (UIComponentTag.isValueReference(value)) { 771 component.setValueBinding(name, createValueBinding(value)); 772 } else { 773 value = removePx(value); 774 component.getAttributes().put(name, new Integer(value)); 775 } 776 } 777 } 778 779 public static String removePx(String value) { 780 if (value != null && value.endsWith("px")) { 781 value = value.substring(0, value.length() - 2); 782 } 783 return value; 784 } 785 786 public static void setIntegerProperty(UIComponent component, 787 String name, String value) { 788 if (value != null) { 789 if (UIComponentTag.isValueReference(value)) { 790 component.setValueBinding(name, createValueBinding(value)); 791 } else { 792 component.getAttributes().put(name, new Integer(value)); 793 } 794 } 795 } 796 797 public static void setBooleanProperty(UIComponent component, 798 String name, String value) { 799 if (value != null) { 800 if (UIComponentTag.isValueReference(value)) { 801 component.setValueBinding(name, createValueBinding(value)); 802 } else { 803 component.getAttributes().put(name, Boolean.valueOf(value)); 804 } 805 } 806 } 807 808 public static void setStringProperty(UIComponent component, String name, 809 String value) { 810 if (value != null) { 811 if (UIComponentTag.isValueReference(value)) { 812 component.setValueBinding(name, createValueBinding(value)); 813 } else { 814 component.getAttributes().put(name, value); 815 } 816 } 817 } 818 819 public static void setValueForValueBinding(String name, Object value) { 820 FacesContext context = FacesContext.getCurrentInstance(); 821 ValueBinding valueBinding = context.getApplication().createValueBinding(name); 822 valueBinding.setValue(context, value); 823 } 824 825 public static ValueBinding createValueBinding(String value) { 826 return FacesContext.getCurrentInstance().getApplication() 827 .createValueBinding(value); 828 } 829 830 public static String getValueFromEl(String script) { 831 if (UIComponentTag.isValueReference(script)) { 832 ValueBinding valueBinding = ComponentUtil.createValueBinding(script); 833 script = (String) valueBinding.getValue(FacesContext.getCurrentInstance()); 834 } 835 return script; 836 } 837 838 /** 839 * Please use createComponent(String componentType, String rendererType, String id) 840 * 841 * @deprecated 842 */ 843 @Deprecated 844 public static UIComponent createComponent(String componentType, String rendererType) { 845 return createComponent(componentType, rendererType, null); 846 } 847 848 public static UIComponent createComponent(String componentType, String rendererType, String id) { 849 final FacesContext facesContext = FacesContext.getCurrentInstance(); 850 return createComponent(facesContext, componentType, rendererType, id); 851 } 852 853 /** 854 * Please use createComponent(FacesContext facesContext, String componentType, String rendererType, String id) 855 * 856 * @deprecated 857 */ 858 @Deprecated 859 public static UIComponent createComponent(FacesContext facesContext, String componentType, String rendererType) { 860 return createComponent(facesContext, componentType, rendererType, null); 861 } 862 863 public static UIComponent createComponent( 864 FacesContext facesContext, String componentType, String rendererType, String id) { 865 UIComponent component 866 = facesContext.getApplication().createComponent(componentType); 867 component.setRendererType(rendererType); 868 component.setId(id); 869 return component; 870 } 871 872 /** 873 * Please use createTextColumn(String label, String sortable, String align, String value, String id) 874 * 875 * @deprecated 876 */ 877 @Deprecated 878 public static UIColumn createTextColumn(String label, String sortable, String align, String value) { 879 return createTextColumn(label, sortable, align, value, null); 880 } 881 882 public static UIColumn createTextColumn(String label, String sortable, String align, String value, String id) { 883 UIComponent text = createComponent(UIOutput.COMPONENT_TYPE, RENDERER_TYPE_OUT, id + "_t"); 884 setStringProperty(text, ATTR_VALUE, value); 885 setBooleanProperty(text, ATTR_CREATE_SPAN, "false"); 886 setBooleanProperty(text, ATTR_ESCAPE, "false"); 887 return createColumn(label, sortable, align, text, id); 888 } 889 890 /** 891 * Please use createColumn(String label, String sortable, String align, UIComponent child) 892 * 893 * @deprecated 894 */ 895 @Deprecated 896 public static UIColumn createColumn(String label, String sortable, String align, UIComponent child) { 897 return createColumn(label, sortable, align, child, null); 898 } 899 900 public static UIColumn createColumn(String label, String sortable, String align, UIComponent child, String id) { 901 UIColumn column = createColumn(label, sortable, align, id); 902 column.getChildren().add(child); 903 return column; 904 } 905 906 private static UIColumn createColumn(String label, String sortable, String align, String id) { 907 UIColumn column = (UIColumn) createComponent(UIColumn.COMPONENT_TYPE, null, id); 908 setStringProperty(column, ATTR_LABEL, label); 909 setBooleanProperty(column, ATTR_SORTABLE, sortable); 910 setStringProperty(column, ATTR_ALIGN, align); 911 return column; 912 } 913 914 /** 915 * Please use createUIMenuSelectOneFacet(FacesContext facesContext, UICommand command, String id) 916 * 917 * @deprecated 918 */ 919 @Deprecated 920 public static UIMenuSelectOne createUIMenuSelectOneFacet(FacesContext facesContext, UICommand command) { 921 return createUIMenuSelectOneFacet(facesContext, command, null); 922 } 923 924 public static UIMenuSelectOne createUIMenuSelectOneFacet(FacesContext facesContext, UICommand command, String id) { 925 UIMenuSelectOne radio = null; 926 final ValueBinding valueBinding = command.getValueBinding(ATTR_VALUE); 927 if (valueBinding != null) { 928 radio = (UIMenuSelectOne) createComponent(facesContext, 929 UIMenuSelectOne.COMPONENT_TYPE, RENDERER_TYPE_SELECT_ONE_RADIO, id); 930 command.getFacets().put(FACET_ITEMS, radio); 931 radio.setValueBinding(ATTR_VALUE, valueBinding); 932 } 933 return radio; 934 } 935 936 937 public static boolean hasSelectedValue(List<SelectItem> items, Object value) { 938 for (SelectItem item : items) { 939 if (item.getValue().equals(value)) { 940 return true; 941 } 942 } 943 return false; 944 } 945 946 /** 947 * Please use createUISelectBooleanFacet(FacesContext facesContext, UICommand command, String id) 948 * 949 * @deprecated 950 */ 951 @Deprecated 952 public static UIComponent createUISelectBooleanFacet(FacesContext facesContext, UICommand command) { 953 return createUISelectBooleanFacet(facesContext, command, null); 954 } 955 956 public static UIComponent createUISelectBooleanFacet(FacesContext facesContext, UICommand command, String id) { 957 UIComponent checkbox 958 = createComponent(facesContext, UISelectBoolean.COMPONENT_TYPE, RENDERER_TYPE_SELECT_BOOLEAN_CHECKBOX, id); 959 command.getFacets().put(FACET_ITEMS, checkbox); 960 ValueBinding valueBinding = command.getValueBinding(ATTR_VALUE); 961 if (valueBinding != null) { 962 checkbox.setValueBinding(ATTR_VALUE, valueBinding); 963 } else { 964 checkbox.getAttributes().put(ATTR_VALUE, command.getAttributes().get(ATTR_VALUE)); 965 } 966 return checkbox; 967 } 968 969 public static int getIntValue(ValueBinding valueBinding) { 970 return getAsInt(valueBinding.getValue(FacesContext.getCurrentInstance())); 971 } 972 973 private static int getAsInt(Object value) { 974 int result; 975 if (value instanceof Number) { 976 result = ((Number) value).intValue(); 977 } else if (value instanceof String) { 978 result = Integer.parseInt((String) value); 979 } else { 980 throw new IllegalArgumentException("Can't convert " + value + " to int!"); 981 } 982 return result; 983 } 984 985 986 public static String createPickerId(FacesContext facesContext, UIComponent component, String postfix) { 987 //String id = component.getId(); 988 String id = getComponentId(facesContext, component); 989 return id + "_picker" + postfix; 990 } 991 992 public static String getComponentId(FacesContext facesContext, UIComponent component) { 993 String id = component.getId(); 994 //if (id == null) { 995 // XXX What is this? 996 // id = component.getClientId(facesContext).substring(id.lastIndexOf('_')); 997 //} 998 return id; 999 } 1000 1001 public static UIComponent provideLabel(FacesContext facesContext, UIComponent component) { 1002 UIComponent label = component.getFacet(FACET_LABEL); 1003 1004 1005 if (label == null) { 1006 final Map attributes = component.getAttributes(); 1007 Object labelText = component.getValueBinding(ATTR_LABEL); 1008 if (labelText == null) { 1009 labelText = attributes.get(ATTR_LABEL); 1010 } 1011 1012 if (labelText != null) { 1013 Application application = FacesContext.getCurrentInstance().getApplication(); 1014 label = application.createComponent(UIOutput.COMPONENT_TYPE); 1015 label.setRendererType(RENDERER_TYPE_LABEL); 1016 String idprefix = ComponentUtil.getComponentId(facesContext, component); 1017 label.setId(idprefix + "_" + FACET_LABEL); 1018 label.setRendered(true); 1019 1020 if (labelText instanceof ValueBinding) { 1021 label.setValueBinding(ATTR_VALUE, (ValueBinding) labelText); 1022 } else { 1023 label.getAttributes().put(ATTR_VALUE, labelText); 1024 } 1025 1026 component.getFacets().put(FACET_LABEL, label); 1027 } 1028 } 1029 return label; 1030 } 1031 1032 /*public static void debug(UIComponent component) { 1033 LOG.error("###############################"); 1034 LOG.error("ID " + component.getId()); 1035 LOG.error("ClassName " + component.getClass().getName()); 1036 if (component instanceof EditableValueHolder) { 1037 EditableValueHolder editableValueHolder = (EditableValueHolder) component; 1038 LOG.error("Valid " + editableValueHolder.isValid()); 1039 LOG.error("SubmittedValue " + editableValueHolder.getSubmittedValue()); 1040 } 1041 for (Iterator it = component.getFacetsAndChildren(); it.hasNext(); ) { 1042 debug((UIComponent)it.next()); 1043 } 1044 } */ 1045 1046 1047 public static List<SelectItem> getItemsToRender(javax.faces.component.UISelectOne component) { 1048 return getItems(component); 1049 } 1050 1051 public static List<SelectItem> getItemsToRender(javax.faces.component.UISelectMany component) { 1052 return getItems(component); 1053 } 1054 1055 private static List<SelectItem> getItems(javax.faces.component.UIInput component) { 1056 1057 List<SelectItem> selectItems = ComponentUtil.getSelectItems(component); 1058 1059 String renderRange = (String) 1060 component.getAttributes().get(ATTR_RENDER_RANGE_EXTERN); 1061 if (renderRange == null) { 1062 renderRange = (String) 1063 component.getAttributes().get(ATTR_RENDER_RANGE); 1064 } 1065 if (renderRange == null) { 1066 return selectItems; 1067 } 1068 1069 int[] indices = RangeParser.getIndices(renderRange); 1070 List<SelectItem> items = new ArrayList<SelectItem>(indices.length); 1071 1072 if (selectItems.size() != 0) { 1073 for (int indice : indices) { 1074 items.add(selectItems.get(indice)); 1075 } 1076 } else { 1077 LOG.warn("No items found! rendering dummys instead!"); 1078 for (int i = 0; i < indices.length; i++) { 1079 items.add(new SelectItem(Integer.toString(i), "Item " + i, "")); 1080 } 1081 } 1082 return items; 1083 } 1084 1085 public static void setValidator(EditableValueHolder editableValueHolder, String validator) { 1086 if (validator != null && editableValueHolder.getValidator() == null) { 1087 if (UIComponentTag.isValueReference(validator)) { 1088 MethodBinding methodBinding = 1089 FacesContext.getCurrentInstance().getApplication().createMethodBinding(validator, VALIDATOR_ARGS); 1090 editableValueHolder.setValidator(methodBinding); 1091 } 1092 } 1093 } 1094 1095 /** 1096 * @param component 1097 * @param converterId 1098 * @deprecated please use the typesave method {@link #setConverter(javax.faces.component.ValueHolder, String)} 1099 */ 1100 @Deprecated 1101 public static void setConverter(UIComponent component, String converterId) { 1102 if (component instanceof ValueHolder) { 1103 setConverter((ValueHolder) component, converterId); 1104 } 1105 } 1106 1107 public static void setConverter(ValueHolder valueHolder, String converterId) { 1108 if (converterId != null && valueHolder.getConverter() == null) { 1109 final FacesContext facesContext = FacesContext.getCurrentInstance(); 1110 final Application application = facesContext.getApplication(); 1111 if (UIComponentTag.isValueReference(converterId)) { 1112 ValueBinding valueBinding = application.createValueBinding(converterId); 1113 if (valueHolder instanceof UIComponent) { 1114 ((UIComponent) valueHolder).setValueBinding(ATTR_CONVERTER, valueBinding); 1115 } 1116 } else { 1117 Converter converter = application.createConverter(converterId); 1118 valueHolder.setConverter(converter); 1119 } 1120 } 1121 } 1122 1123 /** 1124 * @param component 1125 * @param type 1126 * @param action 1127 * @deprecated please use the typesave method {@link #setAction(javax.faces.component.UICommand, String, String)} 1128 */ 1129 @Deprecated 1130 public static void setAction(UIComponent component, String type, String action) { 1131 if (component instanceof UICommand) { 1132 setAction((UICommand) component, type, action); 1133 } 1134 } 1135 1136 public static void setAction(UICommand component, String type, String action) { 1137 String commandType; 1138 final FacesContext facesContext = FacesContext.getCurrentInstance(); 1139 final Application application = facesContext.getApplication(); 1140 if (type != null && UIComponentTag.isValueReference(type)) { 1141 commandType = (String) application.createValueBinding(type).getValue(facesContext); 1142 } else { 1143 commandType = type; 1144 } 1145 if (commandType != null 1146 && (commandType.equals(COMMAND_TYPE_NAVIGATE) 1147 || commandType.equals(COMMAND_TYPE_RESET) 1148 || commandType.equals(COMMAND_TYPE_SCRIPT))) { 1149 if (commandType.equals(COMMAND_TYPE_NAVIGATE)) { 1150 setStringProperty(component, ATTR_ACTION_LINK, action); 1151 } else if (commandType.equals(COMMAND_TYPE_SCRIPT)) { 1152 setStringProperty(component, ATTR_ACTION_ONCLICK, action); 1153 } else { 1154 LOG.warn("Type reset is not supported"); 1155 } 1156 } else { 1157 if (action != null) { 1158 if (UIComponentTag.isValueReference(action)) { 1159 MethodBinding binding = application.createMethodBinding(action, null); 1160 component.setAction(binding); 1161 } else { 1162 component.setAction(new ConstantMethodBinding(action)); 1163 } 1164 } 1165 } 1166 1167 } 1168 1169 /** 1170 * @param component 1171 * @param suggestMethod 1172 * @deprecated please use the typesave method {@link #setSuggestMethodBinding(UIInput, String)} 1173 */ 1174 @Deprecated 1175 public static void setSuggestMethodBinding(UIComponent component, String suggestMethod) { 1176 if (component instanceof UIInput) { 1177 setSuggestMethodBinding((UIInput) component, suggestMethod); 1178 } 1179 } 1180 1181 public static void setSuggestMethodBinding(UIInput component, String suggestMethod) { 1182 if (suggestMethod != null) { 1183 if (UIComponentTag.isValueReference(suggestMethod)) { 1184 final MethodBinding methodBinding = FacesContext.getCurrentInstance().getApplication() 1185 .createMethodBinding(suggestMethod, new Class[]{String.class}); 1186 component.setSuggestMethod(methodBinding); 1187 } else { 1188 throw new IllegalArgumentException( 1189 "Must be a valueReference (suggestMethod): " + suggestMethod); 1190 } 1191 } 1192 } 1193 1194 public static void setActionListener(ActionSource command, String actionListener) { 1195 final FacesContext facesContext = FacesContext.getCurrentInstance(); 1196 final Application application = facesContext.getApplication(); 1197 if (actionListener != null) { 1198 if (UIComponentTag.isValueReference(actionListener)) { 1199 MethodBinding binding 1200 = application.createMethodBinding(actionListener, ACTION_LISTENER_ARGS); 1201 command.setActionListener(binding); 1202 } else { 1203 throw new IllegalArgumentException( 1204 "Must be a valueReference (actionListener): " + actionListener); 1205 } 1206 } 1207 } 1208 1209 public static void setValueChangeListener(EditableValueHolder valueHolder, String valueChangeListener) { 1210 final FacesContext facesContext = FacesContext.getCurrentInstance(); 1211 final Application application = facesContext.getApplication(); 1212 if (valueChangeListener != null) { 1213 if (UIComponentTag.isValueReference(valueChangeListener)) { 1214 MethodBinding binding 1215 = application.createMethodBinding(valueChangeListener, VALUE_CHANGE_LISTENER_ARGS); 1216 valueHolder.setValueChangeListener(binding); 1217 } else { 1218 throw new IllegalArgumentException( 1219 "Must be a valueReference (valueChangeListener): " + valueChangeListener); 1220 } 1221 } 1222 } 1223 1224 1225 public static void setSortActionListener(UIData data, String actionListener) { 1226 final FacesContext facesContext = FacesContext.getCurrentInstance(); 1227 final Application application = facesContext.getApplication(); 1228 if (actionListener != null) { 1229 if (UIComponentTag.isValueReference(actionListener)) { 1230 MethodBinding binding = application.createMethodBinding( 1231 actionListener, ACTION_LISTENER_ARGS); 1232 data.setSortActionListener(binding); 1233 } else { 1234 throw new IllegalArgumentException( 1235 "Must be a valueReference (sortActionListener): " + actionListener); 1236 } 1237 } 1238 } 1239 1240 public static void setValueBinding(UIComponent component, String name, String state) { 1241 // TODO: check, if it is an writeable object 1242 if (state != null && UIComponentTag.isValueReference(state)) { 1243 ValueBinding valueBinding = createValueBinding(state); 1244 component.setValueBinding(name, valueBinding); 1245 } 1246 } 1247 1248 public static void setStateChangeListener(UIData data, String stateChangeListener) { 1249 final FacesContext facesContext = FacesContext.getCurrentInstance(); 1250 final Application application = facesContext.getApplication(); 1251 1252 if (stateChangeListener != null) { 1253 if (UIComponentTag.isValueReference(stateChangeListener)) { 1254 Class[] arguments = {SheetStateChangeEvent.class}; 1255 MethodBinding binding 1256 = application.createMethodBinding(stateChangeListener, arguments); 1257 data.setStateChangeListener(binding); 1258 } else { 1259 throw new IllegalArgumentException( 1260 "Must be a valueReference (actionListener): " + stateChangeListener); 1261 } 1262 } 1263 } 1264 1265 1266 public static String[] getMarkupBinding(FacesContext facesContext, SupportsMarkup component) { 1267 ValueBinding vb = ((UIComponent) component).getValueBinding(ATTR_MARKUP); 1268 if (vb != null) { 1269 Object markups = vb.getValue(facesContext); 1270 if (markups instanceof String[]) { 1271 return (String[]) markups; 1272 } else if (markups instanceof String) { 1273 String[] strings = StringUtils.split((String) markups, ", "); 1274 List<String> result = new ArrayList<String>(strings.length); 1275 for (String string : strings) { 1276 if (string.trim().length() != 0) { 1277 result.add(string.trim()); 1278 } 1279 } 1280 return result.toArray(new String[result.size()]); 1281 } else if (markups == null) { 1282 return new String[0]; 1283 } else { 1284 return new String[]{markups.toString()}; 1285 } 1286 } 1287 1288 return new String[0]; 1289 } 1290 1291 /** 1292 * colonCount == 0: fully relative 1293 * colonCount == 1: absolute (still normal findComponent syntax) 1294 * colonCount > 1: for each extra colon after 1, go up a naming container 1295 * (to the view root, if naming containers run out) 1296 */ 1297 1298 public static UIComponent findComponent(UIComponent from, String relativeId) { 1299 int idLength = relativeId.length(); 1300 // Figure out how many colons 1301 int colonCount = 0; 1302 while (colonCount < idLength) { 1303 if (relativeId.charAt(colonCount) != NamingContainer.SEPARATOR_CHAR) { 1304 break; 1305 } 1306 colonCount++; 1307 } 1308 1309 // colonCount == 0: fully relative 1310 // colonCount == 1: absolute (still normal findComponent syntax) 1311 // colonCount > 1: for each extra colon after 1, go up a naming container 1312 // (to the view root, if naming containers run out) 1313 if (colonCount > 1) { 1314 relativeId = relativeId.substring(colonCount); 1315 for (int j = 1; j < colonCount; j++) { 1316 while (from.getParent() != null) { 1317 from = from.getParent(); 1318 if (from instanceof NamingContainer) { 1319 break; 1320 } 1321 } 1322 } 1323 } 1324 return from.findComponent(relativeId); 1325 } 1326 1327 public static void invokeOnComponent(FacesContext facesContext, String clientId, UIComponent component, 1328 Callback callback) { 1329 List<UIComponent> list = new ArrayList<UIComponent>(); 1330 while (component != null) { 1331 list.add(component); 1332 component = component.getParent(); 1333 } 1334 Collections.reverse(list); 1335 invokeOrPrepare(facesContext, list, clientId, callback); 1336 facesContext.getExternalContext().getRequestMap().remove(TobagoConstants.ATTR_ZINDEX); 1337 } 1338 1339 private static void invokeOrPrepare(FacesContext facesContext, List<UIComponent> list, String clientId, 1340 Callback callback) { 1341 if (list.size() == 1) { 1342 callback.execute(facesContext, list.get(0)); 1343 } else if (list.get(0) instanceof UIData) { 1344 prepareOnUIData(facesContext, list, clientId, callback); 1345 } else if (list.get(0) instanceof UIForm) { 1346 prepareOnUIForm(facesContext, list, clientId, callback); 1347 } else if (list.get(0) instanceof UIPopup) { 1348 prepareOnUIPopup(facesContext, list, clientId, callback); 1349 } else { 1350 prepareOnUIComponent(facesContext, list, clientId, callback); 1351 } 1352 } 1353 1354 @SuppressWarnings(value = "unchecked") 1355 private static void prepareOnUIForm(FacesContext facesContext, List<UIComponent> list, String clientId, 1356 Callback callback) { 1357 UIComponent currentComponent = list.remove(0); 1358 if (!(currentComponent instanceof UIForm)) { 1359 throw new IllegalStateException(currentComponent.getClass().getName()); 1360 } 1361 // TODO is this needed? 1362 if (callback instanceof TobagoCallback) { 1363 if (PhaseId.APPLY_REQUEST_VALUES.equals(((TobagoCallback) callback).getPhaseId())) { 1364 currentComponent.decode(facesContext); 1365 } 1366 } 1367 UIForm uiForm = (UIForm) currentComponent; 1368 facesContext.getExternalContext().getRequestMap().put(UIForm.SUBMITTED_MARKER, uiForm.isSubmitted()); 1369 invokeOrPrepare(facesContext, list, clientId, callback); 1370 1371 } 1372 1373 private static void prepareOnUIComponent( 1374 FacesContext facesContext, List<UIComponent> list, String clientId, Callback callback) { 1375 list.remove(0); 1376 invokeOrPrepare(facesContext, list, clientId, callback); 1377 } 1378 1379 private static void prepareOnUIPopup( 1380 FacesContext facesContext, List<UIComponent> list, String clientId, Callback callback) { 1381 if (callback instanceof TobagoCallback 1382 && PhaseId.RENDER_RESPONSE.equals(((TobagoCallback) callback).getPhaseId())) { 1383 Integer zIndex = (Integer) facesContext.getExternalContext().getRequestMap().get(TobagoConstants.ATTR_ZINDEX); 1384 if (zIndex == null) { 1385 zIndex = 0; 1386 } else { 1387 zIndex += 10; 1388 } 1389 facesContext.getExternalContext().getRequestMap().put(TobagoConstants.ATTR_ZINDEX, zIndex); 1390 } 1391 list.remove(0); 1392 invokeOrPrepare(facesContext, list, clientId, callback); 1393 } 1394 1395 private static void prepareOnUIData(FacesContext facesContext, List<UIComponent> list, String clientId, 1396 Callback callback) { 1397 UIComponent currentComponent = list.remove(0); 1398 if (!(currentComponent instanceof UIData)) { 1399 throw new IllegalStateException(currentComponent.getClass().getName()); 1400 } 1401 1402 // we may need setRowIndex on UIData 1403 javax.faces.component.UIData uiData = (javax.faces.component.UIData) currentComponent; 1404 int oldRowIndex = uiData.getRowIndex(); 1405 String sheetId = uiData.getClientId(facesContext); 1406 String idRemainder = clientId.substring(sheetId.length()); 1407 if (LOG.isInfoEnabled()) { 1408 LOG.info("idRemainder = \"" + idRemainder + "\""); 1409 } 1410 if (idRemainder.startsWith(String.valueOf(NamingContainer.SEPARATOR_CHAR))) { 1411 idRemainder = idRemainder.substring(1); 1412 int idx = idRemainder.indexOf(NamingContainer.SEPARATOR_CHAR); 1413 if (idx > 0) { 1414 String firstPart = idRemainder.substring(0, idx); 1415 if (NumberUtils.isDigits(firstPart)) { 1416 try { 1417 int rowIndex = Integer.parseInt(firstPart); 1418 if (LOG.isInfoEnabled()) { 1419 LOG.info("set rowIndex = \"" + rowIndex + "\""); 1420 } 1421 uiData.setRowIndex(rowIndex); 1422 } catch (NumberFormatException e) { 1423 LOG.error("idRemainder = \"" + idRemainder + "\"", e); 1424 } 1425 } 1426 } 1427 } else { 1428 if (LOG.isInfoEnabled()) { 1429 LOG.info("no match for \"^:\\d+:.*\""); 1430 } 1431 } 1432 1433 invokeOrPrepare(facesContext, list, clientId, callback); 1434 1435 // we should reset rowIndex on UIData 1436 uiData.setRowIndex(oldRowIndex); 1437 } 1438 1439 public static Object getConvertedValue( 1440 FacesContext facesContext, javax.faces.component.UIInput component, String stringValue) { 1441 try { 1442 Renderer renderer = getRenderer(facesContext, component); 1443 if (renderer != null) { 1444 if (component instanceof UISelectMany) { 1445 final Object converted = renderer.getConvertedValue(facesContext, component, new String[]{stringValue}); 1446 return ((Object[]) converted)[0]; 1447 } else { 1448 return renderer.getConvertedValue(facesContext, component, stringValue); 1449 } 1450 } else { 1451 Converter converter = component.getConverter(); 1452 if (converter == null) { 1453 //Try to find out by value binding 1454 ValueBinding vb = component.getValueBinding("value"); 1455 if (vb != null) { 1456 Class valueType = vb.getType(facesContext); 1457 if (valueType != null) { 1458 converter = facesContext.getApplication().createConverter(valueType); 1459 } 1460 } 1461 } 1462 if (converter != null) { 1463 converter.getAsObject(facesContext, component, stringValue); 1464 } 1465 } 1466 } catch (Exception e) { 1467 LOG.warn("Can't convert string value '" + stringValue + "'", e); 1468 } 1469 return stringValue; 1470 } 1471 }