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