001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jdbc.object;
018:
019: import java.util.List;
020: import java.util.Map;
021:
022: import javax.sql.DataSource;
023:
024: import org.springframework.dao.DataAccessException;
025: import org.springframework.dao.support.DataAccessUtils;
026: import org.springframework.jdbc.core.RowMapper;
027: import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
028: import org.springframework.jdbc.core.namedparam.NamedParameterUtils;
029: import org.springframework.jdbc.core.namedparam.ParsedSql;
030:
031: /**
032: * Reusable operation object representing a SQL query.
033: *
034: * <p>Subclasses must implement the {@link #newRowMapper} method to provide
035: * an object that can extract the results of iterating over the
036: * <code>ResultSet</code> created during the execution of the query.
037: *
038: * <p>This class provides a number of public <code>execute</code> methods that are
039: * analogous to the different convenient JDO query execute methods. Subclasses
040: * can either rely on one of these inherited methods, or can add their own
041: * custom execution methods, with meaningful names and typed parameters
042: * (definitely a best practice). Each custom query method will invoke one of
043: * this class's untyped query methods.
044: *
045: * <p>Like all <code>RdbmsOperation</code> classes that ship with the Spring
046: * Framework, <code>SqlQuery</code> instances are thread-safe after their
047: * initialization is complete. That is, after they are constructed and configured
048: * via their setter methods, they can be used safely from multiple threads.
049: *
050: * @author Rod Johnson
051: * @author Juergen Hoeller
052: * @author Thomas Risberg
053: * @see SqlUpdate
054: */
055: public abstract class SqlQuery extends SqlOperation {
056:
057: /** The number of rows to expect; if 0, unknown. */
058: private int rowsExpected = 0;
059:
060: /**
061: * Constructor to allow use as a JavaBean.
062: * <p>The <code>DataSource</code> and SQL must be supplied before
063: * compilation and use.
064: */
065: public SqlQuery() {
066: }
067:
068: /**
069: * Convenient constructor with a <code>DataSource</code> and SQL string.
070: * @param ds the <code>DataSource</code> to use to get connections
071: * @param sql the SQL to execute; SQL can also be supplied at runtime
072: * by overriding the {@link #getSql()} method.
073: */
074: public SqlQuery(DataSource ds, String sql) {
075: setDataSource(ds);
076: setSql(sql);
077: }
078:
079: /**
080: * Set the number of rows expected.
081: * <p>This can be used to ensure efficient storage of results. The
082: * default behavior is not to expect any specific number of rows.
083: */
084: public void setRowsExpected(int rowsExpected) {
085: this .rowsExpected = rowsExpected;
086: }
087:
088: /**
089: * Get the number of rows expected.
090: */
091: public int getRowsExpected() {
092: return this .rowsExpected;
093: }
094:
095: /**
096: * Central execution method. All un-named parameter execution goes through this method.
097: * @param params parameters, similar to JDO query parameters.
098: * Primitive parameters must be represented by their Object wrapper type.
099: * The ordering of parameters is significant.
100: * @param context contextual information passed to the <code>mapRow</code>
101: * callback method. The JDBC operation itself doesn't rely on this parameter,
102: * but it can be useful for creating the objects of the result list.
103: * @return a List of objects, one per row of the ResultSet. Normally all these
104: * will be of the same class, although it is possible to use different types.
105: */
106: public List execute(Object[] params, Map context)
107: throws DataAccessException {
108: validateParameters(params);
109: RowMapper rowMapper = newRowMapper(params, context);
110: return getJdbcTemplate().query(
111: newPreparedStatementCreator(params), rowMapper);
112: }
113:
114: /**
115: * Convenient method to execute without context.
116: * @param params parameters for the query. Primitive parameters must
117: * be represented by their Object wrapper type. The ordering of parameters is
118: * significant.
119: */
120: public List execute(Object[] params) throws DataAccessException {
121: return execute(params, null);
122: }
123:
124: /**
125: * Convenient method to execute without parameters.
126: * @param context the contextual information for object creation
127: */
128: public List execute(Map context) throws DataAccessException {
129: return execute((Object[]) null, context);
130: }
131:
132: /**
133: * Convenient method to execute without parameters nor context.
134: */
135: public List execute() throws DataAccessException {
136: return execute((Object[]) null);
137: }
138:
139: /**
140: * Convenient method to execute with a single int parameter and context.
141: * @param p1 single int parameter
142: * @param context the contextual information for object creation
143: */
144: public List execute(int p1, Map context) throws DataAccessException {
145: return execute(new Object[] { new Integer(p1) }, context);
146: }
147:
148: /**
149: * Convenient method to execute with a single int parameter.
150: * @param p1 single int parameter
151: */
152: public List execute(int p1) throws DataAccessException {
153: return execute(p1, null);
154: }
155:
156: /**
157: * Convenient method to execute with two int parameters and context.
158: * @param p1 first int parameter
159: * @param p2 second int parameter
160: * @param context the contextual information for object creation
161: */
162: public List execute(int p1, int p2, Map context)
163: throws DataAccessException {
164: return execute(
165: new Object[] { new Integer(p1), new Integer(p2) },
166: context);
167: }
168:
169: /**
170: * Convenient method to execute with two int parameters.
171: * @param p1 first int parameter
172: * @param p2 second int parameter
173: */
174: public List execute(int p1, int p2) throws DataAccessException {
175: return execute(p1, p2, null);
176: }
177:
178: /**
179: * Convenient method to execute with a single long parameter and context.
180: * @param p1 single long parameter
181: * @param context the contextual information for object creation
182: */
183: public List execute(long p1, Map context)
184: throws DataAccessException {
185: return execute(new Object[] { new Long(p1) }, context);
186: }
187:
188: /**
189: * Convenient method to execute with a single long parameter.
190: * @param p1 single long parameter
191: */
192: public List execute(long p1) throws DataAccessException {
193: return execute(p1, null);
194: }
195:
196: /**
197: * Convenient method to execute with a single String parameter and context.
198: * @param p1 single String parameter
199: * @param context the contextual information for object creation
200: */
201: public List execute(String p1, Map context)
202: throws DataAccessException {
203: return execute(new Object[] { p1 }, context);
204: }
205:
206: /**
207: * Convenient method to execute with a single String parameter.
208: * @param p1 single String parameter
209: */
210: public List execute(String p1) throws DataAccessException {
211: return execute(p1, null);
212: }
213:
214: /**
215: * Central execution method. All named parameter execution goes through this method.
216: * @param paramMap parameters associated with the name specified while declaring
217: * the SqlParameters. Primitive parameters must be represented by their Object wrapper
218: * type. The ordering of parameters is not significant since they are supplied in a
219: * SqlParameterMap which is an implementation of the Map interface.
220: * @param context contextual information passed to the <code>mapRow</code>
221: * callback method. The JDBC operation itself doesn't rely on this parameter,
222: * but it can be useful for creating the objects of the result list.
223: * @return a List of objects, one per row of the ResultSet. Normally all these
224: * will be of the same class, although it is possible to use different types.
225: */
226: public List executeByNamedParam(Map paramMap, Map context)
227: throws DataAccessException {
228: validateNamedParameters(paramMap);
229: ParsedSql parsedSql = getParsedSql();
230: MapSqlParameterSource paramSource = new MapSqlParameterSource(
231: paramMap);
232: String sqlToUse = NamedParameterUtils
233: .substituteNamedParameters(parsedSql, paramSource);
234: Object[] params = NamedParameterUtils.buildValueArray(
235: parsedSql, paramSource, getDeclaredParameters());
236: RowMapper rowMapper = newRowMapper(params, context);
237: return getJdbcTemplate().query(
238: newPreparedStatementCreator(sqlToUse, params),
239: rowMapper);
240: }
241:
242: /**
243: * Convenient method to execute without context.
244: * @param paramMap parameters associated with the name specified while declaring
245: * the SqlParameters. Primitive parameters must be represented by their Object wrapper
246: * type. The ordering of parameters is not significant.
247: */
248: public List executeByNamedParam(Map paramMap)
249: throws DataAccessException {
250: return executeByNamedParam(paramMap, null);
251: }
252:
253: /**
254: * Generic object finder method, used by all other <code>findObject</code> methods.
255: * Object finder methods are like EJB entity bean finders, in that it is
256: * considered an error if they return more than one result.
257: * @return the result object, or <code>null</code> if not found. Subclasses may
258: * choose to treat this as an error and throw an exception.
259: * @see org.springframework.dao.support.DataAccessUtils#singleResult
260: */
261: public Object findObject(Object[] params, Map context)
262: throws DataAccessException {
263: List results = execute(params, context);
264: return DataAccessUtils.singleResult(results);
265: }
266:
267: /**
268: * Convenient method to find a single object without context.
269: */
270: public Object findObject(Object[] params)
271: throws DataAccessException {
272: return findObject(params, null);
273: }
274:
275: /**
276: * Convenient method to find a single object given a single int parameter
277: * and a context.
278: */
279: public Object findObject(int p1, Map context)
280: throws DataAccessException {
281: return findObject(new Object[] { new Integer(p1) }, context);
282: }
283:
284: /**
285: * Convenient method to find a single object given a single int parameter.
286: */
287: public Object findObject(int p1) throws DataAccessException {
288: return findObject(p1, null);
289: }
290:
291: /**
292: * Convenient method to find a single object given two int parameters
293: * and a context.
294: */
295: public Object findObject(int p1, int p2, Map context)
296: throws DataAccessException {
297: return findObject(new Object[] { new Integer(p1),
298: new Integer(p2) }, context);
299: }
300:
301: /**
302: * Convenient method to find a single object given two int parameters.
303: */
304: public Object findObject(int p1, int p2) throws DataAccessException {
305: return findObject(p1, p2, null);
306: }
307:
308: /**
309: * Convenient method to find a single object given a single long parameter
310: * and a context.
311: */
312: public Object findObject(long p1, Map context)
313: throws DataAccessException {
314: return findObject(new Object[] { new Long(p1) }, context);
315: }
316:
317: /**
318: * Convenient method to find a single object given a single long parameter.
319: */
320: public Object findObject(long p1) throws DataAccessException {
321: return findObject(p1, null);
322: }
323:
324: /**
325: * Convenient method to find a single object given a single String parameter
326: * and a context.
327: */
328: public Object findObject(String p1, Map context)
329: throws DataAccessException {
330: return findObject(new Object[] { p1 }, context);
331: }
332:
333: /**
334: * Convenient method to find a single object given a single String parameter.
335: */
336: public Object findObject(String p1) throws DataAccessException {
337: return findObject(p1, null);
338: }
339:
340: /**
341: * Generic object finder method for named parameters.
342: * @param paramMap Map of parameter name to parameter object,
343: * matching named parameters specified in the SQL statement.
344: * Ordering is not significant.
345: * @param context contextual information passed to the <code>mapRow</code>
346: * callback method. The JDBC operation itself doesn't rely on this parameter,
347: * but it can be useful for creating the objects of the result list.
348: * @return a List of objects, one per row of the ResultSet. Normally all these
349: * will be of the same class, although it is possible to use different types.
350: */
351: public Object findObjectByNamedParam(Map paramMap, Map context)
352: throws DataAccessException {
353: List results = executeByNamedParam(paramMap, context);
354: return DataAccessUtils.singleResult(results);
355: }
356:
357: /**
358: * Convenient method to execute without context.
359: * @param paramMap Map of parameter name to parameter object,
360: * matching named parameters specified in the SQL statement.
361: * Ordering is not significant.
362: */
363: public Object findObjectByNamedParam(Map paramMap)
364: throws DataAccessException {
365: return findObjectByNamedParam(paramMap, null);
366: }
367:
368: /**
369: * Subclasses must implement this method to extract an object per row, to be
370: * returned by the <cod>execute</code> method as an aggregated {@link List}.
371: * @param parameters the parameters to the <code>execute()</code> method,
372: * in case subclass is interested; may be <code>null</code> if there
373: * were no parameters.
374: * @param context contextual information passed to the <code>mapRow</code>
375: * callback method. The JDBC operation itself doesn't rely on this parameter,
376: * but it can be useful for creating the objects of the result list.
377: * @see #execute
378: */
379: protected abstract RowMapper newRowMapper(Object[] parameters,
380: Map context);
381:
382: }
|