001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.dbutils.handlers;
018:
019: import java.sql.ResultSet;
020: import java.sql.SQLException;
021: import java.util.HashMap;
022: import java.util.Map;
023:
024: import org.apache.commons.dbutils.ResultSetHandler;
025: import org.apache.commons.dbutils.RowProcessor;
026:
027: /**
028: * <p>
029: * <code>ResultSetHandler</code> implementation that returns a Map of Maps.
030: * <code>ResultSet</code> rows are converted into Maps which are then stored
031: * in a Map under the given key. Although this implementation uses Maps to
032: * store row contents, subclasses are encouraged to override the
033: * <code>createRow()</code> method to convert the rows into any kind of object.
034: * </p>
035: * <p>
036: * If you had a Person table with a primary key column called ID, you could
037: * retrieve rows from the table like this:
038: * <pre>
039: * ResultSetHandler h = new KeyedHandler("id");
040: * Map found = (Map) queryRunner.query("select id, name, age from person", h);
041: * Map jane = (Map) found.get(new Long(1)); // jane's id is 1
042: * String janesName = (String) jane.get("name");
043: * Integer janesAge = (Integer) jane.get("age");
044: * </pre>
045: * Note that the "id" passed to KeyedHandler and "name" and "age" passed to the
046: * returned Map's get() method can be in any case. The data types returned for
047: * name and age are dependent upon how your JDBC driver converts SQL column
048: * types from the Person table into Java types.
049: * </p>
050: * <p>
051: * To avoid these type issues you could subclass KeyedHandler and override
052: * <code>createRow()</code> to store rows in Java bean instances (ie. a
053: * Person class).
054: * </p>
055: * <p>This class is thread safe.</p>
056: *
057: * @see org.apache.commons.dbutils.ResultSetHandler
058: * @since DbUtils 1.1
059: */
060: public class KeyedHandler implements ResultSetHandler {
061:
062: /**
063: * The RowProcessor implementation to use when converting rows
064: * into Objects.
065: */
066: protected RowProcessor convert = ArrayHandler.ROW_PROCESSOR;
067:
068: /**
069: * The column index to retrieve key values from. Defaults to 1.
070: */
071: protected int columnIndex = 1;
072:
073: /**
074: * The column name to retrieve key values from. Either columnName or
075: * columnIndex will be used but never both.
076: */
077: protected String columnName = null;
078:
079: /**
080: * Creates a new instance of KeyedHandler. The value of the first column
081: * of each row will be a key in the Map.
082: */
083: public KeyedHandler() {
084: super ();
085: }
086:
087: /**
088: * Creates a new instance of KeyedHandler. The value of the first column
089: * of each row will be a key in the Map.
090: *
091: * @param convert The <code>RowProcessor</code> implementation
092: * to use when converting rows into Maps
093: */
094: public KeyedHandler(RowProcessor convert) {
095: super ();
096: this .convert = convert;
097: }
098:
099: /**
100: * Creates a new instance of KeyedHandler.
101: *
102: * @param columnIndex The values to use as keys in the Map are
103: * retrieved from the column at this index.
104: */
105: public KeyedHandler(int columnIndex) {
106: super ();
107: this .columnIndex = columnIndex;
108: }
109:
110: /**
111: * Creates a new instance of KeyedHandler.
112: *
113: * @param columnName The values to use as keys in the Map are
114: * retrieved from the column with this name.
115: */
116: public KeyedHandler(String columnName) {
117: super ();
118: this .columnName = columnName;
119: }
120:
121: /**
122: * Convert each row's columns into a Map and store then
123: * in a <code>Map</code> under <code>ResultSet.getObject(key)</code> key.
124: *
125: * @return A <code>Map</code> of Maps, never <code>null</code>.
126: * @throws SQLException if a database access error occurs
127: * @see org.apache.commons.dbutils.ResultSetHandler#handle(java.sql.ResultSet)
128: */
129: public Object handle(ResultSet rs) throws SQLException {
130: Map result = createMap();
131: while (rs.next()) {
132: result.put(createKey(rs), createRow(rs));
133: }
134: return result;
135: }
136:
137: /**
138: * This factory method is called by <code>handle()</code> to create the Map
139: * to store records in. This implementation returns a <code>HashMap</code>
140: * instance.
141: *
142: * @return Map to store records in
143: */
144: protected Map createMap() {
145: return new HashMap();
146: }
147:
148: /**
149: * This factory method is called by <code>handle()</code> to retrieve the
150: * key value from the current <code>ResultSet</code> row. This
151: * implementation returns <code>ResultSet.getObject()</code> for the
152: * configured key column name or index.
153: * @param rs ResultSet to create a key from
154: * @return Object from the configured key column name/index
155: * @throws SQLException if a database access error occurs
156: */
157: protected Object createKey(ResultSet rs) throws SQLException {
158: return (columnName == null) ? rs.getObject(columnIndex) : rs
159: .getObject(columnName);
160: }
161:
162: /**
163: * This factory method is called by <code>handle()</code> to store the
164: * current <code>ResultSet</code> row in some object. This
165: * implementation returns a <code>Map</code> with case insensitive column
166: * names as keys. Calls to <code>map.get("COL")</code> and
167: * <code>map.get("col")</code> return the same value.
168: * @param rs ResultSet to create a row from
169: * @return Object typed Map containing column names to values
170: * @throws SQLException if a database access error occurs
171: */
172: protected Object createRow(ResultSet rs) throws SQLException {
173: return this.convert.toMap(rs);
174: }
175:
176: }
|