001: /*
002: * Copyright 2004-2006 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.apache.lucene.store.jdbc.support;
018:
019: import java.sql.CallableStatement;
020: import java.sql.Connection;
021: import java.sql.PreparedStatement;
022: import java.sql.ResultSet;
023: import java.sql.SQLException;
024: import java.sql.Statement;
025:
026: import javax.sql.DataSource;
027:
028: import org.apache.lucene.store.jdbc.JdbcDirectorySettings;
029: import org.apache.lucene.store.jdbc.JdbcStoreException;
030: import org.apache.lucene.store.jdbc.datasource.DataSourceUtils;
031:
032: /**
033: * Helper class that isused to encapsulate resource and transaction handling related to <code>DataSource</code>,
034: * <code>Statement</code>, and <code>ResultSet</code>. {@link DataSourceUtils} is used to open/cose relevant
035: * resources.
036: *
037: * @author kimchy
038: * @see DataSourceUtils
039: */
040: public class JdbcTemplate {
041:
042: /**
043: * A callback interface used to initialize a Jdbc <code>PreparedStatement</code>.
044: */
045: public static interface PrepateStatementAwareCallback {
046:
047: /**
048: * Initialize/Fill the given <code>PreparedStatement</code>.
049: */
050: void fillPrepareStatement(PreparedStatement ps)
051: throws Exception;
052: }
053:
054: /**
055: * A callback used to retrieve data from a <code>ResultSet</code>.
056: */
057: public static interface ExecuteSelectCallback extends
058: PrepateStatementAwareCallback {
059:
060: /**
061: * Extract data from the <code>ResultSet</code> and an optional return value.
062: */
063: Object execute(ResultSet rs) throws Exception;
064: }
065:
066: /**
067: * A callback used to work with <code>CallableStatement</code>.
068: */
069: public static interface CallableStatementCallback {
070:
071: /**
072: * initialize/Fill the <code>CallableStatement</code> before it is executed.
073: */
074: void fillCallableStatement(CallableStatement cs)
075: throws Exception;
076:
077: /**
078: * Read/Extract data from the result of the <code>CallableStatement</code> execution. CAn optionally
079: * have a return value.
080: */
081: Object readCallableData(CallableStatement cs) throws Exception;
082: }
083:
084: private DataSource dataSource;
085:
086: private JdbcDirectorySettings settings;
087:
088: /**
089: * Creates a new <code>JdbcTemplate</code>.
090: */
091: public JdbcTemplate(DataSource dataSource,
092: JdbcDirectorySettings settings) {
093: this .dataSource = dataSource;
094: this .settings = settings;
095: }
096:
097: /**
098: * A template method to execute a simple sql select statement. The jdbc
099: * <code>Connection</code>, <code>PreparedStatement</code>, and <code>ResultSet</code>
100: * are managed by the template.
101: */
102: public Object executeSelect(String sql,
103: ExecuteSelectCallback callback) throws JdbcStoreException {
104: Connection con = DataSourceUtils.getConnection(dataSource);
105: PreparedStatement ps = null;
106: ResultSet rs = null;
107: try {
108: ps = con.prepareStatement(sql);
109: ps.setQueryTimeout(settings.getQueryTimeout());
110: callback.fillPrepareStatement(ps);
111: rs = ps.executeQuery();
112: return callback.execute(rs);
113: } catch (JdbcStoreException e) {
114: throw e;
115: } catch (Exception e) {
116: throw new JdbcStoreException("Failed to execute sql ["
117: + sql + "]", e);
118: } finally {
119: DataSourceUtils.closeResultSet(rs);
120: DataSourceUtils.closeStatement(ps);
121: DataSourceUtils.releaseConnection(con);
122: }
123: }
124:
125: /**
126: * A template method to execute a simple sql callable statement. The jdbc
127: * <code>Connection</code>, and <code>CallableStatement</code>
128: * are managed by the template.
129: */
130: public Object executeCallable(String sql,
131: CallableStatementCallback callback)
132: throws JdbcStoreException {
133: Connection con = DataSourceUtils.getConnection(dataSource);
134: CallableStatement cs = null;
135: try {
136: cs = con.prepareCall(sql);
137: cs.setQueryTimeout(settings.getQueryTimeout());
138: callback.fillCallableStatement(cs);
139: cs.execute();
140: return callback.readCallableData(cs);
141: } catch (JdbcStoreException e) {
142: throw e;
143: } catch (Exception e) {
144: throw new JdbcStoreException("Failed to execute sql ["
145: + sql + "]", e);
146: } finally {
147: DataSourceUtils.closeStatement(cs);
148: DataSourceUtils.releaseConnection(con);
149: }
150: }
151:
152: /**
153: * A template method to execute a simple sql update. The jdbc
154: * <code>Connection</code>, and <code>PreparedStatement</code>
155: * are managed by the template. A <code>PreparedStatement</code> can be used
156: * to set values to the given sql.
157: */
158: public void executeUpdate(String sql,
159: PrepateStatementAwareCallback callback)
160: throws JdbcStoreException {
161: Connection con = DataSourceUtils.getConnection(dataSource);
162: PreparedStatement ps = null;
163: try {
164: ps = con.prepareStatement(sql);
165: ps.setQueryTimeout(settings.getQueryTimeout());
166: callback.fillPrepareStatement(ps);
167: ps.executeUpdate();
168: } catch (JdbcStoreException e) {
169: throw e;
170: } catch (Exception e) {
171: throw new JdbcStoreException("Failed to execute sql ["
172: + sql + "]", e);
173: } finally {
174: DataSourceUtils.closeStatement(ps);
175: DataSourceUtils.releaseConnection(con);
176: }
177: }
178:
179: /**
180: * A template method to execute a simpel sql update (with no need for data
181: * initialization).
182: */
183: public void executeUpdate(String sql) throws JdbcStoreException {
184: Connection con = DataSourceUtils.getConnection(dataSource);
185: Statement statement = null;
186: try {
187: statement = con.createStatement();
188: statement.setQueryTimeout(settings.getQueryTimeout());
189: statement.executeUpdate(sql);
190: } catch (SQLException e) {
191: throw new JdbcStoreException("Failed to execute [" + sql
192: + "]", e);
193: } finally {
194: DataSourceUtils.closeStatement(statement);
195: DataSourceUtils.releaseConnection(con);
196: }
197: }
198:
199: /**
200: * A template method to execute a set of sqls in batch.
201: */
202: public int[] executeBatch(String[] sqls) throws JdbcStoreException {
203: Connection con = DataSourceUtils.getConnection(dataSource);
204: Statement statement = null;
205: try {
206: statement = con.createStatement();
207: statement.setQueryTimeout(settings.getQueryTimeout());
208: for (int i = 0; i < sqls.length; i++) {
209: statement.addBatch(sqls[i]);
210: }
211: return statement.executeBatch();
212: } catch (SQLException e) {
213: throw new JdbcStoreException("Failed to execute [" + sqls
214: + "]", e);
215: } finally {
216: DataSourceUtils.closeStatement(statement);
217: DataSourceUtils.releaseConnection(con);
218: }
219: }
220:
221: /**
222: * A template method to execute that can execute the same sql several times using different
223: * values set to it (in the <code>fillPrepareStatement</code>) callback).
224: */
225: public int[] executeBatch(String sql,
226: PrepateStatementAwareCallback callback)
227: throws JdbcStoreException {
228: Connection con = DataSourceUtils.getConnection(dataSource);
229: PreparedStatement ps = null;
230: try {
231: ps = con.prepareStatement(sql);
232: ps.setQueryTimeout(settings.getQueryTimeout());
233: callback.fillPrepareStatement(ps);
234: return ps.executeBatch();
235: } catch (JdbcStoreException e) {
236: throw e;
237: } catch (Exception e) {
238: throw new JdbcStoreException("Failed to execute sql ["
239: + sql + "]", e);
240: } finally {
241: DataSourceUtils.closeStatement(ps);
242: DataSourceUtils.releaseConnection(con);
243: }
244: }
245: }
|