View Javadoc

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 -&gt; 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 }