001: /*
002: *
003: * The DbUnit Database Testing Framework
004: * Copyright (C)2002-2004, DbUnit.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: */
021:
022: package org.dbunit.ant;
023:
024: import org.slf4j.Logger;
025: import org.slf4j.LoggerFactory;
026:
027: import org.apache.tools.ant.AntClassLoader;
028: import org.apache.tools.ant.BuildException;
029: import org.apache.tools.ant.Project;
030: import org.apache.tools.ant.Task;
031: import org.apache.tools.ant.types.Path;
032: import org.apache.tools.ant.types.Reference;
033: import org.dbunit.DatabaseUnitException;
034: import org.dbunit.database.DatabaseConfig;
035: import org.dbunit.database.DatabaseConnection;
036: import org.dbunit.database.ForwardOnlyResultSetTableFactory;
037: import org.dbunit.database.IDatabaseConnection;
038: import org.dbunit.dataset.datatype.IDataTypeFactory;
039:
040: import java.sql.Connection;
041: import java.sql.Driver;
042: import java.sql.SQLException;
043: import java.util.ArrayList;
044: import java.util.Iterator;
045: import java.util.List;
046: import java.util.Properties;
047:
048: /**
049: * <code>DbUnitTask</code> is the task definition for an Ant
050: * interface to <code>DbUnit</code>. DbUnit is a JUnit extension
051: * which sets your database to a known state before executing your
052: * tasks.
053: *
054: * @author Timothy Ruppert
055: * @author Ben Cox
056: * @version $Revision: 558 $
057: * @since Jun 10, 2002
058: * @see org.apache.tools.ant.Task
059: */
060: public class DbUnitTask extends Task {
061:
062: /**
063: * Logger for this class
064: */
065: private static final Logger logger = LoggerFactory
066: .getLogger(DbUnitTask.class);
067:
068: /**
069: * Database connection
070: */
071: private Connection conn = null;
072:
073: /**
074: * DB driver.
075: */
076: private String driver = null;
077:
078: /**
079: * DB url.
080: */
081: private String url = null;
082:
083: /**
084: * User name.
085: */
086: private String userId = null;
087:
088: /**
089: * Password
090: */
091: private String password = null;
092:
093: /**
094: * DB schema.
095: */
096: private String schema = null;
097:
098: /**
099: * Steps
100: */
101: private List steps = new ArrayList();
102:
103: private Path classpath;
104:
105: private AntClassLoader loader;
106:
107: /**
108: * Flag for using the qualified table names.
109: */
110: private boolean useQualifiedTableNames = false;
111:
112: /**
113: * Flag for using batched statements.
114: */
115: private boolean supportBatchStatement = false;
116:
117: /**
118: * Flag for datatype warning.
119: */
120: private boolean datatypeWarning = true;
121:
122: private String escapePattern = null;
123:
124: private String dataTypeFactory = "org.dbunit.dataset.datatype.DefaultDataTypeFactory";
125:
126: /**
127: * Set the JDBC driver to be used.
128: */
129: public void setDriver(String driver) {
130: logger.debug("setDriver(driver=" + driver + ") - start");
131:
132: this .driver = driver;
133: }
134:
135: /**
136: * Set the DB connection url.
137: */
138: public void setUrl(String url) {
139: logger.debug("setUrl(url=" + url + ") - start");
140:
141: this .url = url;
142: }
143:
144: /**
145: * Set the user name for the DB connection.
146: */
147: public void setUserid(String userId) {
148: logger.debug("setUserid(userId=" + userId + ") - start");
149:
150: this .userId = userId;
151: }
152:
153: /**
154: * Set the password for the DB connection.
155: */
156: public void setPassword(String password) {
157: logger.debug("setPassword(password=" + password + ") - start");
158:
159: this .password = password;
160: }
161:
162: /**
163: * Set the schema for the DB connection.
164: */
165: public void setSchema(String schema) {
166: logger.debug("setSchema(schema=" + schema + ") - start");
167:
168: this .schema = schema;
169: }
170:
171: /**
172: * Set the flag for using the qualified table names.
173: */
174: public void setUseQualifiedTableNames(boolean useQualifiedTableNames) {
175: logger
176: .debug("setUseQualifiedTableNames(useQualifiedTableNames="
177: + useQualifiedTableNames + ") - start");
178:
179: this .useQualifiedTableNames = useQualifiedTableNames;
180: }
181:
182: /**
183: * Set the flag for supporting batch statements.
184: * NOTE: This property cannot be used to force the usage of batch
185: * statement if your database does not support it.
186: */
187: public void setSupportBatchStatement(boolean supportBatchStatement) {
188: logger.debug("setSupportBatchStatement(supportBatchStatement="
189: + supportBatchStatement + ") - start");
190:
191: this .supportBatchStatement = supportBatchStatement;
192: }
193:
194: public void setDatatypeWarning(boolean datatypeWarning) {
195: logger.debug("setDatatypeWarning(datatypeWarning="
196: + datatypeWarning + ") - start");
197:
198: this .datatypeWarning = datatypeWarning;
199: }
200:
201: public void setDatatypeFactory(String datatypeFactory) {
202: logger.debug("setDatatypeFactory(datatypeFactory="
203: + datatypeFactory + ") - start");
204:
205: this .dataTypeFactory = datatypeFactory;
206: }
207:
208: public void setEscapePattern(String escapePattern) {
209: logger.debug("setEscapePattern(escapePattern=" + escapePattern
210: + ") - start");
211:
212: this .escapePattern = escapePattern;
213: }
214:
215: /**
216: * Set the classpath for loading the driver.
217: */
218: public void setClasspath(Path classpath) {
219: logger.debug("setClasspath(classpath=" + classpath
220: + ") - start");
221:
222: if (this .classpath == null) {
223: this .classpath = classpath;
224: } else {
225: this .classpath.append(classpath);
226: }
227: }
228:
229: /**
230: * Create the classpath for loading the driver.
231: */
232: public Path createClasspath() {
233: logger.debug("createClasspath() - start");
234:
235: if (this .classpath == null) {
236: this .classpath = new Path(project);
237: }
238: return this .classpath.createPath();
239: }
240:
241: /**
242: * Set the classpath for loading the driver using the classpath reference.
243: */
244: public void setClasspathRef(Reference r) {
245: logger.debug("setClasspathRef(r=" + r + ") - start");
246:
247: createClasspath().setRefid(r);
248: }
249:
250: /**
251: * Gets the Steps.
252: */
253: public List getSteps() {
254: logger.debug("getSteps() - start");
255:
256: return steps;
257: }
258:
259: /**
260: * Adds an Operation.
261: */
262: public void addOperation(Operation operation) {
263: logger.debug("addOperation(operation) - start");
264:
265: steps.add(operation);
266: }
267:
268: /**
269: * Adds a Compare to the steps List.
270: */
271: public void addCompare(Compare compare) {
272: logger.debug("addCompare(compare) - start");
273:
274: steps.add(compare);
275: }
276:
277: /**
278: * Adds an Export to the steps List.
279: */
280: public void addExport(Export export) {
281: logger.debug("addExport(export) - start");
282:
283: export.setParentTask(this );
284: steps.add(export);
285: }
286:
287: /**
288: * Load the step and then execute it
289: */
290: public void execute() throws BuildException {
291: logger.debug("execute() - start");
292:
293: try {
294: IDatabaseConnection connection = createConnection();
295:
296: Iterator stepIter = steps.listIterator();
297: while (stepIter.hasNext()) {
298: DbUnitTaskStep step = (DbUnitTaskStep) stepIter.next();
299: log(step.getLogMessage(), Project.MSG_INFO);
300: step.execute(connection);
301: }
302: } catch (DatabaseUnitException e) {
303: logger.error("execute()", e);
304:
305: throw new BuildException(e, location);
306: } catch (SQLException e) {
307: logger.error("execute()", e);
308:
309: throw new BuildException(e, location);
310: } finally {
311: try {
312: if (conn != null) {
313: conn.close();
314: }
315: } catch (SQLException e) {
316: logger.error("execute()", e);
317: }
318: }
319: }
320:
321: IDatabaseConnection createConnection() throws SQLException {
322: logger.debug("createConnection() - start");
323:
324: if (driver == null) {
325: throw new BuildException("Driver attribute must be set!",
326: location);
327: }
328: if (userId == null) {
329: throw new BuildException("User Id attribute must be set!",
330: location);
331: }
332: if (password == null) {
333: throw new BuildException("Password attribute must be set!",
334: location);
335: }
336: if (url == null) {
337: throw new BuildException("Url attribute must be set!",
338: location);
339: }
340: if (steps.size() == 0) {
341: throw new BuildException(
342: "Must declare at least one step in a <dbunit> task!");
343: }
344:
345: // Instanciate JDBC driver
346: Driver driverInstance = null;
347: try {
348: Class dc;
349: if (classpath != null) {
350: log("Loading " + driver
351: + " using AntClassLoader with classpath "
352: + classpath, Project.MSG_VERBOSE);
353:
354: loader = new AntClassLoader(project, classpath);
355: dc = loader.loadClass(driver);
356: } else {
357: log("Loading " + driver + " using system loader.",
358: Project.MSG_VERBOSE);
359: dc = Class.forName(driver);
360: }
361: driverInstance = (Driver) dc.newInstance();
362: } catch (ClassNotFoundException e) {
363: logger.error("createConnection()", e);
364:
365: throw new BuildException("Class Not Found: JDBC driver "
366: + driver + " could not be loaded", e, location);
367: } catch (IllegalAccessException e) {
368: logger.error("createConnection()", e);
369:
370: throw new BuildException("Illegal Access: JDBC driver "
371: + driver + " could not be loaded", e, location);
372: } catch (InstantiationException e) {
373: logger.error("createConnection()", e);
374:
375: throw new BuildException(
376: "Instantiation Exception: JDBC driver " + driver
377: + " could not be loaded", e, location);
378: }
379:
380: log("connecting to " + url, Project.MSG_VERBOSE);
381: Properties info = new Properties();
382: info.put("user", userId);
383: info.put("password", password);
384: conn = driverInstance.connect(url, info);
385:
386: if (conn == null) {
387: // Driver doesn't understand the URL
388: throw new SQLException("No suitable Driver for " + url);
389: }
390: conn.setAutoCommit(true);
391:
392: IDatabaseConnection connection = new DatabaseConnection(conn,
393: schema);
394: DatabaseConfig config = connection.getConfig();
395: config.setFeature(DatabaseConfig.FEATURE_BATCHED_STATEMENTS,
396: supportBatchStatement);
397: config.setFeature(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES,
398: useQualifiedTableNames);
399: config.setFeature(DatabaseConfig.FEATURE_DATATYPE_WARNING,
400: datatypeWarning);
401: config.setProperty(DatabaseConfig.PROPERTY_ESCAPE_PATTERN,
402: escapePattern);
403: config.setProperty(
404: DatabaseConfig.PROPERTY_RESULTSET_TABLE_FACTORY,
405: new ForwardOnlyResultSetTableFactory());
406:
407: // Setup data type factory
408: try {
409: IDataTypeFactory dataTypeFactory = (IDataTypeFactory) Class
410: .forName(this .dataTypeFactory).newInstance();
411: config.setProperty(
412: DatabaseConfig.PROPERTY_DATATYPE_FACTORY,
413: dataTypeFactory);
414: } catch (ClassNotFoundException e) {
415: logger.error("createConnection()", e);
416:
417: throw new BuildException(
418: "Class Not Found: DataType factory " + driver
419: + " could not be loaded", e, location);
420: } catch (IllegalAccessException e) {
421: logger.error("createConnection()", e);
422:
423: throw new BuildException(
424: "Illegal Access: DataType factory " + driver
425: + " could not be loaded", e, location);
426: } catch (InstantiationException e) {
427: logger.error("createConnection()", e);
428:
429: throw new BuildException(
430: "Instantiation Exception: DataType factory "
431: + driver + " could not be loaded", e,
432: location);
433: }
434:
435: return connection;
436: }
437: }
|