View Javadoc

1   /*
2    * 
3    * 
4    */
5   package net.sf.diaz;
6   
7   import java.sql.*;
8   import java.math.BigDecimal;
9   import java.util.*;
10  
11  /**
12   * 
13   * @author Sean C. Sullivan
14   * 
15   */
16  public abstract class AbstractJdbcDao
17  {
18  	private int fetchSize = 500;
19  	private int maxRows = 2000;
20  	private int queryTimeout = 180; /* seconds */
21  	private boolean closeQuietly = false;
22  	private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
23  	private int resultSetConcurrency = ResultSet.CONCUR_READ_ONLY;
24  	private int transactionIsolation = Connection.TRANSACTION_READ_COMMITTED;
25  
26  	protected int getTransactionIsolation()
27  	{
28  		return transactionIsolation;
29  	}
30  
31  	protected void setTransactionIsolation(int transactionIsolation)
32  	{
33  		this.transactionIsolation = transactionIsolation;
34  	}
35  
36  	/**
37  	 * 
38  	 */
39  	protected GeneratedKeys executeInsert(CharSequence sql, Object... queryParameters)
40  	{
41  		GeneratedKeys keys = (GeneratedKeys) executeUpdate(sql, Statement.RETURN_GENERATED_KEYS, queryParameters);
42  		return keys;
43  	}
44  
45  
46  	protected Object executeUpdate(CharSequence sql)
47  	{
48  		return executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
49  	}
50  	
51  	/**
52  	 * 
53  	 * @param sql
54  	 * @param queryParameters
55  	 * 
56  	 */
57  	protected Object executeUpdate(CharSequence sql, int autoGeneratedKeys, Object... queryParameters)
58  	{
59  		Connection conn = null;
60  		
61  		Object result = null;
62  		
63  		try
64  		{	
65  			conn = getConnection();
66  			result = executeUpdate(conn, sql, autoGeneratedKeys, queryParameters);
67  			return result;
68  		}
69  		catch (SQLException ex)
70  		{
71  			throw new DataAccessException(
72  							buildMessage(sql, queryParameters), 
73  							ex);
74  		}
75  		finally
76  		{
77  			close(conn, null, null);
78  		}
79  	}
80  
81  	/**
82  	 * 
83  	 * @param conn
84  	 * @param sql
85  	 * @param queryParameters
86  	 * 
87  	 */
88  	protected Object executeUpdate(Connection conn, CharSequence sql, int autoGeneratedKeys, Object... queryParameters)
89  	{
90  		PreparedStatement ps = null;
91  		
92  		Object result = null;
93  		
94  		String strSQL = sql.toString();
95  		
96  		try
97  		{
98  			conn = getConnection();
99  			ps = conn.prepareStatement(strSQL, autoGeneratedKeys);
100 			setPreparedStatementParameters(ps, queryParameters);
101 			int rowCount = ps.executeUpdate();
102 			if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS)
103 			{
104 				result = new GeneratedKeys(ps.getGeneratedKeys());
105 			}
106 			else
107 			{
108 				result = new Integer(rowCount);
109 			}
110 			return result;
111 		}
112 		catch (SQLException ex)
113 		{
114 			throw new DataAccessException(
115 							buildMessage(strSQL, queryParameters), 
116 							ex);
117 		}
118 		finally
119 		{
120 			close(null, null, ps);
121 		}
122 	}
123 
124 	/**
125 	 * 
126 	 * @param sql
127 	 * @param queryParameters
128 	 * @return a List containing zero or more {@link Row} objects
129 	 * 
130 	 */
131 	protected List<Row> executeQuery(CharSequence sql, Object... queryParameters)
132 	{
133 		ResultSet rs = null;
134 		PreparedStatement ps = null;
135 		Connection conn = null;
136 		List<Row> rows = null;
137 		
138 		String strSQL = sql.toString();
139 		
140 		try
141 		{
142 			conn = getConnection();
143 			conn.setTransactionIsolation(this.getTransactionIsolation());
144 			ps = conn.prepareStatement(strSQL,
145 							this.getResultSetType(),
146 							this.getResultSetConcurrency());
147 			setPreparedStatementParameters(ps, queryParameters);
148 			ps.setFetchDirection(ResultSet.FETCH_FORWARD);
149 			ps.setFetchSize(this.getFetchSize());
150 			ps.setQueryTimeout(this.getQueryTimeout());
151 			ps.setMaxRows(this.getMaxRows());
152 			rs = ps.executeQuery();
153 			rows = buildRows(rs);
154 			return rows;
155 		}
156 		catch (SQLException ex)
157 		{
158 			throw new DataAccessException(
159 							buildMessage(strSQL, queryParameters),
160 							ex);
161 		}
162 		finally
163 		{
164 			close(conn, rs, ps);
165 		}
166 		
167 	}
168 	
169 	protected int getFetchSize()
170 	{
171 		return fetchSize;
172 	}
173 	
174 	protected void setFetchSize(int size)
175 	{
176 		this.fetchSize = size;
177 	}
178 	
179 	protected List<Row> buildRows(ResultSet rs) throws SQLException
180 	{
181 		List<Row> rows = new LinkedList<Row>();
182 
183 		while (rs.next())
184 		{
185 			Row r = buildSingleRow(rs);
186 			rows.add(r);
187 		}
188 		
189 		return rows; 
190 	}
191 
192 	protected Row buildSingleRow(ResultSet rs) throws SQLException
193 	{
194 		
195 		// todo : add code to handle BLOB's?
196 		
197 		ResultSetMetaData metaData = rs.getMetaData();
198 
199 		int colCount = metaData.getColumnCount();
200 		IndexedMap<String, Object> map = new IndexedMapImpl<String, Object>(colCount);
201 		for (int colIndex = 1; colIndex < colCount; colIndex++)
202 		{
203 			String colName = metaData.getColumnName(colIndex).toUpperCase();
204 			Object colValue = rs.getObject(colIndex);
205 			map.put(colName, colValue);
206 		}
207 		return new Row(map);
208 	}
209 	
210 	protected boolean getCloseQuietly()
211 	{
212 		return closeQuietly;
213 	}
214 	
215 	protected void setCloseQuietly(boolean b)
216 	{
217 		closeQuietly = b;
218 	}
219 	
220 	protected void close(Connection c, ResultSet rs, Statement st)
221 	{
222 		Exception caught = null;
223 		
224 		try
225 		{
226 			if (rs != null)
227 			{
228 				rs.close();
229 			}
230 		}
231 		catch (Exception ex)
232 		{
233 			caught = ex;
234 		}
235 		try
236 		{
237 			if (st != null)
238 			{
239 				st.close();
240 			}
241 		}
242 		catch (Exception ex)
243 		{
244 			caught = ex;
245 		}
246 		try
247 		{
248 			if (c != null)
249 			{
250 				c.close();
251 			}
252 		}
253 		catch (Exception ex)
254 		{
255 			caught = ex;
256 		}
257 		
258 		if ( ( ! getCloseQuietly()) && (caught != null) )
259 		{
260 			throw new DataAccessException(caught); 
261 		}
262 	}
263 	
264 
265 	abstract protected Connection getConnection() throws SQLException;
266 	
267 	protected void setPreparedStatementParameters(PreparedStatement ps, Object[] parameters)
268 				throws SQLException
269 	{
270 		for (int i = 0; i < parameters.length; i++)
271 		{
272 			int parameterIndex = i + 1;
273 			Object param = parameters[i];
274 			if (param == null)
275 			{
276 				ps.setObject(parameterIndex, param);
277 			}
278 			else if (param instanceof java.sql.Time)
279 			{
280 				ps.setTime(parameterIndex, (java.sql.Time) param);
281 			}
282 			else if (param instanceof java.sql.Timestamp)
283 			{
284 				ps.setTimestamp(parameterIndex, (java.sql.Timestamp) param);
285 			}
286 			else if (param instanceof java.sql.Date)
287 			{
288 				java.sql.Date value = (java.sql.Date) param;
289 				ps.setDate(parameterIndex, value);
290 			}
291 			else if (param instanceof java.util.Date)
292 			{
293 				long time = ((java.util.Date) param).getTime();
294 				java.sql.Date value = new java.sql.Date(time);
295 				ps.setDate(parameterIndex, value);
296 			}
297 			else if (param instanceof java.util.Calendar)
298 			{
299 				Calendar c = (Calendar) param;
300 				java.sql.Date d = new java.sql.Date(c.getTime().getTime());
301 				ps.setDate(parameterIndex, d, c);
302 			}
303 			else if (param instanceof String)
304 			{
305 				ps.setString(parameterIndex, (String) param);
306 			}
307 			else if (param instanceof CharSequence)
308 			{
309 				String value = param.toString();
310 				ps.setString(parameterIndex, value);
311 			}
312 			else if (param instanceof char[])
313 			{
314 				String value = new String( (char[]) param );
315 				ps.setString(parameterIndex, value);
316 			}
317 			else if (param instanceof Character)
318 			{
319 				ps.setString(parameterIndex, String.valueOf(param));
320 			}
321 			else if (param instanceof Enum)
322 			{
323 				Enum e = (Enum) param;
324 				int value = e.ordinal();
325 				ps.setInt(parameterIndex, value);
326 			}
327 			else if (param instanceof Integer)
328 			{
329 				int value = ((Integer) param).intValue();
330 				ps.setInt(parameterIndex, value);
331 			}
332 			else if (param instanceof Short)
333 			{
334 				short value = ((Short) param).shortValue();
335 				ps.setShort(parameterIndex, value);
336 			}
337 			else if (param instanceof Long)
338 			{
339 				long value = ((Long) param).longValue();
340 				ps.setLong(parameterIndex, value);
341 			}
342 			else if (param instanceof BigDecimal)
343 			{
344 				BigDecimal value = (BigDecimal) param;
345 				ps.setBigDecimal(parameterIndex, value);
346 			}
347 			else if (param instanceof java.sql.Ref)
348 			{
349 				Ref value = (Ref) param;
350 				ps.setRef(i, value);
351 			}
352 			else if (param instanceof Double)
353 			{
354 				double value = ((Double) param).doubleValue();
355 				ps.setDouble(parameterIndex, value);
356 			}
357 			else if (param instanceof Float)
358 			{
359 				float value = ((Float) param).floatValue();
360 				ps.setFloat(parameterIndex, value);
361 			}
362 			else if (param instanceof Boolean)
363 			{
364 				boolean value = ((Boolean) param).booleanValue();
365 				ps.setBoolean(parameterIndex, value);
366 			}
367 			else if (param instanceof java.sql.Array)
368 			{
369 				ps.setArray(parameterIndex, (java.sql.Array) param);
370 			}
371 			else if (param instanceof java.net.URL)
372 			{
373 				ps.setURL(parameterIndex, (java.net.URL) param);
374 			}
375 			else if (param instanceof byte[])
376 			{
377 				ps.setBytes(parameterIndex, (byte[]) param);
378 			}
379 			else if (param instanceof Clob)
380 			{
381 				ps.setClob(parameterIndex, (Clob) param);
382 			}
383 			else if (param instanceof Blob)
384 			{
385 				ps.setBlob(parameterIndex, (Blob) param);
386 			}
387 			else if (param instanceof Byte)
388 			{
389 				byte value = ((Byte) param).byteValue();
390 				ps.setByte(parameterIndex, value);
391 			}
392 			else
393 			{
394 				throw new IllegalArgumentException("unexpected parameter type: "
395 							+ param.getClass());
396 			}
397 		}
398 	}
399 	
400 	protected String buildMessage(CharSequence sql, Object[] queryParameters)
401 	{
402 		StringBuffer sb = new StringBuffer();
403 		sb.append(sql);
404 		if (queryParameters.length > 0)
405 		{
406 			sb.append(",");
407 			for (Object o : queryParameters)
408 			{
409 				sb.append(" [");
410 				sb.append(o);
411 				sb.append("] ");
412 			}
413 		}
414 		return sb.toString();
415 	}
416 	
417 	protected int getQueryTimeout()
418 	{
419 		return queryTimeout;
420 	}
421 	
422 	protected void setQueryTimeout(int value)
423 	{
424 		queryTimeout = value;
425 	}
426 	
427 	protected int getMaxRows() 
428 	{
429 		return maxRows;
430 	}
431 	
432 
433 	protected void setMaxRows(int value) 
434 	{
435 		this.maxRows = value;
436 	}
437 	
438 	public String toString()
439 	{
440 		return "QueryTimeout=" 
441 			+ getQueryTimeout()
442 			+ ",FetchSize="
443 			+ getFetchSize()
444 			+ ",MaxRows="
445 			+ getMaxRows();
446 	}
447 
448 	protected int getResultSetType()
449 	{
450 		return this.resultSetType;
451 	}
452 	
453 	protected void setResultSetType(int value)
454 	{
455 		this.resultSetType = value;
456 	}
457 
458 	protected int getResultSetConcurrency()
459 	{
460 		return resultSetConcurrency;
461 	}
462 
463 	protected void setResultSetConcurrency(int resultSetConcurrency)
464 	{
465 		this.resultSetConcurrency = resultSetConcurrency;
466 	}
467 	
468 }