View Javadoc

    1   /*
    2    * Copyright 2002,2004 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jelly.tags.core;
    17
    18  import java.util.HashMap;
    19  import java.util.Map;
    20
    21  import org.apache.commons.beanutils.ConversionException;
    22  import org.apache.commons.beanutils.Converter;
    23  import org.apache.commons.beanutils.converters.BooleanConverter;
    24  import org.apache.commons.beanutils.converters.ByteConverter;
    25  import org.apache.commons.beanutils.converters.CharacterConverter;
    26  import org.apache.commons.beanutils.converters.DoubleConverter;
    27  import org.apache.commons.beanutils.converters.FloatConverter;
    28  import org.apache.commons.beanutils.converters.IntegerConverter;
    29  import org.apache.commons.beanutils.converters.LongConverter;
    30  import org.apache.commons.beanutils.converters.ShortConverter;
    31  import org.apache.commons.jelly.JellyTagException;
    32  import org.apache.commons.jelly.XMLOutput;
    33
    34  /***
    35   * An argument to a {@link NewTag} or {@link InvokeTag}.
    36   * This tag MUST be enclosed within an {@link ArgTagParent}
    37   * implementation.
    38   *
    39   * @author Rodney Waldhoff
    40   * @version $Revision: 155420 $
    41   */
    42  public class ArgTag extends BaseClassLoaderTag {
    43
    44      // constructors
    45      //-------------------------------------------------------------------------
    46
    47      public ArgTag() {
    48      }
    49
    50      // attribute setters
    51      //-------------------------------------------------------------------------
    52
    53      /***
    54       * The name of the argument class or type, if any.
    55       * This may be a fully specified class name or
    56       * a primitive type name
    57       * (<code>boolean<code>, <code>int</code>, <code>double</code>, etc.).
    58       */
    59      public void setType(String type) {
    60          this.typeString = type;
    61      }
    62
    63      /*** The (possibly null) value of this argument. */
    64      public void setValue(Object value) {
    65          this.value= value;
    66      }
    67
    68      // tag methods
    69      //-------------------------------------------------------------------------
    70
    71      public void doTag(XMLOutput output) throws JellyTagException {
    72          invokeBody(output);
    73
    74          Class klass = null;
    75          if("boolean".equals(typeString)) {
    76              klass = Boolean.TYPE;
    77              assertNotNull(value);
    78          } else if("byte".equals(typeString)) {
    79              klass = Byte.TYPE;
    80              assertNotNull(value);
    81          } else if("short".equals(typeString)) {
    82              klass = Short.TYPE;
    83              assertNotNull(value);
    84          } else if("int".equals(typeString)) {
    85              klass = Integer.TYPE;
    86              assertNotNull(value);
    87          } else if("char".equals(typeString)) {
    88              klass = Character.TYPE;
    89              assertNotNull(value);
    90          } else if("float".equals(typeString)) {
    91              klass = Float.TYPE;
    92              assertNotNull(value);
    93          } else if("long".equals(typeString)) {
    94              klass = Long.TYPE;
    95              assertNotNull(value);
    96          } else if("double".equals(typeString)) {
    97              klass = Double.TYPE;
    98              assertNotNull(value);
    99          } else if(null != typeString) {
    100             try {
    101               klass = getClassLoader().loadClass(typeString);
    102             } catch (ClassNotFoundException e) {
    103                 throw new JellyTagException(e);
    104             }
    105         } else if(null == value) { // and (by construction) null == typeString
    106             klass = Object.class;
    107         } else {
    108             klass = value.getClass();
    109         }
    110
    111         if(!isInstanceOf(klass,value)) {
    112             if (klass.equals(Class.class))
    113             {
    114                 try {
    115                     value = getClassLoader().loadClass((String) value);
    116                 } catch (ClassNotFoundException e) {
    117                     throw new JellyTagException(e);
    118                 }
    119             }
    120             else
    121             {
    122                 value = convert(klass,value);
    123             }
    124         }
    125
    126         ArgTagParent parent = (ArgTagParent)findAncestorWithClass(ArgTagParent.class);
    127         if(null == parent) {
    128             throw new JellyTagException("This tag must be enclosed inside an ArgTagParent implementation (for example, <new> or <invoke>)" );
    129         } else {
    130             parent.addArgument(klass,value);
    131         }
    132     }
    133
    134     // private methods
    135     //-------------------------------------------------------------------------
    136
    137     private void assertNotNull(Object value) throws JellyTagException {
    138         if(null == value) {
    139             throw new JellyTagException("A " + typeString + " instance cannot be null.");
    140         }
    141     }
    142
    143     private boolean isInstanceOf(Class klass, Object value) {
    144         return (null == value || (klass.isInstance(value)));
    145     }
    146
    147     // attributes
    148     //-------------------------------------------------------------------------
    149
    150     /*** The name of the parameter type, if any. */
    151     private String typeString;
    152
    153     /*** The value of the parameter, if any */
    154     private Object value;
    155
    156     // static stuff
    157     //-------------------------------------------------------------------------
    158
    159     private static Object convert(Class klass, Object value) throws JellyTagException {
    160         if(null == value) {
    161             return null;
    162         } else if(!klass.isInstance(value)) {
    163             Converter converter = (Converter)(converterMap.get(klass));
    164             if(null == converter) {
    165                 throw new JellyTagException("Can't convert " + value + " to " + klass);
    166             } else {
    167                 try {
    168                     return converter.convert(klass,value);
    169                 } catch(ConversionException e) {
    170                     throw new JellyTagException("Can't convert " + value + " to " + klass + " (" + e.toString() + ")",e);
    171                 }
    172             }
    173         } else {
    174             return value;
    175         }
    176
    177     }
    178
    179     /*** My bag of converters, by target Class */
    180     private static Map converterMap = new HashMap();
    181     // these inner classes should probably move to beanutils
    182     static {
    183         {
    184             Converter c = new BooleanConverter();
    185             converterMap.put(Boolean.TYPE,c);
    186             converterMap.put(Boolean.class,c);
    187         }
    188         {
    189             Converter c = new CharacterConverter();
    190             converterMap.put(Character.TYPE,c);
    191             converterMap.put(Character.class,c);
    192         }
    193         {
    194             Converter c = new Converter() {
    195                 public Object convert(Class klass, Object value) {
    196                     if(value instanceof Number) {
    197                         return new Byte(((Number)value).byteValue());
    198                     } else {
    199                         return inner.convert(klass,value);
    200                     }
    201                 }
    202                 private Converter inner = new ByteConverter();
    203             };
    204             converterMap.put(Byte.TYPE,c);
    205             converterMap.put(Byte.class,c);
    206         }
    207         {
    208             Converter c = new Converter() {
    209                 public Object convert(Class klass, Object value) {
    210                     if(value instanceof Number) {
    211                         return new Short(((Number)value).shortValue());
    212                     } else {
    213                         return inner.convert(klass,value);
    214                     }
    215                 }
    216                 private Converter inner = new ShortConverter();
    217             };
    218             converterMap.put(Short.TYPE,c);
    219             converterMap.put(Short.class,c);
    220         }
    221         {
    222             Converter c = new Converter() {
    223                 public Object convert(Class klass, Object value) {
    224                     if(value instanceof Number) {
    225                         return new Integer(((Number)value).intValue());
    226                     } else {
    227                         return inner.convert(klass,value);
    228                     }
    229                 }
    230                 private Converter inner = new IntegerConverter();
    231             };
    232             converterMap.put(Integer.TYPE,c);
    233             converterMap.put(Integer.class,c);
    234         }
    235         {
    236             Converter c = new Converter() {
    237                 public Object convert(Class klass, Object value) {
    238                     if(value instanceof Number) {
    239                         return new Long(((Number)value).longValue());
    240                     } else {
    241                         return inner.convert(klass,value);
    242                     }
    243                 }
    244                 private Converter inner = new LongConverter();
    245             };
    246             converterMap.put(Long.TYPE,c);
    247             converterMap.put(Long.class,c);
    248         }
    249         {
    250             Converter c = new Converter() {
    251                 public Object convert(Class klass, Object value) {
    252                     if(value instanceof Number) {
    253                         return new Float(((Number)value).floatValue());
    254                     } else {
    255                         return inner.convert(klass,value);
    256                     }
    257                 }
    258                 private Converter inner = new FloatConverter();
    259             };
    260             converterMap.put(Float.TYPE,c);
    261             converterMap.put(Float.class,c);
    262         }
    263         {
    264             Converter c = new Converter() {
    265                 public Object convert(Class klass, Object value) {
    266                     if(value instanceof Number) {
    267                         return new Double(((Number)value).doubleValue());
    268                     } else {
    269                         return inner.convert(klass,value);
    270                     }
    271                 }
    272                 private Converter inner = new DoubleConverter();
    273             };
    274             converterMap.put(Double.TYPE,c);
    275             converterMap.put(Double.class,c);
    276         }
    277     }
    278 }