DbUnitTask.java

  1. /*
  2.  *
  3.  * The DbUnit Database Testing Framework
  4.  * Copyright (C)2002-2004, DbUnit.org
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Lesser General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2.1 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Lesser General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Lesser General Public
  17.  * License along with this library; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  *
  20.  */
  21. package org.dbunit.ant;

  22. import java.sql.Connection;
  23. import java.sql.Driver;
  24. import java.sql.SQLException;
  25. import java.util.ArrayList;
  26. import java.util.Iterator;
  27. import java.util.List;
  28. import java.util.Properties;

  29. import org.apache.tools.ant.AntClassLoader;
  30. import org.apache.tools.ant.BuildException;
  31. import org.apache.tools.ant.Project;
  32. import org.apache.tools.ant.Task;
  33. import org.apache.tools.ant.types.Path;
  34. import org.apache.tools.ant.types.Reference;
  35. import org.dbunit.DatabaseUnitException;
  36. import org.dbunit.database.DatabaseConfig;
  37. import org.dbunit.database.DatabaseConnection;
  38. import org.dbunit.database.IDatabaseConnection;
  39. import org.dbunit.dataset.datatype.IDataTypeFactory;
  40. import org.slf4j.Logger;
  41. import org.slf4j.LoggerFactory;

  42. /**
  43.  * <code>DbUnitTask</code> is the task definition for an Ant
  44.  * interface to <code>DbUnit</code>.   DbUnit is a JUnit extension
  45.  * which sets your database to a known state before executing your
  46.  * tasks.
  47.  *
  48.  * @author Timothy Ruppert
  49.  * @author Ben Cox
  50.  * @version $Revision$
  51.  * @since Jun 10, 2002
  52.  * @see org.apache.tools.ant.Task
  53.  */
  54. public class DbUnitTask extends Task
  55. {
  56.     private static final Logger logger = LoggerFactory.getLogger(DbUnitTask.class);

  57.     /**
  58.      * Database connection
  59.      */
  60.     private Connection conn = null;

  61.     /**
  62.      * DB driver.
  63.      */
  64.     private String driver = null;

  65.     /**
  66.      * DB url.
  67.      */
  68.     private String url = null;

  69.     /**
  70.      * User name.
  71.      */
  72.     private String userId = null;

  73.     /**
  74.      * Password
  75.      */
  76.     private String password = null;

  77.     /**
  78.      * DB schema.
  79.      */
  80.     private String schema = null;

  81.     /**
  82.      * Steps
  83.      */
  84.     private List steps = new ArrayList();

  85.     private Path classpath;

  86.     private AntClassLoader loader;

  87.     /**
  88.      * DB configuration child element to configure {@link DatabaseConfig} properties
  89.      * in a generic way.
  90.      */
  91.     private DbConfig dbConfig;

  92.     /**
  93.      * Flag for using the qualified table names.
  94.      * @deprecated since 2.4. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  95.      */
  96.     @Deprecated
  97.     private Boolean useQualifiedTableNames = null;

  98.     /**
  99.      * Flag for using batched statements.
  100.      * @deprecated since 2.4. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  101.      */
  102.     @Deprecated
  103.     private Boolean supportBatchStatement = null;

  104.     /**
  105.      * Flag for datatype warning.
  106.      * @deprecated since 2.4. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  107.      */
  108.     @Deprecated
  109.     private Boolean datatypeWarning = null;

  110.     /**
  111.      * @deprecated since 2.4. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  112.      */
  113.     @Deprecated
  114.     private String escapePattern = null;

  115.     /**
  116.      * @deprecated since 2.4. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  117.      */
  118.     @Deprecated
  119.     private String dataTypeFactory = null;

  120.     /**
  121.      * @deprecated since 2.4. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  122.      */
  123.     @Deprecated
  124.     private String batchSize = null;

  125.     /**
  126.      * @deprecated since 2.4. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  127.      */
  128.     @Deprecated
  129.     private String fetchSize = null;

  130.     /**
  131.      * @deprecated since 2.4. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  132.      */
  133.     @Deprecated
  134.     private Boolean skipOracleRecycleBinTables = null;

  135.     /**
  136.      * @deprecated since 2.5.1. Use {@link #dbConfig} instead. Only here because of backwards compatibility should be removed in the next major release.
  137.      */
  138.     @Deprecated
  139.     private Boolean allowEmptyFields = null;

  140.     /**
  141.      * Set the JDBC driver to be used.
  142.      */
  143.     public void setDriver(final String driver)
  144.     {
  145.         logger.trace("setDriver(driver={}) - start", driver);
  146.         this.driver = driver;
  147.     }

  148.     /**
  149.      * Set the DB connection url.
  150.      */
  151.     public void setUrl(final String url)
  152.     {
  153.         logger.trace("setUrl(url={}) - start", url);
  154.         this.url = url;
  155.     }

  156.     /**
  157.      * Set the user name for the DB connection.
  158.      */
  159.     public void setUserid(final String userId)
  160.     {
  161.         logger.trace("setUserid(userId={}) - start", userId);
  162.         this.userId = userId;
  163.     }

  164.     /**
  165.      * Set the password for the DB connection.
  166.      */
  167.     public void setPassword(final String password)
  168.     {
  169.         logger.trace("setPassword(password=*****) - start");
  170.         this.password = password;
  171.     }

  172.     /**
  173.      * Set the schema for the DB connection.
  174.      */
  175.     public void setSchema(final String schema)
  176.     {
  177.         logger.trace("setSchema(schema={}) - start", schema);
  178.         this.schema = schema;
  179.     }

  180.     /**
  181.      * Set the flag for using the qualified table names.
  182.      */
  183.     public void setUseQualifiedTableNames(final Boolean useQualifiedTableNames)
  184.     {
  185.         logger.trace("setUseQualifiedTableNames(useQualifiedTableNames={}) - start", String.valueOf(useQualifiedTableNames));
  186.         this.useQualifiedTableNames = useQualifiedTableNames;
  187.     }

  188.     /**
  189.      * Set the flag for supporting batch statements.
  190.      * NOTE: This property cannot be used to force the usage of batch
  191.      *       statement if your database does not support it.
  192.      */
  193.     public void setSupportBatchStatement(final Boolean supportBatchStatement)
  194.     {
  195.         logger.trace("setSupportBatchStatement(supportBatchStatement={}) - start", String.valueOf(supportBatchStatement));
  196.         this.supportBatchStatement = supportBatchStatement;
  197.     }

  198.     public void setDatatypeWarning(final Boolean datatypeWarning)
  199.     {
  200.         logger.trace("setDatatypeWarning(datatypeWarning={}) - start", String.valueOf(datatypeWarning));
  201.         this.datatypeWarning = datatypeWarning;
  202.     }

  203.     public void setDatatypeFactory(final String datatypeFactory)
  204.     {
  205.         logger.trace("setDatatypeFactory(datatypeFactory={}) - start", datatypeFactory);
  206.         this.dataTypeFactory = datatypeFactory;
  207.     }

  208.     public void setEscapePattern(final String escapePattern)
  209.     {
  210.         logger.trace("setEscapePattern(escapePattern={}) - start", escapePattern);
  211.         this.escapePattern = escapePattern;
  212.     }

  213.     public DbConfig getDbConfig()
  214.     {
  215.         return dbConfig;
  216.     }

  217.     //    public void setDbConfig(DbConfig dbConfig)
  218.     //    {
  219.     //        logger.debug("setDbConfig(dbConfig={}) - start", dbConfig);
  220.     //        this.dbConfig = dbConfig;
  221.     //    }

  222.     public void addDbConfig(final DbConfig dbConfig)
  223.     {
  224.         logger.trace("addDbConfig(dbConfig={}) - start", dbConfig);
  225.         this.dbConfig = dbConfig;
  226.     }

  227.     /**
  228.      * Set the classpath for loading the driver.
  229.      */
  230.     public void setClasspath(final Path classpath)
  231.     {
  232.         logger.trace("setClasspath(classpath={}) - start", classpath);
  233.         if (this.classpath == null)
  234.         {
  235.             this.classpath = classpath;
  236.         }
  237.         else
  238.         {
  239.             this.classpath.append(classpath);
  240.         }
  241.     }

  242.     /**
  243.      * Create the classpath for loading the driver.
  244.      */
  245.     public Path createClasspath()
  246.     {
  247.         logger.trace("createClasspath() - start");

  248.         if (this.classpath == null)
  249.         {
  250.             this.classpath = new Path(getProject());
  251.         }
  252.         return this.classpath.createPath();
  253.     }

  254.     /**
  255.      * Set the classpath for loading the driver using the classpath reference.
  256.      */
  257.     public void setClasspathRef(final Reference r)
  258.     {
  259.         logger.trace("setClasspathRef(r={}) - start", r);

  260.         createClasspath().setRefid(r);
  261.     }

  262.     /**
  263.      * Gets the Steps.
  264.      */
  265.     public List getSteps()
  266.     {
  267.         return steps;
  268.     }

  269.     /**
  270.      * Adds an Operation.
  271.      */
  272.     public void addOperation(final Operation operation)
  273.     {
  274.         logger.trace("addOperation({}) - start", operation);

  275.         steps.add(operation);
  276.     }

  277.     /**
  278.      * Adds a Compare to the steps List.
  279.      */
  280.     public void addCompare(final Compare compare)
  281.     {
  282.         logger.trace("addCompare({}) - start", compare);

  283.         steps.add(compare);
  284.     }

  285.     /**
  286.      * Adds an Export to the steps List.
  287.      */
  288.     public void addExport(final Export export)
  289.     {
  290.         logger.trace("addExport(export={}) - start", export);

  291.         steps.add(export);
  292.     }


  293.     public String getBatchSize()
  294.     {
  295.         return batchSize;
  296.     }

  297.     /**
  298.      * sets the size of batch inserts.
  299.      * @param batchSize
  300.      */
  301.     public void setBatchSize(final String batchSize)
  302.     {
  303.         this.batchSize = batchSize;
  304.     }


  305.     public String getFetchSize()
  306.     {
  307.         return fetchSize;
  308.     }

  309.     public void setFetchSize(final String fetchSize)
  310.     {
  311.         this.fetchSize = fetchSize;
  312.     }

  313.     public void setSkipOracleRecycleBinTables(final Boolean skipOracleRecycleBinTables)
  314.     {
  315.         this.skipOracleRecycleBinTables = skipOracleRecycleBinTables;
  316.     }

  317.     /**
  318.      * Load the step and then execute it.
  319.      */
  320.     @Override
  321.     public void execute() throws BuildException
  322.     {
  323.         logger.trace("execute() - start");

  324.         try
  325.         {
  326.             final IDatabaseConnection connection = createConnection();

  327.             final Iterator stepIter = steps.listIterator();
  328.             while (stepIter.hasNext())
  329.             {
  330.                 final DbUnitTaskStep step = (DbUnitTaskStep)stepIter.next();
  331.                 log(step.getLogMessage(), Project.MSG_INFO);
  332.                 step.execute(connection);
  333.             }
  334.         }
  335.         catch (DatabaseUnitException | SQLException e)
  336.         {
  337.             throw new BuildException(e, getLocation());
  338.         }
  339.         finally
  340.         {
  341.             try
  342.             {
  343.                 if (conn != null)
  344.                 {
  345.                     conn.close();
  346.                 }
  347.             }
  348.             catch (final SQLException e)
  349.             {
  350.                 logger.error("execute()", e);
  351.             }
  352.         }
  353.     }

  354.     protected IDatabaseConnection createConnection() throws SQLException
  355.     {
  356.         logger.trace("createConnection() - start");

  357.         if (driver == null)
  358.         {
  359.             throw new BuildException("Driver attribute must be set!", getLocation());
  360.         }
  361.         if (userId == null)
  362.         {
  363.             throw new BuildException("User Id attribute must be set!", getLocation());
  364.         }
  365.         if (password == null)
  366.         {
  367.             throw new BuildException("Password attribute must be set!", getLocation());
  368.         }
  369.         if (url == null)
  370.         {
  371.             throw new BuildException("Url attribute must be set!", getLocation());
  372.         }
  373.         if (steps.size() == 0)
  374.         {
  375.             throw new BuildException("Must declare at least one step in a <dbunit> task!", getLocation());
  376.         }

  377.         // Instantiate JDBC driver
  378.         Driver driverInstance = null;
  379.         try
  380.         {
  381.             Class dc;
  382.             if (classpath != null)
  383.             {
  384.                 log("Loading " + driver + " using AntClassLoader with classpath " + classpath,
  385.                         Project.MSG_VERBOSE);

  386.                 loader = new AntClassLoader(getProject(), classpath);
  387.                 dc = loader.loadClass(driver);
  388.             }
  389.             else
  390.             {
  391.                 log("Loading " + driver + " using system loader.", Project.MSG_VERBOSE);
  392.                 dc = Class.forName(driver);
  393.             }
  394.             driverInstance = (Driver)dc.newInstance();
  395.         }
  396.         catch (final ClassNotFoundException e)
  397.         {
  398.             throw new BuildException("Class Not Found: JDBC driver "
  399.                     + driver + " could not be loaded", e, getLocation());
  400.         }
  401.         catch (final IllegalAccessException e)
  402.         {
  403.             throw new BuildException("Illegal Access: JDBC driver "
  404.                     + driver + " could not be loaded", e, getLocation());
  405.         }
  406.         catch (final InstantiationException e)
  407.         {
  408.             throw new BuildException("Instantiation Exception: JDBC driver "
  409.                     + driver + " could not be loaded", e, getLocation());
  410.         }

  411.         log("connecting to " + url, Project.MSG_VERBOSE);
  412.         final Properties info = new Properties();
  413.         info.put("user", userId);
  414.         info.put("password", password);
  415.         conn = driverInstance.connect(url, info);

  416.         if (conn == null)
  417.         {
  418.             // Driver doesn't understand the URL
  419.             throw new SQLException("No suitable Driver for " + url);
  420.         }
  421.         conn.setAutoCommit(true);

  422.         final IDatabaseConnection connection = createDatabaseConnection(conn, schema);
  423.         return connection;
  424.     }

  425.     /**
  426.      * Creates the dbunit connection using the two given arguments. The configuration
  427.      * properties of the dbunit connection are initialized using the fields of this class.
  428.      *
  429.      * @param jdbcConnection
  430.      * @param dbSchema
  431.      * @return The dbunit connection
  432.      */
  433.     protected IDatabaseConnection createDatabaseConnection(final Connection jdbcConnection,
  434.             final String dbSchema)
  435.     {
  436.         logger.trace("createDatabaseConnection(jdbcConnection={}, dbSchema={}) - start", jdbcConnection, dbSchema);

  437.         IDatabaseConnection connection = null;
  438.         try
  439.         {
  440.             connection = new DatabaseConnection(jdbcConnection, dbSchema);
  441.         }
  442.         catch(final DatabaseUnitException e)
  443.         {
  444.             throw new BuildException("Could not create dbunit connection object", e);
  445.         }
  446.         final DatabaseConfig config = connection.getConfig();

  447.         if(this.dbConfig != null){
  448.             try {
  449.                 this.dbConfig.copyTo(config);
  450.             }
  451.             catch(final DatabaseUnitException e)
  452.             {
  453.                 throw new BuildException("Could not populate dbunit config object", e, getLocation());
  454.             }
  455.         }

  456.         // For backwards compatibility (old mode overrides the new one) copy the other attributes to the config
  457.         copyAttributes(config);

  458.         log("Created connection for schema '" + schema + "' with config: " + config, Project.MSG_VERBOSE);

  459.         return connection;
  460.     }

  461.     /**
  462.      * @param config
  463.      * @deprecated since 2.4. Only here because of backwards compatibility should be removed in the next major release.
  464.      */
  465.     @Deprecated
  466.     private void copyAttributes(final DatabaseConfig config)
  467.     {
  468.         if(supportBatchStatement!=null)
  469.             config.setFeature(DatabaseConfig.FEATURE_BATCHED_STATEMENTS, supportBatchStatement.booleanValue());
  470.         if(useQualifiedTableNames!=null)
  471.             config.setFeature(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, useQualifiedTableNames.booleanValue());
  472.         if(datatypeWarning!=null)
  473.             config.setFeature(DatabaseConfig.FEATURE_DATATYPE_WARNING, datatypeWarning.booleanValue());
  474.         if(skipOracleRecycleBinTables!=null)
  475.             config.setFeature(DatabaseConfig.FEATURE_SKIP_ORACLE_RECYCLEBIN_TABLES, skipOracleRecycleBinTables.booleanValue());
  476.         if(allowEmptyFields!=null)
  477.             config.setFeature(DatabaseConfig.FEATURE_ALLOW_EMPTY_FIELDS, allowEmptyFields.booleanValue());

  478.         if(escapePattern!=null)
  479.         {
  480.             config.setProperty(DatabaseConfig.PROPERTY_ESCAPE_PATTERN, escapePattern);
  481.         }
  482.         if (batchSize != null)
  483.         {
  484.             final Integer batchSizeInteger = new Integer(batchSize);
  485.             config.setProperty(DatabaseConfig.PROPERTY_BATCH_SIZE, batchSizeInteger);
  486.         }
  487.         if (fetchSize != null)
  488.         {
  489.             config.setProperty(DatabaseConfig.PROPERTY_FETCH_SIZE, new Integer(fetchSize));
  490.         }

  491.         // Setup data type factory
  492.         if(this.dataTypeFactory!=null) {
  493.             try
  494.             {
  495.                 final IDataTypeFactory dataTypeFactory = (IDataTypeFactory)Class.forName(
  496.                         this.dataTypeFactory).newInstance();
  497.                 config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, dataTypeFactory);
  498.             }
  499.             catch (final ClassNotFoundException e)
  500.             {
  501.                 throw new BuildException("Class Not Found: DataType factory "
  502.                         + driver + " could not be loaded", e, getLocation());
  503.             }
  504.             catch (final IllegalAccessException e)
  505.             {
  506.                 throw new BuildException("Illegal Access: DataType factory "
  507.                         + driver + " could not be loaded", e, getLocation());
  508.             }
  509.             catch (final InstantiationException e)
  510.             {
  511.                 throw new BuildException("Instantiation Exception: DataType factory "
  512.                         + driver + " could not be loaded", e, getLocation());
  513.             }
  514.         }

  515.     }
  516. }