Coverage Report - liquibase.integration.ant.BaseLiquibaseTask
 
Classes in this File Line Coverage Branch Coverage Complexity
BaseLiquibaseTask
6%
8/118
2%
1/38
1.654
BaseLiquibaseTask$1
0%
0/2
N/A
1.654
BaseLiquibaseTask$ChangeLogProperty
0%
0/7
N/A
1.654
BaseLiquibaseTask$LogRedirector
88%
8/9
N/A
1.654
BaseLiquibaseTask$LogRedirector$1
7%
1/14
0%
0/8
1.654
 
 1  
 package liquibase.integration.ant;
 2  
 
 3  
 import java.io.File;
 4  
 import java.io.FileWriter;
 5  
 import java.io.IOException;
 6  
 import java.io.PrintStream;
 7  
 import java.io.Writer;
 8  
 import java.net.URL;
 9  
 import java.net.URLClassLoader;
 10  
 import java.security.AccessController;
 11  
 import java.security.PrivilegedAction;
 12  
 import java.sql.Connection;
 13  
 import java.sql.Driver;
 14  
 import java.util.ArrayList;
 15  
 import java.util.HashMap;
 16  
 import java.util.List;
 17  
 import java.util.Map;
 18  
 import java.util.Properties;
 19  
 import java.util.logging.Handler;
 20  
 import java.util.logging.Level;
 21  
 import java.util.logging.LogRecord;
 22  
 
 23  
 import liquibase.Liquibase;
 24  
 import liquibase.database.Database;
 25  
 import liquibase.database.DatabaseFactory;
 26  
 import liquibase.database.jvm.JdbcConnection;
 27  
 import liquibase.exception.DatabaseException;
 28  
 import liquibase.logging.LogFactory;
 29  
 import liquibase.logging.Logger;
 30  
 import liquibase.resource.CompositeResourceAccessor;
 31  
 import liquibase.resource.FileSystemResourceAccessor;
 32  
 import liquibase.resource.ResourceAccessor;
 33  
 
 34  
 import org.apache.tools.ant.AntClassLoader;
 35  
 import org.apache.tools.ant.BuildException;
 36  
 import org.apache.tools.ant.Project;
 37  
 import org.apache.tools.ant.Task;
 38  
 import org.apache.tools.ant.types.Path;
 39  
 import org.apache.tools.ant.types.Reference;
 40  
 
 41  
 /**
 42  
  * Base class for all Ant Liquibase tasks. This class sets up Liquibase and defines parameters that are common to all
 43  
  * tasks.
 44  
  */
 45  
 public class BaseLiquibaseTask extends Task {
 46  
     private String changeLogFile;
 47  
     private String driver;
 48  
     private String url;
 49  
     private String username;
 50  
     private String password;
 51  
     protected Path classpath;
 52  1
     private boolean promptOnNonLocalDatabase = false;
 53  
     private String currentDateTimeFunction;
 54  
     private String contexts;
 55  
     private String outputFile;
 56  
     private String defaultSchemaName;
 57  
     private String databaseClass;
 58  
     private String databaseChangeLogTableName;
 59  
     private String databaseChangeLogLockTableName;
 60  
 
 61  1
     private Map<String, Object> changeLogProperties = new HashMap<String, Object>();
 62  
 
 63  
     public BaseLiquibaseTask() {
 64  1
         super();
 65  1
         new LogRedirector(this).redirectLogger();
 66  1
     }
 67  
 
 68  
     @Override
 69  
     public void execute() throws BuildException {
 70  0
         super.execute();
 71  
 
 72  0
         AntClassLoader loader = getProject().createClassLoader(classpath);
 73  0
         loader.setParent(this.getClass().getClassLoader());
 74  0
         loader.setThreadContextLoader();
 75  
 
 76  0
     }
 77  
 
 78  
     public boolean isPromptOnNonLocalDatabase() {
 79  0
         return promptOnNonLocalDatabase;
 80  
     }
 81  
 
 82  
     public void setPromptOnNonLocalDatabase(boolean promptOnNonLocalDatabase) {
 83  0
         this.promptOnNonLocalDatabase = promptOnNonLocalDatabase;
 84  0
     }
 85  
 
 86  
     public String getDriver() {
 87  0
         return driver;
 88  
     }
 89  
 
 90  
     public void setDriver(String driver) {
 91  0
         this.driver = driver.trim();
 92  0
     }
 93  
 
 94  
     public String getUrl() {
 95  0
         return url;
 96  
     }
 97  
 
 98  
     public void setUrl(String url) {
 99  0
         this.url = url.trim();
 100  0
     }
 101  
 
 102  
     public String getUsername() {
 103  0
         return username;
 104  
     }
 105  
 
 106  
     public void setUsername(String username) {
 107  0
         this.username = username.trim();
 108  0
     }
 109  
 
 110  
     public String getPassword() {
 111  0
         return password;
 112  
     }
 113  
 
 114  
     public void setPassword(String password) {
 115  0
         this.password = password.trim();
 116  0
     }
 117  
 
 118  
     public String getChangeLogFile() {
 119  0
         return changeLogFile;
 120  
     }
 121  
 
 122  
     public void setChangeLogFile(String changeLogFile) {
 123  0
         this.changeLogFile = changeLogFile.trim();
 124  0
     }
 125  
 
 126  
     public Path createClasspath() {
 127  1
         if (this.classpath == null) {
 128  1
             this.classpath = new Path(getProject());
 129  
         }
 130  1
         return this.classpath.createPath();
 131  
     }
 132  
 
 133  
     public void setClasspathRef(Reference r) {
 134  0
         createClasspath().setRefid(r);
 135  0
     }
 136  
 
 137  
     public String getCurrentDateTimeFunction() {
 138  0
         return currentDateTimeFunction;
 139  
     }
 140  
 
 141  
     public void setCurrentDateTimeFunction(String currentDateTimeFunction) {
 142  0
         this.currentDateTimeFunction = currentDateTimeFunction.trim();
 143  0
     }
 144  
 
 145  
     public String getOutputFile() {
 146  0
         return outputFile;
 147  
     }
 148  
 
 149  
     public void setOutputFile(String outputFile) {
 150  0
         this.outputFile = outputFile.trim();
 151  0
     }
 152  
 
 153  
     public Writer createOutputWriter() throws IOException {
 154  0
         if (outputFile == null) {
 155  0
             return null;
 156  
         }
 157  0
         return new FileWriter(new File(getOutputFile()));
 158  
     }
 159  
 
 160  
     public PrintStream createPrintStream() throws IOException {
 161  0
         if (outputFile == null) {
 162  0
             return null;
 163  
         }
 164  0
         return new PrintStream(new File(getOutputFile()));
 165  
     }
 166  
 
 167  
     public String getDefaultSchemaName() {
 168  0
         return defaultSchemaName;
 169  
     }
 170  
 
 171  
     public void setDefaultSchemaName(String defaultSchemaName) {
 172  0
         this.defaultSchemaName = defaultSchemaName.trim();
 173  0
     }
 174  
 
 175  
     public void addConfiguredChangeLogProperty(ChangeLogProperty changeLogProperty) {
 176  0
         changeLogProperties.put(changeLogProperty.getName(), changeLogProperty.getValue());
 177  0
     }
 178  
 
 179  
     protected Liquibase createLiquibase() throws Exception {
 180  0
         ResourceAccessor antFO = new AntResourceAccessor(getProject(), classpath);
 181  0
         ResourceAccessor fsFO = new FileSystemResourceAccessor();
 182  
 
 183  0
         Database database = createDatabaseObject(getDriver(), getUrl(), getUsername(), getPassword(),
 184  
                 getDefaultSchemaName(), getDatabaseClass());
 185  
 
 186  0
         String changeLogFile = null;
 187  0
         if (getChangeLogFile() != null) {
 188  0
             changeLogFile = getChangeLogFile().trim();
 189  
         }
 190  0
         Liquibase liquibase = new Liquibase(changeLogFile, new CompositeResourceAccessor(antFO, fsFO), database);
 191  0
         liquibase.setCurrentDateTimeFunction(currentDateTimeFunction);
 192  0
         for (Map.Entry<String, Object> entry : changeLogProperties.entrySet()) {
 193  0
             liquibase.setChangeLogParameter(entry.getKey(), entry.getValue());
 194  
         }
 195  
 
 196  0
         return liquibase;
 197  
     }
 198  
 
 199  
     protected Database createDatabaseObject(String driverClassName, String databaseUrl, String username,
 200  
             String password, String defaultSchemaName, String databaseClass) throws Exception {
 201  0
         String[] strings = classpath.list();
 202  
 
 203  0
         final List<URL> taskClassPath = new ArrayList<URL>();
 204  0
         for (String string : strings) {
 205  0
             URL url = new File(string).toURL();
 206  0
             taskClassPath.add(url);
 207  
         }
 208  
 
 209  0
         URLClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<URLClassLoader>() {
 210  
             @Override
 211  
             public URLClassLoader run() {
 212  0
                 return new URLClassLoader(taskClassPath.toArray(new URL[taskClassPath.size()]), Database.class
 213  
                         .getClassLoader());
 214  
             }
 215  
         });
 216  
 
 217  
         Database database;
 218  
 
 219  0
         if (databaseClass != null) {
 220  
             try {
 221  0
                 DatabaseFactory.getInstance().register(
 222  
                         (Database) Class.forName(databaseClass, true, loader).newInstance());
 223  0
             } catch (ClassCastException e) { // fails in Ant in particular
 224  0
                 DatabaseFactory.getInstance().register((Database) Class.forName(databaseClass).newInstance());
 225  0
             }
 226  
         }
 227  
 
 228  0
         if (driverClassName == null) {
 229  0
             driverClassName = DatabaseFactory.getInstance().findDefaultDriver(databaseUrl);
 230  
         }
 231  
 
 232  0
         if (driverClassName == null) {
 233  0
             throw new DatabaseException("driver not specified and no default could be found for " + databaseUrl);
 234  
         }
 235  
 
 236  0
         Driver driver = (Driver) Class.forName(driverClassName, true, loader).newInstance();
 237  
 
 238  0
         Properties info = new Properties();
 239  0
         if (username != null) {
 240  0
             info.put("user", username);
 241  
         }
 242  0
         if (password != null) {
 243  0
             info.put("password", password);
 244  
         }
 245  0
         Connection connection = driver.connect(databaseUrl, info);
 246  
 
 247  0
         if (connection == null) {
 248  0
             throw new DatabaseException("Connection could not be created to " + databaseUrl + " with driver "
 249  
                     + driver.getClass().getName() + ".  Possibly the wrong driver for the given database URL");
 250  
         }
 251  
 
 252  0
         database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
 253  0
         database.setDefaultSchemaName(defaultSchemaName);
 254  
 
 255  0
         if (getDatabaseChangeLogTableName() != null)
 256  0
             database.setDatabaseChangeLogTableName(getDatabaseChangeLogTableName());
 257  
 
 258  0
         if (getDatabaseChangeLogLockTableName() != null)
 259  0
             database.setDatabaseChangeLogLockTableName(getDatabaseChangeLogLockTableName());
 260  
 
 261  0
         return database;
 262  
     }
 263  
 
 264  
     public String getContexts() {
 265  0
         return contexts;
 266  
     }
 267  
 
 268  
     public void setContexts(String cntx) {
 269  0
         this.contexts = cntx.trim();
 270  0
     }
 271  
 
 272  
     /**
 273  
      * Redirector of logs from java.util.logging to ANT's loggging
 274  
      */
 275  0
     protected static class LogRedirector {
 276  
 
 277  
         private final Task task;
 278  
 
 279  
         /**
 280  
          * Constructor
 281  
          * 
 282  
          * @param task
 283  
          */
 284  
         protected LogRedirector(Task task) {
 285  1
             super();
 286  1
             this.task = task;
 287  1
         }
 288  
 
 289  
         protected void redirectLogger() {
 290  1
             registerHandler(createHandler());
 291  1
         }
 292  
 
 293  
         protected void registerHandler(Handler theHandler) {
 294  1
             Logger logger = LogFactory.getLogger();
 295  1
         }
 296  
 
 297  
         protected Handler createHandler() {
 298  1
             return new Handler() {
 299  
                 @Override
 300  
                 public void publish(LogRecord logRecord) {
 301  0
                     task.log(logRecord.getMessage(), mapLevelToAntLevel(logRecord.getLevel()));
 302  0
                 }
 303  
 
 304  
                 @Override
 305  
                 public void close() throws SecurityException {
 306  0
                 }
 307  
 
 308  
                 @Override
 309  
                 public void flush() {
 310  0
                 }
 311  
 
 312  
                 protected int mapLevelToAntLevel(Level level) {
 313  0
                     if (Level.ALL == level) {
 314  0
                         return Project.MSG_INFO;
 315  0
                     } else if (Level.SEVERE == level) {
 316  0
                         return Project.MSG_ERR;
 317  0
                     } else if (Level.WARNING == level) {
 318  0
                         return Project.MSG_WARN;
 319  0
                     } else if (Level.INFO == level) {
 320  0
                         return Project.MSG_INFO;
 321  
                     } else {
 322  0
                         return Project.MSG_VERBOSE;
 323  
                     }
 324  
                 }
 325  
             };
 326  
         }
 327  
 
 328  
     }
 329  
 
 330  
     protected boolean shouldRun() {
 331  0
         String shouldRunProperty = System.getProperty(Liquibase.SHOULD_RUN_SYSTEM_PROPERTY);
 332  0
         if (shouldRunProperty != null && !Boolean.valueOf(shouldRunProperty)) {
 333  0
             log("Liquibase did not run because '" + Liquibase.SHOULD_RUN_SYSTEM_PROPERTY
 334  
                     + "' system property was set to false");
 335  0
             return false;
 336  
         }
 337  0
         return true;
 338  
     }
 339  
 
 340  
     protected void closeDatabase(Liquibase liquibase) {
 341  0
         if (liquibase != null && liquibase.getDatabase() != null && liquibase.getDatabase().getConnection() != null) {
 342  
             try {
 343  0
                 liquibase.getDatabase().close();
 344  0
             } catch (DatabaseException e) {
 345  0
                 log("Error closing database: " + e.getMessage());
 346  0
             }
 347  
         }
 348  0
     }
 349  
 
 350  
     public String getDatabaseClass() {
 351  0
         return databaseClass;
 352  
     }
 353  
 
 354  
     public void setDatabaseClass(String databaseClass) {
 355  0
         this.databaseClass = databaseClass;
 356  0
     }
 357  
 
 358  
     public String getDatabaseChangeLogTableName() {
 359  0
         return databaseChangeLogTableName;
 360  
     }
 361  
 
 362  
     public void setDatabaseChangeLogTableName(String tableName) {
 363  0
         this.databaseChangeLogTableName = tableName;
 364  0
     }
 365  
 
 366  
     public String getDatabaseChangeLogLockTableName() {
 367  0
         return databaseChangeLogLockTableName;
 368  
     }
 369  
 
 370  
     public void setDatabaseChangeLogLockTableName(String tableName) {
 371  0
         this.databaseChangeLogLockTableName = tableName;
 372  0
     }
 373  
 
 374  
     public String getLogLevel() {
 375  0
         return LogFactory.getLogger().getLogLevel().name();
 376  
     }
 377  
 
 378  
     public void setLogLevel(String level) {
 379  0
         LogFactory.getLogger().setLogLevel(level);
 380  0
     }
 381  
 
 382  0
     public static class ChangeLogProperty {
 383  
         private String name;
 384  
         private String value;
 385  
 
 386  
         public String getName() {
 387  0
             return name;
 388  
         }
 389  
 
 390  
         public void setName(String name) {
 391  0
             this.name = name;
 392  0
         }
 393  
 
 394  
         public String getValue() {
 395  0
             return value;
 396  
         }
 397  
 
 398  
         public void setValue(String value) {
 399  0
             this.value = value;
 400  0
         }
 401  
     }
 402  
 }