/*-- Copyright 2000 Brett McLaughlin & Jason Hunter. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions, the disclaimer that follows these conditions, and/or other materials provided with the distribution. 3. The names "JDOM" and "Java Document Object Model" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact license@jdom.org. 4. Products derived from this software may not be called "JDOM", nor may "JDOM" appear in their name, without prior written permission from the JDOM Project Management (pm@jdom.org). THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JDOM PROJECT OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Java Document Object Model Project and was originally created by Brett McLaughlin and Jason Hunter . For more information on the JDOM Project, please see . */ package org.jdom.contrib.input; import java.io.*; import java.sql.*; import java.util.*; import org.jdom.*; import java.text.*; /** *

ResultSetBuilder builds a JDOM tree from a * java.sql.ResultSet. Many good ideas were leveraged from * SQLBuilder written from Jon Baer.

* * Notes: * Uses name returned by rsmd.getColumnName(), not getColumnLabel() * because that is less likely to be a valid XML element title. * Null values are given empty bodies. Be aware that databases may * change the case of column names. setAsXXX() methods are case * insensitive on input column name. Assign each one a proper output name * if you're worried. Only build() throws JDOMException. Any exceptions * encountered in the set methods are thrown during the build(). * The setAsXXX(String columnName, ...) methods do not verify that a column * with the given name actually exists. * Still needs method-by-method Javadocs. *

* Issues: * Do attributes have to be added in a namespace? * * @author Jason Hunter * @author Jon Baer * @author David Bartle * @version 0.5 */ public class ResultSetBuilder { /** The ResultSet that becomes a Document */ private ResultSet rs; /** The meta data from the ResultSet */ private ResultSetMetaData rsmd; /** Allows for throwing an exception whenever needed if caught early on */ private SQLException exception; /** Map of original column names to display names */ private Map names = new HashMap(); /** * Maps column data to be located either as an Attribute of * the row (if in the Map) or a child Element of the row * (if not in the Map) */ private Map attribs = new HashMap(); /** The Namespace to use for each Element */ private Namespace ns = Namespace.NO_NAMESPACE; /** The maximum rows to return from the result set */ int maxRows = Integer.MAX_VALUE; // default to all /** Name for the root Element of the Document */ private String rootName = "result"; /** Name for the each immediate child Element of the root */ private String rowName = "entry"; /** *

* This sets up a java.sql.ResultSet to be built * as a Document. *

* * @param rs java.sql.ResultSet to build */ public ResultSetBuilder(ResultSet rs) { this.rs = rs; try { rsmd = rs.getMetaData(); } catch (SQLException e) { // Hold the exception until build() is called exception = e; } } /** *

* This sets up a java.sql.ResultSet to be built * as a Document. *

* * @param rs java.sql.ResultSet to build from * @param rootName String name for the root * Element * of the Document * @param rowName String name for the each immediate child * Element of the root */ public ResultSetBuilder(ResultSet rs, String rootName, String rowName) { this(rs); setRootName(rootName); setRowName(rowName); } /** *

* This sets up a java.sql.ResultSet to be built * as a Document. *

* * @param rs java.sql.ResultSet to build from * @param rootName String name for the root * Element * of the Document * @param rowName String name for the each immediate child * Element of the root * @param ns Namespace to use for each Element */ public ResultSetBuilder(ResultSet rs, String rootName, String rowName, Namespace ns) { this(rs, rootName, rowName); setNamespace(ns); } /** *

* This builds a Document from the * java.sql.ResultSet. *

* * @return Document - resultant Document object. * @throws JDOMException when there is a problem * with the build. * */ public Document build() throws JDOMException { if (exception != null) { throw new JDOMException("Database problem", exception); } try { int colCount = rsmd.getColumnCount(); Element root = new Element(rootName, ns); Document doc = new Document(root); int rowCount = 0; // get the column labels for this record set String[] columnName = new String[colCount]; for (int index = 0; index < colCount; index++) { columnName[index] = rsmd.getColumnName(index+1); } // build the org.jdom.Document out of the result set String name; String value = ""; Element entry; Element child; while (rs.next() && (rowCount++ < maxRows)) { entry = new Element(rowName, ns); for (int col = 1; col <= colCount; col++) { if (names.isEmpty()) { name = columnName[col-1]; } else { name = lookupName(columnName[col-1]); } int columnType = rsmd.getColumnType(col); if (columnType == java.sql.Types.TIMESTAMP) { java.sql.Timestamp timeStamp = rs.getTimestamp(col); if (timeStamp != null) value = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL).format(timeStamp); } else if (columnType == java.sql.Types.DATE) { java.sql.Date date = rs.getDate(col); if (date != null) value = DateFormat.getDateInstance(DateFormat.FULL).format(date); } else if(columnType == java.sql.Types.TIME) { java.sql.Time time = rs.getTime(col); if (time != null) value = DateFormat.getTimeInstance(DateFormat.FULL).format(time); } else { value = rs.getString(col); } if (!attribs.isEmpty() && isAttribute(name)) { if (!rs.wasNull()) { entry.addAttribute(name, value); } } else { child = new Element(name, ns); if (!rs.wasNull()) { child.setText(value); } entry.addContent(child); } } root.addContent(entry); } return doc; } catch (SQLException e) { throw new JDOMException("Database problem", e); } } private String lookupName(String origName) { String name = (String) names.get(origName.toLowerCase()); if (name != null) { return name; } else { return origName; } } private boolean isAttribute(String origName) { Boolean val = (Boolean) attribs.get(origName.toLowerCase()); if (val == Boolean.TRUE) { return true; } else { return false; } } /** *

* Set the name to use as the root element in * the Document *

* * @param rootName String the new name. * */ public void setRootName(String rootName) { this.rootName = rootName; } /** *

* Set the name to use as the row element in * the Document *

* * @param rowName String the new name. * */ public void setRowName(String rowName) { this.rowName = rowName; } /** *

* Set the Namespace to use for * each Element in the Document. *

* * @param ns String the namespace to use. * */ public void setNamespace(Namespace ns) { this.ns = ns; } /** *

* Set the maximum number of rows to add to your * Document. *

* * @param maxRows int * */ public void setMaxRows(int maxRows) { this.maxRows = maxRows; } /** *

* Set a column as an Attribute of a row using the * original column name. The attribute will appear as the original * column name. *

* * @param columnName String the original column name * */ public void setAsAttribute(String columnName) { attribs.put(columnName.toLowerCase(), Boolean.TRUE); } /** *

* Set a column as an Attribute of a row using the * column name. The attribute will appear as the new name provided. *

* * @param columnName String original column name * @param attribName String new name to use for the attribute * */ public void setAsAttribute(String columnName, String attribName) { attribs.put(columnName.toLowerCase(), Boolean.TRUE); names.put(columnName.toLowerCase(), attribName); } /** *

* Set a column as an Attribute of a row using the * column number. The attribute will appear as the original column * name. *

* * @param columnNum int * */ public void setAsAttribute(int columnNum) { try { String name = rsmd.getColumnName(columnNum).toLowerCase(); attribs.put(name, Boolean.TRUE); } catch (SQLException e) { exception = e; } } /** *

* Set a column as an Attribute of a row using the * column number. The attribute will appear as new name provided. *

* * @param columnNum int * @param attribName String new name to use for the attribute * */ public void setAsAttribute(int columnNum, String attribName) { try { String name = rsmd.getColumnName(columnNum).toLowerCase(); attribs.put(name, Boolean.TRUE); names.put(name, attribName); } catch (SQLException e) { exception = e; } } /** *

* Set a column as an Element of a row using the * column name. The element name will appear as the new name provided. *

* * @param columnName String original column name * @param elemName String new name to use for the element * */ public void setAsElement(String columnName, String elemName) { String name = columnName.toLowerCase(); attribs.put(name, Boolean.FALSE); names.put(name, elemName); } /** *

* Set a column as an Element of a row using the * column number. The element name will appear as new name provided. *

* * @param columnNum int * @param elemName String new name to use for the element * */ public void setAsElement(int columnNum, String elemName) { try { String name = rsmd.getColumnName(columnNum).toLowerCase(); attribs.put(name, Boolean.FALSE); names.put(name, elemName); } catch (SQLException e) { exception = e; } } /* public void setAsIngore(String columnName) { } public void setAsIngore(int columnNum) { } */ }