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 }