KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > ibatis > SqlMapClientTemplate


1 /*
2  * Copyright 2002-2006 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.orm.ibatis;
18
19 import java.sql.Connection JavaDoc;
20 import java.sql.SQLException JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import javax.sql.DataSource JavaDoc;
25
26 import com.ibatis.common.util.PaginatedList;
27 import com.ibatis.sqlmap.client.SqlMapClient;
28 import com.ibatis.sqlmap.client.SqlMapExecutor;
29 import com.ibatis.sqlmap.client.SqlMapSession;
30 import com.ibatis.sqlmap.client.event.RowHandler;
31 import com.ibatis.sqlmap.engine.impl.ExtendedSqlMapClient;
32
33 import org.springframework.dao.DataAccessException;
34 import org.springframework.dao.InvalidDataAccessApiUsageException;
35 import org.springframework.jdbc.JdbcUpdateAffectedIncorrectNumberOfRowsException;
36 import org.springframework.jdbc.datasource.DataSourceUtils;
37 import org.springframework.jdbc.support.JdbcAccessor;
38 import org.springframework.util.Assert;
39
40 /**
41  * Helper class that simplifies data access via the iBATIS
42  * {@link com.ibatis.sqlmap.client.SqlMapClient} API, converting checked
43  * SQLExceptions into unchecked DataAccessExceptions, following the
44  * <code>org.springframework.dao</code> exception hierarchy.
45  * Uses the same {@link org.springframework.jdbc.support.SQLExceptionTranslator}
46  * mechanism as {@link org.springframework.jdbc.core.JdbcTemplate}.
47  *
48  * <p>The main method of this class executes a callback that implements a
49  * data access action. Furthermore, this class provides numerous convenience
50  * methods that mirror {@link com.ibatis.sqlmap.client.SqlMapExecutor}'s
51  * execution methods.
52  *
53  * <p>It is generally recommended to use the convenience methods on this template
54  * for plain query/insert/update/delete operations. However, for more complex
55  * operations like batch updates, a custom SqlMapClientCallback must be implemented,
56  * usually as anonymous inner class. For example:
57  *
58  * <pre class="code">
59  * getSqlMapClientTemplate().execute(new SqlMapClientCallback() {
60  * public Object doInSqlMapClient(SqlMapExecutor executor) throws SQLException {
61  * executor.startBatch();
62  * executor.update("insertSomething", "myParamValue");
63  * executor.update("insertSomethingElse", "myOtherParamValue");
64  * executor.executeBatch();
65  * return null;
66  * }
67  * });</pre>
68  *
69  * The template needs a SqlMapClient to work on, passed in via the "sqlMapClient"
70  * property. A Spring context typically uses a {@link SqlMapClientFactoryBean}
71  * to build the SqlMapClient. The template an additionally be configured with a
72  * DataSource for fetching Connections, although this is not necessary if a
73  * DataSource is specified for the SqlMapClient itself (typically through
74  * SqlMapClientFactoryBean's "dataSource" property).
75  *
76  * @author Juergen Hoeller
77  * @since 24.02.2004
78  * @see #execute
79  * @see #setSqlMapClient
80  * @see #setDataSource
81  * @see #setExceptionTranslator
82  * @see SqlMapClientFactoryBean#setDataSource
83  * @see com.ibatis.sqlmap.client.SqlMapClient#getDataSource
84  * @see com.ibatis.sqlmap.client.SqlMapExecutor
85  */

