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_orchestra.renderkit;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.myfaces.shared_orchestra.renderkit.html.util.FormInfo;
24  import org.apache.myfaces.shared_orchestra.util.HashMapUtils;
25  import org.apache.myfaces.shared_orchestra.util.SelectItemsIterator;
26  
27  import javax.faces.FacesException;
28  import javax.faces.component.*;
29  import javax.faces.component.html.HtmlInputText;
30  import javax.faces.context.FacesContext;
31  import javax.faces.convert.Converter;
32  import javax.faces.convert.ConverterException;
33  import javax.faces.el.PropertyNotFoundException;
34  import javax.faces.el.ValueBinding;
35  import javax.faces.event.PhaseId;
36  import javax.faces.model.SelectItem;
37  import java.io.*;
38  import java.lang.reflect.Array;
39  import java.util.*;
40  
41  /**
42   * @author Manfred Geiler (latest modification by $Author: lu4242 $)
43   * @version $Revision: 777357 $ $Date: 2009-05-21 21:40:33 -0500 (Thu, 21 May 2009) $
44   */
45  public final class RendererUtils {
46  
47      private RendererUtils() {
48          //nope
49      }
50  
51      private static final Log log = LogFactory.getLog(RendererUtils.class);
52  
53      public static final String SELECT_ITEM_LIST_ATTR = RendererUtils.class.getName() + ".LIST";
54      public static final String EMPTY_STRING = "";
55      public static final Object NOTHING = new Serializable() {
56          public boolean equals(final Object o)
57          {
58              if (o != null)
59              {
60                  if (o.getClass().equals(this.getClass()))
61                  {
62                      return true;
63                  }
64              }
65              return false;
66          }
67      };
68  
69      public static final String ACTION_FOR_LIST = "org.apache.myfaces.ActionForList";
70      public static final String ACTION_FOR_PHASE_LIST = "org.apache.myfaces.ActionForPhaseList";
71  
72      public static String getPathToComponent(UIComponent component) {
73          StringBuffer buf = new StringBuffer();
74  
75          if (component == null) {
76              buf.append("{Component-Path : ");
77              buf.append("[null]}");
78              return buf.toString();
79          }
80  
81          getPathToComponent(component, buf);
82  
83          buf.insert(0, "{Component-Path : ");
84          buf.append("}");
85  
86          return buf.toString();
87      }
88  
89      private static void getPathToComponent(UIComponent component, StringBuffer buf) {
90          if (component == null)
91              return;
92  
93          StringBuffer intBuf = new StringBuffer();
94  
95          intBuf.append("[Class: ");
96          intBuf.append(component.getClass().getName());
97          if (component instanceof UIViewRoot) {
98              intBuf.append(",ViewId: ");
99              intBuf.append(((UIViewRoot) component).getViewId());
100         }
101         else {
102             intBuf.append(",Id: ");
103             intBuf.append(component.getId());
104         }
105         intBuf.append("]");
106 
107         buf.insert(0, intBuf.toString());
108 
109         getPathToComponent(component.getParent(), buf);
110     }
111 
112     public static String getConcatenatedId(FacesContext context, UIComponent container,
113                                            String clientId) {
114         UIComponent child = container.findComponent(clientId);
115 
116         if (child == null)
117             return clientId;
118 
119         return getConcatenatedId(context, child);
120     }
121 
122     public static String getConcatenatedId(FacesContext context, UIComponent component) {
123         if (context == null) throw new NullPointerException("context");
124 
125         StringBuffer idBuf = new StringBuffer();
126 
127         idBuf.append(component.getId());
128 
129         UIComponent parent;
130 
131         while ((parent = component.getParent()) != null) {
132             if (parent instanceof NamingContainer) {
133                 idBuf.insert(0, NamingContainer.SEPARATOR_CHAR);
134                 idBuf.insert(0, parent.getId());
135             }
136         }
137 
138         return idBuf.toString();
139     }
140 
141     public static Boolean getBooleanValue(UIComponent component) {
142         Object value = getObjectValue(component);
143         if (value == null || value instanceof Boolean) {
144             return (Boolean) value;
145         }
146         else {
147             throw new IllegalArgumentException("Expected submitted value of type Boolean for Component : " +
148                 getPathToComponent(component));
149         }
150     }
151 
152     public static Date getDateValue(UIComponent component) {
153         Object value = getObjectValue(component);
154         if (value == null || value instanceof Date) {
155             return (Date) value;
156         }
157         else {
158             throw new IllegalArgumentException("Expected submitted value of type Date for component : "
159                 + getPathToComponent(component));
160         }
161     }
162 
163     public static Object getObjectValue(UIComponent component) {
164         if (!(component instanceof ValueHolder)) {
165             throw new IllegalArgumentException("Component : " +
166                 getPathToComponent(component) + "is not a ValueHolder");
167         }
168 
169         if (component instanceof EditableValueHolder) {
170             Object value = ((EditableValueHolder) component).getSubmittedValue();
171             if (value != null && !NOTHING.equals(value)) {
172                 return value;
173             }
174         }
175 
176         return ((ValueHolder) component).getValue();
177     }
178 
179     public static String getStringValue(FacesContext context, ValueBinding vb)
180     {
181         Object value = vb.getValue(context);
182         if (value != null)
183         {
184             return value.toString();
185         }
186         return null;
187     }
188 
189     public static String getStringValue(FacesContext facesContext,
190                                         UIComponent component) {
191         try {
192             if (!(component instanceof ValueHolder)) {
193                 throw new IllegalArgumentException("Component : " + getPathToComponent(component) + "is not a ValueHolder");
194             }
195 
196             if (component instanceof EditableValueHolder) {
197 
198                 EditableValueHolder holder = (EditableValueHolder) component;
199 
200                 Object submittedValue = holder.getSubmittedValue();
201                 if (submittedValue != null) {
202                     if (submittedValue instanceof String) {
203                         return (String) submittedValue;
204                     }
205                     else {
206                         throw new IllegalArgumentException("Expected submitted value of type String for component : "
207                             + getPathToComponent(component));
208                     }
209                 }
210 
211             }
212 
213             Object value;
214 
215             if(component instanceof EditableValueHolder) {
216 
217                 EditableValueHolder holder = (EditableValueHolder) component;
218                 
219                 if(holder.isLocalValueSet()) {
220                     value = holder.getLocalValue();
221                 } else {
222                     value = getValue(component);
223                 }
224             }
225             else {
226                 value = getValue(component);
227             }
228 
229             Converter converter = ((ValueHolder) component).getConverter();
230             if (converter == null && value != null) {
231                 if (value instanceof String) {
232                     return (String) value;
233                 }
234 
235                 try {
236                     converter = facesContext.getApplication().createConverter(value.getClass());
237                 }
238                 catch (FacesException e) {
239                     log.error("No converter for class " + value.getClass().getName() + " found (component id=" + component.getId() + ").");
240                     // converter stays null
241                 }
242             }
243 
244             if (converter == null) {
245                 if (value == null) {
246                     return "";
247                 }
248                 else {
249                     return value.toString();
250                 }
251             }
252             else {
253                 return converter.getAsString(facesContext, component, value);
254             }
255         }
256         catch (PropertyNotFoundException ex) {
257             log.error("Property not found - called by component : " + getPathToComponent(component), ex);
258 
259             throw ex;
260         }
261     }
262 
263     private static Object getValue(UIComponent component) {
264         Object value;
265         try
266                 {
267                     value = ((ValueHolder) component).getValue();
268         }
269         catch(Exception ex)
270         {
271             throw new FacesException("Could not retrieve value of component with path : "+
272                     getPathToComponent(component),ex);
273         }
274         return value;
275     }
276 
277     /**
278      * See JSF Spec. 8.5 Table 8-1
279      *
280      * @param value
281      * @return boolean
282      */
283     public static boolean isDefaultAttributeValue(Object value) {
284         if (value == null) {
285             return true;
286         }
287         else if (value instanceof Boolean) {
288             return !((Boolean) value).booleanValue();
289         }
290         else if (value instanceof Number) {
291             if (value instanceof Integer) {
292                 return ((Number) value).intValue() == Integer.MIN_VALUE;
293             }
294             else if (value instanceof Double) {
295                 return ((Number) value).doubleValue() == Double.MIN_VALUE;
296             }
297             else if (value instanceof Long) {
298                 return ((Number) value).longValue() == Long.MIN_VALUE;
299             }
300             else if (value instanceof Byte) {
301                 return ((Number) value).byteValue() == Byte.MIN_VALUE;
302             }
303             else if (value instanceof Float) {
304                 return ((Number) value).floatValue() == Float.MIN_VALUE;
305             }
306             else if (value instanceof Short) {
307                 return ((Number) value).shortValue() == Short.MIN_VALUE;
308             }
309         }
310         return false;
311     }
312 
313     /**
314      * Find the proper Converter for the given UIOutput component.
315      *
316      * @return the Converter or null if no Converter specified or needed
317      * @throws FacesException if the Converter could not be created
318      */
319     public static Converter findUIOutputConverter(FacesContext facesContext,
320                                                   UIOutput component)
321         throws FacesException {
322         return _SharedRendererUtils.findUIOutputConverter(facesContext, component);
323     }
324 
325 
326     /**
327      * Find proper Converter for the entries in the associated List or Array of
328      * the given UISelectMany as specified in API Doc of UISelectMany.
329      *
330      * @return the Converter or null if no Converter specified or needed
331      * @throws FacesException if the Converter could not be created
332      */
333     public static Converter findUISelectManyConverter(FacesContext facesContext,
334                                                       UISelectMany component) {
335         Converter converter = component.getConverter();
336         if (converter != null) return converter;
337 
338         //Try to find out by value binding
339         ValueBinding vb = component.getValueBinding("value");
340         if (vb == null) return null;
341 
342         Class valueType = vb.getType(facesContext);
343         if (valueType == null) return null;
344 
345         if (List.class.isAssignableFrom(valueType)) {
346             //According to API Doc of UISelectMany the assumed entry type for a List is String
347             //--> so basically no converter needed
348 
349             // However, if the List contains something other than Strings, we can attempt
350             // to find a suitable converter. In JDK 1.4, we can try to find out what the List
351             // contains by looking at the SelectItem value of the first item. With generics in
352             // JDK 1.5, it would be much easier to determine the type.
353 
354             List selectItems = RendererUtils.internalGetSelectItemList(component);
355 
356             if (selectItems != null && selectItems.size() > 0) {
357                 SelectItem selectItem = (SelectItem) selectItems.get(0);
358                 Class listComponentType = selectItem.getValue().getClass();
359 
360                 if (!(String.class.equals(listComponentType))) {
361                     try {
362                         return facesContext.getApplication().createConverter(listComponentType);
363                     }
364                     catch (FacesException e) {
365                         log.error("No Converter for type " + listComponentType.getName() + " found", e);
366                         return null;
367                     }
368                 }
369             }
370 
371             return null;
372         }
373 
374         if (!valueType.isArray()) {
375             throw new IllegalArgumentException("ValueBinding for UISelectMany : " + getPathToComponent(component) + " must be of type List or Array");
376         }
377 
378         Class arrayComponentType = valueType.getComponentType();
379         if (String.class.equals(arrayComponentType)) return null;    //No converter needed for String type
380         if (Object.class.equals(arrayComponentType)) return null;    //There is no converter for Object class
381 
382         try {
383             return facesContext.getApplication().createConverter(arrayComponentType);
384         }
385         catch (FacesException e) {
386             log.error("No Converter for type " + arrayComponentType.getName() + " found", e);
387             return null;
388         }
389     }
390 
391 
392     public static void checkParamValidity(FacesContext facesContext, UIComponent uiComponent, Class compClass) {
393         if (facesContext == null)
394             throw new NullPointerException("facesContext may not be null");
395         if (uiComponent == null)
396             throw new NullPointerException("uiComponent may not be null");
397 
398         //if (compClass != null && !(compClass.isAssignableFrom(uiComponent.getClass())))
399         // why isAssignableFrom with additional getClass method call if isInstance does the same?
400         if (compClass != null && !(compClass.isInstance(uiComponent))) {
401             throw new IllegalArgumentException("uiComponent : " + getPathToComponent(uiComponent) +
402                 " is not instance of " + compClass.getName() + " as it should be");
403         }
404     }
405 
406 
407     public static void renderChildren(FacesContext facesContext, UIComponent component)
408         throws IOException {
409         if (component.getChildCount() > 0) {
410             for (Iterator it = component.getChildren().iterator(); it.hasNext();) {
411                 UIComponent child = (UIComponent) it.next();
412                 renderChild(facesContext, child);
413             }
414         }
415     }
416 
417 
418     public static void renderChild(FacesContext facesContext, UIComponent child)
419         throws IOException {
420         if (!child.isRendered()) {
421             return;
422         }
423 
424         child.encodeBegin(facesContext);
425         if (child.getRendersChildren()) {
426             child.encodeChildren(facesContext);
427         }
428         else {
429             renderChildren(facesContext, child);
430         }
431         child.encodeEnd(facesContext);
432     }
433 
434 
435     /**
436      * @param uiSelectOne
437      * @return List of SelectItem Objects
438      */
439     public static List getSelectItemList(UISelectOne uiSelectOne) {
440         return internalGetSelectItemList(uiSelectOne);
441     }
442 
443     /**
444      * @param uiSelectMany
445      * @return List of SelectItem Objects
446      */
447     public static List getSelectItemList(UISelectMany uiSelectMany) {
448         return internalGetSelectItemList(uiSelectMany);
449     }
450 
451     private static List internalGetSelectItemList(UIComponent uiComponent) {
452         /* TODO: Shall we cache the list in a component attribute?
453         ArrayList list = (ArrayList)uiComponent.getAttributes().get(SELECT_ITEM_LIST_ATTR);
454         if (list != null)
455         {
456             return list;
457         }
458          */
459 
460         List list = new ArrayList();
461 
462         for (Iterator iter = new SelectItemsIterator(uiComponent); iter.hasNext();) {
463             list.add(iter.next());
464         }
465         return list;
466     }
467 
468 
469     /**
470      * Convenient utility method that returns the currently submitted values of
471      * a UISelectMany component as a Set, of which the contains method can then be
472      * easily used to determine if a select item is currently selected.
473      * Calling the contains method of this Set with the renderable (String converted) item value
474      * as argument returns true if this item is selected.
475      *
476      * @param uiSelectMany
477      * @return Set containing all currently selected values
478      */
479     public static Set getSubmittedValuesAsSet(FacesContext context, UIComponent component, Converter converter, UISelectMany uiSelectMany) {
480         Object submittedValues = uiSelectMany.getSubmittedValue();
481         if (submittedValues == null) {
482             return null;
483         }
484         
485         if(converter != null) {
486             converter = new PassThroughAsStringConverter(converter);
487         }
488 
489         return internalSubmittedOrSelectedValuesAsSet(context, component, converter, uiSelectMany, submittedValues);
490     }
491 
492 
493     /**
494      * Convenient utility method that returns the currently selected values of
495      * a UISelectMany component as a Set, of which the contains method can then be
496      * easily used to determine if a value is currently selected.
497      * Calling the contains method of this Set with the item value
498      * as argument returns true if this item is selected.
499      *
500      * @param uiSelectMany
501      * @return Set containing all currently selected values
502      */
503     public static Set getSelectedValuesAsSet(FacesContext context, UIComponent component, Converter converter, UISelectMany uiSelectMany) {
504         Object selectedValues = uiSelectMany.getValue();
505 
506         return internalSubmittedOrSelectedValuesAsSet(context, component, converter, uiSelectMany, selectedValues);
507     }
508 
509 
510     /**
511      * Convenient utility method that returns the currently given value as String,
512      * using the given converter.
513      * Especially usefull for dealing with primitive types.
514      */
515     public static String getConvertedStringValue(FacesContext context,
516                                                  UIComponent component, Converter converter, Object value) {
517         if (converter == null) {
518             if (value == null) {
519                 return "";
520             }
521             else if (value instanceof String) {
522                 return (String) value;
523             } else if (RendererUtils.NOTHING.equals(value)) {
524                 return "";
525             } else {
526                 throw new IllegalArgumentException(
527                     "Value is no String (class=" + value.getClass().getName() + ", value=" + value + ") and component "
528                         + component.getClientId(context) + "with path: "
529                         + getPathToComponent(component)
530                         + " does not have a Converter");
531             }
532         }
533 
534         if (RendererUtils.NOTHING.equals(value))
535         {
536             return converter.getAsString(context, component, "");
537         }
538         else
539         {
540             return converter.getAsString(context, component, value);
541         }
542     }
543 
544 
545     /**
546      * Convenient utility method that returns the currently given SelectItem value
547      * as String, using the given converter.
548      * Especially usefull for dealing with primitive types.
549      */
550     public static String getConvertedStringValue(FacesContext context,
551                                                  UIComponent component, Converter converter, SelectItem selectItem) {
552         return getConvertedStringValue(context, component, converter, selectItem.getValue());
553     }
554 
555 
556     private static Set internalSubmittedOrSelectedValuesAsSet(FacesContext context,
557                                                               UIComponent component, Converter converter, UISelectMany uiSelectMany,
558                                                               Object values) {
559         if (values == null || EMPTY_STRING.equals(values)) {
560             return Collections.EMPTY_SET;
561         }
562         else if (values instanceof Object[]) {
563             //Object array
564             Object[] ar = (Object[]) values;
565             if (ar.length == 0) {
566                 return Collections.EMPTY_SET;
567             }
568 
569             HashSet set = new HashSet(HashMapUtils.calcCapacity(ar.length));
570             for (int i = 0; i < ar.length; i++) {
571                 set.add(getConvertedStringValue(context, component, converter, ar[i]));
572             }
573             return set;
574         }
575         else if (values.getClass().isArray()) {
576             //primitive array
577             int len = Array.getLength(values);
578             HashSet set = new HashSet(org.apache.myfaces.shared_orchestra.util.HashMapUtils.calcCapacity(len));
579             for (int i = 0; i < len; i++) {
580                 set.add(getConvertedStringValue(context, component, converter, Array.get(values, i)));
581             }
582             return set;
583         }
584         else if (values instanceof List) {
585             List lst = (List) values;
586             if (lst.size() == 0) {
587                 return Collections.EMPTY_SET;
588             }
589             else {
590                 HashSet set = new HashSet(HashMapUtils.calcCapacity(lst.size()));
591                 for (Iterator i = lst.iterator(); i.hasNext();)
592                     set.add(getConvertedStringValue(context, component, converter, i.next()));
593 
594                 return set;
595             }
596         }
597         else {
598             throw new IllegalArgumentException("Value of UISelectMany component with path : " + getPathToComponent(uiSelectMany) + " is not of type Array or List");
599         }
600     }
601 
602 
603     public static Object getConvertedUIOutputValue(FacesContext facesContext,
604                                                    UIOutput output,
605                                                    Object submittedValue)
606         throws ConverterException {
607         if (submittedValue != null && !(submittedValue instanceof String)) {
608             if (RendererUtils.NOTHING.equals(submittedValue)) {
609                 return null;
610             }
611             throw new IllegalArgumentException("Submitted value of type String for component : " +
612                 getPathToComponent(output) + "expected");
613         }
614 
615         /* earlier code used to do the following around findUIOutputConverter:
616         try {
617         }
618         catch (FacesException e) {
619             throw new ConverterException(e);
620         }
621         mmarinschek: I believe this is wrong - as it silently swallows exceptions relating to the value-binding of a component.
622         for better error-handling, I disabled this code
623         */
624         Converter converter = findUIOutputConverter(facesContext, output);
625 
626         if (converter == null) {
627             //No conversion needed
628             return submittedValue;
629         }
630         else {
631             //Conversion
632             return converter.getAsObject(facesContext, output, (String) submittedValue);
633         }
634     }
635 
636 
637     public static Object getConvertedUISelectManyValue(FacesContext facesContext,
638                                                        UISelectMany selectMany,
639                                                        Object submittedValue)
640         throws ConverterException {
641         if (submittedValue == null) {
642             return null;
643         }
644         else {
645             if (!(submittedValue instanceof String[])) {
646                 throw new ConverterException("Submitted value of type String[] for component : "
647                     + getPathToComponent(selectMany) + "expected");
648             }
649         }
650         return org.apache.myfaces.shared_orchestra.renderkit._SharedRendererUtils.getConvertedUISelectManyValue(facesContext,
651                                                                                                       selectMany,
652                                                                                                       (String[]) submittedValue);
653     }
654 
655 
656     public static boolean getBooleanAttribute(UIComponent component,
657                                               String attrName,
658                                               boolean defaultValue) {
659         Boolean b = (Boolean) component.getAttributes().get(attrName);
660         return b != null ? b.booleanValue() : defaultValue;
661     }
662 
663     public static int getIntegerAttribute(UIComponent component,
664                                           String attrName,
665                                           int defaultValue) {
666         Integer i = (Integer) component.getAttributes().get(attrName);
667         return i != null ? i.intValue() : defaultValue;
668     }
669 
670     private static final String TRINIDAD_FORM_COMPONENT_FAMILY = "org.apache.myfaces.trinidad.Form";
671     private static final String ADF_FORM_COMPONENT_FAMILY = "oracle.adf.Form";
672 
673 
674     /**
675      * Find the enclosing form of a component
676      * in the view-tree.
677      * All Subclasses of <code>UIForm</code> and all known
678      * form-families are searched for.
679      * Currently those are the Trinidad form family,
680      * and the (old) ADF Faces form family.
681      * <p/>
682      * There might be additional form families
683      * which have to be explicitly entered here.
684      *
685      * @param uiComponent
686      * @param facesContext
687      * @return FormInfo Information about the form - the form itself and its name.
688      */
689     public static FormInfo findNestingForm(UIComponent uiComponent, FacesContext facesContext)
690     {
691         UIComponent parent = uiComponent.getParent();
692         while (parent != null && (!ADF_FORM_COMPONENT_FAMILY.equals(parent.getFamily()) &&
693             !TRINIDAD_FORM_COMPONENT_FAMILY.equals(parent.getFamily()) &&
694             !(parent instanceof UIForm)))
695         {
696             parent = parent.getParent();
697         }
698 
699         if (parent != null)
700         {
701             //link is nested inside a form
702             String formName = parent.getClientId(facesContext);
703             return new FormInfo(parent, formName);
704         }
705 
706         return null;
707     }
708 
709     public static boolean getBooleanValue(String attribute, Object value, boolean defaultValue) {
710         if (value instanceof Boolean) {
711             return ((Boolean) value).booleanValue();
712         }
713         else if (value instanceof String) {
714             return Boolean.valueOf((String) value).booleanValue();
715         }
716         else if (value != null) {
717             log.error("value for attribute " + attribute +
718                 " must be instanceof 'Boolean' or 'String', is of type : " + value.getClass());
719 
720             return defaultValue;
721         }
722 
723         return defaultValue;
724     }
725 
726     public static void copyHtmlInputTextAttributes(HtmlInputText src, HtmlInputText dest) {
727         dest.setId(src.getId());
728         boolean forceId = getBooleanValue(
729             JSFAttr.FORCE_ID_ATTR,
730             src.getAttributes().get(JSFAttr.FORCE_ID_ATTR),
731             false);
732         if (forceId) {
733             dest.getAttributes().put(JSFAttr.FORCE_ID_ATTR, Boolean.TRUE);
734         }
735         dest.setImmediate(src.isImmediate());
736         dest.setTransient(src.isTransient());
737         dest.setAccesskey(src.getAccesskey());
738         dest.setAlt(src.getAlt());
739         dest.setConverter(src.getConverter());
740         dest.setDir(src.getDir());
741         dest.setDisabled(src.isDisabled());
742         dest.setLang(src.getLang());
743         dest.setLocalValueSet(src.isLocalValueSet());
744         dest.setMaxlength(src.getMaxlength());
745         dest.setOnblur(src.getOnblur());
746         dest.setOnchange(src.getOnchange());
747         dest.setOnclick(src.getOnclick());
748         dest.setOndblclick(src.getOndblclick());
749         dest.setOnfocus(src.getOnfocus());
750         dest.setOnkeydown(src.getOnkeydown());
751         dest.setOnkeypress(src.getOnkeypress());
752         dest.setOnkeyup(src.getOnkeyup());
753         dest.setOnmousedown(src.getOnmousedown());
754         dest.setOnmousemove(src.getOnmousemove());
755         dest.setOnmouseout(src.getOnmouseout());
756         dest.setOnmouseover(src.getOnmouseover());
757         dest.setOnmouseup(src.getOnmouseup());
758         dest.setOnselect(src.getOnselect());
759         dest.setReadonly(src.isReadonly());
760         dest.setRendered(src.isRendered());
761         dest.setRequired(src.isRequired());
762         dest.setSize(src.getSize());
763         dest.setStyle(src.getStyle());
764         dest.setStyleClass(src.getStyleClass());
765         dest.setTabindex(src.getTabindex());
766         dest.setTitle(src.getTitle());
767         dest.setValidator(src.getValidator());
768     }
769 
770     public static UIComponent findComponent(UIComponent headerComp, Class clazz) {
771         if (clazz.isAssignableFrom(headerComp.getClass())) {
772             return headerComp;
773         }
774 
775         List li = headerComp.getChildren();
776 
777         for (int i = 0; i < li.size(); i++) {
778             UIComponent comp = (UIComponent) li.get(i);
779 
780             //recursively iterate through children to find the component
781             UIComponent lookupComp = findComponent(comp, clazz);
782 
783             if (lookupComp != null)
784                 return lookupComp;
785         }
786 
787         return null;
788     }
789 
790     public static void addOrReplaceChild(UIInput component, UIComponent child) {
791         List li = component.getChildren();
792 
793         for (int i = 0; i < li.size(); i++) {
794             UIComponent oldChild = (UIComponent) li.get(i);
795 
796             if (oldChild.getId() != null && oldChild.getId().equals(child.getId())) {
797                 li.set(i, child);
798                 return;
799             }
800         }
801 
802         component.getChildren().add(child);
803     }
804 
805     public static String getClientId(FacesContext facesContext, UIComponent uiComponent, String forAttr) {
806         UIComponent forComponent = uiComponent.findComponent(forAttr);
807         if (forComponent == null) {
808             if (log.isInfoEnabled()) {
809                 log.info("Unable to find component '" + forAttr +
810                     "' (calling findComponent on component '" + uiComponent.getClientId(facesContext) + "')." +
811                     " We'll try to return a guessed client-id anyways -" +
812                     " this will be a problem if you put the referenced component" +
813                     " into a different naming-container. If this is the case, you can always use the full client-id.");
814             }
815             if (forAttr.length() > 0 && forAttr.charAt(0) == UINamingContainer.SEPARATOR_CHAR) {
816                 //absolute id path
817                 return forAttr.substring(1);
818             }
819             else {
820                 //relative id path, we assume a component on the same level as the label component
821                 String labelClientId = uiComponent.getClientId(facesContext);
822                 int colon = labelClientId.lastIndexOf(UINamingContainer.SEPARATOR_CHAR);
823                 if (colon == -1) {
824                     return forAttr;
825                 }
826                 else {
827                     return labelClientId.substring(0, colon + 1) + forAttr;
828                 }
829             }
830         }
831         else {
832             return forComponent.getClientId(facesContext);
833         }
834     }
835 
836     public static List convertIdsToClientIds(String actionFor, FacesContext facesContext, UIComponent component) {
837         List li = new ArrayList();
838 
839         String[] ids = actionFor.split(",");
840 
841         for (int i = 0; i < ids.length; i++) {
842             String trimedId = ids[i].trim();
843             if (trimedId.equals("none"))
844                 li.add(trimedId);
845             else
846                 li.add(RendererUtils.getClientId(facesContext, component, trimedId));
847         }
848         return li;
849     }
850 
851     public static List convertPhasesToPhasesIds(String actionForPhase) {
852         List li = new ArrayList();
853 
854         if (actionForPhase == null) {
855             return li;
856         }
857 
858         String[] ids = actionForPhase.split(",");
859 
860         for (int i = 0; i < ids.length; i++) {
861             if (ids[i].equals("PROCESS_VALIDATIONS")) {
862                 li.add(PhaseId.PROCESS_VALIDATIONS);
863             }
864             else if (ids[i].equals("UPDATE_MODEL_VALUES")) {
865                 li.add(PhaseId.UPDATE_MODEL_VALUES);
866             }
867         }
868         return li;
869     }
870 
871     /**
872      * Helper method which loads a resource file (such as css) by a given context path and a file name.
873      * Useful to provide css files (or js files) inline.
874      *
875      * @param ctx  <code>FacesContext</code> object to calculate the context path of the web application.
876      * @param file name of the resource file (e.g. <code>foo.css</code>).
877      * @return the content of the resource file, or <code>null</code> if no such file is available.
878      */
879     public static String loadResourceFile(FacesContext ctx, String file) {
880 
881         ByteArrayOutputStream content = new ByteArrayOutputStream(10240);
882 
883         InputStream in = null;
884         try {
885             in = ctx.getExternalContext().getResourceAsStream(file);
886             if (in == null)
887             {
888                 return null;
889             }
890 
891             byte[] fileBuffer = new byte[10240];
892             int read;
893             while ((read = in.read(fileBuffer)) > -1)
894             {
895                 content.write(fileBuffer, 0, read);
896             }
897         }
898         catch (FileNotFoundException e) {
899             if (log.isWarnEnabled())
900                 log.warn("no such file " + file, e);
901             content = null;
902         }
903         catch (IOException e) {
904             if (log.isWarnEnabled())
905                 log.warn("problems during processing resource " + file, e);
906             content = null;
907         }
908         finally
909         {
910             try
911             {
912                 content.close();
913             }
914             catch (IOException e)
915             {
916                 log.warn(e.getLocalizedMessage(), e);
917             }
918             if (in != null)
919             {
920                 try
921                 {
922                     in.close();
923                 }
924                 catch (IOException e)
925                 {
926                     log.warn(e.getLocalizedMessage(), e);
927                 }
928             }
929         }
930 
931         return content.toString();
932     }
933 
934     /**
935      * check for partial validation or model update attributes being set
936      * and initialize the request-map accordingly.
937      * SubForms will work with this information.
938      */
939     public static void initPartialValidationAndModelUpdate(UIComponent component, FacesContext facesContext) {
940         String actionFor = (String) component.getAttributes().get("actionFor");
941 
942         if (actionFor != null) {
943             List li = convertIdsToClientIds(actionFor, facesContext, component);
944 
945             facesContext.getExternalContext().getRequestMap().put(ACTION_FOR_LIST, li);
946 
947             String actionForPhase = (String) component.getAttributes().get("actionForPhase");
948 
949             if (actionForPhase != null) {
950                 List phaseList = convertPhasesToPhasesIds(actionForPhase);
951 
952                 facesContext.getExternalContext().getRequestMap().put(ACTION_FOR_PHASE_LIST, phaseList);
953             }
954         }
955     }
956 
957     public static boolean isAdfOrTrinidadForm(UIComponent component) {
958         if (component == null)
959             return false;
960         return ADF_FORM_COMPONENT_FAMILY.equals(component.getFamily()) ||
961             TRINIDAD_FORM_COMPONENT_FAMILY.equals(component.getFamily());
962     }
963 
964 
965     /**
966      * Special converter for handling submitted values which don't need to be converted. 
967      * 
968      * @author mathias (latest modification by $Author: lu4242 $)
969      * @version $Revision: 777357 $ $Date: 2009-05-21 21:40:33 -0500 (Thu, 21 May 2009) $
970      */
971     private static class PassThroughAsStringConverter implements Converter
972     {
973         private final Converter converter;
974 
975         public PassThroughAsStringConverter(Converter converter)
976         {
977             this.converter = converter;
978         }
979 
980         public Object getAsObject(FacesContext context, UIComponent component,
981                 String value) throws ConverterException
982         {
983             return converter.getAsObject(context, component, value);
984         }
985 
986         public String getAsString(FacesContext context, UIComponent component,
987                 Object value) throws ConverterException
988         {
989             return (String)value;
990         }
991 
992     }
993 }