001: package liquibase.servlet;
002:
003: import liquibase.log.LogFactory;
004: import liquibase.*;
005: import liquibase.util.NetUtil;
006: import liquibase.database.DatabaseFactory;
007:
008: import javax.servlet.ServletContextListener;
009: import javax.servlet.ServletContextEvent;
010: import javax.naming.Context;
011: import javax.naming.InitialContext;
012: import javax.sql.DataSource;
013: import java.util.logging.Handler;
014: import java.util.logging.LogRecord;
015: import java.net.InetAddress;
016: import java.net.UnknownHostException;
017: import java.sql.Connection;
018:
019: /**
020: * Servlet listener than can be added to web.xml to allow LiquiBase to run on every application server startup.
021: * Using this listener allows users to know that they always have the most up to date database, although it will
022: * slow down application server startup slightly.
023: * See the <a href="http://www.liquibase.org/manual/latest/servlet_listener_migrator.html">LiquiBase documentation</a> for
024: * more information.
025: */
026: public class LiquibaseServletListener implements ServletContextListener {
027:
028: private String changeLogFile;
029: private String dataSource;
030: private String contexts;
031:
032: public String getChangeLogFile() {
033: return changeLogFile;
034: }
035:
036: public void setContexts(String ctxt) {
037: contexts = ctxt;
038: }
039:
040: public String getContexts() {
041: return contexts;
042: }
043:
044: public void setChangeLogFile(String changeLogFile) {
045: this .changeLogFile = changeLogFile;
046: }
047:
048: public String getDataSource() {
049: return dataSource;
050: }
051:
052: public void setDataSource(String dataSource) {
053: this .dataSource = dataSource;
054: }
055:
056: public void contextInitialized(
057: ServletContextEvent servletContextEvent) {
058: LogFactory.getLogger().addHandler(new Handler() {
059: public synchronized void publish(LogRecord record) {
060: LiquibaseStatusServlet.logMessage(record);
061: }
062:
063: public void flush() {
064: }
065:
066: public void close() throws SecurityException {
067: }
068: });
069: String hostName;
070: try {
071: hostName = NetUtil.getLocalHost().getHostName();
072: } catch (Exception e) {
073: servletContextEvent.getServletContext().log(
074: "Cannot find hostname: " + e.getMessage());
075: return;
076: }
077:
078: String shouldRunProperty = System
079: .getProperty(Liquibase.SHOULD_RUN_SYSTEM_PROPERTY);
080: if (shouldRunProperty != null
081: && !Boolean.valueOf(shouldRunProperty)) {
082: LogFactory.getLogger().info(
083: "LiquiBase did not run on " + hostName
084: + " because '"
085: + Liquibase.SHOULD_RUN_SYSTEM_PROPERTY
086: + "' system property was set to false");
087: return;
088: }
089:
090: String machineIncludes = servletContextEvent
091: .getServletContext().getInitParameter(
092: "LIQUIBASE_HOST_INCLUDES");
093: String machineExcludes = servletContextEvent
094: .getServletContext().getInitParameter(
095: "LIQUIBASE_HOST_EXCLUDES");
096: String failOnError = servletContextEvent.getServletContext()
097: .getInitParameter("LIQUIBASE_FAIL_ON_ERROR");
098:
099: boolean shouldRun = false;
100: if (machineIncludes == null && machineExcludes == null) {
101: shouldRun = true;
102: } else if (machineIncludes != null) {
103: for (String machine : machineIncludes.split(",")) {
104: machine = machine.trim();
105: if (hostName.equalsIgnoreCase(machine)) {
106: shouldRun = true;
107: }
108: }
109: } else if (machineExcludes != null) {
110: shouldRun = true;
111: for (String machine : machineExcludes.split(",")) {
112: machine = machine.trim();
113: if (hostName.equalsIgnoreCase(machine)) {
114: shouldRun = false;
115: }
116: }
117: }
118:
119: if (!shouldRun) {
120: servletContextEvent
121: .getServletContext()
122: .log(
123: "LiquibaseServletListener did not run due to LIQUIBASE_HOST_INCLUDES and/or LIQUIBASE_HOST_EXCLUDES");
124: return;
125: }
126:
127: setDataSource(servletContextEvent.getServletContext()
128: .getInitParameter("LIQUIBASE_DATA_SOURCE"));
129: setChangeLogFile(servletContextEvent.getServletContext()
130: .getInitParameter("LIQUIBASE_CHANGELOG"));
131: setContexts(servletContextEvent.getServletContext()
132: .getInitParameter("LIQUIBASE_CONTEXTS"));
133: if (getChangeLogFile() == null) {
134: throw new RuntimeException(
135: "Cannot run LiquiBase, LIQUIBASE_CHANGELOG is not set");
136: }
137: if (getDataSource() == null) {
138: throw new RuntimeException(
139: "Cannot run LiquiBase, LIQUIBASE_DATA_SOURCE is not set");
140: }
141:
142: try {
143: Context ic = null;
144: Connection connection = null;
145: try {
146: ic = new InitialContext();
147: DataSource dataSource = (DataSource) ic
148: .lookup(this .dataSource);
149:
150: connection = dataSource.getConnection();
151:
152: FileOpener clFO = new ClassLoaderFileOpener();
153: FileOpener fsFO = new FileSystemFileOpener();
154:
155: Liquibase liquibase = new Liquibase(getChangeLogFile(),
156: new CompositeFileOpener(clFO, fsFO),
157: DatabaseFactory.getInstance()
158: .findCorrectDatabaseImplementation(
159: connection));
160: liquibase.update(getContexts());
161: } finally {
162: if (ic != null) {
163: ic.close();
164: }
165: if (connection != null) {
166: connection.close();
167: connection.close();
168: }
169: }
170:
171: } catch (Exception e) {
172: if (!"false".equals(failOnError)) {
173: throw new RuntimeException(e);
174: }
175: }
176: }
177:
178: public void contextDestroyed(ServletContextEvent servletContextEvent) {
179: }
180:
181: }
|