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.Map;
022    
023    import org.apache.commons.dbutils.RowProcessor;
024    
025    /**
026     * <p>
027     * <code>ResultSetHandler</code> implementation that returns a Map of Maps.
028     * <code>ResultSet</code> rows are converted into Maps which are then stored
029     * in a Map under the given key.
030     * </p>
031     * <p>
032     * If you had a Person table with a primary key column called ID, you could
033     * retrieve rows from the table like this:
034     * <pre>
035     * ResultSetHandler h = new KeyedHandler("id");
036     * Map found = (Map) queryRunner.query("select id, name, age from person", h);
037     * Map jane = (Map) found.get(new Long(1)); // jane's id is 1
038     * String janesName = (String) jane.get("name");
039     * Integer janesAge = (Integer) jane.get("age");
040     * </pre>
041     * Note that the "id" passed to KeyedHandler and "name" and "age" passed to the
042     * returned Map's get() method can be in any case.  The data types returned for
043     * name and age are dependent upon how your JDBC driver converts SQL column
044     * types from the Person table into Java types.
045     * </p>
046     * <p>This class is thread safe.</p>
047     *
048     * @see org.apache.commons.dbutils.ResultSetHandler
049     * @since DbUtils 1.1
050     */
051    public class KeyedHandler extends AbstractKeyedHandler<Object, Map<String, Object>> {
052    
053        /**
054         * The RowProcessor implementation to use when converting rows
055         * into Objects.
056         */
057        protected final RowProcessor convert;
058    
059        /**
060         * The column index to retrieve key values from.  Defaults to 1.
061         */
062        protected final int columnIndex;
063    
064        /**
065         * The column name to retrieve key values from.  Either columnName or
066         * columnIndex will be used but never both.
067         */
068        protected final String columnName;
069    
070        /**
071         * Creates a new instance of KeyedHandler.  The value of the first column
072         * of each row will be a key in the Map.
073         */
074        public KeyedHandler() {
075            this(ArrayHandler.ROW_PROCESSOR, 1, null);
076        }
077    
078        /**
079         * Creates a new instance of KeyedHandler.  The value of the first column
080         * of each row will be a key in the Map.
081         *
082         * @param convert The <code>RowProcessor</code> implementation
083         * to use when converting rows into Maps
084         */
085        public KeyedHandler(RowProcessor convert) {
086            this(convert, 1, null);
087        }
088    
089        /**
090         * Creates a new instance of KeyedHandler.
091         *
092         * @param columnIndex The values to use as keys in the Map are
093         * retrieved from the column at this index.
094         */
095        public KeyedHandler(int columnIndex) {
096            this(ArrayHandler.ROW_PROCESSOR, columnIndex, null);
097        }
098    
099        /**
100         * Creates a new instance of KeyedHandler.
101         *
102         * @param columnName The values to use as keys in the Map are
103         * retrieved from the column with this name.
104         */
105        public KeyedHandler(String columnName) {
106            this(ArrayHandler.ROW_PROCESSOR, 1, columnName);
107        }
108    
109        /** Private Helper
110         * @param convert The <code>RowProcessor</code> implementation
111         * to use when converting rows into Maps
112         * @param columnIndex The values to use as keys in the Map are
113         * retrieved from the column at this index.
114         * @param columnName The values to use as keys in the Map are
115         * retrieved from the column with this name.
116         */
117        private KeyedHandler(RowProcessor convert, int columnIndex,
118                String columnName) {
119            super();
120            this.convert = convert;
121            this.columnIndex = columnIndex;
122            this.columnName = columnName;
123        }
124        /**
125         * This factory method is called by <code>handle()</code> to retrieve the
126         * key value from the current <code>ResultSet</code> row.  This
127         * implementation returns <code>ResultSet.getObject()</code> for the
128         * configured key column name or index.
129         * @param rs ResultSet to create a key from
130         * @return Object from the configured key column name/index
131         * @throws SQLException if a database access error occurs
132         */
133        @Override
134        protected Object createKey(ResultSet rs) throws SQLException {
135            return (columnName == null) ? rs.getObject(columnIndex) : rs
136                    .getObject(columnName);
137        }
138    
139        /**
140         * This factory method is called by <code>handle()</code> to store the
141         * current <code>ResultSet</code> row in some object. This
142         * implementation returns a <code>Map</code> with case insensitive column
143         * names as keys.  Calls to <code>map.get("COL")</code> and
144         * <code>map.get("col")</code> return the same value.
145         * @param rs ResultSet to create a row from
146         * @return Object typed Map containing column names to values
147         * @throws SQLException if a database access error occurs
148         */
149        @Override
150        protected Map<String, Object> createRow(ResultSet rs) throws SQLException {
151            return this.convert.toMap(rs);
152        }
153    
154    }