| /* |
| * Copyright 2002,2004 The Apache Software Foundation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.jelly.tags.core; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.apache.commons.beanutils.ConversionException; |
| import org.apache.commons.beanutils.Converter; |
| import org.apache.commons.beanutils.converters.BooleanConverter; |
| import org.apache.commons.beanutils.converters.ByteConverter; |
| import org.apache.commons.beanutils.converters.CharacterConverter; |
| import org.apache.commons.beanutils.converters.DoubleConverter; |
| import org.apache.commons.beanutils.converters.FloatConverter; |
| import org.apache.commons.beanutils.converters.IntegerConverter; |
| import org.apache.commons.beanutils.converters.LongConverter; |
| import org.apache.commons.beanutils.converters.ShortConverter; |
| import org.apache.commons.jelly.JellyTagException; |
| import org.apache.commons.jelly.XMLOutput; |
| |
| /** |
| * An argument to a {@link NewTag} or {@link InvokeTag}. |
| * This tag MUST be enclosed within an {@link ArgTagParent} |
| * implementation. |
| * |
| * @author Rodney Waldhoff |
| * @version $Revision: 1.9 $ |
| */ |
| public class ArgTag extends BaseClassLoaderTag { |
| |
| // constructors |
| //------------------------------------------------------------------------- |
| |
| public ArgTag() { |
| } |
| |
| // attribute setters |
| //------------------------------------------------------------------------- |
| |
| /** |
| * The name of the argument class or type, if any. |
| * This may be a fully specified class name or |
| * a primitive type name |
| * (<code>boolean<code>, <code>int</code>, <code>double</code>, etc.). |
| */ |
| public void setType(String type) { |
| this.typeString = type; |
| } |
| |
| /** The (possibly null) value of this argument. */ |
| public void setValue(Object value) { |
| this.value= value; |
| } |
| |
| // tag methods |
| //------------------------------------------------------------------------- |
| |
| public void doTag(XMLOutput output) throws JellyTagException { |
| invokeBody(output); |
| |
| Class klass = null; |
| if("boolean".equals(typeString)) { |
| klass = Boolean.TYPE; |
| assertNotNull(value); |
| } else if("byte".equals(typeString)) { |
| klass = Byte.TYPE; |
| assertNotNull(value); |
| } else if("short".equals(typeString)) { |
| klass = Short.TYPE; |
| assertNotNull(value); |
| } else if("int".equals(typeString)) { |
| klass = Integer.TYPE; |
| assertNotNull(value); |
| } else if("char".equals(typeString)) { |
| klass = Character.TYPE; |
| assertNotNull(value); |
| } else if("float".equals(typeString)) { |
| klass = Float.TYPE; |
| assertNotNull(value); |
| } else if("long".equals(typeString)) { |
| klass = Long.TYPE; |
| assertNotNull(value); |
| } else if("double".equals(typeString)) { |
| klass = Double.TYPE; |
| assertNotNull(value); |
| } else if(null != typeString) { |
| try { |
| klass = getClassLoader().loadClass(typeString); |
| } catch (ClassNotFoundException e) { |
| throw new JellyTagException(e); |
| } |
| } else if(null == value) { // and (by construction) null == typeString |
| klass = Object.class; |
| } else { |
| klass = value.getClass(); |
| } |
| |
| if(!isInstanceOf(klass,value)) { |
| if (klass.equals(Class.class)) |
| { |
| try { |
| value = getClassLoader().loadClass((String) value); |
| } catch (ClassNotFoundException e) { |
| throw new JellyTagException(e); |
| } |
| } |
| else |
| { |
| value = convert(klass,value); |
| } |
| } |
| |
| ArgTagParent parent = (ArgTagParent)findAncestorWithClass(ArgTagParent.class); |
| if(null == parent) { |
| throw new JellyTagException("This tag must be enclosed inside an ArgTagParent implementation (for example, <new> or <invoke>)" ); |
| } else { |
| parent.addArgument(klass,value); |
| } |
| } |
| |
| // private methods |
| //------------------------------------------------------------------------- |
| |
| private void assertNotNull(Object value) throws JellyTagException { |
| if(null == value) { |
| throw new JellyTagException("A " + typeString + " instance cannot be null."); |
| } |
| } |
| |
| private boolean isInstanceOf(Class klass, Object value) { |
| return (null == value || (klass.isInstance(value))); |
| } |
| |
| // attributes |
| //------------------------------------------------------------------------- |
| |
| /** The name of the parameter type, if any. */ |
| private String typeString; |
| |
| /** The value of the parameter, if any */ |
| private Object value; |
| |
| // static stuff |
| //------------------------------------------------------------------------- |
| |
| private static Object convert(Class klass, Object value) throws JellyTagException { |
| if(null == value) { |
| return null; |
| } else if(!klass.isInstance(value)) { |
| Converter converter = (Converter)(converterMap.get(klass)); |
| if(null == converter) { |
| throw new JellyTagException("Can't convert " + value + " to " + klass); |
| } else { |
| try { |
| return converter.convert(klass,value); |
| } catch(ConversionException e) { |
| throw new JellyTagException("Can't convert " + value + " to " + klass + " (" + e.toString() + ")",e); |
| } |
| } |
| } else { |
| return value; |
| } |
| |
| } |
| |
| /** My bag of converters, by target Class */ |
| private static Map converterMap = new HashMap(); |
| // these inner classes should probably move to beanutils |
| static { |
| { |
| Converter c = new BooleanConverter(); |
| converterMap.put(Boolean.TYPE,c); |
| converterMap.put(Boolean.class,c); |
| } |
| { |
| Converter c = new CharacterConverter(); |
| converterMap.put(Character.TYPE,c); |
| converterMap.put(Character.class,c); |
| } |
| { |
| Converter c = new Converter() { |
| public Object convert(Class klass, Object value) { |
| if(value instanceof Number) { |
| return new Byte(((Number)value).byteValue()); |
| } else { |
| return inner.convert(klass,value); |
| } |
| } |
| private Converter inner = new ByteConverter(); |
| }; |
| converterMap.put(Byte.TYPE,c); |
| converterMap.put(Byte.class,c); |
| } |
| { |
| Converter c = new Converter() { |
| public Object convert(Class klass, Object value) { |
| if(value instanceof Number) { |
| return new Short(((Number)value).shortValue()); |
| } else { |
| return inner.convert(klass,value); |
| } |
| } |
| private Converter inner = new ShortConverter(); |
| }; |
| converterMap.put(Short.TYPE,c); |
| converterMap.put(Short.class,c); |
| } |
| { |
| Converter c = new Converter() { |
| public Object convert(Class klass, Object value) { |
| if(value instanceof Number) { |
| return new Integer(((Number)value).intValue()); |
| } else { |
| return inner.convert(klass,value); |
| } |
| } |
| private Converter inner = new IntegerConverter(); |
| }; |
| converterMap.put(Integer.TYPE,c); |
| converterMap.put(Integer.class,c); |
| } |
| { |
| Converter c = new Converter() { |
| public Object convert(Class klass, Object value) { |
| if(value instanceof Number) { |
| return new Long(((Number)value).longValue()); |
| } else { |
| return inner.convert(klass,value); |
| } |
| } |
| private Converter inner = new LongConverter(); |
| }; |
| converterMap.put(Long.TYPE,c); |
| converterMap.put(Long.class,c); |
| } |
| { |
| Converter c = new Converter() { |
| public Object convert(Class klass, Object value) { |
| if(value instanceof Number) { |
| return new Float(((Number)value).floatValue()); |
| } else { |
| return inner.convert(klass,value); |
| } |
| } |
| private Converter inner = new FloatConverter(); |
| }; |
| converterMap.put(Float.TYPE,c); |
| converterMap.put(Float.class,c); |
| } |
| { |
| Converter c = new Converter() { |
| public Object convert(Class klass, Object value) { |
| if(value instanceof Number) { |
| return new Double(((Number)value).doubleValue()); |
| } else { |
| return inner.convert(klass,value); |
| } |
| } |
| private Converter inner = new DoubleConverter(); |
| }; |
| converterMap.put(Double.TYPE,c); |
| converterMap.put(Double.class,c); |
| } |
| } |
| } |