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