1 | /* |
2 | * Copyright 2006-2007 the original author or authors. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | package org.springframework.batch.test; |
18 | |
19 | import java.io.IOException; |
20 | import java.util.List; |
21 | |
22 | import javax.sql.DataSource; |
23 | |
24 | import org.apache.commons.io.IOUtils; |
25 | import org.apache.commons.logging.Log; |
26 | import org.apache.commons.logging.LogFactory; |
27 | import org.springframework.beans.factory.BeanInitializationException; |
28 | import org.springframework.beans.factory.DisposableBean; |
29 | import org.springframework.beans.factory.InitializingBean; |
30 | import org.springframework.context.support.ClassPathXmlApplicationContext; |
31 | import org.springframework.core.io.Resource; |
32 | import org.springframework.dao.DataAccessException; |
33 | import org.springframework.jdbc.core.JdbcTemplate; |
34 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; |
35 | import org.springframework.transaction.TransactionStatus; |
36 | import org.springframework.transaction.support.TransactionCallback; |
37 | import org.springframework.transaction.support.TransactionTemplate; |
38 | import org.springframework.util.Assert; |
39 | import org.springframework.util.ClassUtils; |
40 | import org.springframework.util.StringUtils; |
41 | |
42 | /** |
43 | * Wrapper for a {@link DataSource} that can run scripts on start up and shut |
44 | * down. Us as a bean definition <br/><br/> |
45 | * |
46 | * Run this class to initialize a database in a running server process. |
47 | * Make sure the server is running first by launching the "hsql-server" from the |
48 | * <code>hsql.server</code> project. Then you can right click in Eclipse and |
49 | * Run As -> Java Application. Do the same any time you want to wipe the |
50 | * database and start again. |
51 | * |
52 | * @author Dave Syer |
53 | * |
54 | */ |
55 | public class DataSourceInitializer implements InitializingBean, DisposableBean { |
56 | |
57 | private static final Log logger = LogFactory.getLog(DataSourceInitializer.class); |
58 | |
59 | private Resource[] initScripts; |
60 | |
61 | private Resource[] destroyScripts; |
62 | |
63 | private DataSource dataSource; |
64 | |
65 | private boolean ignoreFailedDrop = true; |
66 | |
67 | private boolean initialized = false; |
68 | |
69 | /** |
70 | * Main method as convenient entry point. |
71 | * |
72 | * @param args |
73 | */ |
74 | public static void main(String... args) { |
75 | new ClassPathXmlApplicationContext(ClassUtils.addResourcePathToPackagePath(DataSourceInitializer.class, |
76 | DataSourceInitializer.class.getSimpleName() + "-context.xml")); |
77 | } |
78 | |
79 | @Override |
80 | public void destroy() { |
81 | if (destroyScripts==null) return; |
82 | for (int i = 0; i < destroyScripts.length; i++) { |
83 | Resource destroyScript = destroyScripts[i]; |
84 | try { |
85 | doExecuteScript(destroyScript); |
86 | } |
87 | catch (Exception e) { |
88 | if (logger.isDebugEnabled()) { |
89 | logger.warn("Could not execute destroy script [" + destroyScript + "]", e); |
90 | } |
91 | else { |
92 | logger.warn("Could not execute destroy script [" + destroyScript + "]"); |
93 | } |
94 | } |
95 | } |
96 | } |
97 | |
98 | @Override |
99 | public void afterPropertiesSet() throws Exception { |
100 | Assert.notNull(dataSource); |
101 | initialize(); |
102 | } |
103 | |
104 | private void initialize() { |
105 | if (!initialized) { |
106 | destroy(); |
107 | if (initScripts != null) { |
108 | for (int i = 0; i < initScripts.length; i++) { |
109 | Resource initScript = initScripts[i]; |
110 | doExecuteScript(initScript); |
111 | } |
112 | } |
113 | initialized = true; |
114 | } |
115 | } |
116 | |
117 | private void doExecuteScript(final Resource scriptResource) { |
118 | if (scriptResource == null || !scriptResource.exists()) |
119 | return; |
120 | TransactionTemplate transactionTemplate = new TransactionTemplate(new DataSourceTransactionManager(dataSource)); |
121 | transactionTemplate.execute(new TransactionCallback() { |
122 | |
123 | @Override |
124 | @SuppressWarnings("unchecked") |
125 | public Object doInTransaction(TransactionStatus status) { |
126 | JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource); |
127 | String[] scripts; |
128 | try { |
129 | scripts = StringUtils.delimitedListToStringArray(stripComments(IOUtils.readLines(scriptResource |
130 | .getInputStream())), ";"); |
131 | } |
132 | catch (IOException e) { |
133 | throw new BeanInitializationException("Cannot load script from [" + scriptResource + "]", e); |
134 | } |
135 | for (int i = 0; i < scripts.length; i++) { |
136 | String script = scripts[i].trim(); |
137 | if (StringUtils.hasText(script)) { |
138 | try { |
139 | jdbcTemplate.execute(script); |
140 | } |
141 | catch (DataAccessException e) { |
142 | if (ignoreFailedDrop && script.toLowerCase().startsWith("drop")) { |
143 | logger.debug("DROP script failed (ignoring): " + script); |
144 | } |
145 | else { |
146 | throw e; |
147 | } |
148 | } |
149 | } |
150 | } |
151 | return null; |
152 | } |
153 | |
154 | }); |
155 | |
156 | } |
157 | |
158 | private String stripComments(List<String> list) { |
159 | StringBuffer buffer = new StringBuffer(); |
160 | for (String line : list) { |
161 | if (!line.startsWith("//") && !line.startsWith("--")) { |
162 | buffer.append(line + "\n"); |
163 | } |
164 | } |
165 | return buffer.toString(); |
166 | } |
167 | |
168 | public void setInitScripts(Resource[] initScripts) { |
169 | this.initScripts = initScripts; |
170 | } |
171 | |
172 | public void setDestroyScripts(Resource[] destroyScripts) { |
173 | this.destroyScripts = destroyScripts; |
174 | } |
175 | |
176 | public void setDataSource(DataSource dataSource) { |
177 | this.dataSource = dataSource; |
178 | } |
179 | |
180 | public void setIgnoreFailedDrop(boolean ignoreFailedDrop) { |
181 | this.ignoreFailedDrop = ignoreFailedDrop; |
182 | } |
183 | |
184 | } |