001: /*
002: * Copyright 2003 The Apache Software Foundation.
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 velosurf.sql;
018:
019: import java.sql.PreparedStatement;
020: import java.sql.ResultSet;
021: import java.sql.SQLException;
022:
023: import java.util.ArrayList;
024: import java.util.Iterator;
025: import java.util.List;
026: import java.util.Map;
027: import java.util.Set;
028: import java.util.HashSet;
029: import java.util.TreeMap;
030:
031: import velosurf.context.RowIterator;
032: import velosurf.model.Entity;
033: import velosurf.util.Logger;
034: import velosurf.util.StringLists;
035:
036: /** this class encapsulates a jdbc PreparedStatement.
037: *
038: * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
039: *
040: */
041:
042: public class PooledPreparedStatement extends PooledStatement implements
043: RowHandler {
044:
045: /** org.apache.velocity.tools.generic.ValueParser$ValueParserSub class, if found in the classpath. */
046: private static Class valueParserSubClass = null;
047:
048: static {
049: try {
050: valueParserSubClass = Class
051: .forName("org.apache.velocity.tools.generic.ValueParser$ValueParserSub");
052: } catch (ClassNotFoundException cnfe) {
053: }
054: }
055:
056: /** build a new PooledPreparedStatement.
057: *
058: * @param connection database connection
059: * @param preparedStatement wrapped prepared statement
060: */
061: public PooledPreparedStatement(ConnectionWrapper connection,
062: PreparedStatement preparedStatement) {
063: this .connection = connection;
064: this .preparedStatement = preparedStatement;
065: }
066:
067: /** get a unique object by id.
068: *
069: * @param params parameter values
070: * @exception SQLException thrown bu the database engine
071: * @return fetched Instance
072: */
073: public synchronized Object fetch(List params) throws SQLException {
074: return fetch(params, null);
075: }
076:
077: /** get a unique object by id and specify the Entity this object is an Instance of.
078: *
079: * @param params parameter values
080: * @param resultEntity resulting entity
081: * @exception SQLException thrown by the database engine
082: * @return the fetched Instance
083: */
084: public synchronized Object fetch(List params, Entity resultEntity)
085: throws SQLException {
086: Map<String, Object> row = null;
087: try {
088: notifyInUse();
089: //Logger.trace("fetch-params="+StringLists.join(params,","));
090: setParams(params);
091: connection.enterBusyState();
092: resultSet = preparedStatement.executeQuery();
093: boolean hasNext = resultSet.next();
094: connection.leaveBusyState();
095: entity = resultEntity;
096: if (hasNext) {
097: if (resultEntity != null)
098: row = resultEntity.newInstance(
099: new ReadOnlyMap(this ), true);
100: else {
101: row = new TreeMap<String, Object>();
102: if (columnNames == null)
103: columnNames = SqlUtil.getColumnNames(resultSet);
104: for (Iterator it = columnNames.iterator(); it
105: .hasNext();) {
106: String column = (String) it.next();
107: Object value = resultSet.getObject(column);
108: if (value != null && !resultSet.wasNull())
109: row.put(column, value);
110: }
111: }
112: }
113: } finally {
114: notifyOver();
115: }
116: return row;
117: }
118:
119: /** get a unique object by id and specify the Entity this object is an Instance of.
120: *
121: * @param params parameter values
122: * @param resultEntity resulting entity
123: * @exception SQLException thrown by the database engine
124: * @return the fetched Instance
125: */
126: public synchronized Object fetch(Map<String, Object> params,
127: Entity resultEntity) throws SQLException {
128: List<Object> values = new ArrayList<Object>();
129: for (Iterator i = resultEntity.getPKCols().iterator(); i
130: .hasNext();) {
131: String key = (String) i.next();
132: String value = (String) params.get(key);
133: if (value == null)
134: throw new SQLException("Error: key column '" + key
135: + "' is not specified!");
136: values.add(value);
137: }
138: return fetch(values, resultEntity);
139: }
140:
141: /** get the rowset.
142: *
143: * @param params parameter values
144: * @exception SQLException thrown by the database engine
145: * @return the resulting row iterator
146: */
147: public synchronized RowIterator query(List params)
148: throws SQLException {
149: return query(params, null);
150: }
151:
152: /** get the rowset.
153: *
154: * @param params parameter values
155: * @param resultEntity resulting entity
156: * @exception SQLException thrown by the database engine
157: * @return resulting RowIterator
158: */
159: public synchronized RowIterator query(List params,
160: Entity resultEntity) throws SQLException {
161: notifyInUse();
162: //Logger.trace("query-params="+StringLists.join(params,","));
163: if (params != null) {
164: setParams(params);
165: }
166: connection.enterBusyState();
167: RowIterator result = new RowIterator(this , preparedStatement
168: .executeQuery(), resultEntity);
169: connection.leaveBusyState();
170: return result;
171: }
172:
173: /** get a scalar result from this statement.
174: *
175: * @param params parameter values
176: * @exception SQLException thrown bu the database engine
177: * @return scalar result
178: */
179: public synchronized Object evaluate(List params)
180: throws SQLException {
181: Object value = null;
182: ResultSet rs = null;
183: try {
184: notifyInUse();
185: //Logger.trace("evaluate-params="+StringLists.join(params,","));
186: if (params != null) {
187: setParams(params);
188: }
189: connection.enterBusyState();
190: rs = preparedStatement.executeQuery();
191: boolean hasNext = rs.next();
192: connection.leaveBusyState();
193: if (hasNext) {
194: value = rs.getObject(1);
195: if (rs.wasNull())
196: value = null;
197: }
198: } finally {
199: if (rs != null)
200: rs.close();
201: notifyOver();
202: }
203: return value;
204: }
205:
206: /** issue the modification query of this prepared statement.
207: *
208: * @param params parameter values
209: * @exception SQLException thrown by the database engine
210: * @return the numer of affected rows
211: */
212: public synchronized int update(List params) throws SQLException {
213: try {
214: notifyInUse();
215: //Logger.trace("update-params="+StringLists.join(params,","));
216: setParams(params);
217: connection.enterBusyState();
218: int rows = preparedStatement.executeUpdate();
219: connection.leaveBusyState();
220: return rows;
221: } finally {
222: notifyOver();
223: }
224: }
225:
226: /** get the object value of the specified resultset column.
227: *
228: * @param key the name of the resultset column
229: * @exception SQLException thrown by the database engine
230: * @return the object value returned by jdbc
231: */
232:
233: public synchronized Object get(Object key) throws SQLException {
234: if (!(key instanceof String))
235: return null;
236: Object ret = resultSet.getObject((String) key);
237: if (entity != null && entity.isObfuscated((String) key))
238: ret = entity.obfuscate((ret));
239: return ret;
240: }
241:
242: public Set<String> keySet() throws SQLException {
243: return new HashSet<String>(SqlUtil.getColumnNames(resultSet));
244: }
245:
246: /** get the last insert id.
247: *
248: * @exception SQLException thrown by the database engine
249: * @return the last insert id
250: */
251: public synchronized long getLastInsertID() throws SQLException {
252: return ((ConnectionWrapper) connection)
253: .getLastInsertId(preparedStatement);
254: }
255:
256: /** close this statement.
257: *
258: * @exception SQLException thrown by the database engine
259: */
260: public synchronized void close() throws SQLException {
261: if (preparedStatement != null)
262: preparedStatement.close();
263: }
264:
265: /** get statement Connection.
266: *
267: * @return the Connection object (usually a ConnectionWrapper object)
268: */
269: public ConnectionWrapper getConnection() {
270: return connection;
271: }
272:
273: /** set prepared parameter values.
274: *
275: * @param params parameter values
276: * @exception SQLException thrown by the database engine
277: */
278: private void setParams(List params) throws SQLException {
279: for (int i = 0; i < params.size(); i++) {
280: Object param = params.get(i);
281: if (valueParserSubClass != null
282: && valueParserSubClass.isAssignableFrom(param
283: .getClass())) {
284: param = param.toString();
285: }
286: preparedStatement.setObject(i + 1, param);
287: }
288: }
289:
290: /** the connection.
291: */
292: private ConnectionWrapper connection = null;
293: /** the result set.
294: */
295: private ResultSet resultSet = null;
296: /** column names.
297: */
298: private List columnNames = null;
299: /** wrapped prepared statement.
300: */
301: private PreparedStatement preparedStatement = null;
302: /** the resulting entity.
303: */
304: private Entity entity = null;
305: /** has meta information been fetched?
306: */
307: }
|