KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > controls > system > jdbc > RowToXmlObjectMapper


1 /*
2  * Copyright 2005 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  * $Header:$
17  */

18
19 package org.apache.beehive.controls.system.jdbc;
20
21 import org.apache.beehive.controls.api.ControlException;
22 import org.apache.xmlbeans.SchemaProperty;
23 import org.apache.xmlbeans.SchemaType;
24 import org.apache.xmlbeans.XmlObject;
25 import org.apache.xmlbeans.XmlOptions;
26
27 import java.lang.reflect.Field JavaDoc;
28 import java.lang.reflect.InvocationTargetException JavaDoc;
29 import java.lang.reflect.Method JavaDoc;
30 import java.lang.reflect.Modifier JavaDoc;
31 import java.sql.ResultSet JavaDoc;
32 import java.sql.ResultSetMetaData JavaDoc;
33 import java.sql.SQLException JavaDoc;
34 import java.util.Calendar JavaDoc;
35 import java.util.HashMap JavaDoc;
36
37 /**
38  * Maps a ResultSet row to an XmlObject.
39  */

40 public class RowToXmlObjectMapper extends RowMapper {
41
42     private final int _columnCount;
43     private final SchemaType _schemaType;
44
45     private SetterMethod[] _setterMethods;
46     private final Object JavaDoc[] _args = new Object JavaDoc[1];
47
48     /**
49      * Create a new RowToXmlObjectMapper.
50      *
51      * @param resultSet ResultSet to map
52      * @param returnTypeClass Class to map to.
53      * @param cal Calendar instance for date/time mappings.
54      * @throws SQLException on error.
55      */

56     RowToXmlObjectMapper(ResultSet JavaDoc resultSet, Class JavaDoc returnTypeClass, Calendar JavaDoc cal)
57             throws SQLException JavaDoc {
58         super(resultSet, returnTypeClass, cal);
59
60         _columnCount = resultSet.getMetaData().getColumnCount();
61         _schemaType = getSchemaType(_returnTypeClass);
62         _setterMethods = null;
63     }
64
65     /**
66      * map a row from the ResultSet to an XmlObject instance
67      *
68      * @return An XmlObject instance.
69      */

70     public Object JavaDoc mapRowToReturnType() {
71
72         Object JavaDoc resultObject = null;
73         if (_columnCount == 1) {
74
75             final int typeId = _tmf.getTypeId(_returnTypeClass);
76
77             try {
78                 if (typeId != TypeMappingsFactory.TYPE_UNKNOWN) {
79                     return extractColumnValue(1, typeId);
80                 } else {
81                     // we still might want a single value (i.e. java.util.Date)
82
Object JavaDoc val = extractColumnValue(1, typeId);
83                     if (_returnTypeClass.isAssignableFrom(val.getClass())) {
84                         return val;
85                     }
86                 }
87             } catch (SQLException JavaDoc e) {
88                 throw new ControlException(e.getMessage(), e);
89             }
90         }
91
92         if (_setterMethods == null) {
93             try {
94                 getResultSetMappings();
95             } catch (SQLException JavaDoc e) {
96                 throw new ControlException(e.getMessage(), e);
97             }
98         }
99
100         resultObject = XmlObject.Factory.newInstance(new XmlOptions().setDocumentType(_schemaType));
101
102         for (int i = 1; i < _setterMethods.length; i++) {
103             Method JavaDoc setterMethod = _setterMethods[i].getSetter();
104             Object JavaDoc resultValue = null;
105
106             try {
107                 resultValue = extractColumnValue(i, _setterMethods[i].getParameterType());
108
109                 // if the setter is for an xmlbean enum type, convert the extracted resultset column
110
// value to the proper xmlbean enum type. All xmlbean enums are derived from the class
111
// StringEnumAbstractBase
112
if (_setterMethods[i].getParameterType() == TypeMappingsFactory.TYPE_XMLBEAN_ENUM) {
113                     Class JavaDoc parameterClass = _setterMethods[i].getParameterClass();
114                     Method JavaDoc m = parameterClass.getMethod("forString", new Class JavaDoc[]{String JavaDoc.class});
115                     resultValue = m.invoke(null, new Object JavaDoc[]{resultValue});
116                 }
117
118                 _args[0] = resultValue;
119                 setterMethod.invoke(resultObject, _args);
120
121                 if (_setterMethods[i].getNilable() != null) {
122                     if (_resultSet.wasNull()) {
123                         _setterMethods[i].getNilable().invoke(resultObject, (Object JavaDoc[]) null);
124                     }
125                 }
126             } catch (SQLException JavaDoc se) {
127                 throw new ControlException(se.getMessage(), se);
128             } catch (IllegalArgumentException JavaDoc iae) {
129                 try {
130                     ResultSetMetaData JavaDoc md = _resultSet.getMetaData();
131                     throw new ControlException("The declared Java type for method " + setterMethod.getName()
132                                                + setterMethod.getParameterTypes()[0].toString()
133                                                + " is incompatible with the SQL format of column " + md.getColumnName(i).toString()
134                                                + md.getColumnTypeName(i).toString()
135                                                + " which returns objects of type " + resultValue.getClass().getName());
136                 } catch (SQLException JavaDoc e) {
137                     throw new ControlException(e.getMessage(), e);
138                 }
139             } catch (IllegalAccessException JavaDoc e) {
140                 throw new ControlException("IllegalAccessException when trying to access method " + setterMethod.getName(), e);
141             } catch (NoSuchMethodException JavaDoc e) {
142                 throw new ControlException("NoSuchMethodException when trying to map schema enum value using Enum.forString().", e);
143             } catch (InvocationTargetException JavaDoc e) {
144                 throw new ControlException("IllegalInvocationException when trying to access method " + setterMethod.getName(), e);
145             }
146         }
147         return resultObject;
148     }
149
150
151 // ///////////////////////////////////////////////// private methods /////////////////////////////////////////////////
152

153     /**
154      * Build the necessary structures to do the mapping
155      *
156      * @throws SQLException
157      */

158     private void getResultSetMappings() throws SQLException JavaDoc {
159
160         //
161
// special case for XmlObject, find factory class
162
//
163
if (_schemaType.isDocumentType()) {
164             return;
165         }
166
167         final String JavaDoc[] keys = getKeysFromResultSet();
168
169         //
170
// find setters for return class
171
//
172
HashMap JavaDoc<String JavaDoc, Method JavaDoc> mapFields = new HashMap JavaDoc<String JavaDoc, Method JavaDoc>(_columnCount * 2);
173         for (int i = 1; i <= _columnCount; i++) {
174             mapFields.put(keys[i], null);
175         }
176
177         // public methods
178
Method JavaDoc[] classMethods = _returnTypeClass.getMethods();
179         for (Method JavaDoc method : classMethods) {
180
181             if (isSetterMethod(method)) {
182                 final String JavaDoc fieldName = method.getName().substring(3).toUpperCase();
183                 if (mapFields.containsKey(fieldName)) {
184                     mapFields.put(fieldName, method);
185                 }
186             }
187         }
188
189         // finally actually init the fields array
190
_setterMethods = new SetterMethod[_columnCount + 1];
191
192         for (int i = 1; i < _setterMethods.length; i++) {
193             Method JavaDoc setterMethod = mapFields.get(keys[i]);
194             if (setterMethod == null) {
195                 throw new ControlException("Unable to map the SQL column " + keys[i]
196                                            + " to a field on the " + _returnTypeClass.getName() +
197                                            " class. Mapping is done using a case insensitive comparision of SQL ResultSet "
198                                            + "columns to public setter methods on the return class.");
199             }
200
201             _setterMethods[i] = new SetterMethod(setterMethod);
202         }
203     }
204
205     /**
206      * Build a String array of column names from the ResultSet.
207      *
208      * @return A String array containing the column names contained within the ResultSet.
209      * @throws SQLException on error
210      */

211     protected String JavaDoc[] getKeysFromResultSet()
212             throws SQLException JavaDoc {
213
214         String JavaDoc[] keys = super.getKeysFromResultSet();
215
216         // check schemaProperty mapping names for more accurate column->field mapping
217
SchemaProperty[] props = _schemaType.getElementProperties();
218         for (int i = 0; i < props.length; i++) {
219
220             int col = -1;
221             try {
222                 col = _resultSet.findColumn(props[i].getName().getLocalPart());
223             } catch (SQLException JavaDoc x) {
224             }
225
226             if (col > 0) {
227                 keys[col] = props[i].getJavaPropertyName().toUpperCase();
228             }
229         }
230         return keys;
231     }
232
233     /**
234      * Get the SchemaType for the specified class.
235      *
236      * @param returnType Class to get the SchemaType for.
237      * @return SchemaType
238      */

239     private SchemaType getSchemaType(Class JavaDoc returnType) {
240         SchemaType schemaType = null;
241         if (XmlObject.class.isAssignableFrom(returnType)) {
242             try {
243                 Field JavaDoc f = returnType.getField("type");
244                 if (SchemaType.class.isAssignableFrom(f.getType()) && Modifier.isStatic(f.getModifiers())) {
245                     schemaType = (SchemaType) f.get(null);
246                 }
247             } catch (NoSuchFieldException JavaDoc x) {
248             } catch (IllegalAccessException JavaDoc x) {
249             }
250         }
251         return schemaType;
252     }
253
254     // /////////////////////////////////////////////INNER CLASSES/////////////////////////////////////////////////
255

256     /**
257      * Helper class which contains setter method information.
258      */

259     private final class SetterMethod {
260         private final Method JavaDoc _setter;
261         private final int _parameterType;
262         private final Class JavaDoc _parameterClass;
263         private final Method JavaDoc _nilable;
264
265         /**
266          * Create a new setter method.
267          *
268          * @param setter Method instance.
269          */

270         SetterMethod(Method JavaDoc setter) {
271             _setter = setter;
272             _parameterClass = _setter.getParameterTypes()[0];
273             _parameterType = _tmf.getTypeId(_parameterClass);
274             _nilable = isNilable();
275         }
276
277         /**
278          * Return the setter method.
279          *
280          * @return Method
281          */

282         Method JavaDoc getSetter() { return _setter; }
283
284         /**
285          * Return the class of the setter method's paramater.
286          *
287          * @return Class of the setter method's param.
288          */

289         Class JavaDoc getParameterClass() { return _parameterClass; }
290
291         /**
292          * Get the type of the methods paramter.
293          * Type is defined by the TypeMappingsFactory, prefixed by TYPE_.
294          *
295          * @return int type.
296          */

297         int getParameterType() { return _parameterType; }
298
299         /**
300          * Get the nilable method for this setter.
301          *
302          * @return Method.
303          */

304         Method JavaDoc getNilable() { return _nilable; }
305
306         /**
307          * This takes care of the special case for xml beans return types.
308          * since they return primitive types even if they are nillable, we
309          * must explicitly call setNil after getting the column out of the resultSet.
310          * for that, we need to keep track of each field's setNil method.
311          * if the field is not nillable, it will not have a setNil method, and
312          * that array index will be null.
313          *
314          * @return Method
315          */

316         private Method JavaDoc isNilable() {
317             try {
318                 return _returnTypeClass.getMethod("setNil" + _setter.getName().substring(3), new Class JavaDoc[]{});
319             } catch (NoSuchMethodException JavaDoc e) {
320                 // NOOP - just means there is no setNil
321
}
322             return null;
323         }
324     }
325 }
326
Popular Tags