1. /*
  2. * Copyright 2002-2004 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. package org.springframework.jdbc.object;
  17. import java.sql.ResultSet;
  18. import java.sql.SQLException;
  19. import java.util.ArrayList;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.Map;
  23. import javax.sql.DataSource;
  24. import org.springframework.jdbc.core.ResultReader;
  25. /**
  26. * Reusable RDBMS query in which concrete subclasses must implement
  27. * the abstract updateRow(ResultSet, int, context) method to update each
  28. * row of the JDBC ResultSet and optionally map contents into an object.
  29. *
  30. * <p>Subclasses can be constructed providing SQL, parameter types
  31. * and a DataSource. SQL will often vary between subclasses.
  32. *
  33. * @author Thomas Risberg
  34. * @see org.springframework.jdbc.object.SqlQuery
  35. */
  36. public abstract class UpdatableSqlQuery extends SqlQuery {
  37. /**
  38. * Constructor to allow use as a JavaBean
  39. */
  40. public UpdatableSqlQuery() {
  41. setUpdatableResults(true);
  42. }
  43. /**
  44. * Convenient constructor with DataSource and SQL string.
  45. * @param ds DataSource to use to get connections
  46. * @param sql SQL to run
  47. */
  48. public UpdatableSqlQuery(DataSource ds, String sql) {
  49. super(ds, sql);
  50. setUpdatableResults(true);
  51. }
  52. /**
  53. * Implementation of protected abstract method. This invokes the subclass's
  54. * implementation of the updateRow() method.
  55. */
  56. protected ResultReader newResultReader(int rowsExpected, Object[] parameters, Map context) {
  57. return new ResultReaderImpl(rowsExpected, context);
  58. }
  59. /**
  60. * Subclasses must implement this method to update each row of the
  61. * ResultSet and optionally create object of the result type.
  62. * @param rs ResultSet we're working through
  63. * @param rowNum row number (from 0) we're up to
  64. * @param context passed to the execute() method.
  65. * It can be null if no contextual information is need. If you
  66. * need to pass in data for each row, you can pass in a HashMap with
  67. * the primary key of the row being the key for the HashMap. That way
  68. * it is easy to locate the updates for each row
  69. * @return an object of the result type
  70. * @throws SQLException if there's an error updateing data.
  71. * Subclasses can simply not catch SQLExceptions, relying on the
  72. * framework to clean up.
  73. */
  74. protected abstract Object updateRow(ResultSet rs, int rowNum, Map context) throws SQLException;
  75. /**
  76. * Implementation of ResultReader that calls the enclosing
  77. * class's updateRow() method for each row.
  78. */
  79. protected class ResultReaderImpl implements ResultReader {
  80. /** List to save results in */
  81. private final List results;
  82. private final Map context;
  83. private int rowNum = 0;
  84. /**
  85. * Use an array results. More efficient if we know how many results to expect.
  86. */
  87. public ResultReaderImpl(int rowsExpected, Map context) {
  88. // use the more efficient collection if we know how many rows to expect
  89. this.results = (rowsExpected > 0) ? (List) new ArrayList(rowsExpected) : (List) new LinkedList();
  90. this.context = context;
  91. }
  92. public void processRow(ResultSet rs) throws SQLException {
  93. this.results.add(updateRow(rs, this.rowNum++, this.context));
  94. rs.updateRow();
  95. }
  96. public List getResults() {
  97. return this.results;
  98. }
  99. }
  100. }