View Javadoc

1   /**
2    * Copyright 2010-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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  package org.kuali.common.jdbc;
17  
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.List;
21  import java.util.Properties;
22  
23  import org.apache.commons.lang3.StringUtils;
24  import org.junit.Ignore;
25  import org.junit.Test;
26  import org.kuali.common.jdbc.context.ExecutionContext;
27  import org.kuali.common.jdbc.context.JdbcContext;
28  import org.kuali.common.jdbc.listener.LogSqlListener;
29  import org.kuali.common.jdbc.listener.NotifyingListener;
30  import org.kuali.common.jdbc.listener.ProgressListener;
31  import org.kuali.common.jdbc.listener.SqlListener;
32  import org.kuali.common.jdbc.listener.SummaryListener;
33  import org.kuali.common.util.CollectionUtils;
34  import org.kuali.common.util.FormatUtils;
35  import org.kuali.common.util.LocationUtils;
36  import org.kuali.common.util.PropertyUtils;
37  import org.kuali.common.util.nullify.NullUtils;
38  import org.kuali.common.util.property.Constants;
39  import org.slf4j.Logger;
40  import org.slf4j.LoggerFactory;
41  import org.springframework.jdbc.datasource.DriverManagerDataSource;
42  import org.springframework.util.PropertyPlaceholderHelper;
43  
44  public class DefaultJdbcServiceTest {
45  
46  	private static final Logger logger = LoggerFactory.getLogger(DefaultJdbcServiceTest.class);
47  	PropertyPlaceholderHelper helper = Constants.DEFAULT_PROPERTY_PLACEHOLDER_HELPER;
48  	SqlReader reader = new DefaultSqlReader();
49  	String vendor = System.getProperty("db.vendor") == null ? "mysql" : System.getProperty("db.vendor");
50  	boolean mysqlRice = Boolean.getBoolean("mysql.rice");
51  	Properties properties = getProperties();
52  	JdbcContext jdbcDba = getJdbcDba();
53  	JdbcContext jdbcContext = getJdbc();
54  	String dataThreads = System.getProperty("sql.threads") == null ? getValue("sql.threads") : System.getProperty("sql.threads");
55  
56  	protected Properties getProperties() {
57  		Properties sql1 = PropertyUtils.load("classpath:org/kuali/common/sql/mysql.xml");
58  		Properties sql2 = PropertyUtils.load("classpath:org/kuali/common/sql/oracle.xml");
59  		Properties jdbc1 = PropertyUtils.load("classpath:org/kuali/common/jdbc/jdbc.properties");
60  		Properties jdbc2 = PropertyUtils.load("classpath:org/kuali/common/deploy/jdbc.properties");
61  		Properties service = PropertyUtils.load("classpath:org/kuali/common/jdbc/service.properties");
62  		Properties ole = PropertyUtils.load("classpath:ole-fs.properties");
63  		Properties properties = PropertyUtils.combine(sql1, sql2, jdbc1, jdbc2, ole, service);
64  		properties.setProperty("db.vendor", vendor);
65  		properties.setProperty("jdbc.username", "JDBCTEST");
66  		properties.setProperty("oracle.dba.url", "jdbc:oracle:thin:@oraperf.ks.kuali.org:1521:ORAPERF");
67  		properties.setProperty("oracle.dba.username", "master");
68  		properties.setProperty("oracle.dba.password", "gw570229");
69  		if (mysqlRice) {
70  			mysqlRice(properties);
71  		} else {
72  			mysqlLocalhost(properties);
73  		}
74  		return properties;
75  	}
76  
77  	protected void mysqlLocalhost(Properties properties) {
78  		properties.setProperty("mysql.dba.url", "jdbc:mysql://localhost");
79  		properties.setProperty("mysql.dba.username", "root");
80  		properties.setProperty("mysql.dba.password", "NONE");
81  	}
82  
83  	protected void mysqlRice(Properties properties) {
84  		properties.setProperty("mysql.dba.url", "jdbc:mysql://mysql.rice.kuali.org");
85  		properties.setProperty("mysql.dba.username", "master");
86  		properties.setProperty("mysql.dba.password", "gw570229");
87  	}
88  
89  	protected String getValue(String key) {
90  		String original = properties.getProperty(key);
91  		if (NullUtils.isNullOrNone(original)) {
92  			return null;
93  		}
94  		String resolved = helper.replacePlaceholders(original, properties);
95  		if (NullUtils.isNullOrNone(resolved)) {
96  			return null;
97  		} else {
98  			return resolved;
99  		}
100 	}
101 
102 	protected JdbcContext getJdbcDba() {
103 		String url = getValue("jdbc.dba.url");
104 		String driver = getValue("jdbc.driver");
105 		String username = getValue("jdbc.dba.username");
106 		String password = getValue("jdbc.dba.password");
107 		JdbcContext context = new JdbcContext();
108 		DriverManagerDataSource dataSource = new DriverManagerDataSource(url, username, password);
109 		dataSource.setDriverClassName(driver);
110 		context.setDataSource(dataSource);
111 		return context;
112 	}
113 
114 	protected JdbcContext getJdbc() {
115 
116 		String url = getValue("jdbc.url");
117 		String driver = getValue("jdbc.driver");
118 		String username = getValue("jdbc.username");
119 		String password = getValue("jdbc.password");
120 
121 		DriverManagerDataSource dataSource = new DriverManagerDataSource(url, username, password);
122 		dataSource.setDriverClassName(driver);
123 
124 		JdbcContext context = new JdbcContext();
125 		context.setDataSource(dataSource);
126 		return context;
127 	}
128 
129 	protected ExecutionContext getDbaContext() {
130 		ExecutionContext ec = new ExecutionContext();
131 		ec.setMessage("Executing DBA SQL");
132 		ec.setJdbcContext(jdbcDba);
133 		ec.setReader(reader);
134 		ec.setSql(Arrays.asList(getValue("sql.drop"), getValue("sql.create")));
135 		ec.setListener(getDbaListener());
136 		return ec;
137 	}
138 
139 	protected void validateExists(List<String> locations) {
140 		for (String location : locations) {
141 			if (!LocationUtils.exists(location)) {
142 				throw new IllegalArgumentException(location + " does not exist");
143 			}
144 		}
145 	}
146 
147 	protected List<ExecutionContext> getExecutionContexts(String prefix, int threads) {
148 
149 		String concurrent = getValue(prefix + ".concurrent");
150 		String sequential = getValue(prefix + ".sequential");
151 
152 		String concurrentMsg = getValue(prefix + ".concurrent.message");
153 		String sequentialMsg = getValue(prefix + ".sequential.message");
154 
155 		List<String> concurrentLocations = getLocationsFromCSV(concurrent);
156 		List<String> sequentialLocations = getLocationsFromCSV(sequential);
157 
158 		validateExists(concurrentLocations);
159 		validateExists(sequentialLocations);
160 
161 		String order = getValue(prefix + ".order");
162 		if (order == null) {
163 			order = "concurrent,sequential";
164 		}
165 		List<String> orderings = CollectionUtils.getTrimmedListFromCSV(order);
166 		if (orderings.size() != ExecutionMode.values().length) {
167 			throw new IllegalArgumentException("Only valid values for ordering are " + ExecutionMode.CONCURRENT + " and " + ExecutionMode.SEQUENTIAL);
168 		}
169 
170 		ExecutionMode one = ExecutionMode.valueOf(orderings.get(0).toUpperCase());
171 		ExecutionMode two = ExecutionMode.valueOf(orderings.get(1).toUpperCase());
172 
173 		// They can't be the same
174 		if (one.equals(two)) {
175 			throw new IllegalArgumentException(getInvalidOrderingMessage(order));
176 		}
177 
178 		List<ExecutionContext> contexts = new ArrayList<ExecutionContext>();
179 		ExecutionContext context1 = new ExecutionContext();
180 		ExecutionContext context2 = new ExecutionContext();
181 
182 		if (one.equals(ExecutionMode.CONCURRENT)) {
183 			// Concurrent first, then sequential
184 			context1.setLocations(concurrentLocations);
185 			context1.setThreads(threads);
186 			context1.setMessage(concurrentMsg);
187 			context2.setLocations(sequentialLocations);
188 			context2.setMessage(sequentialMsg);
189 		} else {
190 			// Sequential first, then concurrent
191 			context1.setLocations(sequentialLocations);
192 			context1.setMessage(sequentialMsg);
193 			context2.setLocations(concurrentLocations);
194 			context2.setMessage(concurrentMsg);
195 			context2.setThreads(threads);
196 		}
197 
198 		// Add context1 to the list (if it has any locations)
199 		if (!CollectionUtils.isEmpty(context1.getLocations())) {
200 			contexts.add(context1);
201 		}
202 
203 		// Add context2 to the list (if it has any locations)
204 		if (!CollectionUtils.isEmpty(context2.getLocations())) {
205 			contexts.add(context2);
206 		}
207 
208 		// Return the list
209 		return contexts;
210 	}
211 
212 	protected String getInvalidOrderingMessage(String order) {
213 		StringBuilder sb = new StringBuilder();
214 		sb.append("Ordering [" + order + "] is invalid.  ");
215 		sb.append("Ordering must be provided as either [" + ExecutionMode.CONCURRENT + "," + ExecutionMode.SEQUENTIAL + "] or ");
216 		sb.append("[" + ExecutionMode.CONCURRENT + "," + ExecutionMode.SEQUENTIAL + "]");
217 		return sb.toString();
218 	}
219 
220 	protected List<String> getLocationsFromCSV(String csv) {
221 		// Parse the CSV into a list
222 		List<String> keys = CollectionUtils.getTrimmedListFromCSV(csv);
223 
224 		// Allocate some storage for the locations we find
225 		List<String> locations = new ArrayList<String>();
226 
227 		// Iterate through the keys
228 		for (String key : keys) {
229 
230 			// Extract the value associated with the key
231 			String value = getValue(key);
232 
233 			// The properties file is not configured correctly
234 			if (value == null) {
235 				throw new IllegalArgumentException("Could not locate a value for [" + key + "]");
236 			}
237 
238 			// This key has a value but has been explicitly configured to NONE
239 			if (NullUtils.isNullOrNone(value)) {
240 				continue;
241 			}
242 
243 			// Are we dealing with a SQL file or a list of SQL files
244 			if (StringUtils.endsWith(key, ".list")) {
245 				// If the key we used to look up the value ends with ".list", the value is a resource containing a list of SQL locations
246 				locations.addAll(LocationUtils.getLocations(value));
247 			} else {
248 				// Otherwise, it is a SQL location itself
249 				locations.add(value);
250 			}
251 		}
252 
253 		// Return the locations we found
254 		return locations;
255 	}
256 
257 	protected NotifyingListener getDefaultListener() {
258 		List<SqlListener> listeners = new ArrayList<SqlListener>();
259 		listeners.add(new ProgressListener());
260 		listeners.add(new SummaryListener());
261 		return new NotifyingListener(listeners);
262 	}
263 
264 	protected NotifyingListener getDbaListener() {
265 		List<SqlListener> listeners = new ArrayList<SqlListener>();
266 		listeners.add(new LogSqlListener());
267 		listeners.add(new SummaryListener());
268 		return new NotifyingListener(listeners);
269 	}
270 
271 	@Test
272 	@Ignore
273 	public void testReset() {
274 		try {
275 
276 			logger.info(getValue("jdbc.url"));
277 			logger.info(getValue("jdbc.dba.url"));
278 			logger.info(getValue("jdbc.username"));
279 			logger.info(getValue("jdbc.password"));
280 			logger.info(getValue("jdbc.dba.username"));
281 			logger.info(getValue("jdbc.dba.password"));
282 
283 			int threads = new Integer(dataThreads);
284 
285 			List<ExecutionContext> schemas = getExecutionContexts("sql.schema", threads);
286 			List<ExecutionContext> data = getExecutionContexts("sql.data", threads);
287 			List<ExecutionContext> constraints = getExecutionContexts("sql.constraints", threads);
288 
289 			List<ExecutionContext> contexts = new ArrayList<ExecutionContext>();
290 			contexts.addAll(schemas);
291 			contexts.addAll(data);
292 			contexts.addAll(constraints);
293 
294 			boolean skip = Boolean.getBoolean("sql.skip") || false;
295 
296 			JdbcService service = new DefaultJdbcService();
297 			ExecutionContext dba = getDbaContext();
298 			dba.setExecute(!skip);
299 
300 			long start = System.currentTimeMillis();
301 			service.executeSql(dba);
302 			for (ExecutionContext context : contexts) {
303 				if (skip) {
304 					context.setExecute(false);
305 				}
306 				context.setEncoding("UTF-8");
307 				context.setReader(reader);
308 				context.setJdbcContext(jdbcContext);
309 				context.setListener(getDefaultListener());
310 				service.executeSql(context);
311 			}
312 			String time = FormatUtils.getTime(System.currentTimeMillis() - start);
313 			logger.info("Total time: {}", time);
314 		} catch (Throwable e) {
315 			e.printStackTrace();
316 		}
317 	}
318 }