86 public class SqlMapClientTemplate extends JdbcAccessor implements SqlMapClientOperations {
87
88     private SqlMapClient sqlMapClient;
89
90     private boolean lazyLoadingAvailable = true;
91
92
93     /**
94      * Create a new SqlMapClientTemplate.
95      */

96     public SqlMapClientTemplate() {
97     }
98
99     /**
100      * Create a new SqlMapTemplate.
101      * @param sqlMapClient iBATIS SqlMapClient that defines the mapped statements
102      */

103     public SqlMapClientTemplate(SqlMapClient sqlMapClient) {
104         setSqlMapClient(sqlMapClient);
105         afterPropertiesSet();
106     }
107
108     /**
109      * Create a new SqlMapTemplate.
110      * @param dataSource JDBC DataSource to obtain connections from
111      * @param sqlMapClient iBATIS SqlMapClient that defines the mapped statements
112      */

113     public SqlMapClientTemplate(DataSource JavaDoc dataSource, SqlMapClient sqlMapClient) {
114         setDataSource(dataSource);
115         setSqlMapClient(sqlMapClient);
116         afterPropertiesSet();
117     }
118
119     /**
120      * Set the iBATIS Database Layer SqlMapClient that defines the mapped statements.
121      */

122     public void setSqlMapClient(SqlMapClient sqlMapClient) {
123         this.sqlMapClient = sqlMapClient;
124     }
125
126     /**
127      * Return the iBATIS Database Layer SqlMapClient that this template works with.
128      */

129     public SqlMapClient getSqlMapClient() {
130         return sqlMapClient;
131     }
132
133     /**
134      * If no DataSource specified, use SqlMapClient's DataSource.
135      * @see com.ibatis.sqlmap.client.SqlMapClient#getDataSource
136      */

137     public DataSource JavaDoc getDataSource() {
138         DataSource JavaDoc ds = super.getDataSource();
139         return (ds != null ? ds : this.sqlMapClient.getDataSource());
140     }
141
142     public void afterPropertiesSet() {
143         if (this.sqlMapClient == null) {
144             throw new IllegalArgumentException JavaDoc("sqlMapClient is required");
145         }
146         if (this.sqlMapClient instanceof ExtendedSqlMapClient) {
147             // Check whether iBATIS lazy loading is available, that is,
148
// whether a DataSource was specified on the SqlMapClient itself.
149
this.lazyLoadingAvailable = (((ExtendedSqlMapClient) this.sqlMapClient).getDelegate().getTxManager() != null);
150         }
151         super.afterPropertiesSet();
152     }
153
154
155     /**
156      * Execute the given data access action on a SqlMapExecutor.
157      * @param action callback object that specifies the data access action
158      * @return a result object returned by the action, or <code>null</code>
159      * @throws DataAccessException in case of SQL Maps errors
160      */

161     public Object JavaDoc execute(SqlMapClientCallback action) throws DataAccessException {
162         Assert.notNull(action, "Callback object must not be null");
163         Assert.notNull(this.sqlMapClient, "No SqlMapClient specified");
164
165         // We always needs to use a SqlMapSession, as we need to pass a Spring-managed
166
// Connection (potentially transactional) in. This shouldn't be necessary if
167
// we run against a TransactionAwareDataSourceProxy underneath, but unfortunately
168
// we still need it to make iBATIS batch execution work properly: If iBATIS
169
// doesn't recognize an existing transaction, it automatically executes the
170
// batch for every single statement...
171

172         SqlMapSession session = this.sqlMapClient.openSession();
173         Connection JavaDoc ibatisCon = null;
174         try {
175             if (logger.isDebugEnabled()) {
176                 logger.debug("Opened SqlMapSession [" + session + "] for iBATIS operation");
177             }
178             Connection JavaDoc springCon = null;
179             try {
180                 ibatisCon = session.getCurrentConnection();
181                 if (ibatisCon == null) {
182                     springCon = DataSourceUtils.getConnection(getDataSource());
183                     session.setUserConnection(springCon);
184                     if (logger.isDebugEnabled()) {
185                         logger.debug("Obtained JDBC Connection [" + springCon + "] for iBATIS operation");
186                     }
187                 }
188                 else {
189                     if (logger.isDebugEnabled()) {
190                         logger.debug("Reusing JDBC Connection [" + ibatisCon + "] for iBATIS operation");
191                     }
192                 }
193                 return action.doInSqlMapClient(session);
194             }
195             catch (SQLException JavaDoc ex) {
196                 throw getExceptionTranslator().translate("SqlMapClient operation", null, ex);
197             }
198             finally {
199                 DataSourceUtils.releaseConnection(springCon, getDataSource());
200             }
201         }
202         finally {
203             // Only close SqlMapSession if we know we've actually opened it
204
// at the present level.
205
if (ibatisCon == null) {
206                 session.close();
207             }
208         }
209     }
210
211     /**
212      * Execute the given data access action on a SqlMapExecutor,
213      * expecting a List result.
214      * @param action callback object that specifies the data access action
215      * @return the List result
216      * @throws DataAccessException in case of SQL Maps errors
217      */

218     public List JavaDoc executeWithListResult(SqlMapClientCallback action) throws DataAccessException {
219         return (List JavaDoc) execute(action);
220     }
221
222     /**
223      * Execute the given data access action on a SqlMapExecutor,
224      * expecting a Map result.
225      * @param action callback object that specifies the data access action
226      * @return the Map result
227      * @throws DataAccessException in case of SQL Maps errors
228      */

229     public Map JavaDoc executeWithMapResult(SqlMapClientCallback action) throws DataAccessException {
230         return (Map JavaDoc) execute(action);
231     }
232
233
234     public Object JavaDoc queryForObject(String JavaDoc statementName) throws DataAccessException {
235         return queryForObject(statementName, null);
236     }
237
238     public Object JavaDoc queryForObject(final String JavaDoc statementName, final Object JavaDoc parameterObject)
239             throws DataAccessException {
240
241         return execute(new SqlMapClientCallback() {
242             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
243                 return executor.queryForObject(statementName, parameterObject);
244             }
245         });
246     }
247
248     public Object JavaDoc queryForObject(
249             final String JavaDoc statementName, final Object JavaDoc parameterObject, final Object JavaDoc resultObject)
250             throws DataAccessException {
251
252         return execute(new SqlMapClientCallback() {
253             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
254                 return executor.queryForObject(statementName, parameterObject, resultObject);
255             }
256         });
257     }
258
259     public List JavaDoc queryForList(String JavaDoc statementName) throws DataAccessException {
260         return queryForList(statementName, null);
261     }
262
263     public List JavaDoc queryForList(final String JavaDoc statementName, final Object JavaDoc parameterObject)
264             throws DataAccessException {
265
266         return executeWithListResult(new SqlMapClientCallback() {
267             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
268                 return executor.queryForList(statementName, parameterObject);
269             }
270         });
271     }
272
273     public List JavaDoc queryForList(String JavaDoc statementName, int skipResults, int maxResults)
274             throws DataAccessException {
275
276         return queryForList(statementName, null, skipResults, maxResults);
277     }
278
279     public List JavaDoc queryForList(
280             final String JavaDoc statementName, final Object JavaDoc parameterObject, final int skipResults, final int maxResults)
281             throws DataAccessException {
282
283         return executeWithListResult(new SqlMapClientCallback() {
284             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
285                 return executor.queryForList(statementName, parameterObject, skipResults, maxResults);
286             }
287         });
288     }
289
290     public void queryWithRowHandler(String JavaDoc statementName, RowHandler rowHandler)
291             throws DataAccessException {
292
293         queryWithRowHandler(statementName, null, rowHandler);
294     }
295
296     public void queryWithRowHandler(
297             final String JavaDoc statementName, final Object JavaDoc parameterObject, final RowHandler rowHandler)
298             throws DataAccessException {
299
300         execute(new SqlMapClientCallback() {
301             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
302                 executor.queryWithRowHandler(statementName, parameterObject, rowHandler);
303                 return null;
304             }
305         });
306     }
307
308     /**
309      * @deprecated as of iBATIS 2.3.0
310      */

