001: /*
002: * Copyright 2002,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jelly.tags.core;
017:
018: import java.util.HashMap;
019: import java.util.Map;
020:
021: import org.apache.commons.beanutils.ConversionException;
022: import org.apache.commons.beanutils.Converter;
023: import org.apache.commons.beanutils.converters.BooleanConverter;
024: import org.apache.commons.beanutils.converters.ByteConverter;
025: import org.apache.commons.beanutils.converters.CharacterConverter;
026: import org.apache.commons.beanutils.converters.DoubleConverter;
027: import org.apache.commons.beanutils.converters.FloatConverter;
028: import org.apache.commons.beanutils.converters.IntegerConverter;
029: import org.apache.commons.beanutils.converters.LongConverter;
030: import org.apache.commons.beanutils.converters.ShortConverter;
031: import org.apache.commons.jelly.JellyTagException;
032: import org.apache.commons.jelly.XMLOutput;
033:
034: /**
035: * An argument to a {@link NewTag} or {@link InvokeTag}.
036: * This tag MUST be enclosed within an {@link ArgTagParent}
037: * implementation.
038: *
039: * @author Rodney Waldhoff
040: * @version $Revision: 155420 $
041: */
042: public class ArgTag extends BaseClassLoaderTag {
043:
044: // constructors
045: //-------------------------------------------------------------------------
046:
047: public ArgTag() {
048: }
049:
050: // attribute setters
051: //-------------------------------------------------------------------------
052:
053: /**
054: * The name of the argument class or type, if any.
055: * This may be a fully specified class name or
056: * a primitive type name
057: * (<code>boolean<code>, <code>int</code>, <code>double</code>, etc.).
058: */
059: public void setType(String type) {
060: this .typeString = type;
061: }
062:
063: /** The (possibly null) value of this argument. */
064: public void setValue(Object value) {
065: this .value = value;
066: }
067:
068: // tag methods
069: //-------------------------------------------------------------------------
070:
071: public void doTag(XMLOutput output) throws JellyTagException {
072: invokeBody(output);
073:
074: Class klass = null;
075: if ("boolean".equals(typeString)) {
076: klass = Boolean.TYPE;
077: assertNotNull(value);
078: } else if ("byte".equals(typeString)) {
079: klass = Byte.TYPE;
080: assertNotNull(value);
081: } else if ("short".equals(typeString)) {
082: klass = Short.TYPE;
083: assertNotNull(value);
084: } else if ("int".equals(typeString)) {
085: klass = Integer.TYPE;
086: assertNotNull(value);
087: } else if ("char".equals(typeString)) {
088: klass = Character.TYPE;
089: assertNotNull(value);
090: } else if ("float".equals(typeString)) {
091: klass = Float.TYPE;
092: assertNotNull(value);
093: } else if ("long".equals(typeString)) {
094: klass = Long.TYPE;
095: assertNotNull(value);
096: } else if ("double".equals(typeString)) {
097: klass = Double.TYPE;
098: assertNotNull(value);
099: } 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: try {
114: value = getClassLoader().loadClass((String) value);
115: } catch (ClassNotFoundException e) {
116: throw new JellyTagException(e);
117: }
118: } else {
119: value = convert(klass, value);
120: }
121: }
122:
123: ArgTagParent parent = (ArgTagParent) findAncestorWithClass(ArgTagParent.class);
124: if (null == parent) {
125: throw new JellyTagException(
126: "This tag must be enclosed inside an ArgTagParent implementation (for example, <new> or <invoke>)");
127: } else {
128: parent.addArgument(klass, value);
129: }
130: }
131:
132: // private methods
133: //-------------------------------------------------------------------------
134:
135: private void assertNotNull(Object value) throws JellyTagException {
136: if (null == value) {
137: throw new JellyTagException("A " + typeString
138: + " instance cannot be null.");
139: }
140: }
141:
142: private boolean isInstanceOf(Class klass, Object value) {
143: return (null == value || (klass.isInstance(value)));
144: }
145:
146: // attributes
147: //-------------------------------------------------------------------------
148:
149: /** The name of the parameter type, if any. */
150: private String typeString;
151:
152: /** The value of the parameter, if any */
153: private Object value;
154:
155: // static stuff
156: //-------------------------------------------------------------------------
157:
158: private static Object convert(Class klass, Object value)
159: 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
166: + " to " + klass);
167: } else {
168: try {
169: return converter.convert(klass, value);
170: } catch (ConversionException e) {
171: throw new JellyTagException("Can't convert "
172: + value + " to " + klass + " ("
173: + e.toString() + ")", e);
174: }
175: }
176: } else {
177: return value;
178: }
179:
180: }
181:
182: /** My bag of converters, by target Class */
183: private static Map converterMap = new HashMap();
184: // these inner classes should probably move to beanutils
185: static {
186: {
187: Converter c = new BooleanConverter();
188: converterMap.put(Boolean.TYPE, c);
189: converterMap.put(Boolean.class, c);
190: }
191: {
192: Converter c = new CharacterConverter();
193: converterMap.put(Character.TYPE, c);
194: converterMap.put(Character.class, c);
195: }
196: {
197: Converter c = new Converter() {
198: public Object convert(Class klass, Object value) {
199: if (value instanceof Number) {
200: return new Byte(((Number) value).byteValue());
201: } else {
202: return inner.convert(klass, value);
203: }
204: }
205:
206: private Converter inner = new ByteConverter();
207: };
208: converterMap.put(Byte.TYPE, c);
209: converterMap.put(Byte.class, c);
210: }
211: {
212: Converter c = new Converter() {
213: public Object convert(Class klass, Object value) {
214: if (value instanceof Number) {
215: return new Short(((Number) value).shortValue());
216: } else {
217: return inner.convert(klass, value);
218: }
219: }
220:
221: private Converter inner = new ShortConverter();
222: };
223: converterMap.put(Short.TYPE, c);
224: converterMap.put(Short.class, c);
225: }
226: {
227: Converter c = new Converter() {
228: public Object convert(Class klass, Object value) {
229: if (value instanceof Number) {
230: return new Integer(((Number) value).intValue());
231: } else {
232: return inner.convert(klass, value);
233: }
234: }
235:
236: private Converter inner = new IntegerConverter();
237: };
238: converterMap.put(Integer.TYPE, c);
239: converterMap.put(Integer.class, c);
240: }
241: {
242: Converter c = new Converter() {
243: public Object convert(Class klass, Object value) {
244: if (value instanceof Number) {
245: return new Long(((Number) value).longValue());
246: } else {
247: return inner.convert(klass, value);
248: }
249: }
250:
251: private Converter inner = new LongConverter();
252: };
253: converterMap.put(Long.TYPE, c);
254: converterMap.put(Long.class, c);
255: }
256: {
257: Converter c = new Converter() {
258: public Object convert(Class klass, Object value) {
259: if (value instanceof Number) {
260: return new Float(((Number) value).floatValue());
261: } else {
262: return inner.convert(klass, value);
263: }
264: }
265:
266: private Converter inner = new FloatConverter();
267: };
268: converterMap.put(Float.TYPE, c);
269: converterMap.put(Float.class, c);
270: }
271: {
272: Converter c = new Converter() {
273: public Object convert(Class klass, Object value) {
274: if (value instanceof Number) {
275: return new Double(((Number) value)
276: .doubleValue());
277: } else {
278: return inner.convert(klass, value);
279: }
280: }
281:
282: private Converter inner = new DoubleConverter();
283: };
284: converterMap.put(Double.TYPE, c);
285: converterMap.put(Double.class, c);
286: }
287: }
288: }
|