View Javadoc
1 /* ====================================================================
2 * License:
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in
13 * the documentation and/or other materials provided with the
14 * distribution.
15 *
16 * 3. The end-user documentation included with the redistribution,
17 * if any, must include the following acknowledgment:
18 * "This product includes software developed by
19 * Robert Half International (http://www.rhi.com/)."
20 * Alternately, this acknowledgment may appear in the software itself,
21 * if and wherever such third-party acknowledgments normally appear.
22 *
23 * 4. The names "Parc", "RHI", and "Robert Half International" must
24 * not be used to endorse or promote products derived from this
25 * software without prior written permission. For written
26 * permission, please contact pete.mckinstry@rhi.com.
27 *
28 * 5. Products derived from this software may not be called "PARC",
29 * nor may "PARC" appear in their name, without prior written
30 * permission of Robert Half International.
31 *
32 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
33 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
34 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
36 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
37 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
38 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
39 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
40 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
41 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
42 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 * ====================================================================
45 *
46 */
47 package com.rhi.architecture.parc.adapter.jdbc;
48
49 import com.rhi.architecture.config.ConfigurationException;
50 import com.rhi.architecture.db.DBUtil;
51 import com.rhi.architecture.logging.LogUtil;
52 import com.rhi.architecture.logging.Logger;
53 import com.rhi.architecture.parc.ProcessingException;
54 import com.rhi.architecture.parc.Record;
55 import com.rhi.architecture.parc.adapter.AbstractInputAdapter;
56 import com.rhi.architecture.resource.InitializationException;
57
58 import java.sql.Connection;
59 import java.sql.PreparedStatement;
60 import java.sql.ResultSet;
61 import java.sql.SQLException;
62 import java.util.ArrayList;
63 import java.util.Collection;
64 import java.util.Properties;
65
66 import javax.sql.DataSource;
67
68 /***
69 * Generic JDBC InputAdapter.
70 *
71 * @author Pete McKinstry
72 * @copyright 2002, Robert Half Int'l., Inc. All rights reserved.
73 *
74 * @since 1.0
75 */
76 public abstract class JDBCInputAdapter extends AbstractInputAdapter {
77
78 private static Logger log = null;
79
80 private static String query;
81 private static final String QUERY_KEY =
82 "JDBCInputAdapter.SELECT_RECORDS";
83
84 private static long batchSize;
85 private static final String BATCH_SIZE_KEY =
86 "JDBCInputAdapter.BATCH_SIZE";
87
88 /***
89 * Default Constructor
90 *
91 * @since 1.0
92 */
93 public JDBCInputAdapter() {
94 // no-op
95 }
96
97 /***
98 * Perform any resource initialization.
99 *
100 * @param props
101 * @throws InitializationException
102 * @since 1.0
103 */
104 public void init(Properties props) throws InitializationException {
105 // in case AbstractInputAdapter needs to do anything...
106 super.init(props);
107
108 query = props.getProperty(QUERY_KEY, "N/A");
109 if (query.equals("N/A")) {
110 throw new InitializationException(
111 "JDBCInputAdapter config error. "
112 + QUERY_KEY
113 + " property not found.");
114 }
115
116 String batchSizeString = props.getProperty(BATCH_SIZE_KEY, "0");
117 try {
118 batchSize = Long.parseLong(batchSizeString);
119 }
120 catch (NumberFormatException e) {
121 throw new InitializationException(
122 "batch size not number. " + "value = " + batchSizeString,
123 e);
124 }
125
126 try {
127 log = LogUtil.getLogger();
128 }
129 catch (ConfigurationException e) {
130 throw new InitializationException(e.toString(), e);
131 }
132 }
133
134 /***
135 * Retrieve all the source records that should be processed by the pipeline.
136 *
137 * @return Collection - contains all the records ready for processing.
138 * @throws ProcessingException
139 * @since 1.0
140 */
141 protected Collection loadBatch() throws ProcessingException {
142 log.debug("loadBatch()");
143
144 ArrayList records = new ArrayList();
145
146 Connection conn = null;
147 PreparedStatement stmt = null;
148 ResultSet rs = null;
149 try {
150 DataSource ds = DBUtil.getDataSource();
151 if (ds == null) {
152 log.error("DataSource invalid.");
153 throw new ProcessingException("DataSource invalid.");
154 }
155
156 conn = ds.getConnection();
157 if (conn == null) {
158 log.error("connection error.");
159 throw new ProcessingException("unable to retrieve db connection");
160 }
161
162 stmt = prepareStatement(conn);
163
164 rs = stmt.executeQuery();
165 while (rs.next()) { // using PK in select. only 1 row.
166 Record record = readRow(rs);
167 records.add(record);
168 }
169 log.debug("found " + records.size() + " source records");
170
171 return records;
172 }
173 catch (SQLException e) {
174 log.error("sqlexception thrown loading record", e);
175 throw new ProcessingException(e.toString(), e);
176 }
177 catch (ConfigurationException e) {
178 log.error("configuration exception in JDBCInputAdapter", e);
179 throw new ProcessingException(e.toString(), e);
180 }
181 finally {
182 if (rs != null) {
183 try {
184 rs.close();
185 }
186 catch (SQLException e) {
187 log.error("sqlexception closing resultset.", e);
188 }
189 }
190 if (stmt != null) {
191 try {
192 stmt.close();
193 }
194 catch (SQLException e) {
195 log.error("sqlexception closing db statement.", e);
196 }
197 }
198 if (conn != null) {
199 try {
200 conn.close();
201 }
202 catch (SQLException e) {
203 log.error("sqlexception closing db connection.", e);
204 }
205 }
206 }
207
208 }
209
210 /***
211 * Allow override of Statement preparation in cases where the Input
212 * Adapters should load batches of records.
213 *
214 * @param conn
215 * @return PreparedStatement
216 * @throws SQLException
217 *
218 * @since 1.1
219 */
220 protected PreparedStatement prepareStatement(Connection conn)
221 throws SQLException {
222 StringBuffer buf = new StringBuffer();
223 buf.append(getQuery());
224 if (getBatchSize() > 0) {
225 buf.append(" FETCH FIRST ");
226 buf.append(getBatchSize());
227 buf.append(" ROWS ONLY ");
228 }
229 else if (getQuery().indexOf("FOR FETCH ONLY") == -1) {
230 buf.append(" FOR FETCH ONLY ");
231 }
232 PreparedStatement stmt = conn.prepareStatement(buf.toString());
233
234 // bind values may be useful if you need to set parameters
235 // for your input adapter query.
236 bindValues(stmt);
237
238 return stmt;
239 }
240
241 /***
242 * Get method for SQL - allows override by sub-classes
243 *
244 * @return String SQL
245 *
246 * @since 1.0
247 */
248 protected String getQuery() {
249 return query;
250 }
251
252 /***
253 * Get method for batch size - allows override by sub-classes
254 *
255 * @return long batch size
256 *
257 * @since 1.0
258 */
259 protected long getBatchSize() {
260 return batchSize;
261 }
262
263 /***
264 * If necessary, bind the appropriate values to the PreparedStatement.
265 * The default implemenation is empty.
266 *
267 * @param stmt - the prepared statement to be executed.
268 * @throws SQLException
269 *
270 * @since 1.1
271 */
272 protected void bindValues(PreparedStatement stmt) throws SQLException {
273 // no op
274 }
275
276 /***
277 * Extract the attributes from the ResultSet and return a Record object.
278 * When overriding this method, create the appropriate Record type for
279 * your interface & return it through the generic Record interface.
280 *
281 * @param rs
282 * @exception SQLException
283 *
284 * @return Record
285 *
286 * @since 1.0
287 */
288 protected abstract Record readRow(ResultSet rs) throws SQLException;
289
290 }
This page was automatically generated by Maven