KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > lateralnz > common > util > ResultSetConverter


1 /* ====================================================================
2  * The LateralNZ Software License, Version 1.0
3  *
4  * Copyright (c) 2003 LateralNZ. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by
21  * LateralNZ (http://www.lateralnz.org/) and other third parties."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. The names "LateralNZ" must not be used to endorse or promote
26  * products derived from this software without prior written
27  * permission. For written permission, please
28  * contact oss@lateralnz.org.
29  *
30  * 5. Products derived from this software may not be called "Panther",
31  * or "Lateral" or "LateralNZ", nor may "PANTHER" or "LATERAL" or
32  * "LATERALNZ" appear in their name, without prior written
33  * permission of LateralNZ.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of LateralNZ. For more
51  * information on Lateral, please see http://www.lateralnz.com/ or
52  * http://www.lateralnz.org
53  *
54  */

55 package org.lateralnz.common.util;
56
57 import java.io.File JavaDoc;
58 import java.io.FileWriter JavaDoc;
59 import java.io.FileInputStream JavaDoc;
60 import java.io.InputStreamReader JavaDoc;
61 import java.lang.reflect.Field JavaDoc;
62 import java.sql.ResultSet JavaDoc;
63 import java.sql.ResultSetMetaData JavaDoc;
64 import java.sql.Types JavaDoc;
65 import java.util.ArrayList JavaDoc;
66 import java.util.Date JavaDoc;
67 import java.util.HashMap JavaDoc;
68 import java.util.List JavaDoc;
69
70 /**
71  * a singleton utility class which creates (& compiles) a class based upon a JDBC resultset
72  * and then returns a list with objects of that class populated with the resultset data
73  *
74  * @author J R Briggs
75  */

