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