311     public PaginatedList queryForPaginatedList(String JavaDoc statementName, int pageSize)
312             throws DataAccessException {
313
314         return queryForPaginatedList(statementName, null, pageSize);
315     }
316
317     /**
318      * @deprecated as of iBATIS 2.3.0
319      */

320     public PaginatedList queryForPaginatedList(
321             final String JavaDoc statementName, final Object JavaDoc parameterObject, final int pageSize)
322             throws DataAccessException {
323
324         // Throw exception if lazy loading will not work.
325
if (!this.lazyLoadingAvailable) {
326             throw new InvalidDataAccessApiUsageException(
327                     "SqlMapClient needs to have DataSource to allow for lazy loading" +
328                     " - specify SqlMapClientFactoryBean's 'dataSource' property");
329         }
330
331         return (PaginatedList) execute(new SqlMapClientCallback() {
332             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
333                 return executor.queryForPaginatedList(statementName, parameterObject, pageSize);
334             }
335         });
336     }
337
338     public Map JavaDoc queryForMap(
339             final String JavaDoc statementName, final Object JavaDoc parameterObject, final String JavaDoc keyProperty)
340             throws DataAccessException {
341
342         return executeWithMapResult(new SqlMapClientCallback() {
343             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
344                 return executor.queryForMap(statementName, parameterObject, keyProperty);
345             }
346         });
347     }
348
349     public Map JavaDoc queryForMap(
350             final String JavaDoc statementName, final Object JavaDoc parameterObject, final String JavaDoc keyProperty, final String JavaDoc valueProperty)
351             throws DataAccessException {
352
353         return executeWithMapResult(new SqlMapClientCallback() {
354             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
355                 return executor.queryForMap(statementName, parameterObject, keyProperty, valueProperty);
356             }
357         });
358     }
359
360     public Object JavaDoc insert(String JavaDoc statementName) throws DataAccessException {
361         return insert(statementName, null);
362     }
363
364     public Object JavaDoc insert(final String JavaDoc statementName, final Object JavaDoc parameterObject)
365             throws DataAccessException {
366
367         return execute(new SqlMapClientCallback() {
368             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
369                 return executor.insert(statementName, parameterObject);
370             }
371         });
372     }
373
374     public int update(String JavaDoc statementName) throws DataAccessException {
375         return update(statementName, null);
376     }
377
378     public int update(final String JavaDoc statementName, final Object JavaDoc parameterObject)
379             throws DataAccessException {
380
381         Integer JavaDoc result = (Integer JavaDoc) execute(new SqlMapClientCallback() {
382             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
383                 return new Integer JavaDoc(executor.update(statementName, parameterObject));
384             }
385         });
386         return result.intValue();
387     }
388
389     public void update(String JavaDoc statementName, Object JavaDoc parameterObject, int requiredRowsAffected)
390             throws DataAccessException {
391
392         int actualRowsAffected = update(statementName, parameterObject);
393         if (actualRowsAffected != requiredRowsAffected) {
394             throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
395                     statementName, requiredRowsAffected, actualRowsAffected);
396         }
397     }
398
399     public int delete(String JavaDoc statementName) throws DataAccessException {
400         return delete(statementName, null);
401     }
402
403     public int delete(final String JavaDoc statementName, final Object JavaDoc parameterObject)
404             throws DataAccessException {
405
406         Integer JavaDoc result = (Integer JavaDoc) execute(new SqlMapClientCallback() {
407             public Object JavaDoc doInSqlMapClient(SqlMapExecutor executor) throws SQLException JavaDoc {
408                 return new Integer JavaDoc(executor.delete(statementName, parameterObject));
409             }
410         });
411         return result.intValue();
412     }
413
414     public void delete(String JavaDoc statementName, Object JavaDoc parameterObject, int requiredRowsAffected)
415             throws DataAccessException {
416
417         int actualRowsAffected = delete(statementName, parameterObject);
418         if (actualRowsAffected != requiredRowsAffected) {
419             throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(
420                     statementName, requiredRowsAffected, actualRowsAffected);
421         }
422     }
423
424 }
425
Popular Tags