1 | |
package liquibase.integration.spring; |
2 | |
|
3 | |
import java.io.FileNotFoundException; |
4 | |
import java.io.IOException; |
5 | |
import java.io.InputStream; |
6 | |
import java.net.URL; |
7 | |
import java.sql.Connection; |
8 | |
import java.sql.SQLException; |
9 | |
import java.util.Enumeration; |
10 | |
import java.util.Map; |
11 | |
import java.util.Vector; |
12 | |
|
13 | |
import javax.sql.DataSource; |
14 | |
|
15 | |
import liquibase.Liquibase; |
16 | |
import liquibase.database.Database; |
17 | |
import liquibase.database.DatabaseFactory; |
18 | |
import liquibase.database.jvm.JdbcConnection; |
19 | |
import liquibase.exception.DatabaseException; |
20 | |
import liquibase.exception.LiquibaseException; |
21 | |
import liquibase.logging.LogFactory; |
22 | |
import liquibase.logging.Logger; |
23 | |
import liquibase.resource.ResourceAccessor; |
24 | |
|
25 | |
import org.springframework.beans.factory.BeanNameAware; |
26 | |
import org.springframework.beans.factory.InitializingBean; |
27 | |
import org.springframework.context.ResourceLoaderAware; |
28 | |
import org.springframework.core.io.Resource; |
29 | |
import org.springframework.core.io.ResourceLoader; |
30 | |
|
31 | |
|
32 | |
|
33 | |
|
34 | |
|
35 | |
|
36 | |
|
37 | |
|
38 | |
|
39 | |
|
40 | |
|
41 | |
|
42 | |
|
43 | |
|
44 | |
|
45 | |
|
46 | |
|
47 | |
|
48 | |
|
49 | |
|
50 | |
|
51 | |
|
52 | |
|
53 | |
|
54 | |
|
55 | |
|
56 | |
|
57 | |
|
58 | |
|
59 | |
|
60 | |
|
61 | |
|
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
|
67 | |
|
68 | |
|
69 | |
|
70 | |
|
71 | |
|
72 | |
public class SpringLiquibase implements InitializingBean, BeanNameAware, ResourceLoaderAware { |
73 | |
public class SpringResourceOpener implements ResourceAccessor { |
74 | |
private String parentFile; |
75 | |
|
76 | 0 | public SpringResourceOpener(String parentFile) { |
77 | 0 | this.parentFile = parentFile; |
78 | 0 | } |
79 | |
|
80 | |
public InputStream getResourceAsStream(String file) throws IOException { |
81 | |
try { |
82 | 0 | Resource resource = getResource(file); |
83 | 0 | return resource.getInputStream(); |
84 | 0 | } catch (FileNotFoundException ex) { |
85 | 0 | return null; |
86 | |
} |
87 | |
} |
88 | |
|
89 | |
public Enumeration<URL> getResources(String packageName) throws IOException { |
90 | 0 | Vector<URL> tmp = new Vector<URL>(); |
91 | |
|
92 | 0 | tmp.add(getResource(packageName).getURL()); |
93 | |
|
94 | 0 | return tmp.elements(); |
95 | |
} |
96 | |
|
97 | |
public Resource getResource(String file) { |
98 | 0 | return getResourceLoader().getResource(adjustClasspath(file)); |
99 | |
} |
100 | |
|
101 | |
private String adjustClasspath(String file) { |
102 | 0 | return isClasspathPrefixPresent(parentFile) && !isClasspathPrefixPresent(file) ? ResourceLoader.CLASSPATH_URL_PREFIX |
103 | |
+ file |
104 | |
: file; |
105 | |
} |
106 | |
|
107 | |
public boolean isClasspathPrefixPresent(String file) { |
108 | 0 | return file.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX); |
109 | |
} |
110 | |
|
111 | |
public ClassLoader toClassLoader() { |
112 | 0 | return getResourceLoader().getClassLoader(); |
113 | |
} |
114 | |
} |
115 | |
|
116 | |
private String beanName; |
117 | |
|
118 | |
private ResourceLoader resourceLoader; |
119 | |
|
120 | |
private DataSource dataSource; |
121 | |
|
122 | 0 | private Logger log = LogFactory.getLogger(SpringLiquibase.class.getName()); |
123 | |
|
124 | |
private String changeLog; |
125 | |
|
126 | |
private String contexts; |
127 | |
|
128 | |
private Map<String, String> parameters; |
129 | |
|
130 | |
private String defaultSchema; |
131 | |
|
132 | |
public SpringLiquibase() { |
133 | 0 | super(); |
134 | 0 | } |
135 | |
|
136 | |
public String getDatabaseProductName() throws DatabaseException { |
137 | 0 | Connection connection = null; |
138 | 0 | String name = "unknown"; |
139 | |
try { |
140 | 0 | connection = getDataSource().getConnection(); |
141 | 0 | Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation( |
142 | |
new JdbcConnection(dataSource.getConnection())); |
143 | 0 | name = database.getDatabaseProductName(); |
144 | 0 | } catch (SQLException e) { |
145 | 0 | throw new DatabaseException(e); |
146 | |
} finally { |
147 | 0 | if (connection != null) { |
148 | |
try { |
149 | 0 | if (!connection.getAutoCommit()) { |
150 | 0 | connection.rollback(); |
151 | |
} |
152 | 0 | connection.close(); |
153 | 0 | } catch (Exception e) { |
154 | 0 | log.warning("problem closing connection", e); |
155 | 0 | } |
156 | |
} |
157 | |
} |
158 | 0 | return name; |
159 | |
} |
160 | |
|
161 | |
|
162 | |
|
163 | |
|
164 | |
|
165 | |
|
166 | |
public DataSource getDataSource() { |
167 | 0 | return dataSource; |
168 | |
} |
169 | |
|
170 | |
|
171 | |
|
172 | |
|
173 | |
public void setDataSource(DataSource dataSource) { |
174 | 0 | this.dataSource = dataSource; |
175 | 0 | } |
176 | |
|
177 | |
|
178 | |
|
179 | |
|
180 | |
|
181 | |
|
182 | |
public String getChangeLog() { |
183 | 0 | return changeLog; |
184 | |
} |
185 | |
|
186 | |
|
187 | |
|
188 | |
|
189 | |
|
190 | |
public void setChangeLog(String dataModel) { |
191 | |
|
192 | 0 | this.changeLog = dataModel; |
193 | 0 | } |
194 | |
|
195 | |
public String getContexts() { |
196 | 0 | return contexts; |
197 | |
} |
198 | |
|
199 | |
public void setContexts(String contexts) { |
200 | 0 | this.contexts = contexts; |
201 | 0 | } |
202 | |
|
203 | |
public String getDefaultSchema() { |
204 | 0 | return defaultSchema; |
205 | |
} |
206 | |
|
207 | |
public void setDefaultSchema(String defaultSchema) { |
208 | 0 | this.defaultSchema = defaultSchema; |
209 | 0 | } |
210 | |
|
211 | |
|
212 | |
|
213 | |
|
214 | |
public void afterPropertiesSet() throws LiquibaseException { |
215 | 0 | String shouldRunProperty = System.getProperty(Liquibase.SHOULD_RUN_SYSTEM_PROPERTY); |
216 | 0 | if (shouldRunProperty != null && !Boolean.valueOf(shouldRunProperty)) { |
217 | 0 | System.out.println("Liquibase did not run because '" + Liquibase.SHOULD_RUN_SYSTEM_PROPERTY |
218 | |
+ "' system property was set to false"); |
219 | 0 | return; |
220 | |
} |
221 | |
|
222 | 0 | Connection c = null; |
223 | 0 | Liquibase liquibase = null; |
224 | |
try { |
225 | 0 | c = getDataSource().getConnection(); |
226 | 0 | liquibase = createLiquibase(c); |
227 | 0 | liquibase.update(getContexts()); |
228 | 0 | } catch (SQLException e) { |
229 | 0 | throw new DatabaseException(e); |
230 | |
} finally { |
231 | 0 | if (liquibase != null) { |
232 | 0 | liquibase.forceReleaseLocks(); |
233 | |
} |
234 | 0 | if (c != null) { |
235 | |
try { |
236 | 0 | c.rollback(); |
237 | 0 | c.close(); |
238 | 0 | } catch (SQLException e) { |
239 | |
|
240 | 0 | } |
241 | |
} |
242 | |
} |
243 | |
|
244 | 0 | } |
245 | |
|
246 | |
protected Liquibase createLiquibase(Connection c) throws LiquibaseException { |
247 | 0 | Liquibase liquibase = new Liquibase(getChangeLog(), createResourceOpener(), createDatabase(c)); |
248 | 0 | if (parameters != null) { |
249 | 0 | for (Map.Entry<String, String> entry : parameters.entrySet()) { |
250 | 0 | liquibase.setChangeLogParameter(entry.getKey(), entry.getValue()); |
251 | |
} |
252 | |
} |
253 | |
|
254 | 0 | return liquibase; |
255 | |
} |
256 | |
|
257 | |
|
258 | |
|
259 | |
|
260 | |
|
261 | |
|
262 | |
|
263 | |
|
264 | |
|
265 | |
protected Database createDatabase(Connection c) throws DatabaseException { |
266 | 0 | Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(c)); |
267 | 0 | if (this.defaultSchema != null) { |
268 | 0 | database.setDefaultSchemaName(this.defaultSchema); |
269 | |
} |
270 | 0 | return database; |
271 | |
} |
272 | |
|
273 | |
public void setChangeLogParameters(Map<String, String> parameters) { |
274 | 0 | this.parameters = parameters; |
275 | 0 | } |
276 | |
|
277 | |
|
278 | |
|
279 | |
|
280 | |
protected SpringResourceOpener createResourceOpener() { |
281 | 0 | return new SpringResourceOpener(getChangeLog()); |
282 | |
} |
283 | |
|
284 | |
|
285 | |
|
286 | |
|
287 | |
public void setBeanName(String name) { |
288 | 0 | this.beanName = name; |
289 | 0 | } |
290 | |
|
291 | |
|
292 | |
|
293 | |
|
294 | |
|
295 | |
|
296 | |
public String getBeanName() { |
297 | 0 | return beanName; |
298 | |
} |
299 | |
|
300 | |
public void setResourceLoader(ResourceLoader resourceLoader) { |
301 | 0 | this.resourceLoader = resourceLoader; |
302 | 0 | } |
303 | |
|
304 | |
public ResourceLoader getResourceLoader() { |
305 | 0 | return resourceLoader; |
306 | |
} |
307 | |
|
308 | |
@Override |
309 | |
public String toString() { |
310 | 0 | return getClass().getName() + "(" + this.getResourceLoader().toString() + ")"; |
311 | |
} |
312 | |
} |