001 /**
002 * Copyright 2010-2013 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.common.jdbc.spring;
017
018 import java.util.ArrayList;
019 import java.util.List;
020
021 import javax.sql.DataSource;
022
023 import org.apache.commons.lang3.StringUtils;
024 import org.kuali.common.jdbc.JdbcExecutable;
025 import org.kuali.common.jdbc.context.JdbcContext;
026 import org.kuali.common.jdbc.context.SqlExecutionContext;
027 import org.kuali.common.jdbc.context.SqlMode;
028 import org.kuali.common.jdbc.listener.LogSqlListener;
029 import org.kuali.common.jdbc.listener.NotifyingListener;
030 import org.kuali.common.jdbc.listener.ProgressListener;
031 import org.kuali.common.jdbc.listener.SqlListener;
032 import org.kuali.common.jdbc.supplier.SqlSupplier;
033 import org.kuali.common.util.CollectionUtils;
034 import org.kuali.common.util.LocationUtils;
035 import org.kuali.common.util.Str;
036 import org.kuali.common.util.nullify.NullUtils;
037 import org.kuali.common.util.spring.SpringUtils;
038 import org.slf4j.Logger;
039 import org.slf4j.LoggerFactory;
040 import org.springframework.core.env.Environment;
041 import org.springframework.util.Assert;
042
043 /**
044 * @deprecated
045 */
046 @Deprecated
047 public class SqlConfigUtils {
048
049 private static final Logger logger = LoggerFactory.getLogger(SqlConfigUtils.class);
050
051 public static final String SQL_ORDER_KEY = "sql.execution.order";
052 public static final String RESOURCES_SUFFIX = ".resources";
053
054 public static final String SQL_NAMESPACE_TOKEN = "sql";
055
056 protected static final String SKIP_PROPERTY_KEY_SUFFIX = ".skip";
057
058 protected static final String SKIP_EXECUTABLE_PROPERTY_KEY_SUFFIX = ".executable.skip";
059
060 protected static final String TRACK_PROGRESS_KEY_SUFFIX = ".trackProgressByUpdateCount";
061
062 public static JdbcExecutable getJdbcExecutable(SqlConfigContext scc) {
063 String skipKey = scc.getContext().getGroup() + SKIP_EXECUTABLE_PROPERTY_KEY_SUFFIX;
064
065 JdbcContext context = getJdbcContext(scc);
066 context.setListener(getSqlListener(scc.getContext().getMode()));
067
068 JdbcExecutable exec = new JdbcExecutable();
069 exec.setSkip(SpringUtils.getBoolean(scc.getEnv(), skipKey, false));
070 exec.setService(scc.getCommonConfig().jdbcService());
071 exec.setContext(context);
072 return exec;
073 }
074
075 public static SqlListener getSqlListener(SqlMode mode) {
076 switch (mode) {
077 case CONCURRENT:
078 return new LogSqlListener();
079 case SEQUENTIAL:
080 List<SqlListener> listeners = new ArrayList<SqlListener>();
081 listeners.add(new LogSqlListener());
082 listeners.add(new ProgressListener());
083 return new NotifyingListener(listeners);
084 default:
085 throw new IllegalArgumentException("mode [" + mode.name() + "] is unknown");
086 }
087 }
088
089 public static JdbcContext getJdbcContext(SqlConfigContext scc) {
090 SqlExecutionContext ctx = scc.getContext();
091 SqlMode mode = ctx.getMode();
092 switch (mode) {
093 case CONCURRENT:
094 return getConcurrentJdbcContext(scc);
095 case SEQUENTIAL:
096 return getSequentialJdbcContext(scc);
097 default:
098 throw new IllegalArgumentException("mode [" + mode.name() + "] is unknown");
099 }
100 }
101
102 public static List<SqlExecutionContext> getSqlExecutionContexts(Environment env) {
103 // Extract the CSV value for "sql.execution.order" from the environment
104 String csv = SpringUtils.getProperty(env, SQL_ORDER_KEY);
105
106 // NONE or NULL means there is no sql to execute
107 if (NullUtils.isNullOrNone(csv)) {
108 csv = Str.EMPTY_STRING;
109 }
110
111 // Convert the CSV to a list of property keys
112 List<String> propertyKeys = CollectionUtils.getTrimmedListFromCSV(csv);
113
114 // Validate that the property keys referenced by sql.execution.order actually exist
115 // Validate that all of the resources referenced by any of the properties also exist
116 validateSqlExecutionOrderValues(env, propertyKeys);
117
118 // Convert the text values into pojo's
119 return getSqlExecutionContexts(propertyKeys);
120 }
121
122 public static void validateSqlExecutionOrderValues(Environment env, List<String> propertykeys) {
123
124 // Go through the list of keys and check each one
125 for (String propertyKey : propertykeys) {
126
127 // This is a CSV list of actual resources (or .resources files) to load
128 String csv = SpringUtils.getProperty(env, propertyKey);
129
130 // Extract the CSV list of resources referenced by this property key
131 List<String> resources = CollectionUtils.getTrimmedListFromCSV(csv);
132
133 // Validate that all of the resources exist and that all of the locations referenced by any .resources files also exist
134 validateResources(resources);
135 }
136 }
137
138 public static void validateResources(List<String> resources) {
139 // Validate that every resource exists
140 for (String resource : resources) {
141
142 // Make sure the .resources file exists
143 LocationUtils.validateLocation(resource);
144
145 // Make sure each resource inside the .resources file exists
146 if (StringUtils.endsWithIgnoreCase(resource, RESOURCES_SUFFIX)) {
147 LocationUtils.validateLocationListing(resource);
148 }
149 }
150 }
151
152 public static List<SqlExecutionContext> getSqlExecutionContexts(List<String> propertyKeys) {
153
154 // Setup some storage for the contexts
155 List<SqlExecutionContext> contexts = new ArrayList<SqlExecutionContext>();
156
157 // Each property key will be something like "sql.schema.concurrent" where the last 2 tokens represent the "group" and the "execution mode"
158 for (String propertyKey : propertyKeys) {
159
160 // properties are assumed to have the following structure:
161 // "sql." + any user string + "." + valid SqlMode
162 // ex. "sql.foo.bar.concurrent"
163 String[] tokens = StringUtils.split(propertyKey, Str.DOT);
164
165 // Must have at least 3 tokens
166 Assert.isTrue(tokens.length >= 3, "tokens.length < 3");
167
168 // These are the indexes corresponding to the tokens that indicate sql prefix and mode
169 int sqlTokenIndex = 0;
170 int modeIndex = tokens.length - 1;
171
172 Assert.isTrue(tokens[sqlTokenIndex].equals(SQL_NAMESPACE_TOKEN), "sql execution properties must start with a 'sql.' namespace");
173
174 StringBuilder sb = new StringBuilder();
175 boolean first = true;
176 for(int i = 0; i < tokens.length; i++) {
177
178 if (i != modeIndex) {
179 // append a dot, but only if at least one token has been appended
180 if(first) {
181 first = false;
182 }
183 else {
184 sb.append(Str.DOT);
185 }
186
187 // append the token
188 sb.append(tokens[i]);
189 }
190 }
191
192 // Extract the group. This can be any arbitrary text that indicates some kind of SQL grouping, eg "schema", "data", "other"
193 String group = sb.toString();
194
195 // Extract the mode and convert to upper case
196 // Only values allowed here are "sequential" and "concurrent"
197 String modeString = StringUtils.trim(tokens[modeIndex].toUpperCase());
198
199 // Convert the mode string to a strongly typed object
200 SqlMode mode = SqlMode.valueOf(modeString);
201
202 // Create a new context and add it to the list
203 contexts.add(new SqlExecutionContext(propertyKey, group, mode));
204 }
205
206 // Return the list we created
207 return contexts;
208 }
209
210 public static JdbcContext getConcurrentJdbcContext(SqlConfigContext rcc) {
211 String threads = SpringUtils.getProperty(rcc.getEnv(), "sql.threads");
212 JdbcContext ctx = getBaseJdbcContext(rcc);
213 ctx.setMultithreaded(true);
214 ctx.setThreads(new Integer(threads));
215 return ctx;
216 }
217
218 public static JdbcContext getSequentialJdbcContext(SqlConfigContext rcc) {
219 JdbcContext ctx = getBaseJdbcContext(rcc);
220 ctx.setMultithreaded(false);
221 ctx.setThreads(1);
222 return ctx;
223 }
224
225 protected static JdbcContext getBaseJdbcContext(SqlConfigContext scc) {
226 SqlExecutionContext sec = scc.getContext();
227 // dba, schema, data, constraints, other
228 String group = sec.getGroup();
229 // sql.dba.concurrent, sql.dba.sequential, sql.schema.concurrent, sql.schema.sequential, etc
230 String propertyKey = scc.getContext().getKey();
231 String skipKey = group + SKIP_PROPERTY_KEY_SUFFIX;
232 String trackProgressKey = propertyKey + TRACK_PROGRESS_KEY_SUFFIX;
233 String message = "[" + sec.getGroup() + ":" + sec.getMode().name().toLowerCase() + "]";
234
235
236 boolean skip = SpringUtils.getBoolean(scc.getEnv(), skipKey, false);
237 boolean trackProgressByUpdateCount = SpringUtils.getBoolean(scc.getEnv(), trackProgressKey, false);
238 logger.debug("{}={}", trackProgressKey, trackProgressByUpdateCount);
239 List<SqlSupplier> suppliers = scc.getCommonConfig().getSqlSuppliers(propertyKey);
240 DataSource dataSource = scc.getDataSourceConfig().jdbcDataSource();
241
242 JdbcContext ctx = new JdbcContext();
243 ctx.setMessage(message);
244 ctx.setSkip(skip);
245 ctx.setDataSource(dataSource);
246 ctx.setTrackProgressByUpdateCount(trackProgressByUpdateCount);
247 ctx.setSuppliers(suppliers);
248 return ctx;
249 }
250
251 }