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