001: /*
002: * $Id: ResultSetBean.java,v 1.9 2005/05/03 17:22:38 spal Exp $
003: * $Source: /cvsroot/sqlunit/sqlunit/src/net/sourceforge/sqlunit/beans/ResultSetBean.java,v $
004: * SQLUnit - a test harness for unit testing database stored procedures.
005: * Copyright (C) 2003 The SQLUnit Team
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: */
021: package net.sourceforge.sqlunit.beans;
022:
023: import net.sourceforge.sqlunit.IErrorCodes;
024: import net.sourceforge.sqlunit.IType;
025: import net.sourceforge.sqlunit.SQLUnitException;
026: import net.sourceforge.sqlunit.SymbolTable;
027: import net.sourceforge.sqlunit.TypeFactory;
028: import net.sourceforge.sqlunit.types.BinaryType;
029: import net.sourceforge.sqlunit.types.TextType;
030: import net.sourceforge.sqlunit.utils.TypeUtils;
031:
032: import org.apache.log4j.Logger;
033: import org.jdom.Element;
034:
035: import java.sql.ResultSet;
036: import java.sql.ResultSetMetaData;
037: import java.sql.SQLException;
038: import java.util.ArrayList;
039: import java.util.Arrays;
040: import java.util.List;
041:
042: /**
043: * Models a ResultSet element, wrapping multiple Row objects.
044: * @author Sujit Pal (spal@users.sourceforge.net)
045: * @version $Revision: 1.9 $
046: */
047: public class ResultSetBean {
048:
049: private static final Logger LOG = Logger
050: .getLogger(ResultSetBean.class);
051:
052: private String id;
053: private boolean partial = false; // the default if not specified
054: private int rowCount = -1; // the default if not specified
055: private String[] sortBy = null; // the default if not specified
056: private Row[] rows = new Row[0];
057: private boolean isRowCountOverriden = false;
058:
059: /**
060: * Default constructor.
061: */
062: public ResultSetBean() {
063: // default constructor
064: }
065:
066: /**
067: * Constructs and populates a ResultSetBean object from a ResultSet
068: * object.
069: * @param rs the ResultSet object to build from.
070: * @param id the id for the resultset, defaults to 1 if not set.
071: * @exception SQLUnitException if there was a problem building the bean.
072: */
073: public ResultSetBean(final ResultSet rs, final int id)
074: throws SQLUnitException {
075: this ();
076: setId((new Integer(id)).toString());
077: SymbolTable.setCurrentResultSet((new Integer(id)).toString());
078: try {
079: List rowList = new ArrayList();
080: ResultSetMetaData rsmd = rs.getMetaData();
081: int numCols = rsmd.getColumnCount();
082: int rowId = 1;
083: while (rs.next()) {
084: SymbolTable.setCurrentRow((new Integer(rowId))
085: .toString());
086: Col[] cols = new Col[numCols];
087: for (int colId = 1; colId <= numCols; colId++) {
088: int colType = rsmd.getColumnType(colId);
089: SymbolTable.setCurrentCol((new Integer(colId))
090: .toString());
091: IType colTypeObj = TypeFactory.getInstance(colType);
092: // some type checks here
093: Object colValue;
094: if (colTypeObj instanceof BinaryType) {
095: colValue = rs.getBinaryStream(colId);
096: } else if (colTypeObj instanceof TextType) {
097: colValue = rs.getAsciiStream(colId);
098: } else {
099: colValue = rs.getObject(colId);
100: }
101: cols[colId - 1] = new Col();
102: cols[colId - 1].setId((new Integer(colId))
103: .toString());
104: cols[colId - 1].setName(rsmd.getColumnName(colId));
105: cols[colId - 1].setType(TypeUtils
106: .getXmlTypeFromSqlType(colType));
107: cols[colId - 1].setValue(colTypeObj
108: .toString(colValue));
109: }
110: rowList.add(cols);
111: rowId++;
112: }
113: int numRows = rowList.size();
114: Row[] theRows = new Row[numRows];
115: for (int i = 0; i < numRows; i++) {
116: theRows[i] = new Row();
117: theRows[i].setId((new Integer(i + 1)).toString());
118: theRows[i].setCols((Col[]) rowList.get(i));
119: }
120: setRows(theRows);
121: rs.close();
122: } catch (SQLException e) {
123: throw new SQLUnitException(IErrorCodes.GENERIC_ERROR,
124: new String[] { "SQL", e.getClass().getName(),
125: e.getMessage() }, e);
126: }
127: }
128:
129: /**
130: * Returns the Id for this row.
131: * @return the id for this row.
132: */
133: public final String getId() {
134: return id;
135: }
136:
137: /**
138: * Set the id for this row.
139: * @param id the id for this row.
140: */
141: public final void setId(final String id) {
142: this .id = id;
143: }
144:
145: /**
146: * Return true if the resultset specifies rows partially, else false.
147: * @return true if rows are partially specified. Default is false.
148: */
149: public final boolean isPartial() {
150: return partial;
151: }
152:
153: /**
154: * Sets the partial row specification attribute for the resultset.
155: * @param partial true or false.
156: */
157: public final void setPartial(String partial) {
158: this .partial = (partial.equals("true"));
159: }
160:
161: /**
162: * Returns the rowCount override (if specified) for the resultset. If
163: * the rowcount has been set from the rowcount attribute (overrides
164: * the actual value of the rowcount), then it returns that, else it
165: * returns the number of Row objects.
166: * @return the rowcount override (if specified) for the resultset.
167: */
168: public final int getRowCount() {
169: if (rowCount != -1) { // overriden
170: return rowCount;
171: } else {
172: return getRows().length;
173: }
174: }
175:
176: /**
177: * Sets the rowCount override for the resultset.
178: * @param rowCount the rowcount override to set.
179: */
180: public final void setRowCount(final int rowCount) {
181: this .rowCount = rowCount;
182: this .isRowCountOverriden = true;
183: }
184:
185: /**
186: * Returns true if rowcount has been overriden by the caller.
187: * @return true if rowcount has been overriden by caller.
188: */
189: public final boolean isRowCountOverriden() {
190: return this .isRowCountOverriden;
191: }
192:
193: /**
194: * Returns the rows in the resultset.
195: * @return an array of Row objects in the ResultSet object.
196: */
197: public final Row[] getRows() {
198: return rows;
199: }
200:
201: /**
202: * Sets the rows in the resultset.
203: * @param rows an array of Row objects to set.
204: */
205: public final void setRows(final Row[] rows) {
206: this .rows = rows;
207: }
208:
209: /**
210: * Returns the array of column ids on which the rows of this ResultSetBean
211: * was sorted. This value is set as a side-effect of the sortBy() call.
212: * @return an array of column ids.
213: */
214: public final String[] getSortBy() {
215: return sortBy;
216: }
217:
218: /**
219: * Sets the colIds from the colIdList.
220: * @param colIdList a comma-separated list of col ids to sort by.
221: */
222: public final void setSortBy(final String colIdList) {
223: this .sortBy = colIdList.split("\\s*,\\s*");
224: }
225:
226: /**
227: * Allows sorting of rows in a resultset by the columns specified in
228: * the sortColIds array.
229: */
230: public final void sort() {
231: // no sorting needed for this condition
232: if (rows == null || rows.length <= 1) {
233: return;
234: }
235: // no sort columns specified, repopulate sortColIds with all col ids
236: boolean isNaturallySorted = false;
237: if (this .sortBy == null || this .sortBy.length == 0) {
238: Col[] colsInRow = rows[0].getCols();
239: this .sortBy = new String[colsInRow.length];
240: for (int i = 0; i < colsInRow.length; i++) {
241: this .sortBy[i] = colsInRow[i].getId();
242: }
243: isNaturallySorted = true;
244: }
245: // set up the rows for sorting
246: for (int i = 0; i < rows.length; i++) {
247: rows[i].setSortCols(this .sortBy);
248: }
249: // sort it
250: Object[] rowObjs = (Object[]) rows;
251: Arrays.sort(rowObjs);
252: rows = (Row[]) rowObjs;
253: // if naturally sorted, reset the sortBy field
254: if (isNaturallySorted) {
255: this .sortBy = null;
256: }
257: }
258:
259: /**
260: * Returns a JDOM Element representing this ResultSet object.
261: * @return a JDOM Element representing this ResultSet object.
262: */
263: public final Element toElement() {
264: Element elResultSet = new Element("resultset");
265: elResultSet.setAttribute("id", getId());
266: if (isRowCountOverriden()) {
267: elResultSet.setAttribute("rowcount", (new Integer(
268: getRowCount())).toString());
269: }
270: Row[] theRows = getRows();
271: for (int i = 0; i < theRows.length; i++) {
272: Element elRow = theRows[i].toElement();
273: elResultSet.addContent(elRow);
274: }
275: return elResultSet;
276: }
277:
278: /**
279: * Useful method for debugging. Returns the String representation
280: * of this ResultSetBean.
281: * @return the String representation of this result set bean.
282: */
283: public final String toString() {
284: StringBuffer buffer = new StringBuffer();
285: Row[] theRows = getRows();
286: for (int i = 0; i < theRows.length; i++) {
287: buffer.append(theRows[i].toString()).append("\n");
288: }
289: return buffer.toString();
290: }
291: }
|