1 /*
2 * Copyright 2002-2005 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.springframework.jdbc.object;
18
19 import java.sql.ResultSet;
20 import java.sql.SQLException;
21 import java.util.Map;
22
23 import javax.sql.DataSource;
24
25 import org.springframework.jdbc.core.RowMapper;
26
27 /**
28 * Reusable RDBMS query in which concrete subclasses must implement
29 * the abstract updateRow(ResultSet, int, context) method to update each
30 * row of the JDBC ResultSet and optionally map contents into an object.
31 *
32 * <p>Subclasses can be constructed providing SQL, parameter types
33 * and a DataSource. SQL will often vary between subclasses.
34 *
35 * @author Thomas Risberg
36 * @see org.springframework.jdbc.object.SqlQuery
37 */
38 public abstract class UpdatableSqlQuery extends SqlQuery {
39
40 /**
41 * Constructor to allow use as a JavaBean
42 */
43 public UpdatableSqlQuery() {
44 setUpdatableResults(true);
45 }
46
47 /**
48 * Convenient constructor with DataSource and SQL string.
49 * @param ds DataSource to use to get connections
50 * @param sql SQL to run
51 */
52 public UpdatableSqlQuery(DataSource ds, String sql) {
53 super(ds, sql);
54 setUpdatableResults(true);
55 }
56
57 /**
58 * Implementation of the superclass template method. This invokes the subclass's
59 * implementation of the <code>updateRow()</code> method.
60 */
61 protected RowMapper newRowMapper(Object[] parameters, Map context) {
62 return new RowMapperImpl(context);
63 }
64
65 /**
66 * Subclasses must implement this method to update each row of the
67 * ResultSet and optionally create object of the result type.
68 * @param rs ResultSet we're working through
69 * @param rowNum row number (from 0) we're up to
70 * @param context passed to the execute() method.
71 * It can be <code>null</code> if no contextual information is need. If you
72 * need to pass in data for each row, you can pass in a HashMap with
73 * the primary key of the row being the key for the HashMap. That way
74 * it is easy to locate the updates for each row
75 * @return an object of the result type
76 * @throws SQLException if there's an error updateing data.
77 * Subclasses can simply not catch SQLExceptions, relying on the
78 * framework to clean up.
79 */
80 protected abstract Object updateRow(ResultSet rs, int rowNum, Map context) throws SQLException;
81
82
83 /**
84 * Implementation of RowMapper that calls the enclosing
85 * class's <code>updateRow()</code> method for each row.
86 */
87 protected class RowMapperImpl implements RowMapper {
88
89 private final Map context;
90
91 public RowMapperImpl(Map context) {
92 this.context = context;
93 }
94
95 public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
96 Object result = updateRow(rs, rowNum, this.context);
97 rs.updateRow();
98 return result;
99 }
100 }
101
102 }