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