1 /***
2 * Copyright (c) 2003 held jointly by the individual authors.
3 *
4 * This library is free software; you can redistribute it and/or modify it under
5 * the terms of the GNU Lesser General Public License as published by the Free
6 * Software Foundation; either version 2.1 of the License, or (at your option)
7 * any later version.
8 *
9 * This library is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12 * for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17 * > http://www.gnu.org/copyleft/lesser.html >
18 * http://www.opensource.org/licenses/lgpl-license.php
19 */
20 package net.mlw.vlh.adapter.jdbc;
21
22 import java.sql.Connection;
23 import java.sql.PreparedStatement;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.util.List;
27
28 import javax.sql.DataSource;
29
30 import net.mlw.vlh.DefaultListBackedValueList;
31 import net.mlw.vlh.ValueList;
32 import net.mlw.vlh.ValueListInfo;
33 import net.mlw.vlh.adapter.AbstractValueListAdapter;
34 import net.mlw.vlh.adapter.jdbc.objectWrapper.ResultSetDecorator;
35 import net.mlw.vlh.adapter.jdbc.util.ConnectionCreator;
36 import net.mlw.vlh.adapter.jdbc.util.JdbcUtil;
37 import net.mlw.vlh.adapter.jdbc.util.SqlPagingSupport;
38 import net.mlw.vlh.adapter.jdbc.util.StandardConnectionCreator;
39 import net.mlw.vlh.adapter.jdbc.util.StandardStatementBuilder;
40 import net.mlw.vlh.adapter.jdbc.util.StatementBuilder;
41 import net.mlw.vlh.adapter.util.ObjectValidator;
42
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45
46 /***
47 * This adapter handles the standard functionality of creating a query and
48 * execution it...
49 *
50 * If you set validator, it will use special ResultSetDecorator.
51 *
52 * @see net.mlw.vlh.adapter.jdbc.objectWrapper.ResultSetDecorator
53 * @author Matthew L. Wilson, Andrej Zachar
54 * @version $Revision: 1.27 $ $Date: 2006/04/18 17:15:05 $
55 */
56 public abstract class AbstractJdbcAdapter extends AbstractValueListAdapter
57 {
58 /*** Commons logger. */
59 private static final Log LOGGER = LogFactory.getLog(AbstractJdbcAdapter.class);
60
61 /*** The sql to execute. */
62 private String sql;
63
64 /*** Display generated sql on th standard output */
65 private boolean showSql = false;
66
67 /*** The StatementBuilder to help generate a sql query. */
68 private StatementBuilder statementBuilder = new StandardStatementBuilder();
69
70 /*** The ConnectionCreator to help SQL connection handling */
71 private ConnectionCreator connectionCreator = new StandardConnectionCreator();
72
73 /***
74 * The validator for ResultSet's records.
75 */
76 private ObjectValidator _validator = null;
77
78 /***
79 * Helper to provide true in-database paging.
80 */
81 private SqlPagingSupport sqlPagingSupport;
82
83 public AbstractJdbcAdapter()
84 {}
85
86 /***
87 * @see net.mlw.vlh.ValueListAdapter#getValueList(java.lang.String,
88 * net.mlw.vlh.ValueListInfo)
89 */
90 public ValueList getValueList(String name, ValueListInfo info)
91 {
92 if (info.getSortingColumn() == null)
93 {
94 info.setPrimarySortColumn(getDefaultSortColumn());
95 info.setPrimarySortDirection(getDefaultSortDirectionInteger());
96 }
97
98 int numberPerPage = info.getPagingNumberPer();
99
100 if (numberPerPage == Integer.MAX_VALUE)
101 {
102 numberPerPage = getDefaultNumberPerPage();
103 info.setPagingNumberPer(numberPerPage);
104 }
105
106 Connection connection = null;
107 PreparedStatement statement = null;
108 ResultSet result = null;
109
110 try
111 {
112 boolean doSqlPaging = ((getAdapterType() & DO_PAGE) == 0);
113
114 connection = connectionCreator.createConnection();
115
116 StringBuffer query = (sqlPagingSupport != null) ? sqlPagingSupport.getPagedQuery(sql) : new StringBuffer(sql);
117 statement = statementBuilder.generate(connection, query, info.getFilters(), sqlPagingSupport == null && doSqlPaging);
118
119 if (LOGGER.isDebugEnabled())
120 {
121 LOGGER.debug(query.toString());
122 }
123 if (showSql)
124 {
125 System.out.println("sql: " + query.toString());
126 }
127 result = getResultSet(statement, info);
128
129 if (sqlPagingSupport != null)
130 {
131 PreparedStatement countStatement = null;
132 ResultSet countResult = null;
133
134 try
135 {
136 StringBuffer countQuery = sqlPagingSupport.getCountQuery(sql);
137 countStatement = statementBuilder.generate(connection, countQuery, info.getFilters(), false);
138 if (showSql)
139 {
140 System.out.println("count sql: " + countQuery.toString());
141 }
142
143 countResult = countStatement.executeQuery();
144 if (countResult.next())
145 {
146 info.setTotalNumberOfEntries(countResult.getInt(1));
147 }
148 }
149 finally
150 {
151 JdbcUtil.close(countResult, countStatement, null);
152 }
153
154 }
155 else if (doSqlPaging)
156 {
157 result.last();
158 int totalRows = result.getRow();
159 info.setTotalNumberOfEntries(totalRows);
160
161 if (numberPerPage == 0)
162 {
163 numberPerPage = getDefaultNumberPerPage();
164 }
165
166 int pageNumber = info.getPagingPage();
167 if (pageNumber > 1)
168 {
169 if ((pageNumber - 1) * numberPerPage > totalRows)
170 {
171 pageNumber = ((totalRows - 1) / numberPerPage) + 1;
172 info.setPagingPage(pageNumber);
173 }
174 }
175
176 if (pageNumber > 1)
177 {
178 result.absolute((pageNumber - 1) * numberPerPage);
179 }
180 else
181 {
182 result.beforeFirst();
183 }
184 }
185
186 List list = processResultSet(name, result, (doSqlPaging) ? numberPerPage : Integer.MAX_VALUE, info);
187
188 if (!doSqlPaging)
189 {
190 info.setTotalNumberOfEntries(list.size());
191 }
192
193 return new DefaultListBackedValueList(list, info);
194
195 }
196 catch (Exception e)
197 {
198 LOGGER.error(e);
199 throw new RuntimeException(e);
200 }
201 finally
202 {
203 connectionCreator.close(result, statement, connection);
204 }
205 }
206
207 /***
208 * @param statement
209 * @param info This info will be set to validator.
210 * @return ResultSet (validator is null) or ResultSetDecorator (validator is
211 * not null)
212 * @throws SQLException
213 * @see net.mlw.vlh.adapter.util.ObjectValidator
214 * @see net.mlw.vlh.adapter.jdbc.objectWrapper.ResultSetDecorator
215 */
216 private ResultSet getResultSet(PreparedStatement statement, ValueListInfo info) throws SQLException
217 {
218 if (_validator == null)
219 {
220 return statement.executeQuery();
221 }
222 else
223 {
224 _validator.setValueListInfo(info);
225 return new ResultSetDecorator(statement.executeQuery(), _validator);
226 }
227 }
228
229 /***
230 * This method takes the result and puts the VOs in the List.
231 *
232 * @param result The ResultSet to interate through.
233 * @param info is ussually constant during this process, you can use it for
234 * passing additional parameters from controler. (Like in
235 * DefaultWrapperAdapter)
236 * @return The List of VOs.
237 */
238 public abstract List processResultSet(String name, ResultSet result, int numberPerPage, ValueListInfo info) throws SQLException;
239
240 /***
241 * @return Returns the dataSource.
242 */
243 public DataSource getDataSource()
244 {
245 return connectionCreator.getDataSource();
246 }
247
248 /***
249 * @param dataSource The dataSource to set.
250 */
251 public void setDataSource(DataSource dataSource)
252 {
253 connectionCreator.setDataSource(dataSource);
254 }
255
256 /***
257 * @return Returns the sql.
258 */
259 public String getSql()
260 {
261 return sql;
262 }
263
264 /***
265 * @param sql The sql to set.
266 */
267 public void setSql(String sql)
268 {
269 this.sql = sql;
270 }
271
272 /***
273 * @return Returns the statementBuilder.
274 */
275 public StatementBuilder getStatementBuilder()
276 {
277 return statementBuilder;
278 }
279
280 /***
281 * @param statementBuilder The statementBuilder to set.
282 */
283 public void setStatementBuilder(StatementBuilder statementBuilder)
284 {
285 this.statementBuilder = statementBuilder;
286 }
287
288 /***
289 * @return Returns the showSql.
290 */
291 public boolean isShowSql()
292 {
293 return showSql;
294 }
295
296 /***
297 * @param showSql The showSql to set.
298 */
299 public void setShowSql(boolean showSql)
300 {
301 this.showSql = showSql;
302 }
303
304 /***
305 * @return Returns the objectValidator.
306 */
307 public ObjectValidator getValidator()
308 {
309 return _validator;
310 }
311
312 /***
313 * <p>
314 * If is set to not null value, it uses a special
315 * <code>ResultsSetDecorator<code>, that enable or
316 * disable filtering objects in the final valuelist.
317 * </p>
318 * <h4>NOTE:</h4>
319 * <p>
320 * It respects the total count of entries that overlap your paged
321 * list. Simply spoken it supports features such as paging.
322 * </p>
323 * @param objectValidator The objectValidator to set.
324 * The null value means that validator is disabled.
325 * @see net.mlw.vlh.adapter.util.ObjectValidator
326 * @see net.mlw.vlh.adapter.jdbc.objectWrapper.ResultSetDecorator
327 */
328 public void setValidator(ObjectValidator objectValidator)
329 {
330 this._validator = objectValidator;
331 }
332
333 /***
334 * @return Returns the connectionCreator.
335 */
336 public ConnectionCreator getConnectionCreator()
337 {
338 return connectionCreator;
339 }
340
341 /***
342 * @param connectionCreator The connectionCreator to set.
343 */
344 public void setConnectionCreator(ConnectionCreator connectionCreator)
345 {
346 this.connectionCreator = connectionCreator;
347 }
348
349 public SqlPagingSupport getSqlPagingSupport()
350 {
351 return sqlPagingSupport;
352 }
353
354 public void setSqlPagingSupport(SqlPagingSupport sqlPagingSupport)
355 {
356 this.sqlPagingSupport = sqlPagingSupport;
357 }
358 }