KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jdom > contrib > input > ResultSetBuilder


1 /*--
2
3  $Id: ResultSetBuilder.java,v 1.12 2004/12/11 00:06:40 jhunter Exp $
4
5  Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
6  All rights reserved.
7
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions
10  are met:
11
12  1. Redistributions of source code must retain the above copyright
13     notice, this list of conditions, and the following disclaimer.
14
15  2. Redistributions in binary form must reproduce the above copyright
16     notice, this list of conditions, and the disclaimer that follows
17     these conditions in the documentation and/or other materials
18     provided with the distribution.
19
20  3. The name "JDOM" must not be used to endorse or promote products
21     derived from this software without prior written permission. For
22     written permission, please contact <request_AT_jdom_DOT_org>.
23
24  4. Products derived from this software may not be called "JDOM", nor
25     may "JDOM" appear in their name, without prior written permission
26     from the JDOM Project Management <request_AT_jdom_DOT_org>.
27
28  In addition, we request (but do not require) that you include in the
29  end-user documentation provided with the redistribution and/or in the
30  software itself an acknowledgement equivalent to the following:
31      "This product includes software developed by the
32       JDOM Project (http://www.jdom.org/)."
33  Alternatively, the acknowledgment may be graphical using the logos
34  available at http://www.jdom.org/images/logos.
35
36  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
40  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  SUCH DAMAGE.
48
49  This software consists of voluntary contributions made by many
50  individuals on behalf of the JDOM Project and was originally
51  created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
52  Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
53  on the JDOM Project, please see <http://www.jdom.org/>.
54
55  */

56
57 package org.jdom.contrib.input;
58
59 import java.io.*;
60 import java.sql.*;
61 import java.text.*;
62 import java.util.*;
63
64 import org.jdom.*;
65
66 /**
67  * <p><code>ResultSetBuilder</code> builds a JDOM tree from a
68  * <code>java.sql.ResultSet</code>. Many good ideas were leveraged from
69  * SQLBuilder written from Jon Baer.</p>
70  *
71  * Notes:
72  * Uses name returned by rsmd.getColumnName(), not getColumnLabel()
73  * because that is less likely to be a valid XML element title.
74  * Null values are given empty bodies, but you can mark them as empty with
75  * an attribute using the setNullAttribute() method. Be aware that databases
76  * may change the case of column names. setAsXXX() methods are case
77  * insensitive on input column name. Assign each one a proper output name
78  * if you're worried. Only build() throws JDOMException. Any exceptions
79  * encountered in the set methods are thrown during the build().
80  * The setAsXXX(String columnName, ...) methods do not verify that a column
81  * with the given name actually exists.
82  *
83  * Still needs method-by-method Javadocs.
84  * <p>
85  * Issues:
86  * Do attributes have to be added in a namespace?
87  *
88  * @author Jason Hunter
89  * @author Jon Baer
90  * @author David Bartle
91  * @author Robert J. Munro
92  * @version 0.5
93  */