76 public class ResultSetConverter implements Constants {
77   private static final Class JavaDoc[] DATE_CLASS_TYPE = { Date JavaDoc.class };
78   private static final Class JavaDoc[] DOUBLE_CLASS_TYPE = { Double JavaDoc.class };
79   private static final Class JavaDoc[] LONG_CLASS_TYPE = { Long JavaDoc.class };
80   private static final Class JavaDoc[] STRING_CLASS_TYPE = { String JavaDoc.class };
81
82   private static HashMap JavaDoc instances = new HashMap JavaDoc();
83   
84   private HashMap JavaDoc classes = new HashMap JavaDoc();
85   private String JavaDoc compilerExecutable;
86   
87   // Singleton instance.
88
private static ResultSetConverter instance = null;
89   
90   private ResultSetConverter(String JavaDoc compilerExecutable) {
91     setCompilerExecutable(compilerExecutable);
92   }
93   
94   private void setCompilerExecutable(String JavaDoc compilerExecutable) {
95     this.compilerExecutable = compilerExecutable;
96   }
97   
98   public static ResultSetConverter getInstance() throws Exception JavaDoc {
99     return getInstance("javac");
100   }
101   
102   /**
103   * Singleton method.
104   */

105   public static ResultSetConverter getInstance(String JavaDoc compilerExecutable) throws Exception JavaDoc {
106     if (!instances.containsKey(compilerExecutable)) {
107       synchronized (instances) {
108         if (!instances.containsKey(compilerExecutable)) {
109           ResultSetConverter rsc = new ResultSetConverter(compilerExecutable);
110           instances.put(compilerExecutable, rsc);
111         }
112       }
113     }
114
115     return (ResultSetConverter)instances.get(compilerExecutable);
116   }
117   
118   private final MetaClass getClassForResultSet(String JavaDoc resultName, ResultSet JavaDoc rs) throws Exception JavaDoc {
119     ResultSetMetaData JavaDoc md = rs.getMetaData();
120     
121     int count = md.getColumnCount();
122     
123     MetaClass metaclass = new MetaClass(count);
124     
125     String JavaDoc[] getmethods = new String JavaDoc[count];
126     String JavaDoc[] getomethods = new String JavaDoc[count];
127     String JavaDoc[] setmethods = new String JavaDoc[count];
128     String JavaDoc[] vars = new String JavaDoc[count];
129     
130     StringBuffer JavaDoc staticColnames = new StringBuffer JavaDoc("public static String[] colnames = new String[]{ ");
131         
132     for (int i = 0, j = 1; i < count; i++, j++) {
133       int type = md.getColumnType(j);
134       String JavaDoc colname = md.getColumnName(j);
135       staticColnames.append(QUOTE).append(colname).append(QUOTE);
136       if (i < count-1) {
137         staticColnames.append(COMMA);
138       }
139       if (colname.indexOf(SPACE) >= 0) {
140         colname = StringUtils.replace(colname, SPACE, UNDERSCORE);
141       }
142       colname = colname.substring(0,1).toUpperCase() + colname.substring(1);
143       switch (type) {
144         case Types.DECIMAL:
145         case Types.FLOAT:
146         case Types.DOUBLE:
147           metaclass.types[i] = MetaClass.DOUBLE;
148           vars[i] = "public double col" + j + ";";
149           getmethods[i] = "public double get" + colname + "() { return this.col" + j + "; }";
150           getomethods[i] = " new Double(col" + j +")";
151           setmethods[i] = "public void set" + colname + "(double d) { this.col" + j + " = d; }";
152           break;
153         case Types.INTEGER:
154         case Types.SMALLINT:
155         case Types.TINYINT:
156           metaclass.types[i] = MetaClass.LONG;
157           vars[i] = "public long col" + j + ";";
158           getmethods[i] = "public long get" + colname + "() { return this.col" + j + "; }";
159           getomethods[i] = " new Long(col" + j +")";
160           setmethods[i] = "public void set" + colname + "(long l) { this.col" + j + " = l; }";
161           break;
162         case Types.DATE:
163         case Types.TIME:
164         case Types.TIMESTAMP:
165           metaclass.types[i] = MetaClass.DATE;
166           vars[i] = "public Date col" + j + " = null;";
167           getmethods[i] = "public Date get" + colname + "() { return this.col" + j + "; }";
168           getomethods[i] = " col" + j;
169           setmethods[i] = "public void set" + colname + "(Date d) { this.col" + j + " = d; }";
170           break;
171         case Types.VARCHAR:
172         case Types.CHAR:
173         default:
174           metaclass.types[i] = MetaClass.STRING;
175           vars[i] = "public String col" + j + " = null;";
176           getmethods[i] = "public String get" + colname + "() { return this.col" + j + "; }";
177           getomethods[i] = " col" + j;
178           setmethods[i] = "public void set" + colname + "(String s) { this.col" + j + " = s; }";
179           break;
180       }
181     }
182     
183     staticColnames.append("};\n\n");
184     staticColnames.append("public static String getColName(int idx) { return colnames[idx]; }\n\n");
185     staticColnames.append("public static int getColCount() { return colnames.length; }\n\n");
186     
187     StringBuffer JavaDoc sb = new StringBuffer JavaDoc("import java.util.Date;\nimport java.util.Iterator;\nimport java.io.Serializable;\n\n");
188     sb.append("public class ResultSetValue_" + resultName + " implements Iterator, Serializable {\n");
189     sb.append(staticColnames.toString()).append(NEWLINE).append(NEWLINE);
190     sb.append("int pos = 0;\nint max = ").append(count).append(";\n\n");
191
192     for (int i = 0; i < count; i++) {
193       sb.append(vars[i]).append(NEWLINE);
194     }
195     for (int i = 0; i < count; i++) {
196       sb.append(getmethods[i]).append(NEWLINE);
197       sb.append(setmethods[i]).append(NEWLINE);
198     }
199     sb.append("public boolean hasNext() { return (pos < max); }\n\n");
200     sb.append("public Object next() {\ntry {\nswitch (pos) {\n");
201     for (int i = 0; i < count; i++) {
202       sb.append("case ").append(i).append(": return ").append(getomethods[i]).append(";\n");
203     }
204     sb.append("default: return null;\n}\n} finally { pos++; }\n}\npublic void remove() { }\n");
205     
206     if (count > 0) {
207       sb.append("\npublic String toString() {\nreturn \"\" + ");
208       for (int i = 1; i <= count; i++) {
209         sb.append("col").append(i);
210         if (i < count) {
211           sb.append(" + \",\" + ");
212         }
213       }
214       sb.append(";\n}\n");
215     }
216     
217     sb.append(NEWLINE).append("}");
218
219     FileWriter JavaDoc fw = new FileWriter JavaDoc("ResultSetValue_" + resultName + ".java");
220     fw.write(sb.toString());
221  
222     fw.close();
223     
224     Process JavaDoc p = Runtime.getRuntime().exec(compilerExecutable + " ResultSetValue_" + resultName + ".java");
225     p.waitFor();
226     if (p.exitValue() != 0) {
227       InputStreamReader JavaDoc isr = null;
228       try {
229         isr = new InputStreamReader JavaDoc(p.getErrorStream());
230         throw new Exception JavaDoc("error compiling " + StringUtils.readFrom(isr));
231       }
232       finally {
233         IOUtils.close(isr);
234       }
235     }
236     
237     File JavaDoc f = new File JavaDoc("ResultSetValue_" + resultName + ".class");
238     FileInputStream JavaDoc fis = null;
239     byte[] b;
240     try {
241       fis = new FileInputStream JavaDoc(f);
242       b = new byte[(int)f.length()];
243       fis.read(b);
244     }
245     finally {
246       IOUtils.close(fis);
247     }
248   
249     InternalClassLoader icl = new InternalClassLoader();
250     Class JavaDoc c = icl.getClass("ResultSetValue_" + resultName, b);
251     metaclass.c = c;
252     classes.put(resultName, metaclass);
253     
254     return metaclass;
255   }
256
257   private final Field JavaDoc[] getFields(MetaClass mc) throws Exception JavaDoc {
258     Field JavaDoc[] f = new Field JavaDoc[mc.numOfFields];
259     for (int i = 0, j = 1; i < f.length; i++, j++) {
260       f[i] = mc.c.getField("col" + j);
261     }
262     return f;
263   }
264   
265  /**
266   * return a resultset as a list of objects representing the rows data of the resultset
267   * @param resultSetName the name to refer to resultsets of this type (so we don't have
268   * to create the class every time we call this method
269   * @param rs the resultset data
270   * @param forceClassReload forces the class to be rebuilt
271   */

272   public List JavaDoc getResultSetAsList(String JavaDoc resultSetName, ResultSet JavaDoc rs, boolean forceClassReload) throws Exception JavaDoc {
273     MetaClass metaclass;
274     if (!classes.containsKey(resultSetName) || forceClassReload) {
275       metaclass = getClassForResultSet(resultSetName, rs);
276     }
277     else {
278       metaclass = (MetaClass)classes.get(resultSetName);
279     }
280     
281     Field JavaDoc[] fields = getFields(metaclass);
282     Object JavaDoc[] val = new Object JavaDoc[1];
283     ArrayList JavaDoc al = new ArrayList JavaDoc();
284     while (rs.next()) {
285       Object JavaDoc valobj = metaclass.c.newInstance();
286       
287       for (int i = 0, j = 1; i < fields.length; i++, j++) {
288         switch (metaclass.types[i]) {
289           case MetaClass.DATE :
290             fields[i].set(valobj, rs.getTimestamp(j));
291             break;
292           case MetaClass.DOUBLE :
293             fields[i].setDouble(valobj, rs.getDouble(j));
294             break;
295           case MetaClass.LONG :
296             fields[i].setLong(valobj, rs.getLong(j));
297             break;
298           default :
299             fields[i].set(valobj, rs.getString(j));
300             break;
301         }
302       }
303       al.add(valobj);
304     }
305     
306     return al;
307   }
308   
309   public void reset(String JavaDoc name) {
310     classes.remove(name);
311   }
312   
313  /**
314   * the classloader used to load the 'converter' classes
315   */

316   class InternalClassLoader extends ClassLoader JavaDoc {
317     public InternalClassLoader() {
318       super();
319     }
320     
321     public Class JavaDoc getClass(String JavaDoc name, byte[] b) {
322       return super.defineClass(name, b, 0, b.length);
323     }
324   }
325   
326   class MetaClass {
327     public static final int STRING = 0;
328     public static final int LONG = 1;
329     public static final int DOUBLE = 2;
330     public static final int DATE = 3;
331     
332     int numOfFields;
333     int[] types;
334     Class JavaDoc c;
335     
336     public MetaClass(int numOfFields) {
337       this.numOfFields = numOfFields;
338       types = new int[numOfFields];
339     }
340   }
341 }
Popular Tags