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