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