KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ws > jaxme > xs > parser > impl > AttributeSetterImpl


1 /*
2  * Copyright 2003, 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  */

17 package org.apache.ws.jaxme.xs.parser.impl;
18
19 import java.lang.reflect.Constructor JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.lang.reflect.Method JavaDoc;
22 import java.lang.reflect.Modifier JavaDoc;
23 import java.lang.reflect.UndeclaredThrowableException JavaDoc;
24
25 import org.apache.ws.jaxme.xs.XSParser;
26 import org.apache.ws.jaxme.xs.parser.*;
27 import org.xml.sax.SAXException JavaDoc;
28
29
30 /** <p>Default implementation of the {@link org.apache.ws.jaxme.xs.parser.AttributeSetter}
31  * interface.</p>
32  *
33  * @author <a HREF="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
34  */

35 public class AttributeSetterImpl implements AttributeSetter {
36   static final Class JavaDoc[] ONE_STRING_CLASS = new Class JavaDoc[]{String JavaDoc.class};
37   private static final Class JavaDoc[] FOUR_STRING_CLASSES =
38     new Class JavaDoc[]{String JavaDoc.class, String JavaDoc.class, String JavaDoc.class, String JavaDoc.class};
39
40   protected XSContext getData() {
41     XSContext result = XSParser.getRunningInstance().getContext();
42     if (result == null) {
43       throw new IllegalStateException JavaDoc("Parser data is not set.");
44     }
45     return result;
46   }
47
48   /** <p>This method configures the bean <code>pBean</code> as follows:
49    * <ol>
50    * <li>If the bean has a method
51    * <code>setAttribute(String, String, String)</code>, it is invoked
52    * with the following arguments:
53    * <ul>
54    * <li>The attributes namespace URI (empty string for the default
55    * namespace),</li>
56    * <li>the attributes local name,</li>
57    * <li>and the property value</li>
58    * </ul>
59    * </li>
60    * <li>Otherwise invokes its own method {@link #setProperty(Object, String, String, String)}.</li>
61    * </ol>
62    */

63   public void setAttribute(String JavaDoc pQName, String JavaDoc pNamespaceURI, String JavaDoc pLocalName, String JavaDoc pValue)
64       throws SAXException JavaDoc {
65     XsSAXParser handler = ((XsSAXParser) getData().getCurrentContentHandler());
66     if (handler == null) {
67       throw new IllegalStateException JavaDoc("Current XsSAXParser is null.");
68     }
69     Object JavaDoc bean = ((XsSAXParser) getData().getCurrentContentHandler()).getBean();
70     try {
71       Method JavaDoc m = bean.getClass().getMethod("setAttribute", FOUR_STRING_CLASSES);
72       if (Modifier.isPublic(m.getModifiers())) {
73         Object JavaDoc[] o = new Object JavaDoc[]{pQName, pNamespaceURI, pLocalName, pValue};
74         Object JavaDoc result = invokeMethod(bean, m, pQName, o);
75         if (!boolean.class.equals(m.getReturnType()) || ((Boolean JavaDoc) result).booleanValue()) {
76           return;
77         }
78       }
79     } catch (NoSuchMethodException JavaDoc e) {
80     }
81
82     if (!setProperty(bean, pQName, pLocalName, pValue)) {
83       throw new IllegalStateException JavaDoc("Unknown attribute of " + bean.getClass().getName() + ": " + pQName);
84     }
85   }
86
87
88   /** <p>This method invokes the beans <code>pBean</code> method <code>pMethod</code>,
89    * setting the attribute <code>pName</code> to the value <code>pArgs</code>.</p>
90    */

91   protected Object JavaDoc invokeMethod(Object JavaDoc pBean, Method JavaDoc pMethod, String JavaDoc pName, Object JavaDoc[] pArgs) throws SAXException JavaDoc {
92     try {
93       return pMethod.invoke(pBean, pArgs);
94     } catch (InvocationTargetException JavaDoc e) {
95       Throwable JavaDoc t = e.getTargetException();
96       if (t instanceof SAXException JavaDoc) {
97         throw (SAXException JavaDoc) t;
98       } else if (t instanceof RuntimeException JavaDoc) {
99         throw (RuntimeException JavaDoc) t;
100       } else {
101         throw new UndeclaredThrowableException JavaDoc(t);
102       }
103     } catch (IllegalAccessException JavaDoc e) {
104       StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Failed to invoke method ");
105       sb.append(pMethod.getName()).append(" of class ").append(pBean.getClass().getName());
106       sb.append(" with argument ");
107       for (int i = 0; i < pArgs.length; i++) {
108         if (i > 0) {
109           sb.append(", ");
110         }
111         sb.append(pArgs[i]);
112       }
113       sb.append(": ").append(e.getClass().getName()).append(", ").append(e.getMessage());
114       throw new IllegalStateException JavaDoc(sb.toString());
115     }
116   }
117
118   private interface ParameterClass {
119     public Object JavaDoc matches(Class JavaDoc pClass);
120     public void invoke(AttributeSetterImpl pAttributeSetter, Object JavaDoc pBean, String JavaDoc pValue,
121                         Method JavaDoc pMethod, Object JavaDoc pMethodObject, String JavaDoc pQName)
122       throws SAXException JavaDoc;
123   }
124
125   private static class StringClass implements ParameterClass {
126     public Object JavaDoc matches(Class JavaDoc pClass) {
127       return String JavaDoc.class.equals(pClass) ? Boolean.TRUE : null;
128     }
129     public void invoke(AttributeSetterImpl pAttributeSetter, Object JavaDoc pBean, String JavaDoc pValue,
130                         Method JavaDoc pMethod, Object JavaDoc pMethodObject, String JavaDoc pQName) throws SAXException JavaDoc {
131       pAttributeSetter.invokeMethod(pBean, pMethod, pQName, new Object JavaDoc[]{pValue});
132     }
133   }
134
135   private static class ValueOfParameterClass implements ParameterClass {
136     public Object JavaDoc matches(Class JavaDoc pClass) {
137       try {
138         Method JavaDoc valueOfMethod = pClass.getMethod("valueOf", ONE_STRING_CLASS);
139         if (Modifier.isPublic(valueOfMethod.getModifiers()) && !void.class.equals(valueOfMethod.getReturnType())) {
140           return valueOfMethod;
141         }
142       } catch (NoSuchMethodException JavaDoc e) {
143       }
144       return null;
145     }
146     public void invoke(AttributeSetterImpl pAttributeSetter, Object JavaDoc pBean, String JavaDoc pValue,
147                         Method JavaDoc pMethod, Object JavaDoc pMethodObject, String JavaDoc pQName) throws SAXException JavaDoc {
148       Method JavaDoc m = (Method JavaDoc) pMethodObject;
149       Object JavaDoc o;
150       try {
151         o = m.invoke(null, new Object JavaDoc[]{pValue});
152       } catch (InvocationTargetException JavaDoc e) {
153         throw new IllegalArgumentException JavaDoc("Illegal argument for attribute '" + pQName + "': " + pValue +
154                                             "; " + e.getTargetException().getClass().getName() +
155                                             ", " + e.getTargetException().getMessage());
156       } catch (IllegalAccessException JavaDoc e) {
157         throw new IllegalStateException JavaDoc("Invalid access to method " + m.getName() + " of class " +
158                                          pBean.getClass() + ": IllegalAccessException, " + e.getMessage());
159       }
160       pAttributeSetter.invokeMethod(pBean, pMethod, pQName, new Object JavaDoc[]{o});
161     }
162   }
163
164   private static class StringConstructorClass implements ParameterClass {
165     public Object JavaDoc matches(Class JavaDoc pClass) {
166       try {
167         Constructor JavaDoc con = pClass.getConstructor(ONE_STRING_CLASS);
168         if (Modifier.isPublic(con.getModifiers())) {
169           return con;
170         }
171       } catch (NoSuchMethodException JavaDoc e) {
172       }
173       return null;
174     }
175     public void invoke(AttributeSetterImpl pAttributeSetter, Object JavaDoc pBean, String JavaDoc pValue,
176                         Method JavaDoc pMethod, Object JavaDoc pMethodObject, String JavaDoc pQName) throws SAXException JavaDoc {
177       Constructor JavaDoc con = (Constructor JavaDoc) pMethodObject;
178       Object JavaDoc o;
179       try {
180         o = con.newInstance(new Object JavaDoc[]{pValue});
181       } catch (InvocationTargetException JavaDoc e) {
182         throw new IllegalArgumentException JavaDoc("Illegal argument for attribute '" + pQName + "': " + pValue +
183                                             "; " + e.getTargetException().getClass().getName() +
184                                             ", " + e.getTargetException().getMessage());
185       } catch (InstantiationException JavaDoc e) {
186         throw new IllegalStateException JavaDoc("Invalid access to constructor " + pBean.getClass().getName() +
187                                          "(): " + e.getClass().getName() + ", " + e.getMessage());
188       } catch (IllegalAccessException JavaDoc e) {
189         throw new IllegalStateException JavaDoc("Invalid access to constructor " + pBean.getClass().getName() +
190                                          "(): " + e.getClass().getName() + ", " + e.getMessage());
191       }
192       pAttributeSetter.invokeMethod(pBean, pMethod, pQName, new Object JavaDoc[]{o});
193     }
194   }
195
196   private static class PrimitiveParameterClass extends StringConstructorClass {
197     private final Class JavaDoc primitiveClass;
198     private final Class JavaDoc nonPrimitiveClass;
199     private final Constructor JavaDoc stringConstructor;
200     private PrimitiveParameterClass(Class JavaDoc pPrimitiveClass, Class JavaDoc pNonPrimitiveClass) {
201       primitiveClass = pPrimitiveClass;
202       nonPrimitiveClass = pNonPrimitiveClass;
203       try {
204         stringConstructor = pNonPrimitiveClass.getConstructor(ONE_STRING_CLASS);
205       } catch (NoSuchMethodException JavaDoc e) {
206         throw new IllegalStateException JavaDoc("The primitive class " + pNonPrimitiveClass.getName() +
207                                          " doesn't have a string valued constructor!");
208       }
209     }
210     public Object JavaDoc matches(Class JavaDoc pClass) {
211       return (primitiveClass.equals(pClass) || nonPrimitiveClass.equals(pClass)) ? stringConstructor : null;
212     }
213   }
214
215   private static class CharacterClass implements ParameterClass {
216     public Object JavaDoc matches(Class JavaDoc pClass) {
217       return (Character.TYPE.equals(pClass) || Character JavaDoc.class.equals(pClass)) ? Boolean.TRUE : null;
218     }
219
220     public void invoke(AttributeSetterImpl pAttributeSetter, Object JavaDoc pBean, String JavaDoc pValue, Method JavaDoc pMethod, Object JavaDoc pMethodObject, String JavaDoc pQName) throws SAXException JavaDoc {
221       if (pValue.length() != 1) {
222         throw new IllegalArgumentException JavaDoc("Invalid value for '" + pQName +"': " + pValue +
223                                             "; must have exactly one character.");
224       }
225       pAttributeSetter.invokeMethod(pBean, pMethod, pQName, new Object JavaDoc[]{new Character JavaDoc(pValue.charAt(0))});
226     }
227   }
228
229   private static class BooleanClass implements ParameterClass {
230     public Object JavaDoc matches(Class JavaDoc pClass) {
231       return (Boolean.TYPE.equals(pClass) || Boolean JavaDoc.class.equals(pClass)) ? Boolean.TRUE : null;
232     }
233
234     public void invoke(AttributeSetterImpl pAttributeSetter, Object JavaDoc pBean, String JavaDoc pValue, Method JavaDoc pMethod, Object JavaDoc pMethodObject, String JavaDoc pQName) throws SAXException JavaDoc {
235       Boolean JavaDoc b = ("true".equals(pValue) || "1".equals(pValue)) ? Boolean.TRUE : Boolean.FALSE;
236       pAttributeSetter.invokeMethod(pBean, pMethod, pQName, new Object JavaDoc[]{b});
237     }
238   }
239
240   private static final ParameterClass[] knownClasses = new ParameterClass[]{
241     new BooleanClass(),
242     new StringClass(),
243     new ValueOfParameterClass(),
244     new StringConstructorClass(),
245     new CharacterClass(),
246     new PrimitiveParameterClass(long.class, Long JavaDoc.class),
247     new PrimitiveParameterClass(int.class, Integer JavaDoc.class),
248     new PrimitiveParameterClass(short.class, Short JavaDoc.class),
249     new PrimitiveParameterClass(byte.class, Byte JavaDoc.class),
250     new PrimitiveParameterClass(double.class, Double JavaDoc.class),
251     new PrimitiveParameterClass(float.class, Float JavaDoc.class),
252     new CharacterClass(),
253   };
254
255   /** <p>This method is invoked from within {@link #setAttribute(String, String, String, String)}.
256    * It configures the bean <code>pBean</code> as follows;
257    * <ol>
258    * <li>If the bean has a method <code>setProperty(String)</code>
259    * this method is invoked with the attribute value.</li>
260    * <li>If the bean has a method <code>setProperty(T)</code>, and
261    * the class <code>T</code> has either of a method
262    * <code>public static T valueOf(String)</code> or a constructor
263    * <code>public T(String)</code> (in that order), then the method
264    * <code>setProperty(T)</code> is invoked with the value obtained
265    * by an invocation of the method <code>valueOf()</code>, or
266    * the constructor, respectively. Note, that this applies in
267    * particular to the classes {@link Long}, {@link Integer},
268    * {@link Short}, {@link Byte}, {@link Double}, {@link Float},
269    * <code>java.math.BigInteger</code>, <code>java.math.BigDecimal</code>,
270    * {@link java.io.File}, and {@link java.lang.StringBuffer}.</li>
271    * <li>If the bean has a method <code>setProperty(boolean)</code>,
272    * the method will be invoked with the value <i>true</i>
273    * (the value specified in the XML file is either of
274    * <code>true</code>, or <code>1</code>, otherwise with the
275    * value <code>false</code>.</li>
276    * <li>If the bean has a method <code>setProperty(char)</code>,
277    * or <code>setProperty(Character)</code>, the method will be
278    * invoked with the first character of the value specified in
279    * the XML file. If the value contains zero or multiple characters,
280    * an {@link IllegalArgumentException} is thrown.</li>
281    * <li>If the bean has either of the following methods, in that order:
282    * <ul>
283    * <li><code>setProperty(long)</code></li>
284    * <li><code>setProperty(int)</code></li>
285    * <li><code>setProperty(short)</code></li>
286    * <li><code>setProperty(byte)</code></li>
287    * <li><code>setProperty(double)</code></li>
288    * <li><code>setProperty(float)</code></li>
289    * </ul>
290    * then the property value is converted into the respective type
291    * and the method is invoked. An {@link IllegalArgumentException}
292    * is thrown, if the conversion fails.</li>
293    * <li>If the bean has a method <code>java.lang.Class</code>, the
294    * <code>XsSAXParser</code> will interpret the value given in the
295    * XML file as a Java class name and load the named class from its
296    * class loader. If the class cannot be loaded, it will also try
297    * to use the current threads context class loader. An
298    * exception is thrown, if neither of the class loaders can
299    * load the class.</li>
300    * </ol>
301    * </p>
302    *
303    * @return True, if a method for setting the property was found. Otherwise
304    * false.
305    */

306   protected boolean setProperty(Object JavaDoc pBean, String JavaDoc pQName, String JavaDoc pName, String JavaDoc pValue)
307       throws SAXException JavaDoc {
308     Class JavaDoc c = pBean.getClass();
309     String JavaDoc s = "set" + Character.toUpperCase(pName.charAt(0)) + pName.substring(1);
310     int parameterClassNum = knownClasses.length;
311     Method JavaDoc[] methods = c.getMethods();
312     Method JavaDoc method = null;
313     Object JavaDoc methodObject = null;
314     for (int i = 0; i < methods.length; i++) {
315       Method JavaDoc m = methods[i];
316       if (!s.equals(m.getName()) || !Modifier.isPublic(m.getModifiers())) {
317         continue;
318       }
319
320       Class JavaDoc[] params = m.getParameterTypes();
321       if (params.length != 1) {
322         continue;
323       }
324
325       Class JavaDoc paramsClass = params[0];
326       for (int j = 0; j < parameterClassNum; j++) {
327         ParameterClass parameterClass = knownClasses[j];
328         Object JavaDoc o = parameterClass.matches(paramsClass);
329         if (o != null) {
330           parameterClassNum = j;
331           method = m;
332           methodObject = o;
333           break;
334         }
335       }
336     }
337
338     if (method == null) {
339       return false;
340     } else {
341       knownClasses[parameterClassNum].invoke(this, pBean, pValue, method, methodObject, pQName);
342       return true;
343     }
344   }
345 }
346
Popular Tags