View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.myfaces.shared.renderkit;
20  
21  import java.io.ByteArrayOutputStream;
22  import java.io.FileNotFoundException;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.io.Serializable;
26  import java.lang.reflect.Array;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Collections;
30  import java.util.Date;
31  import java.util.HashSet;
32  import java.util.Iterator;
33  import java.util.List;
34  import java.util.Map;
35  import java.util.Set;
36  import java.util.logging.Level;
37  import java.util.logging.Logger;
38  
39  import javax.el.ValueExpression;
40  import javax.faces.FacesException;
41  import javax.faces.FactoryFinder;
42  import javax.faces.application.FacesMessage;
43  import javax.faces.application.ProjectStage;
44  import javax.faces.application.Resource;
45  import javax.faces.application.ResourceHandler;
46  import javax.faces.component.EditableValueHolder;
47  import javax.faces.component.NamingContainer;
48  import javax.faces.component.UIComponent;
49  import javax.faces.component.UIForm;
50  import javax.faces.component.UIInput;
51  import javax.faces.component.UIOutput;
52  import javax.faces.component.UISelectMany;
53  import javax.faces.component.UISelectOne;
54  import javax.faces.component.UIViewRoot;
55  import javax.faces.component.ValueHolder;
56  import javax.faces.component.html.HtmlInputText;
57  import javax.faces.context.FacesContext;
58  import javax.faces.convert.Converter;
59  import javax.faces.convert.ConverterException;
60  import javax.faces.el.PropertyNotFoundException;
61  import javax.faces.el.ValueBinding;
62  import javax.faces.event.PhaseId;
63  import javax.faces.model.SelectItem;
64  import javax.faces.render.RenderKit;
65  import javax.faces.render.RenderKitFactory;
66  import javax.faces.render.ResponseStateManager;
67  
68  import org.apache.myfaces.shared.renderkit.html.util.FormInfo;
69  import org.apache.myfaces.shared.util.HashMapUtils;
70  import org.apache.myfaces.shared.util.SelectItemsIterator;
71  
72  public final class RendererUtils
73  {
74      private RendererUtils()
75      {
76          //nope
77      }
78  
79      //private static final Log log = LogFactory.getLog(RendererUtils.class);
80      private static final Logger log = Logger.getLogger(RendererUtils.class
81              .getName());
82  
83      public static final String SELECT_ITEM_LIST_ATTR = RendererUtils.class
84              .getName() + ".LIST";
85      public static final String EMPTY_STRING = "";
86      //This constant is no longer used by UISelectOne/UISelectMany instances
87      public static final Object NOTHING = new Serializable()
88      {
89          public boolean equals(final Object o)
90          {
91              if (o != null)
92              {
93                  if (o.getClass().equals(this.getClass()))
94                  {
95                      return true;
96                  }
97              }
98              return false;
99          }
100 
101         @Override
102         public int hashCode()
103         {
104             return super.hashCode();
105         }
106     };
107 
108     public static final String ACTION_FOR_LIST = "org.apache.myfaces.ActionForList";
109     public static final String ACTION_FOR_PHASE_LIST = "org.apache.myfaces.ActionForPhaseList";
110 
111     public static final String SEQUENCE_PARAM = "jsf_sequence";
112 
113     private static final String RENDER_KIT_IMPL = RendererUtils.class.getName()
114             + ".RenderKitImpl";
115 
116     // This nice constant is "specified" 13.1.1.2 The Resource API Approach in Spec as an example
117     public static final String RES_NOT_FOUND = "RES_NOT_FOUND";
118 
119     public static String getPathToComponent(UIComponent component)
120     {
121         StringBuilder buf = new StringBuilder();
122 
123         if (component == null)
124         {
125             buf.append("{Component-Path : ");
126             buf.append("[null]}");
127             return buf.toString();
128         }
129 
130         getPathToComponent(component, buf);
131 
132         buf.insert(0, "{Component-Path : ");
133         Object location = component.getAttributes().get(
134                 UIComponent.VIEW_LOCATION_KEY);
135         if (location != null)
136         {
137             buf.append(" Location: ").append(location);
138         }
139         buf.append("}");
140 
141         return buf.toString();
142     }
143 
144     private static void getPathToComponent(UIComponent component,
145             StringBuilder buf)
146     {
147         if (component == null)
148         {
149             return;
150         }
151 
152         StringBuilder intBuf = new StringBuilder();
153 
154         intBuf.append("[Class: ");
155         intBuf.append(component.getClass().getName());
156         if (component instanceof UIViewRoot)
157         {
158             intBuf.append(",ViewId: ");
159             intBuf.append(((UIViewRoot) component).getViewId());
160         }
161         else
162         {
163             intBuf.append(",Id: ");
164             intBuf.append(component.getId());
165         }
166         intBuf.append("]");
167 
168         buf.insert(0, intBuf.toString());
169 
170         getPathToComponent(component.getParent(), buf);
171     }
172 
173     public static String getConcatenatedId(FacesContext context,
174             UIComponent container, String clientId)
175     {
176         UIComponent child = container.findComponent(clientId);
177 
178         if (child == null)
179         {
180             return clientId;
181         }
182 
183         return getConcatenatedId(context, child);
184     }
185 
186     public static String getConcatenatedId(FacesContext context,
187             UIComponent component)
188     {
189         if (context == null)
190         {
191             throw new NullPointerException("context");
192         }
193 
194         StringBuilder idBuf = new StringBuilder();
195 
196         idBuf.append(component.getId());
197 
198         UIComponent parent;
199 
200         while ((parent = component.getParent()) != null)
201         {
202             if (parent instanceof NamingContainer)
203             {
204                 idBuf.insert(0, context.getNamingContainerSeparatorChar());
205                 idBuf.insert(0, parent.getId());
206             }
207         }
208 
209         return idBuf.toString();
210     }
211 
212     public static Boolean getBooleanValue(UIComponent component)
213     {
214         Object value = getObjectValue(component);
215         // Try to convert to Boolean if it is a String
216         if (value instanceof String)
217         {
218             value = Boolean.valueOf((String) value);
219         }
220 
221         if (value == null || value instanceof Boolean)
222         {
223             return (Boolean) value;
224         }
225 
226         throw new IllegalArgumentException(
227                 "Expected submitted value of type Boolean for Component : "
228                         + getPathToComponent(component));
229 
230     }
231 
232     public static Date getDateValue(UIComponent component)
233     {
234         Object value = getObjectValue(component);
235         if (value == null || value instanceof Date)
236         {
237             return (Date) value;
238         }
239 
240         throw new IllegalArgumentException(
241                 "Expected submitted value of type Date for component : "
242                         + getPathToComponent(component));
243     }
244 
245     public static Object getObjectValue(UIComponent component)
246     {
247         if (!(component instanceof ValueHolder))
248         {
249             throw new IllegalArgumentException("Component : "
250                     + getPathToComponent(component) + "is not a ValueHolder");
251         }
252 
253         if (component instanceof EditableValueHolder)
254         {
255             Object value = ((EditableValueHolder) component)
256                     .getSubmittedValue();
257             if (value != null)
258             {
259                 return value;
260             }
261         }
262 
263         return ((ValueHolder) component).getValue();
264     }
265 
266     @Deprecated
267     public static String getStringValue(FacesContext context, ValueBinding vb)
268     {
269         Object value = vb.getValue(context);
270         if (value != null)
271         {
272             return value.toString();
273         }
274         return null;
275     }
276 
277     public static String getStringValue(FacesContext context, ValueExpression ve)
278     {
279         Object value = ve.getValue(context.getELContext());
280         if (value != null)
281         {
282             return value.toString();
283         }
284         return null;
285     }
286 
287     public static String getStringValue(FacesContext facesContext,
288             UIComponent component)
289     {
290         if (!(component instanceof ValueHolder))
291         {
292             throw new IllegalArgumentException("Component : "
293                     + getPathToComponent(component)
294                     + "is not a ValueHolder");
295         }
296 
297         if (component instanceof EditableValueHolder)
298         {
299             Object submittedValue = ((EditableValueHolder) component)
300                     .getSubmittedValue();
301             if (submittedValue != null)
302             {
303                 if (log.isLoggable(Level.FINE))
304                 {
305                     log.fine("returning 1 '" + submittedValue + "'");
306                 }
307                 return submittedValue.toString();
308             }
309         }
310 
311         Object value;
312 
313         if (component instanceof EditableValueHolder)
314         {
315 
316             EditableValueHolder holder = (EditableValueHolder) component;
317 
318             if (holder.isLocalValueSet())
319             {
320                 value = holder.getLocalValue();
321             }
322             else
323             {
324                 value = getValue(component);
325             }
326         }
327         else
328         {
329             value = getValue(component);
330         }
331 
332         Converter converter = ((ValueHolder) component).getConverter();
333         if (converter == null && value != null)
334         {
335 
336             try
337             {
338                 converter = facesContext.getApplication().createConverter(
339                         value.getClass());
340                 if (log.isLoggable(Level.FINE))
341                 {
342                     log.fine("the created converter is " + converter);
343                 }
344             }
345             catch (FacesException e)
346             {
347                 log.log(Level.SEVERE, "No converter for class "
348                         + value.getClass().getName()
349                         + " found (component id=" + component.getId()
350                         + ").", e);
351                 // converter stays null
352             }
353         }
354 
355         if (converter == null)
356         {
357             if (value == null)
358             {
359                 if (log.isLoggable(Level.FINE))
360                 {
361                     log.fine("returning an empty string");
362                 }
363                 return "";
364             }
365 
366             if (log.isLoggable(Level.FINE))
367             {
368                 log.fine("returning an .toString");
369             }
370             return value.toString();
371 
372         }
373 
374         if (log.isLoggable(Level.FINE))
375         {
376             log.fine("returning converter get as string " + converter);
377         }
378         return converter.getAsString(facesContext, component, value);
379     }
380 
381     public static String getStringFromSubmittedValueOrLocalValueReturnNull(
382             FacesContext facesContext, UIComponent component)
383     {
384         try
385         {
386             if (!(component instanceof ValueHolder))
387             {
388                 throw new IllegalArgumentException("Component : "
389                         + getPathToComponent(component)
390                         + "is not a ValueHolder");
391             }
392 
393             if (component instanceof EditableValueHolder)
394             {
395                 Object submittedValue = ((EditableValueHolder) component)
396                         .getSubmittedValue();
397                 if (submittedValue != null)
398                 {
399                     if (log.isLoggable(Level.FINE))
400                     {
401                         log.fine("returning 1 '" + submittedValue + "'");
402                     }
403                     return submittedValue.toString();
404                 }
405             }
406 
407             Object value;
408 
409             if (component instanceof EditableValueHolder)
410             {
411 
412                 EditableValueHolder holder = (EditableValueHolder) component;
413 
414                 if (holder.isLocalValueSet())
415                 {
416                     value = holder.getLocalValue();
417                 }
418                 else
419                 {
420                     value = getValue(component);
421                 }
422             }
423             else
424             {
425                 value = getValue(component);
426             }
427 
428             Converter converter = ((ValueHolder) component).getConverter();
429             if (converter == null && value != null)
430             {
431 
432                 try
433                 {
434                     converter = facesContext.getApplication().createConverter(
435                             value.getClass());
436                     if (log.isLoggable(Level.FINE))
437                     {
438                         log.fine("the created converter is " + converter);
439                     }
440                 }
441                 catch (FacesException e)
442                 {
443                     log.log(Level.SEVERE, "No converter for class "
444                             + value.getClass().getName()
445                             + " found (component id=" + component.getId()
446                             + ").", e);
447                     // converter stays null
448                 }
449             }
450 
451             if (converter == null)
452             {
453                 if (value == null)
454                 {
455                     //if (log.isLoggable(Level.FINE))
456                     //    log.fine("returning an empty string");
457                     return null;
458                 }
459 
460                 if (log.isLoggable(Level.FINE))
461                 {
462                     log.fine("returning an .toString");
463                 }
464                 return value.toString();
465 
466             }
467 
468             if (log.isLoggable(Level.FINE))
469             {
470                 log.fine("returning converter get as string " + converter);
471             }
472             return converter.getAsString(facesContext, component, value);
473 
474         }
475         catch (PropertyNotFoundException ex)
476         {
477             log.log(Level.SEVERE, "Property not found - called by component : "
478                     + getPathToComponent(component), ex);
479 
480             throw ex;
481         }
482     }
483 
484     private static Object getValue(UIComponent component)
485     {
486         Object value = ((ValueHolder) component).getValue();
487         return value;
488     }
489 
490     /**
491      * See JSF Spec. 8.5 Table 8-1
492      * @param value
493      * @return boolean
494      */
495     public static boolean isDefaultAttributeValue(Object value)
496     {
497         if (value == null)
498         {
499             return true;
500         }
501         else if (value instanceof Boolean)
502         {
503             return !((Boolean) value).booleanValue();
504         }
505         else if (value instanceof Number)
506         {
507             if (value instanceof Integer)
508             {
509                 return ((Number) value).intValue() == Integer.MIN_VALUE;
510             }
511             else if (value instanceof Double)
512             {
513                 return ((Number) value).doubleValue() == Double.MIN_VALUE;
514             }
515             else if (value instanceof Long)
516             {
517                 return ((Number) value).longValue() == Long.MIN_VALUE;
518             }
519             else if (value instanceof Byte)
520             {
521                 return ((Number) value).byteValue() == Byte.MIN_VALUE;
522             }
523             else if (value instanceof Float)
524             {
525                 return ((Number) value).floatValue() == Float.MIN_VALUE;
526             }
527             else if (value instanceof Short)
528             {
529                 return ((Number) value).shortValue() == Short.MIN_VALUE;
530             }
531         }
532         return false;
533     }
534 
535     /**
536      * Find the proper Converter for the given UIOutput component.
537      * @return the Converter or null if no Converter specified or needed
538      * @throws FacesException if the Converter could not be created
539      */
540     public static Converter findUIOutputConverter(FacesContext facesContext,
541             UIOutput component) throws FacesException
542     {
543         return _SharedRendererUtils.findUIOutputConverter(facesContext,
544                 component);
545     }
546 
547     /**
548      * Calls findUISelectManyConverter with considerValueType = false.
549      * @param facesContext
550      * @param component
551      * @return
552      */
553     public static Converter findUISelectManyConverter(
554             FacesContext facesContext, UISelectMany component)
555     {
556         return findUISelectManyConverter(facesContext, component, false);
557     }
558 
559     /**
560      * Find proper Converter for the entries in the associated Collection or array of
561      * the given UISelectMany as specified in API Doc of UISelectMany.
562      * If considerValueType is true, the valueType attribute will be used
563      * in addition to the standard algorithm to get a valid converter.
564      * 
565      * @return the Converter or null if no Converter specified or needed
566      * @throws FacesException if the Converter could not be created
567      */
568     public static Converter findUISelectManyConverter(
569             FacesContext facesContext, UISelectMany component,
570             boolean considerValueType)
571     {
572         // If the component has an attached Converter, use it.
573         Converter converter = component.getConverter();
574         if (converter != null)
575         {
576             return converter;
577         }
578 
579         if (considerValueType)
580         {
581             // try to get a converter from the valueType attribute
582             converter = _SharedRendererUtils.getValueTypeConverter(
583                     facesContext, component);
584             if (converter != null)
585             {
586                 return converter;
587             }
588         }
589 
590         //Try to find out by value expression
591         ValueExpression ve = component.getValueExpression("value");
592         if (ve == null)
593         {
594             return null;
595         }
596 
597         // Try to get the type from the actual value or,
598         // if value == null, obtain the type from the ValueExpression
599         Class<?> valueType = null;
600         Object value = ve.getValue(facesContext.getELContext());
601         valueType = (value != null) ? value.getClass() : ve
602                 .getType(facesContext.getELContext());
603 
604         if (valueType == null)
605         {
606             return null;
607         }
608 
609         // a valueType of Object is also permitted, in order to support
610         // managed bean properties of type Object that resolve to null at this point
611         if (Collection.class.isAssignableFrom(valueType)
612                 || Object.class.equals(valueType))
613         {
614             // try to get the by-type-converter from the type of the SelectItems
615             return _SharedRendererUtils.getSelectItemsValueConverter(
616                     new SelectItemsIterator(component, facesContext),
617                     facesContext);
618         }
619 
620         if (!valueType.isArray())
621         {
622             throw new IllegalArgumentException(
623                     "ValueExpression for UISelectMany : "
624                             + getPathToComponent(component)
625                             + " must be of type Collection or Array");
626         }
627 
628         Class<?> arrayComponentType = valueType.getComponentType();
629         if (String.class.equals(arrayComponentType))
630         {
631             return null; //No converter needed for String type
632         }
633 
634         if (Object.class.equals(arrayComponentType))
635         {
636             // There is no converter for Object class
637             // try to get the by-type-converter from the type of the SelectItems
638             return _SharedRendererUtils.getSelectItemsValueConverter(
639                     new SelectItemsIterator(component, facesContext),
640                     facesContext);
641         }
642 
643         try
644         {
645             return facesContext.getApplication().createConverter(
646                     arrayComponentType);
647         }
648         catch (FacesException e)
649         {
650             log.log(Level.SEVERE,
651                     "No Converter for type " + arrayComponentType.getName()
652                             + " found", e);
653             return null;
654         }
655     }
656 
657     public static void checkParamValidity(FacesContext facesContext,
658             UIComponent uiComponent, Class compClass)
659     {
660         if (facesContext == null)
661         {
662             throw new NullPointerException("facesContext may not be null");
663         }
664         if (uiComponent == null)
665         {
666             throw new NullPointerException("uiComponent may not be null");
667         }
668 
669         //if (compClass != null && !(compClass.isAssignableFrom(uiComponent.getClass())))
670         // why isAssignableFrom with additional getClass method call if isInstance does the same?
671         if (compClass != null && !(compClass.isInstance(uiComponent)))
672         {
673             throw new IllegalArgumentException("uiComponent : "
674                     + getPathToComponent(uiComponent) + " is not instance of "
675                     + compClass.getName() + " as it should be");
676         }
677     }
678 
679     public static void renderChildren(FacesContext facesContext,
680             UIComponent component) throws IOException
681     {
682         if (component.getChildCount() > 0)
683         {
684             for (int i = 0; i < component.getChildCount(); i++)
685             {
686                 UIComponent child = component.getChildren().get(i);
687                 //renderChild(facesContext, child);
688                 child.encodeAll(facesContext);
689             }
690         }
691     }
692 
693     /**
694      * 
695      * @param facesContext
696      * @param child
697      * @throws IOException
698      * @deprecated use UIComponent.encodeAll() instead
699      */
700     @Deprecated
701     public static void renderChild(FacesContext facesContext, UIComponent child)
702             throws IOException
703     {
704         // The next isRendered() call is only shortcut:
705         // methods encodeBegin, encodeChildren and encodeEnd should proceed only if 
706         // "If our rendered property is true, render the (beginning, child, ending) of this component"
707         if (!isRendered(facesContext, child))
708         {
709             return;
710         }
711 
712         child.encodeBegin(facesContext);
713         if (child.getRendersChildren())
714         {
715             child.encodeChildren(facesContext);
716         }
717         else
718         {
719             renderChildren(facesContext, child);
720         }
721         child.encodeEnd(facesContext);
722     }
723 
724     /**
725      * Call {@link UIComponent#pushComponentToEL(javax.faces.context.FacesContext, javax.faces.component.UIComponent)}, 
726      * reads the isRendered property, call {@link
727      * UIComponent#popComponentFromEL(javax.faces.context.FacesContext)} and returns the value of isRendered.
728      */
729     public static boolean isRendered(FacesContext facesContext,
730             UIComponent uiComponent)
731     {
732         // We must call pushComponentToEL here because ValueExpression may have 
733         // implicit object "component" used. 
734         try
735         {
736             uiComponent.pushComponentToEL(facesContext, uiComponent);
737             return uiComponent.isRendered();
738         }
739         finally
740         {
741             uiComponent.popComponentFromEL(facesContext);
742         }
743     }
744 
745     public static List getSelectItemList(UISelectOne uiSelectOne)
746     {
747         return internalGetSelectItemList(uiSelectOne,
748                 FacesContext.getCurrentInstance());
749     }
750 
751     /**
752      * @param uiSelectOne
753      * @param facesContext
754      * @return List of SelectItem Objects
755      */
756     public static List<SelectItem> getSelectItemList(UISelectOne uiSelectOne,
757             FacesContext facesContext)
758     {
759         return internalGetSelectItemList(uiSelectOne, facesContext);
760     }
761 
762     public static List<SelectItem> getSelectItemList(UISelectMany uiSelectMany)
763     {
764         return internalGetSelectItemList(uiSelectMany,
765                 FacesContext.getCurrentInstance());
766     }
767 
768     /**
769      * @param uiSelectMany
770      * @param facesContext
771      * @return List of SelectItem Objects
772      */
773     public static List<SelectItem> getSelectItemList(UISelectMany uiSelectMany,
774             FacesContext facesContext)
775     {
776         return internalGetSelectItemList(uiSelectMany, facesContext);
777     }
778 
779     private static List<SelectItem> internalGetSelectItemList(UIComponent uiComponent,
780             FacesContext facesContext)
781     {
782         /* TODO: Shall we cache the list in a component attribute?
783         ArrayList list = (ArrayList)uiComponent.getAttributes().get(SELECT_ITEM_LIST_ATTR);
784         if (list != null)
785         {
786             return list;
787         }
788          */
789 
790         List<SelectItem> list = new ArrayList<SelectItem>();
791 
792         for (SelectItemsIterator iter = new SelectItemsIterator(uiComponent, facesContext); iter.hasNext();)
793         {
794             list.add(iter.next());
795         }
796         return list;
797     }
798 
799     /**
800      * Convenient utility method that returns the currently submitted values of
801      * a UISelectMany component as a Set, of which the contains method can then be
802      * easily used to determine if a select item is currently selected.
803      * Calling the contains method of this Set with the renderable (String converted) item value
804      * as argument returns true if this item is selected.
805      * @param uiSelectMany
806      * @return Set containing all currently selected values
807      */
808     public static Set getSubmittedValuesAsSet(FacesContext context,
809             UIComponent component, Converter converter,
810             UISelectMany uiSelectMany)
811     {
812         Object submittedValues = uiSelectMany.getSubmittedValue();
813         if (submittedValues == null)
814         {
815             return null;
816         }
817 
818         if (converter != null)
819         {
820             converter = new PassThroughAsStringConverter(converter);
821         }
822 
823         return internalSubmittedOrSelectedValuesAsSet(context, component,
824                 converter, uiSelectMany, submittedValues, false);
825     }
826 
827     /**
828      * Convenient utility method that returns the currently selected values of
829      * a UISelectMany component as a Set, of which the contains method can then be
830      * easily used to determine if a value is currently selected.
831      * Calling the contains method of this Set with the item value
832      * as argument returns true if this item is selected.
833      * @param uiSelectMany
834      * @return Set containing all currently selected values
835      */
836     public static Set getSelectedValuesAsSet(FacesContext context,
837             UIComponent component, Converter converter,
838             UISelectMany uiSelectMany)
839     {
840         Object selectedValues = uiSelectMany.getValue();
841 
842         return internalSubmittedOrSelectedValuesAsSet(context, component,
843                 converter, uiSelectMany, selectedValues, true);
844     }
845 
846     /**
847      * Convenient utility method that returns the currently given value as String,
848      * using the given converter.
849      * Especially usefull for dealing with primitive types.
850      */
851     public static String getConvertedStringValue(FacesContext context,
852             UIComponent component, Converter converter, Object value)
853     {
854         if (converter == null)
855         {
856             if (value == null)
857             {
858                 return "";
859             }
860             else if (value instanceof String)
861             {
862                 return (String) value;
863             }
864             else
865             {
866                 return value.toString();
867             }
868         }
869 
870         return converter.getAsString(context, component, value);
871     }
872 
873     /**
874      * Convenient utility method that returns the currently given SelectItem value
875      * as String, using the given converter.
876      * Especially usefull for dealing with primitive types.
877      */
878     public static String getConvertedStringValue(FacesContext context,
879             UIComponent component, Converter converter, SelectItem selectItem)
880     {
881         return getConvertedStringValue(context, component, converter,
882                 selectItem.getValue());
883     }
884 
885     private static Set internalSubmittedOrSelectedValuesAsSet(
886             FacesContext context, UIComponent component, Converter converter,
887             UISelectMany uiSelectMany, Object values,
888             boolean allowNonArrayOrCollectionValue)
889     {
890         if (values == null || EMPTY_STRING.equals(values))
891         {
892             return Collections.EMPTY_SET;
893         }
894         else if (values instanceof Object[])
895         {
896             //Object array
897             Object[] ar = (Object[]) values;
898             if (ar.length == 0)
899             {
900                 return Collections.EMPTY_SET;
901             }
902 
903             HashSet set = new HashSet(HashMapUtils.calcCapacity(ar.length));
904             for (int i = 0; i < ar.length; i++)
905             {
906                 set.add(getConvertedStringValue(context, component, converter,
907                         ar[i]));
908             }
909             return set;
910         }
911         else if (values.getClass().isArray())
912         {
913             //primitive array
914             int len = Array.getLength(values);
915             HashSet set = new HashSet(
916                     org.apache.myfaces.shared.util.HashMapUtils
917                             .calcCapacity(len));
918             for (int i = 0; i < len; i++)
919             {
920                 set.add(getConvertedStringValue(context, component, converter,
921                         Array.get(values, i)));
922             }
923             return set;
924         }
925         else if (values instanceof Collection)
926         {
927             Collection col = (Collection) values;
928             if (col.isEmpty())
929             {
930                 return Collections.EMPTY_SET;
931             }
932 
933             HashSet set = new HashSet(HashMapUtils.calcCapacity(col.size()));
934             for (Iterator i = col.iterator(); i.hasNext();)
935             {
936                 set.add(getConvertedStringValue(context, component, converter,
937                         i.next()));
938             }
939 
940             return set;
941 
942         }
943         else if (allowNonArrayOrCollectionValue)
944         {
945             HashSet set = new HashSet(HashMapUtils.calcCapacity(1));
946             set.add(values);
947             return set;
948         }
949         else
950         {
951             throw new IllegalArgumentException(
952                     "Value of UISelectMany component with path : "
953                             + getPathToComponent(uiSelectMany)
954                             + " is not of type Array or List");
955         }
956     }
957 
958     public static Object getConvertedUISelectOneValue(
959             FacesContext facesContext, UISelectOne output, Object submittedValue)
960     {
961         if (submittedValue != null && !(submittedValue instanceof String))
962         {
963             throw new IllegalArgumentException(
964                     "Submitted value of type String for component : "
965                             + getPathToComponent(output) + "expected");
966         }
967 
968         //To be compatible with jsf ri, and according to issue 69
969         //[  Permit the passing of a null value to SelectItem.setValue()  ]
970         //If submittedValue == "" then convert to null.
971         if ((submittedValue != null)
972                 && ("".equals(submittedValue)))
973         {
974             //Replace "" by null value
975             submittedValue = null;
976         }
977 
978         Converter converter;
979         try
980         {
981             converter = findUIOutputConverter(facesContext, output);
982         }
983         catch (FacesException e)
984         {
985             throw new ConverterException(e);
986         }
987 
988         return converter == null ? submittedValue : converter.getAsObject(
989                 facesContext, output, (String) submittedValue);
990     }
991 
992     public static Object getConvertedUIOutputValue(FacesContext facesContext,
993             UIOutput output, Object submittedValue) throws ConverterException
994     {
995         if (submittedValue != null && !(submittedValue instanceof String))
996         {
997             submittedValue = submittedValue.toString();
998         }
999 
1000         Converter converter;
1001         try
1002         {
1003             converter = findUIOutputConverter(facesContext, output);
1004         }
1005         catch (FacesException e)
1006         {
1007             throw new ConverterException(e);
1008         }
1009 
1010         return converter == null ? submittedValue : converter.getAsObject(
1011                 facesContext, output, (String) submittedValue);
1012     }
1013 
1014     /**
1015      * Invokes getConvertedUISelectManyValue() with considerValueType = false, thus
1016      * implementing the standard behavior of the spec (valueType comes from Tomahawk).
1017      * 
1018      * @param facesContext
1019      * @param selectMany
1020      * @param submittedValue
1021      * @return
1022      * @throws ConverterException
1023      */
1024     public static Object getConvertedUISelectManyValue(
1025             FacesContext facesContext, UISelectMany selectMany,
1026             Object submittedValue) throws ConverterException
1027     {
1028         // do not consider the valueType attribute
1029         return getConvertedUISelectManyValue(facesContext, selectMany,
1030                 submittedValue, false);
1031     }
1032 
1033     /**
1034      * Gets the converted value of a UISelectMany component.
1035      * 
1036      * @param facesContext
1037      * @param selectMany
1038      * @param submittedValue
1039      * @param considerValueType if true, the valueType attribute of the component will
1040      *                          also be used (applies for Tomahawk UISelectMany components)
1041      * @return
1042      * @throws ConverterException
1043      */
1044     public static Object getConvertedUISelectManyValue(
1045             FacesContext facesContext, UISelectMany selectMany,
1046             Object submittedValue, boolean considerValueType)
1047             throws ConverterException
1048     {
1049         if (submittedValue == null)
1050         {
1051             return null;
1052         }
1053 
1054         if (!(submittedValue instanceof String[]))
1055         {
1056             throw new ConverterException(
1057                     "Submitted value of type String[] for component : "
1058                             + getPathToComponent(selectMany) + "expected");
1059         }
1060 
1061         return _SharedRendererUtils.getConvertedUISelectManyValue(facesContext,
1062                 selectMany, (String[]) submittedValue, considerValueType);
1063     }
1064 
1065     public static boolean getBooleanAttribute(UIComponent component,
1066             String attrName, boolean defaultValue)
1067     {
1068         Boolean b = (Boolean) component.getAttributes().get(attrName);
1069         return b != null ? b.booleanValue() : defaultValue;
1070     }
1071 
1072     public static int getIntegerAttribute(UIComponent component,
1073             String attrName, int defaultValue)
1074     {
1075         Integer i = (Integer) component.getAttributes().get(attrName);
1076         return i != null ? i.intValue() : defaultValue;
1077     }
1078 
1079     private static final String TRINIDAD_FORM_COMPONENT_FAMILY = "org.apache.myfaces.trinidad.Form";
1080     private static final String ADF_FORM_COMPONENT_FAMILY = "oracle.adf.Form";
1081 
1082     /**
1083      * Find the enclosing form of a component
1084      * in the view-tree.
1085      * All Subclasses of <code>UIForm</code> and all known
1086      * form-families are searched for.
1087      * Currently those are the Trinidad form family,
1088      * and the (old) ADF Faces form family.
1089      * <p>
1090      * There might be additional form families
1091      * which have to be explicitly entered here.</p>
1092      *
1093      * @param uiComponent
1094      * @param facesContext
1095      * @return FormInfo Information about the form - the form itself and its name.
1096      */
1097     public static FormInfo findNestingForm(UIComponent uiComponent,
1098             FacesContext facesContext)
1099     {
1100         UIComponent parent = uiComponent.getParent();
1101         while (parent != null
1102                 && (!ADF_FORM_COMPONENT_FAMILY.equals(parent.getFamily())
1103                         && !TRINIDAD_FORM_COMPONENT_FAMILY.equals(parent
1104                                 .getFamily()) && !(parent instanceof UIForm)))
1105         {
1106             parent = parent.getParent();
1107         }
1108 
1109         if (parent != null)
1110         {
1111             //link is nested inside a form
1112             String formName = parent.getClientId(facesContext);
1113             return new FormInfo(parent, formName);
1114         }
1115 
1116         return null;
1117     }
1118 
1119     public static boolean getBooleanValue(String attribute, Object value,
1120             boolean defaultValue)
1121     {
1122         if (value instanceof Boolean)
1123         {
1124             return ((Boolean) value).booleanValue();
1125         }
1126         else if (value instanceof String)
1127         {
1128             return Boolean.valueOf((String) value).booleanValue();
1129         }
1130         else if (value != null)
1131         {
1132             log.severe("value for attribute "
1133                     + attribute
1134                     + " must be instanceof 'Boolean' or 'String', is of type : "
1135                     + value.getClass());
1136 
1137             return defaultValue;
1138         }
1139 
1140         return defaultValue;
1141     }
1142 
1143     public static void copyHtmlInputTextAttributes(HtmlInputText src,
1144             HtmlInputText dest)
1145     {
1146         dest.setId(src.getId());
1147         boolean forceId = getBooleanValue(JSFAttr.FORCE_ID_ATTR, src
1148                 .getAttributes().get(JSFAttr.FORCE_ID_ATTR), false);
1149         if (forceId)
1150         {
1151             dest.getAttributes().put(JSFAttr.FORCE_ID_ATTR, Boolean.TRUE);
1152         }
1153         dest.setImmediate(src.isImmediate());
1154         dest.setTransient(src.isTransient());
1155         dest.setAccesskey(src.getAccesskey());
1156         dest.setAlt(src.getAlt());
1157         dest.setConverter(src.getConverter());
1158         dest.setDir(src.getDir());
1159         dest.setDisabled(src.isDisabled());
1160         dest.setLang(src.getLang());
1161         dest.setLocalValueSet(src.isLocalValueSet());
1162         dest.setMaxlength(src.getMaxlength());
1163         dest.setOnblur(src.getOnblur());
1164         dest.setOnchange(src.getOnchange());
1165         dest.setOnclick(src.getOnclick());
1166         dest.setOndblclick(src.getOndblclick());
1167         dest.setOnfocus(src.getOnfocus());
1168         dest.setOnkeydown(src.getOnkeydown());
1169         dest.setOnkeypress(src.getOnkeypress());
1170         dest.setOnkeyup(src.getOnkeyup());
1171         dest.setOnmousedown(src.getOnmousedown());
1172         dest.setOnmousemove(src.getOnmousemove());
1173         dest.setOnmouseout(src.getOnmouseout());
1174         dest.setOnmouseover(src.getOnmouseover());
1175         dest.setOnmouseup(src.getOnmouseup());
1176         dest.setOnselect(src.getOnselect());
1177         dest.setReadonly(src.isReadonly());
1178         dest.setRendered(src.isRendered());
1179         dest.setRequired(src.isRequired());
1180         dest.setSize(src.getSize());
1181         dest.setStyle(src.getStyle());
1182         dest.setStyleClass(src.getStyleClass());
1183         dest.setTabindex(src.getTabindex());
1184         dest.setTitle(src.getTitle());
1185         dest.setValidator(src.getValidator());
1186     }
1187 
1188     public static UIComponent findComponent(UIComponent headerComp, Class clazz)
1189     {
1190         if (clazz.isAssignableFrom(headerComp.getClass()))
1191         {
1192             return headerComp;
1193         }
1194 
1195         List li = headerComp.getChildren();
1196 
1197         for (int i = 0; i < li.size(); i++)
1198         {
1199             UIComponent comp = (UIComponent) li.get(i);
1200 
1201             //recursively iterate through children to find the component
1202             UIComponent lookupComp = findComponent(comp, clazz);
1203 
1204             if (lookupComp != null)
1205             {
1206                 return lookupComp;
1207             }
1208         }
1209 
1210         return null;
1211     }
1212 
1213     public static void addOrReplaceChild(UIInput component, UIComponent child)
1214     {
1215         List li = component.getChildren();
1216 
1217         for (int i = 0; i < li.size(); i++)
1218         {
1219             UIComponent oldChild = (UIComponent) li.get(i);
1220 
1221             if (oldChild.getId() != null
1222                     && oldChild.getId().equals(child.getId()))
1223             {
1224                 li.set(i, child);
1225                 return;
1226             }
1227         }
1228 
1229         component.getChildren().add(child);
1230     }
1231 
1232     public static String getClientId(FacesContext facesContext,
1233             UIComponent uiComponent, String forAttr)
1234     {
1235         UIComponent forComponent = uiComponent.findComponent(forAttr);
1236         if (forComponent == null)
1237         {
1238             final char separatorChar = facesContext.getNamingContainerSeparatorChar();
1239             
1240             Level level = Level.WARNING;
1241             boolean productionStage = facesContext.isProjectStage(ProjectStage.Production);
1242             if (productionStage)
1243             {
1244                 level = Level.FINE;
1245             }
1246             if (log.isLoggable(level))
1247             {
1248                 StringBuilder sb = new StringBuilder();
1249                 sb.append("Unable to find component '");
1250                 sb.append(forAttr);
1251                 sb.append("' (calling findComponent on component '");
1252                 sb.append(uiComponent.getClientId(facesContext));
1253                 sb.append("'");
1254                 if (!productionStage)
1255                 {
1256                     sb.append(", viewLocation: ");
1257                     sb.append(uiComponent.getAttributes().get(UIComponent.VIEW_LOCATION_KEY));
1258                 }
1259                 sb.append(").");
1260                 sb.append(" We'll try to return a guessed client-id anyways -");
1261                 sb.append(" this will be a problem if you put the referenced component");
1262                 sb.append(" into a different naming-container. If this is the case, ");
1263                 sb.append("you can always use the full client-id.");
1264                 log.info(sb.toString());
1265             }
1266             if (forAttr.length() > 0 && forAttr.charAt(0) == separatorChar)
1267             {
1268                 //absolute id path
1269                 return forAttr.substring(1);
1270             }
1271 
1272             //relative id path, we assume a component on the same level as the label component
1273             String labelClientId = uiComponent.getClientId(facesContext);
1274             int colon = labelClientId.lastIndexOf(separatorChar);
1275 
1276             return colon == -1 ? forAttr : labelClientId
1277                     .substring(0, colon + 1) + forAttr;
1278 
1279         }
1280 
1281         return forComponent.getClientId(facesContext);
1282 
1283     }
1284 
1285     public static List convertIdsToClientIds(String actionFor,
1286             FacesContext facesContext, UIComponent component)
1287     {
1288         List li = new ArrayList();
1289 
1290         String[] ids = actionFor.split(",");
1291 
1292         for (int i = 0; i < ids.length; i++)
1293         {
1294             String trimedId = ids[i].trim();
1295             if (trimedId.equals("none"))
1296             {
1297                 li.add(trimedId);
1298             }
1299             else
1300             {
1301                 li.add(RendererUtils.getClientId(facesContext, component,
1302                         trimedId));
1303             }
1304         }
1305         return li;
1306     }
1307 
1308     public static List convertPhasesToPhasesIds(String actionForPhase)
1309     {
1310         List li = new ArrayList();
1311 
1312         if (actionForPhase == null)
1313         {
1314             return li;
1315         }
1316 
1317         String[] ids = actionForPhase.split(",");
1318 
1319         for (int i = 0; i < ids.length; i++)
1320         {
1321             if (ids[i].equals("PROCESS_VALIDATIONS"))
1322             {
1323                 li.add(PhaseId.PROCESS_VALIDATIONS);
1324             }
1325             else if (ids[i].equals("UPDATE_MODEL_VALUES"))
1326             {
1327                 li.add(PhaseId.UPDATE_MODEL_VALUES);
1328             }
1329         }
1330         return li;
1331     }
1332 
1333     /**
1334      * Helper method which loads a resource file (such as css) by a given context path and a file name.
1335      * Useful to provide css files (or js files) inline.
1336      * 
1337      * @param ctx <code>FacesContext</code> object to calculate the context path of the web application.
1338      * @param file name of the resource file (e.g. <code>foo.css</code>).
1339      * @return the content of the resource file, or <code>null</code> if no such file is available.
1340      */
1341     public static String loadResourceFile(FacesContext ctx, String file)
1342     {
1343 
1344         ByteArrayOutputStream content = new ByteArrayOutputStream(10240);
1345 
1346         InputStream in = null;
1347         try
1348         {
1349             in = ctx.getExternalContext().getResourceAsStream(file);
1350             if (in == null)
1351             {
1352                 return null;
1353             }
1354 
1355             byte[] fileBuffer = new byte[10240];
1356             int read;
1357             while ((read = in.read(fileBuffer)) > -1)
1358             {
1359                 content.write(fileBuffer, 0, read);
1360             }
1361         }
1362         catch (FileNotFoundException e)
1363         {
1364             if (log.isLoggable(Level.WARNING))
1365             {
1366                 log.log(Level.WARNING, "no such file " + file, e);
1367             }
1368             content = null;
1369         }
1370         catch (IOException e)
1371         {
1372             if (log.isLoggable(Level.WARNING))
1373             {
1374                 log.log(Level.WARNING, "problems during processing resource "
1375                         + file, e);
1376             }
1377             content = null;
1378         }
1379         finally
1380         {
1381             try
1382             {
1383                 if (content != null)
1384                 {
1385                     content.close();
1386                 }
1387             }
1388             catch (IOException e)
1389             {
1390                 log.log(Level.WARNING, e.getLocalizedMessage(), e);
1391             }
1392             if (in != null)
1393             {
1394                 try
1395                 {
1396                     in.close();
1397                 }
1398                 catch (IOException e)
1399                 {
1400                     log.log(Level.WARNING, e.getLocalizedMessage(), e);
1401                 }
1402             }
1403         }
1404 
1405         return content != null ? content.toString() : null;
1406     }
1407 
1408     /**
1409      * check for partial validation or model update attributes being set
1410      * and initialize the request-map accordingly.
1411      * SubForms will work with this information.
1412      */
1413     public static void initPartialValidationAndModelUpdate(
1414             UIComponent component, FacesContext facesContext)
1415     {
1416         String actionFor = (String) component.getAttributes().get("actionFor");
1417 
1418         if (actionFor != null)
1419         {
1420             List li = convertIdsToClientIds(actionFor, facesContext, component);
1421 
1422             facesContext.getExternalContext().getRequestMap()
1423                     .put(ACTION_FOR_LIST, li);
1424 
1425             String actionForPhase = (String) component.getAttributes().get(
1426                     "actionForPhase");
1427 
1428             if (actionForPhase != null)
1429             {
1430                 List phaseList = convertPhasesToPhasesIds(actionForPhase);
1431 
1432                 facesContext.getExternalContext().getRequestMap()
1433                         .put(ACTION_FOR_PHASE_LIST, phaseList);
1434             }
1435         }
1436     }
1437 
1438     public static boolean isAdfOrTrinidadForm(UIComponent component)
1439     {
1440         if (component == null)
1441         {
1442             return false;
1443         }
1444         return ADF_FORM_COMPONENT_FAMILY.equals(component.getFamily())
1445                 || TRINIDAD_FORM_COMPONENT_FAMILY.equals(component.getFamily());
1446     }
1447 
1448     /**
1449      * Gets the ResponseStateManager for the renderKit Id provided
1450      * 
1451      * @deprecated use FacesContext.getRenderKit() or getRenderKitFactory().getRenderKit(
1452      *               context, renderKitId).getResponseStateManager()
1453      */
1454     @Deprecated
1455     public static ResponseStateManager getResponseStateManager(
1456             FacesContext facesContext, String renderKitId)
1457             throws FacesException
1458     {
1459         RenderKit renderKit = facesContext.getRenderKit();
1460 
1461         if (renderKit == null)
1462         {
1463             // look for the renderkit in the request
1464             Map attributesMap = facesContext.getAttributes();
1465             RenderKitFactory factory = (RenderKitFactory) attributesMap
1466                     .get(RENDER_KIT_IMPL);
1467 
1468             if (factory != null)
1469             {
1470                 renderKit = factory.getRenderKit(facesContext, renderKitId);
1471             }
1472             else
1473             {
1474                 factory = (RenderKitFactory) FactoryFinder
1475                         .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
1476 
1477                 if (factory == null)
1478                 {
1479                     throw new IllegalStateException("Factory is null");
1480                 }
1481 
1482                 attributesMap.put(RENDER_KIT_IMPL, factory);
1483 
1484                 renderKit = factory.getRenderKit(facesContext, renderKitId);
1485             }
1486         }
1487 
1488         if (renderKit == null)
1489         {
1490             throw new IllegalArgumentException(
1491                     "Could not find a RenderKit for \"" + renderKitId + "\"");
1492         }
1493 
1494         return renderKit.getResponseStateManager();
1495     }
1496 
1497     /**
1498       * Checks for name/library attributes on component and if they are avaliable,
1499       * creates {@link Resource} and returns it's path suitable for rendering.
1500       * If component doesn't have name/library gets value for attribute named <code>attributeName</code> 
1501       * returns it processed with {@link #toResourceUri(javax.faces.context.FacesContext, java.lang.Object)}
1502       *       
1503       * @param facesContext a {@link FacesContext}
1504       * @param component a {@link UIComponent}
1505       * @param attributeName name of attribute that represents "image", "icon", "source", ... 
1506       * 
1507       * @since 4.0.1
1508       */
1509     public static String getIconSrc(final FacesContext facesContext,
1510             final UIComponent component, final String attributeName)
1511     {
1512 
1513         // JSF 2.0: if "name" attribute is available, treat as a resource reference.
1514         final Map<String, Object> attributes = component.getAttributes();
1515         final String resourceName = (String) attributes.get(JSFAttr.NAME_ATTR);
1516         if (resourceName != null && (resourceName.length() > 0))
1517         {
1518 
1519             final ResourceHandler resourceHandler = facesContext
1520                     .getApplication().getResourceHandler();
1521             final Resource resource;
1522 
1523             final String libraryName = (String) component.getAttributes().get(
1524                     JSFAttr.LIBRARY_ATTR);
1525             if ((libraryName != null) && (libraryName.length() > 0))
1526             {
1527                 resource = resourceHandler.createResource(resourceName,
1528                         libraryName);
1529             }
1530             else
1531             {
1532                 resource = resourceHandler.createResource(resourceName);
1533             }
1534 
1535             if (resource == null)
1536             {
1537                 // If resourceName/libraryName are set but no resource created -> probably a typo,
1538                 // show a message
1539                 if (facesContext.isProjectStage(ProjectStage.Development))
1540                 {
1541                     String summary = "Unable to find resource: " + resourceName;
1542                     if (libraryName != null)
1543                     {
1544                         summary = summary + " from library: " + libraryName;
1545                     }
1546                     facesContext.addMessage(
1547                             component.getClientId(facesContext),
1548                             new FacesMessage(FacesMessage.SEVERITY_WARN,
1549                                     summary, summary));
1550                 }
1551 
1552                 return RES_NOT_FOUND;
1553             }
1554             else
1555             {
1556                 return resource.getRequestPath();
1557             }
1558         }
1559         else
1560         {
1561             String value = (String) component.getAttributes()
1562                     .get(attributeName);
1563             return toResourceUri(facesContext, value);
1564         }
1565     }
1566 
1567     /**
1568      * Coerces an object into a resource URI, calling the view-handler.
1569      */
1570     static public String toResourceUri(FacesContext facesContext, Object o)
1571     {
1572         if (o == null)
1573         {
1574             return null;
1575         }
1576 
1577         String uri = o.toString();
1578 
1579         // *** EL Coercion problem ***
1580         // If icon or image attribute was declared with #{resource[]} and that expression
1581         // evaluates to null (it means ResourceHandler.createResource returns null because 
1582         // requested resource does not exist)
1583         // EL implementation turns null into ""
1584         // see http://www.irian.at/blog/blogid/unifiedElCoercion/#unifiedElCoercion
1585         if (uri.length() == 0)
1586         {
1587             return null;
1588         }
1589 
1590         // With JSF 2.0 url for resources can be done with EL like #{resource['resourcename']}
1591         // and such EL after evalution contains context path for the current web application already,
1592         // -> we dont want call viewHandler.getResourceURL()
1593         if (uri.contains(ResourceHandler.RESOURCE_IDENTIFIER))
1594         {
1595             return uri;
1596         }
1597 
1598         // Treat two slashes as server-relative
1599         if (uri.startsWith("//"))
1600         {
1601             return uri.substring(1);
1602         }
1603         else
1604         {
1605             // If the specified path starts with a "/",
1606             // following method will prefix it with the context path for the current web application,
1607             // and return the result
1608             String resourceURL = facesContext.getApplication().getViewHandler()
1609                     .getResourceURL(facesContext, uri);
1610             return facesContext.getExternalContext().encodeResourceURL(
1611                     resourceURL);
1612         }
1613     }
1614 
1615     /**
1616      * Special converter for handling submitted values which don't need to be converted.
1617      */
1618     private static class PassThroughAsStringConverter implements Converter
1619     {
1620         private final Converter converter;
1621 
1622         public PassThroughAsStringConverter(Converter converter)
1623         {
1624             this.converter = converter;
1625         }
1626 
1627         public Object getAsObject(FacesContext context, UIComponent component,
1628                 String value) throws ConverterException
1629         {
1630             return converter.getAsObject(context, component, value);
1631         }
1632 
1633         public String getAsString(FacesContext context, UIComponent component,
1634                 Object value) throws ConverterException
1635         {
1636             return (String) value;
1637         }
1638 
1639     }
1640 }