94 public class ResultSetBuilder {
95     
96     /** The ResultSet that becomes a <code>Document</code> */
97     private ResultSet rs;
98
99     /** The meta data from the ResultSet */
100     private ResultSetMetaData rsmd;
101
102     /** Allows for throwing an exception whenever needed if caught early on */
103     private SQLException exception;
104
105     /** Map of original column names to display names */
106     private Map names = new HashMap();
107
108     /**
109      * Maps column data to be located either as an <code>Attribute</code> of
110      * the row (if in the Map) or a child <code>Element</code> of the row
111      * (if not in the Map)
112      */

113     private Map attribs = new HashMap();
114
115     /** The <code>Namespace</code> to use for each <code>Element</code> */
116     private Namespace ns = Namespace.NO_NAMESPACE;
117
118     /** The maximum rows to return from the result set */
119     int maxRows = Integer.MAX_VALUE; // default to all
120

121     /** Name for the root <code>Element</code> of the <code>Document</code> */
122     private String JavaDoc rootName = "result";
123
124     /** Name for the each immediate child <code>Element</code> of the root */
125     private String JavaDoc rowName = "entry";
126
127     /** Name for attribute to mark that a field was null */
128     private String JavaDoc nullAttribName = null;
129
130     /** Value for attribute to mark that a field was null */
131     private String JavaDoc nullAttribValue = null;
132     
133     /**
134      * <p>
135      * This sets up a <code>java.sql.ResultSet</code> to be built
136      * as a <code>Document</code>.
137      * </p>
138      *
139      * @param rs <code>java.sql.ResultSet</code> to build
140      */

141     public ResultSetBuilder(ResultSet rs) {
142       this.rs = rs;
143       try {
144         rsmd = rs.getMetaData();
145       }
146       catch (SQLException e) {
147         // Hold the exception until build() is called
148
exception = e;
149       }
150     }
151
152     /**
153      * <p>
154      * This sets up a <code>java.sql.ResultSet</code> to be built
155      * as a <code>Document</code>.
156      * </p>
157      *
158      * @param rs <code>java.sql.ResultSet</code> to build from
159      * @param rootName <code>String</code> name for the root
160      * <code>Element</code>
161      * of the <code>Document</code>
162      * @param rowName <code>String</code> name for the each immediate child
163      * <code>Element</code> of the root
164      */

165     public ResultSetBuilder(ResultSet rs, String JavaDoc rootName, String JavaDoc rowName) {
166         this(rs);
167         setRootName(rootName);
168         setRowName(rowName);
169     }
170
171     /**
172      * <p>
173      * This sets up a <code>java.sql.ResultSet</code> to be built
174      * as a <code>Document</code>.
175      * </p>
176      *
177      * @param rs <code>java.sql.ResultSet</code> to build from
178      * @param rootName <code>String</code> name for the root
179      * <code>Element</code>
180      * of the <code>Document</code>
181      * @param rowName <code>String</code> name for the each immediate child
182      * <code>Element</code> of the root
183      * @param ns <code>Namespace</code> to use for each <code>Element</code>
184      */

185     public ResultSetBuilder(ResultSet rs,
186                             String JavaDoc rootName, String JavaDoc rowName, Namespace ns) {
187         this(rs, rootName, rowName);
188         setNamespace(ns);
189     }
190
191     /**
192      * <p>
193      * This builds a <code>Document</code> from the
194      * <code>java.sql.ResultSet</code>.
195      * </p>
196      *
197      * @return <code>Document</code> - resultant Document object.
198      * @throws <code>JDOMException</code> when there is a problem
199      * with the build.
200      *
201      */

202     public Document build() throws JDOMException {
203       if (exception != null) {
204         throw new JDOMException("Database problem", exception);
205       }
206
207       try {
208         int colCount = rsmd.getColumnCount();
209
210         Element root = new Element(rootName, ns);
211         Document doc = new Document(root);
212
213         int rowCount = 0;
214
215         // get the column labels for this record set
216
String JavaDoc[] columnName = new String JavaDoc[colCount];
217         for (int index = 0; index < colCount; index++) {
218           columnName[index] = rsmd.getColumnName(index+1);
219         }
220
221         // build the org.jdom.Document out of the result set
222
String JavaDoc name;
223         String JavaDoc value;
224         Element entry;
225         Element child;
226         
227         while (rs.next() && (rowCount++ < maxRows)) {
228           entry = new Element(rowName, ns);
229           for (int col = 1; col <= colCount; col++) {
230             if (names.isEmpty()) {
231               name = columnName[col-1];
232             }
233             else {
234               name = lookupName(columnName[col-1]);
235             }
236
237             value = getString(rs, col, rsmd.getColumnType(col));
238             if (!attribs.isEmpty() && isAttribute(columnName[col-1])) {
239               if (!rs.wasNull()) {
240                 entry.setAttribute(name, value);
241               }
242             }
243             else {
244               child = new Element(name, ns);
245               if (!rs.wasNull()) {
246                 child.setText(value);
247               } else {
248                 if (nullAttribName != null) {
249                   child.setAttribute(nullAttribName, nullAttribValue);
250                 }
251               }
252               entry.addContent(child);
253             }
254           }
255           root.addContent(entry);
256         }
257
258         return doc;
259       }
260       catch (SQLException e) {
261         throw new JDOMException("Database problem", e);
262       }
263     }
264
265     protected String JavaDoc getString(ResultSet rs, int column, int columnType)
266                                    throws SQLException {
267         if (columnType == Types.TIMESTAMP) {
268             Timestamp timeStamp = rs.getTimestamp(column);
269             if (timeStamp != null) {
270                 return DateFormat.getDateTimeInstance(DateFormat.FULL,
271                                      DateFormat.FULL).format(timeStamp);
272             }
273         }
274         if (columnType == Types.DATE) {
275             java.sql.Date JavaDoc date = rs.getDate(column);
276             if (date != null) {
277                 return DateFormat.getDateInstance(DateFormat.FULL).format(date);
278             }
279         }
280         if (columnType == Types.TIME) {
281             java.sql.Time JavaDoc time = rs.getTime(column);
282             if (time != null) {
283                 return DateFormat.getTimeInstance(DateFormat.FULL).format(time);
284             }
285         }
286         return rs.getString(column);
287     }
288
289     private String JavaDoc lookupName(String JavaDoc origName) {
290       String JavaDoc name = (String JavaDoc) names.get(origName.toLowerCase());
291       if (name != null) {
292         return name;
293       }
294       else {
295         return origName;
296       }
297     }
298
299     private boolean isAttribute(String JavaDoc origName) {
300       Boolean JavaDoc val = (Boolean JavaDoc) attribs.get(origName.toLowerCase());
301       if (val == Boolean.TRUE) {
302         return true;
303       }
304       else {
305         return false;
306       }
307     }
308
309     /**
310      * Set the name to use as the root element in
311      * the <code>Document</code>.
312      *
313      * @param rootName <code>String</code> the new name.
314      *
315      */

316     public void setRootName(String JavaDoc rootName) {
317       this.rootName = rootName;
318     }
319
320     /**
321      * Set the name to use as the row element in
322      * the <code>Document</code>.
323      *
324      * @param rowName <code>String</code> the new name.
325      *
326      */

327     public void setRowName(String JavaDoc rowName) {
328       this.rowName = rowName;
329     }
330
331     /**
332      * <p>
333      * Set the <code>Namespace</code> to use for
334      * each <code>Element</code> in the <code>Document</code>.
335      * </p>
336      *
337      * @param ns <code>String</code> the namespace to use.
338      *
339      */

340     public void setNamespace(Namespace ns) {
341       this.ns = ns;
342     }
343
344      /**
345      * <p>
346      * Set the maximum number of rows to add to your
347      * <code>Document</code>.
348      * </p>
349      *
350      * @param maxRows <code>int</code>
351      *
352      */

353     public void setMaxRows(int maxRows) {
354       this.maxRows = maxRows;
355     }
356
357     /**
358      * <p>
359      * Set a column as an <code>Attribute</code> of a row using the
360      * original column name. The attribute will appear as the original
361      * column name.
362      * </p>
363      *
364      * @param columnName <code>String</code> the original column name
365      *
366      */

367     public void setAsAttribute(String JavaDoc columnName) {
368       attribs.put(columnName.toLowerCase(), Boolean.TRUE);
369     }
370
371     /**
372      * <p>
373      * Set a column as an <code>Attribute</code> of a row using the
374      * column name. The attribute will appear as the new name provided.
375      * </p>
376      *
377      * @param columnName <code>String</code> original column name
378      * @param attribName <code>String</code> new name to use for the attribute
379      *
380      */

381     public void setAsAttribute(String JavaDoc columnName, String JavaDoc attribName) {
382       attribs.put(columnName.toLowerCase(), Boolean.TRUE);
383       names.put(columnName.toLowerCase(), attribName);
384     }
385
386     /**
387      * <p>
388      * Set a column as an <code>Attribute</code> of a row using the
389      * column number. The attribute will appear as the original column
390      * name.
391      * </p>
392      *
393      * @param columnNum <code>int</code>
394      *
395      */

396     public void setAsAttribute(int columnNum) {
397       try {
398         String JavaDoc name = rsmd.getColumnName(columnNum).toLowerCase();
399         attribs.put(name, Boolean.TRUE);
400       }
401       catch (SQLException e) {
402         exception = e;
403       }
404     }
405
406     /**
407      * <p>
408      * Set a column as an <code>Attribute</code> of a row using the
409      * column number. The attribute will appear as new name provided.
410      * </p>
411      *
412      * @param columnNum <code>int</code>
413      * @param attribName <code>String</code> new name to use for the attribute
414      *
415      */

416     public void setAsAttribute(int columnNum, String JavaDoc attribName) {
417       try {
418         String JavaDoc name = rsmd.getColumnName(columnNum).toLowerCase();
419         attribs.put(name, Boolean.TRUE);
420         names.put(name, attribName);
421       }
422       catch (SQLException e) {
423         exception = e;
424       }
425     }
426
427     /**
428      * <p>
429      * Set a column as an <code>Element</code> of a row using the
430      * column name. The element name will appear as the new name provided.
431      * </p>
432      *
433      * @param columnName <code>String</code> original column name
434      * @param elemName <code>String</code> new name to use for the element
435      *
436      */

437     public void setAsElement(String JavaDoc columnName, String JavaDoc elemName) {
438       String JavaDoc name = columnName.toLowerCase();
439       attribs.put(name, Boolean.FALSE);
440       names.put(name, elemName);
441     }
442
443     /**
444      * <p>
445      * Set a column as an <code>Element</code> of a row using the
446      * column number. The element name will appear as new name provided.
447      * </p>
448      *
449      * @param columnNum <code>int</code>
450      * @param elemName <code>String</code> new name to use for the element
451      *
452      */

453     public void setAsElement(int columnNum, String JavaDoc elemName) {
454       try {
455         String JavaDoc name = rsmd.getColumnName(columnNum).toLowerCase();
456         attribs.put(name, Boolean.FALSE);
457         names.put(name, elemName);
458       }
459       catch (SQLException e) {
460         exception = e;
461       }
462     }
463
464     /**
465      * <p>
466      * Set a specific attribute to use to mark that a value in the
467      * database was null, not just an empty string. This is necessary
468      * because &lt;foo/&gt; semantically represents both null and empty.
469      * This method lets you have &lt;foo null="true"&gt;.
470      * </p>
471      *
472      * @param nullAttribName <code>String</code> name of attribute to add
473      * @param nullAttribValue <code>String</code> value to set it to.
474      *
475      */

476     public void setNullAttribute(String JavaDoc nullAttribName,
477                                  String JavaDoc nullAttribValue) {
478         this.nullAttribName = nullAttribName;
479         this.nullAttribValue = nullAttribValue;
480     }
481
482 /*
483     public void setAsIngore(String columnName) {
484     }
485
486     public void setAsIngore(int columnNum) {
487     }
488 */

489
490 }
491
Popular Tags