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