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.util.List;
  18. import java.util.Map;
  19. import javax.sql.DataSource;
  20. import org.springframework.dao.DataAccessException;
  21. import org.springframework.dao.support.DataAccessUtils;
  22. import org.springframework.jdbc.core.ResultReader;
  23. /**
  24. * Reusable threadsafe object to represent a SQL query. Subclasses must
  25. * implement the <code>newResultReader</code> method to provide an object
  26. * that can save the results of iterating over the ResultSet.
  27. *
  28. * <p>This class provides a number of public <code>execute</code> methods that are
  29. * analogous to the different convenient JDO query execute methods. Subclasses
  30. * can either rely on one of these inherited methods, or can add their own
  31. * custom execution methods, with meaningful names and typed parameters. Each
  32. * custom query method will invoke one of this class's untype query methods.
  33. *
  34. * @author Rod Johnson
  35. * @author Jean-Pierre Pawlak
  36. * @version $Id: SqlQuery.java,v 1.8 2004/05/28 14:13:13 jhoeller Exp $
  37. */
  38. public abstract class SqlQuery extends SqlOperation {
  39. /** Number of rows to expect. If 0, unknown. */
  40. private int rowsExpected = 0;
  41. //-------------------------------------------------------------------------
  42. // Constructors
  43. //-------------------------------------------------------------------------
  44. /**
  45. * Constructor to allow use as a JavaBean. DataSource and SQL
  46. * must be supplied before compilation and use.
  47. */
  48. public SqlQuery() {
  49. }
  50. /**
  51. * Convenient constructor with DataSource and SQL string.
  52. * @param ds DataSource to use to get connections
  53. * @param sql to execute. SQL can also be supplied at runtime
  54. * by overriding the getSql() method.
  55. */
  56. public SqlQuery(DataSource ds, String sql) {
  57. setDataSource(ds);
  58. setSql(sql);
  59. }
  60. //-------------------------------------------------------------------------
  61. // Bean properties
  62. //-------------------------------------------------------------------------
  63. /**
  64. * Set the number of rows expected. This can be used to ensure
  65. * efficient storage of results. The default behavior is not to
  66. * expect any specific number of rows.
  67. */
  68. public void setRowsExpected(int rowsExpected) {
  69. this.rowsExpected = rowsExpected;
  70. }
  71. /**
  72. * Get the number of rows expected.
  73. */
  74. public int getRowsExpected() {
  75. return rowsExpected;
  76. }
  77. //-------------------------------------------------------------------------
  78. // Execute methods
  79. //-------------------------------------------------------------------------
  80. /**
  81. * Central execution method. All execution goes through this method.
  82. * @param parameters parameters, similar to JDO query parameters.
  83. * Primitive parameters must be represented by their Object wrapper type.
  84. * The ordering of parameters is significant.
  85. * @param context contextual information passed to the callback mapRow method.
  86. * This parameter doesn't rely on the JDBC request itself, but can be useful
  87. * for creating the objects of the result list.
  88. * @return a List of objects, one per row of the ResultSet. Normally all these
  89. * will be of the same class, although it is possible to use different types.
  90. */
  91. public List execute(final Object[] parameters, Map context) throws DataAccessException {
  92. validateParameters(parameters);
  93. ResultReader rr = newResultReader(this.rowsExpected, parameters, context);
  94. return getJdbcTemplate().query(newPreparedStatementCreator(parameters), rr);
  95. }
  96. /**
  97. * Convenient method to execute without context.
  98. * @param parameters parameters, as to JDO queries. Primitive parameters must
  99. * be represented by their Object wrapper type. The ordering of parameters is
  100. * significant.
  101. */
  102. public List execute(final Object[] parameters) throws DataAccessException {
  103. return execute(parameters, null);
  104. }
  105. /**
  106. * Convenient method to execute without parameters.
  107. * @param context The contextual information for object creation
  108. */
  109. public List execute(Map context) throws DataAccessException {
  110. return execute((Object[]) null, context);
  111. }
  112. /**
  113. * Convenient method to execute without parameters nor context.
  114. */
  115. public List execute() throws DataAccessException {
  116. return execute((Object[]) null);
  117. }
  118. /**
  119. * Convenient method to execute with a single int parameter and context.
  120. * @param p1 single int parameter
  121. * @param context the contextual information for object creation
  122. */
  123. public List execute(int p1, Map context) throws DataAccessException {
  124. return execute(new Object[] {new Integer(p1)}, context);
  125. }
  126. /**
  127. * Convenient method to execute with a single int parameter.
  128. * @param p1 single int parameter
  129. */
  130. public List execute(int p1) throws DataAccessException {
  131. return execute(p1, null);
  132. }
  133. /**
  134. * Convenient method to execute with two int parameters and context.
  135. * @param p1 first int parameter
  136. * @param p2 second int parameter
  137. * @param context the contextual information for object creation
  138. */
  139. public List execute(int p1, int p2, Map context) throws DataAccessException {
  140. return execute(new Object[] {new Integer(p1), new Integer(p2)}, context);
  141. }
  142. /**
  143. * Convenient method to execute with two int parameters.
  144. * @param p1 first int parameter
  145. * @param p2 second int parameter
  146. */
  147. public List execute(int p1, int p2) throws DataAccessException {
  148. return execute(p1, p2, null);
  149. }
  150. /**
  151. * Convenient method to execute with a single long parameter and context.
  152. * @param p1 single long parameter
  153. * @param context the contextual information for object creation
  154. */
  155. public List execute(long p1, Map context) throws DataAccessException {
  156. return execute(new Object[] {new Long(p1)}, context);
  157. }
  158. /**
  159. * Convenient method to execute with a single long parameter.
  160. * @param p1 single long parameter
  161. */
  162. public List execute(long p1) throws DataAccessException {
  163. return execute(p1, null);
  164. }
  165. /**
  166. * Convenient method to execute with a single String parameter and context.
  167. * @param p1 single String parameter
  168. * @param context the contextual information for object creation
  169. */
  170. public List execute(String p1, Map context) throws DataAccessException {
  171. return execute(new Object[] {p1}, context);
  172. }
  173. /**
  174. * Convenient method to execute with a single String parameter.
  175. * @param p1 single String parameter
  176. */
  177. public List execute(String p1) throws DataAccessException {
  178. return execute(p1, null);
  179. }
  180. /**
  181. * Generic findObject method, used by all other findObject() methods.
  182. * findObject() methods are like EJB entity bean finders, in that it is
  183. * considered an error if they return more than one result.
  184. * @return null if not found. Subclasses may choose to treat this
  185. * as an error and throw an exception.
  186. * @see org.springframework.dao.support.DataAccessUtils#uniqueResult
  187. */
  188. public Object findObject(Object[] parameters, Map context) throws DataAccessException {
  189. List results = execute(parameters, context);
  190. return DataAccessUtils.uniqueResult(results);
  191. }
  192. /**
  193. * Convenient method to find a single object without context.
  194. */
  195. public Object findObject(Object[] parameters) throws DataAccessException {
  196. return findObject(parameters, null);
  197. }
  198. /**
  199. * Convenient method to find a single object given a single int parameter
  200. * and a context.
  201. */
  202. public Object findObject(int p1, Map context) throws DataAccessException {
  203. return findObject(new Object[] {new Integer(p1)}, context);
  204. }
  205. /**
  206. * Convenient method to find a single object given a single int parameter.
  207. */
  208. public Object findObject(int p1) throws DataAccessException {
  209. return findObject(p1, null);
  210. }
  211. /**
  212. * Convenient method to find a single object given two int parameters
  213. * and a context.
  214. */
  215. public Object findObject(int p1, int p2, Map context) throws DataAccessException {
  216. return findObject(new Object[] {new Integer(p1), new Integer(p2)}, context);
  217. }
  218. /**
  219. * Convenient method to find a single object given two int parameters.
  220. */
  221. public Object findObject(int p1, int p2) throws DataAccessException {
  222. return findObject(p1, p2, null);
  223. }
  224. /**
  225. * Convenient method to find a single object given a single long parameter
  226. * and a context.
  227. */
  228. public Object findObject(long p1, Map context) throws DataAccessException {
  229. return findObject(new Object[] {new Long(p1)}, context);
  230. }
  231. /**
  232. * Convenient method to find a single object given a single long parameter.
  233. */
  234. public Object findObject(long p1) throws DataAccessException {
  235. return findObject(p1, null);
  236. }
  237. /**
  238. * Convenient method to find a single object given a single String parameter
  239. * and a context.
  240. */
  241. public Object findObject(String p1, Map context) throws DataAccessException {
  242. return findObject(new Object[] {p1}, context);
  243. }
  244. /**
  245. * Convenient method to find a single object given a single String parameter.
  246. */
  247. public Object findObject(String p1) throws DataAccessException {
  248. return findObject(p1, null);
  249. }
  250. //-------------------------------------------------------------------------
  251. // Methods to be implemented by subclasses
  252. //-------------------------------------------------------------------------
  253. /**
  254. * Subclasses must implement this method to save a List of objects
  255. * returned by the execute method.
  256. * @param rowsExpected If 0, we don't know how many rows to expect.
  257. * This parameter can be ignored, but may help some implementations
  258. * choose the most efficient Collection type: e.g. ArrayList
  259. * instead of LinkedList for large result sets.
  260. * @param parameters parameters to the execute() method, in case subclass
  261. * is interested. May be null if there were no parameters.
  262. * @see #execute
  263. */
  264. protected abstract ResultReader newResultReader(int rowsExpected, Object[] parameters, Map context);
  265. }