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 }