001: package liquibase.ant;
002:
003: import liquibase.CompositeFileOpener;
004: import liquibase.FileOpener;
005: import liquibase.FileSystemFileOpener;
006: import liquibase.Liquibase;
007: import liquibase.database.Database;
008: import liquibase.database.DatabaseFactory;
009: import liquibase.exception.JDBCException;
010: import liquibase.log.LogFactory;
011: import org.apache.tools.ant.Project;
012: import org.apache.tools.ant.Task;
013: import org.apache.tools.ant.types.Path;
014: import org.apache.tools.ant.types.Reference;
015:
016: import java.io.*;
017: import java.net.URL;
018: import java.net.URLClassLoader;
019: import java.security.AccessController;
020: import java.security.PrivilegedAction;
021: import java.sql.Connection;
022: import java.sql.Driver;
023: import java.sql.SQLException;
024: import java.util.ArrayList;
025: import java.util.List;
026: import java.util.Properties;
027: import java.util.logging.Handler;
028: import java.util.logging.Level;
029: import java.util.logging.LogRecord;
030: import java.util.logging.Logger;
031:
032: /**
033: * Base class for all Ant LiquiBase tasks. This class sets up LiquiBase and defines parameters
034: * that are common to all tasks.
035: */
036: public class BaseLiquibaseTask extends Task {
037: private String changeLogFile;
038: private String driver;
039: private String url;
040: private String username;
041: private String password;
042: protected Path classpath;
043: private boolean promptOnNonLocalDatabase = false;
044: private String currentDateTimeFunction;
045: private String contexts;
046: private String outputFile;
047: private String defaultSchemaName;
048:
049: public BaseLiquibaseTask() {
050: super ();
051: new LogRedirector(this ).redirectLogger();
052: }
053:
054: public boolean isPromptOnNonLocalDatabase() {
055: return promptOnNonLocalDatabase;
056: }
057:
058: public void setPromptOnNonLocalDatabase(
059: boolean promptOnNonLocalDatabase) {
060: this .promptOnNonLocalDatabase = promptOnNonLocalDatabase;
061: }
062:
063: public String getDriver() {
064: return driver;
065: }
066:
067: public void setDriver(String driver) {
068: this .driver = driver;
069: }
070:
071: public String getUrl() {
072: return url;
073: }
074:
075: public void setUrl(String url) {
076: this .url = url;
077: }
078:
079: public String getUsername() {
080: return username;
081: }
082:
083: public void setUsername(String username) {
084: this .username = username;
085: }
086:
087: public String getPassword() {
088: return password;
089: }
090:
091: public void setPassword(String password) {
092: this .password = password;
093: }
094:
095: public String getChangeLogFile() {
096: return changeLogFile;
097: }
098:
099: public void setChangeLogFile(String changeLogFile) {
100: this .changeLogFile = changeLogFile;
101: }
102:
103: public Path createClasspath() {
104: if (this .classpath == null) {
105: this .classpath = new Path(getProject());
106: }
107: return this .classpath.createPath();
108: }
109:
110: public void setClasspathRef(Reference r) {
111: createClasspath().setRefid(r);
112: }
113:
114: public String getCurrentDateTimeFunction() {
115: return currentDateTimeFunction;
116: }
117:
118: public void setCurrentDateTimeFunction(
119: String currentDateTimeFunction) {
120: this .currentDateTimeFunction = currentDateTimeFunction;
121: }
122:
123: public String getOutputFile() {
124: return outputFile;
125: }
126:
127: public void setOutputFile(String outputFile) {
128: this .outputFile = outputFile;
129: }
130:
131: public Writer createOutputWriter() throws IOException {
132: if (outputFile == null) {
133: return null;
134: }
135: return new FileWriter(new File(getOutputFile()));
136: }
137:
138: public PrintStream createPrintStream() throws IOException {
139: if (outputFile == null) {
140: return null;
141: }
142: return new PrintStream(new File(getOutputFile()));
143: }
144:
145: public String getDefaultSchemaName() {
146: return defaultSchemaName;
147: }
148:
149: public void setDefaultSchemaName(String defaultSchemaName) {
150: this .defaultSchemaName = defaultSchemaName;
151: }
152:
153: protected Liquibase createLiquibase() throws Exception {
154: FileOpener antFO = new AntFileOpener(getProject(), classpath);
155: FileOpener fsFO = new FileSystemFileOpener();
156:
157: Database database = createDatabaseObject(getDriver(), getUrl(),
158: getUsername(), getPassword(), getDefaultSchemaName());
159: Liquibase liquibase = new Liquibase(getChangeLogFile().trim(),
160: new CompositeFileOpener(antFO, fsFO), database);
161: liquibase.setCurrentDateTimeFunction(currentDateTimeFunction);
162:
163: return liquibase;
164: }
165:
166: protected Database createDatabaseObject(String driverClassName,
167: String databaseUrl, String username, String password,
168: String defaultSchemaName) throws Exception {
169: String[] strings = classpath.list();
170:
171: final List<URL> taskClassPath = new ArrayList<URL>();
172: for (String string : strings) {
173: URL url = new File(string).toURL();
174: taskClassPath.add(url);
175: }
176:
177: URLClassLoader loader = AccessController
178: .doPrivileged(new PrivilegedAction<URLClassLoader>() {
179: public URLClassLoader run() {
180: return new URLClassLoader(taskClassPath
181: .toArray(new URL[taskClassPath.size()]));
182: }
183: });
184:
185: if (driverClassName == null) {
186: driverClassName = DatabaseFactory.getInstance()
187: .findDefaultDriver(databaseUrl);
188: }
189:
190: if (driverClassName == null) {
191: throw new JDBCException(
192: "driver not specified and no default could be found for "
193: + databaseUrl);
194: }
195:
196: Driver driver = (Driver) Class.forName(driverClassName, true,
197: loader).newInstance();
198:
199: Properties info = new Properties();
200: info.put("user", username);
201: info.put("password", password);
202: Connection connection = driver.connect(databaseUrl, info);
203:
204: if (connection == null) {
205: throw new JDBCException(
206: "Connection could not be created to "
207: + databaseUrl
208: + " with driver "
209: + driver.getClass().getName()
210: + ". Possibly the wrong driver for the given database URL");
211: }
212:
213: Database database = DatabaseFactory.getInstance()
214: .findCorrectDatabaseImplementation(connection);
215: database.setDefaultSchemaName(defaultSchemaName);
216:
217: return database;
218: }
219:
220: public String getContexts() {
221: return contexts;
222: }
223:
224: public void setContexts(String cntx) {
225: this .contexts = cntx;
226: }
227:
228: /**
229: * Redirector of logs from java.util.logging to ANT's loggging
230: */
231: protected static class LogRedirector {
232:
233: private final Task task;
234:
235: /**
236: * Constructor
237: *
238: * @param task
239: */
240: protected LogRedirector(Task task) {
241: super ();
242: this .task = task;
243: }
244:
245: protected void redirectLogger() {
246: registerHandler(createHandler());
247: }
248:
249: protected void registerHandler(Handler theHandler) {
250: Logger logger = LogFactory.getLogger();
251: for (Handler handler : logger.getHandlers()) {
252: logger.removeHandler(handler);
253: }
254: logger.addHandler(theHandler);
255: logger.setUseParentHandlers(false);
256: }
257:
258: protected Handler createHandler() {
259: return new Handler() {
260: public void publish(LogRecord logRecord) {
261: task.log(logRecord.getMessage(),
262: mapLevelToAntLevel(logRecord.getLevel()));
263: }
264:
265: @Override
266: public void close() throws SecurityException {
267: }
268:
269: @Override
270: public void flush() {
271: }
272:
273: protected int mapLevelToAntLevel(Level level) {
274: if (Level.ALL == level) {
275: return Project.MSG_INFO;
276: } else if (Level.SEVERE == level) {
277: return Project.MSG_ERR;
278: } else if (Level.WARNING == level) {
279: return Project.MSG_WARN;
280: } else if (Level.INFO == level) {
281: return Project.MSG_INFO;
282: } else {
283: return Project.MSG_VERBOSE;
284: }
285: }
286: };
287: }
288:
289: }
290:
291: protected boolean shouldRun() {
292: String shouldRunProperty = System
293: .getProperty(Liquibase.SHOULD_RUN_SYSTEM_PROPERTY);
294: if (shouldRunProperty != null
295: && !Boolean.valueOf(shouldRunProperty)) {
296: log("LiquiBase did not run because '"
297: + Liquibase.SHOULD_RUN_SYSTEM_PROPERTY
298: + "' system property was set to false");
299: return false;
300: }
301: return true;
302: }
303:
304: protected void closeDatabase(Liquibase liquibase) {
305: if (liquibase != null && liquibase.getDatabase() != null
306: && liquibase.getDatabase().getConnection() != null) {
307: try {
308: liquibase.getDatabase().close();
309: } catch (JDBCException e) {
310: log("Error closing database: " + e.getMessage());
311: }
312: }
313: }
314:
315: }
|