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 public SpringResourceOpener(String parentFile) {
77 this.parentFile = parentFile;
78 }
79
80 public InputStream getResourceAsStream(String file) throws IOException {
81 try {
82 Resource resource = getResource(file);
83 return resource.getInputStream();
84 } catch (FileNotFoundException ex) {
85 return null;
86 }
87 }
88
89 public Enumeration<URL> getResources(String packageName) throws IOException {
90 Vector<URL> tmp = new Vector<URL>();
91
92 tmp.add(getResource(packageName).getURL());
93
94 return tmp.elements();
95 }
96
97 public Resource getResource(String file) {
98 return getResourceLoader().getResource(adjustClasspath(file));
99 }
100
101 private String adjustClasspath(String file) {
102 return isClasspathPrefixPresent(parentFile) && !isClasspathPrefixPresent(file) ? ResourceLoader.CLASSPATH_URL_PREFIX
103 + file
104 : file;
105 }
106
107 public boolean isClasspathPrefixPresent(String file) {
108 return file.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX);
109 }
110
111 public ClassLoader toClassLoader() {
112 return getResourceLoader().getClassLoader();
113 }
114 }
115
116 private String beanName;
117
118 private ResourceLoader resourceLoader;
119
120 private DataSource dataSource;
121
122 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 super();
134 }
135
136 public String getDatabaseProductName() throws DatabaseException {
137 Connection connection = null;
138 String name = "unknown";
139 try {
140 connection = getDataSource().getConnection();
141 Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(
142 new JdbcConnection(dataSource.getConnection()));
143 name = database.getDatabaseProductName();
144 } catch (SQLException e) {
145 throw new DatabaseException(e);
146 } finally {
147 if (connection != null) {
148 try {
149 if (!connection.getAutoCommit()) {
150 connection.rollback();
151 }
152 connection.close();
153 } catch (Exception e) {
154 log.warning("problem closing connection", e);
155 }
156 }
157 }
158 return name;
159 }
160
161
162
163
164
165
166 public DataSource getDataSource() {
167 return dataSource;
168 }
169
170
171
172
173 public void setDataSource(DataSource dataSource) {
174 this.dataSource = dataSource;
175 }
176
177
178
179
180
181
182 public String getChangeLog() {
183 return changeLog;
184 }
185
186
187
188
189
190 public void setChangeLog(String dataModel) {
191
192 this.changeLog = dataModel;
193 }
194
195 public String getContexts() {
196 return contexts;
197 }
198
199 public void setContexts(String contexts) {
200 this.contexts = contexts;
201 }
202
203 public String getDefaultSchema() {
204 return defaultSchema;
205 }
206
207 public void setDefaultSchema(String defaultSchema) {
208 this.defaultSchema = defaultSchema;
209 }
210
211
212
213
214 public void afterPropertiesSet() throws LiquibaseException {
215 String shouldRunProperty = System.getProperty(Liquibase.SHOULD_RUN_SYSTEM_PROPERTY);
216 if (shouldRunProperty != null && !Boolean.valueOf(shouldRunProperty)) {
217 System.out.println("Liquibase did not run because '" + Liquibase.SHOULD_RUN_SYSTEM_PROPERTY
218 + "' system property was set to false");
219 return;
220 }
221
222 Connection c = null;
223 Liquibase liquibase = null;
224 try {
225 c = getDataSource().getConnection();
226 liquibase = createLiquibase(c);
227 liquibase.update(getContexts());
228 } catch (SQLException e) {
229 throw new DatabaseException(e);
230 } finally {
231 if (liquibase != null) {
232 liquibase.forceReleaseLocks();
233 }
234 if (c != null) {
235 try {
236 c.rollback();
237 c.close();
238 } catch (SQLException e) {
239
240 }
241 }
242 }
243
244 }
245
246 protected Liquibase createLiquibase(Connection c) throws LiquibaseException {
247 Liquibase liquibase = new Liquibase(getChangeLog(), createResourceOpener(), createDatabase(c));
248 if (parameters != null) {
249 for (Map.Entry<String, String> entry : parameters.entrySet()) {
250 liquibase.setChangeLogParameter(entry.getKey(), entry.getValue());
251 }
252 }
253
254 return liquibase;
255 }
256
257
258
259
260
261
262
263
264
265 protected Database createDatabase(Connection c) throws DatabaseException {
266 Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(c));
267 if (this.defaultSchema != null) {
268 database.setDefaultSchemaName(this.defaultSchema);
269 }
270 return database;
271 }
272
273 public void setChangeLogParameters(Map<String, String> parameters) {
274 this.parameters = parameters;
275 }
276
277
278
279
280 protected SpringResourceOpener createResourceOpener() {
281 return new SpringResourceOpener(getChangeLog());
282 }
283
284
285
286
287 public void setBeanName(String name) {
288 this.beanName = name;
289 }
290
291
292
293
294
295
296 public String getBeanName() {
297 return beanName;
298 }
299
300 public void setResourceLoader(ResourceLoader resourceLoader) {
301 this.resourceLoader = resourceLoader;
302 }
303
304 public ResourceLoader getResourceLoader() {
305 return resourceLoader;
306 }
307
308 @Override
309 public String toString() {
310 return getClass().getName() + "(" + this.getResourceLoader().toString() + ")";
311 }
312 }