1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
|
15 | |
|
16 | |
package org.kuali.rice.core.framework.persistence.jdbc.sql; |
17 | |
|
18 | |
import java.sql.Timestamp; |
19 | |
import java.util.ArrayList; |
20 | |
import java.util.Arrays; |
21 | |
import java.util.Calendar; |
22 | |
import java.util.Collection; |
23 | |
import java.util.Collections; |
24 | |
import java.util.HashMap; |
25 | |
import java.util.List; |
26 | |
import java.util.Map; |
27 | |
import java.util.regex.Matcher; |
28 | |
import java.util.regex.Pattern; |
29 | |
|
30 | |
import org.apache.commons.lang.StringUtils; |
31 | |
import org.kuali.rice.core.framework.logic.LogicalOperator; |
32 | |
import org.kuali.rice.kns.util.KNSConstants; |
33 | |
|
34 | |
|
35 | |
|
36 | |
|
37 | |
|
38 | |
|
39 | |
|
40 | |
public final class SQLUtils { |
41 | |
|
42 | 0 | private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SQLUtils.class); |
43 | |
|
44 | |
private static final String DATE_REGEX_SMALL_TWO_DIGIT_YEAR = "^\\d{1,2}/\\d{1,2}/\\d{2}$|^\\d{1,2}-\\d{1,2}-\\d{2}$"; |
45 | |
private static final String DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT = "(\\d{1,2})[/,-](\\d{1,2})[/,-](\\d{2})"; |
46 | |
private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR = "^\\d{1,2}/\\d{1,2}/\\d{4}$|^\\d{1,2}-\\d{1,2}-\\d{4}$"; |
47 | |
private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT = "(\\d{1,2})[/,-](\\d{1,2})[/,-](\\d{4})"; |
48 | |
|
49 | |
private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST = "^\\d{4}/\\d{1,2}/\\d{1,2}$|^\\d{4}-\\d{1,2}-\\d{1,2}$"; |
50 | |
private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT = "(\\d{4})[/,-](\\d{1,2})[/,-](\\d{1,2})"; |
51 | |
|
52 | |
private static final String DATE_REGEX_WHOLENUM_SMALL = "^\\d{6}$"; |
53 | |
private static final String DATE_REGEX_WHOLENUM_SMALL_SPLIT = "(\\d{2})(\\d{2})(\\d{2})"; |
54 | |
private static final String DATE_REGEX_WHOLENUM_LARGE = "^\\d{8}$"; |
55 | |
private static final String DATE_REGEX_WHOLENUM_LARGE_SPLIT = "(\\d{2})(\\d{2})(\\d{4})"; |
56 | |
|
57 | |
private static final String TIME_REGEX = "([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])"; |
58 | |
|
59 | |
|
60 | 0 | private static final Collection<String> DOCUMENT_SEARCH_DATE_VALIDATION_REGEX_EXPRESSIONS = Collections.unmodifiableCollection(Arrays.asList(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR, DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST)); |
61 | |
|
62 | |
|
63 | |
private static final Map<String, String> REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION; |
64 | |
static { |
65 | 0 | final Map<String, String> map = new HashMap<String, String>(); |
66 | |
|
67 | 0 | map.put(DATE_REGEX_SMALL_TWO_DIGIT_YEAR, DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT); |
68 | 0 | map.put(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR, DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT); |
69 | 0 | map.put(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST, DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT); |
70 | 0 | map.put(DATE_REGEX_WHOLENUM_SMALL, DATE_REGEX_WHOLENUM_SMALL_SPLIT); |
71 | 0 | map.put(DATE_REGEX_WHOLENUM_LARGE,DATE_REGEX_WHOLENUM_LARGE_SPLIT); |
72 | 0 | REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION = Collections.unmodifiableMap(map); |
73 | 0 | } |
74 | |
|
75 | 0 | private SQLUtils() { |
76 | 0 | throw new UnsupportedOperationException("do not call"); |
77 | |
} |
78 | |
|
79 | |
|
80 | |
|
81 | |
|
82 | |
|
83 | |
|
84 | |
|
85 | |
|
86 | |
public static String getSqlFormattedDate(String date) { |
87 | 0 | DateComponent dc = formatDateToDateComponent(date, REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.keySet()); |
88 | 0 | if (dc == null) { |
89 | 0 | return null; |
90 | |
} |
91 | 0 | return dc.getYear() + "/" + dc.getMonth() + "/" + dc.getDate(); |
92 | |
} |
93 | |
|
94 | |
public static Timestamp convertStringDateToTimestamp(String dateWithoutTime) { |
95 | 0 | Pattern p = Pattern.compile(TIME_REGEX); |
96 | 0 | Matcher util = p.matcher(dateWithoutTime); |
97 | 0 | if (util.find()) { |
98 | 0 | dateWithoutTime = StringUtils.substringBeforeLast(dateWithoutTime, " "); |
99 | |
} |
100 | 0 | DateComponent formattedDate = formatDateToDateComponent(dateWithoutTime, REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.keySet()); |
101 | 0 | if (formattedDate == null) { |
102 | 0 | return null; |
103 | |
} |
104 | 0 | Calendar c = Calendar.getInstance(); |
105 | 0 | c.clear(); |
106 | 0 | c.set(Calendar.MONTH, Integer.valueOf(formattedDate.getMonth()).intValue() - 1); |
107 | 0 | c.set(Calendar.DATE, Integer.valueOf(formattedDate.getDate()).intValue()); |
108 | 0 | c.set(Calendar.YEAR, Integer.valueOf(formattedDate.getYear()).intValue()); |
109 | 0 | return convertCalendar(c); |
110 | |
} |
111 | |
|
112 | |
private static class DateComponent { |
113 | |
protected String month; |
114 | |
protected String date; |
115 | |
protected String year; |
116 | |
|
117 | 0 | public DateComponent(String year, String month, String date) { |
118 | 0 | this.month = month; |
119 | 0 | this.date = date; |
120 | 0 | this.year = year; |
121 | 0 | } |
122 | |
|
123 | |
public String getDate() { |
124 | 0 | return date; |
125 | |
} |
126 | |
|
127 | |
public String getMonth() { |
128 | 0 | return month; |
129 | |
} |
130 | |
|
131 | |
public String getYear() { |
132 | 0 | return year; |
133 | |
} |
134 | |
} |
135 | |
|
136 | |
|
137 | |
|
138 | |
|
139 | |
|
140 | |
|
141 | |
|
142 | |
|
143 | |
public static String getEntryFormattedDate(String date) { |
144 | 0 | Pattern p = Pattern.compile(TIME_REGEX); |
145 | 0 | Matcher util = p.matcher(date); |
146 | 0 | if (util.find()) { |
147 | 0 | date = StringUtils.substringBeforeLast(date, " "); |
148 | |
} |
149 | 0 | DateComponent dc = formatDateToDateComponent(date, DOCUMENT_SEARCH_DATE_VALIDATION_REGEX_EXPRESSIONS); |
150 | 0 | if (dc == null) { |
151 | 0 | return null; |
152 | |
} |
153 | 0 | return dc.getMonth() + "/" + dc.getDate() + "/" + dc.getYear(); |
154 | |
} |
155 | |
|
156 | |
private static DateComponent formatDateToDateComponent(String date, Collection<String> regularExpressionList) { |
157 | 0 | String matchingRegexExpression = null; |
158 | 0 | for (String string : regularExpressionList) { |
159 | 0 | String matchRegex = string; |
160 | 0 | if (!REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.containsKey(matchRegex)) { |
161 | 0 | String errorMsg = ""; |
162 | 0 | LOG.error("formatDateToDateComponent(String,List) " + errorMsg); |
163 | |
|
164 | |
} |
165 | 0 | Pattern p = Pattern.compile(matchRegex); |
166 | 0 | if ((p.matcher(date)).matches()) { |
167 | 0 | matchingRegexExpression = matchRegex; |
168 | 0 | break; |
169 | |
} |
170 | 0 | } |
171 | |
|
172 | 0 | if (matchingRegexExpression == null) { |
173 | 0 | String errorMsg = "formatDate(String,List) Date string given '" + date + "' is not valid according to Workflow defaults. Returning null value."; |
174 | 0 | if (StringUtils.isNotBlank(date)) { |
175 | 0 | LOG.warn(errorMsg); |
176 | |
} else { |
177 | 0 | LOG.debug(errorMsg); |
178 | |
} |
179 | 0 | return null; |
180 | |
} |
181 | 0 | String regexSplitExpression = REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.get(matchingRegexExpression); |
182 | |
|
183 | |
|
184 | |
|
185 | 0 | Pattern p = Pattern.compile(regexSplitExpression); |
186 | 0 | Matcher util = p.matcher(date); |
187 | 0 | util.matches(); |
188 | 0 | if (regexSplitExpression.equals(DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT)) { |
189 | 0 | StringBuffer yearBuf = new StringBuffer(); |
190 | 0 | StringBuffer monthBuf = new StringBuffer(); |
191 | 0 | StringBuffer dateBuf = new StringBuffer(); |
192 | 0 | Integer year = Integer.valueOf(util.group(3)); |
193 | |
|
194 | 0 | if (year.intValue() <= 50) { |
195 | 0 | yearBuf.append("20").append(util.group(3)); |
196 | 0 | } else if (util.group(3).length() < 3) { |
197 | 0 | yearBuf.append("19").append(util.group(3)); |
198 | |
} else { |
199 | 0 | yearBuf.append(util.group(3)); |
200 | |
} |
201 | |
|
202 | 0 | if (util.group(1).length() < 2) { |
203 | 0 | monthBuf.append("0").append(util.group(1)); |
204 | |
} else { |
205 | 0 | monthBuf.append(util.group(1)); |
206 | |
} |
207 | |
|
208 | 0 | if (util.group(2).length() < 2) { |
209 | 0 | dateBuf.append("0").append(util.group(2)); |
210 | |
} else { |
211 | 0 | dateBuf.append(util.group(2)); |
212 | |
} |
213 | |
|
214 | 0 | return new DateComponent(yearBuf.toString(), monthBuf.toString(), dateBuf.toString()); |
215 | |
|
216 | |
|
217 | 0 | } else if (regexSplitExpression.equals(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT)) { |
218 | 0 | StringBuffer yearBuf = new StringBuffer(util.group(3)); |
219 | 0 | StringBuffer monthBuf = new StringBuffer(); |
220 | 0 | StringBuffer dateBuf = new StringBuffer(); |
221 | |
|
222 | 0 | if (util.group(1).length() < 2) { |
223 | 0 | monthBuf.append("0").append(util.group(1)); |
224 | |
} else { |
225 | 0 | monthBuf.append(util.group(1)); |
226 | |
} |
227 | |
|
228 | 0 | if (util.group(2).length() < 2) { |
229 | 0 | dateBuf.append("0").append(util.group(2)); |
230 | |
} else { |
231 | 0 | dateBuf.append(util.group(2)); |
232 | |
} |
233 | |
|
234 | 0 | return new DateComponent(yearBuf.toString(), monthBuf.toString(), dateBuf.toString()); |
235 | |
|
236 | |
|
237 | 0 | } else if (regexSplitExpression.equals(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT)) { |
238 | 0 | StringBuffer yearBuf = new StringBuffer(util.group(1)); |
239 | 0 | StringBuffer monthBuf = new StringBuffer(); |
240 | 0 | StringBuffer dateBuf = new StringBuffer(); |
241 | |
|
242 | 0 | if (util.group(2).length() < 2) { |
243 | 0 | monthBuf.append("0").append(util.group(2)); |
244 | |
} else { |
245 | 0 | monthBuf.append(util.group(2)); |
246 | |
} |
247 | |
|
248 | 0 | if (util.group(3).length() < 2) { |
249 | 0 | dateBuf.append("0").append(util.group(3)); |
250 | |
} else { |
251 | 0 | dateBuf.append(util.group(3)); |
252 | |
} |
253 | |
|
254 | 0 | return new DateComponent(yearBuf.toString(), monthBuf.toString(), dateBuf.toString()); |
255 | |
|
256 | |
|
257 | 0 | } else if (regexSplitExpression.equals(DATE_REGEX_WHOLENUM_LARGE_SPLIT)) { |
258 | 0 | return new DateComponent(util.group(3), util.group(1), util.group(2)); |
259 | |
|
260 | |
|
261 | 0 | } else if (regexSplitExpression.equals(DATE_REGEX_WHOLENUM_SMALL_SPLIT)) { |
262 | 0 | StringBuffer yearBuf = new StringBuffer(); |
263 | 0 | Integer year = Integer.valueOf(util.group(3)); |
264 | |
|
265 | 0 | if (year.intValue() < 50) { |
266 | 0 | yearBuf.append("20"); |
267 | |
} else { |
268 | 0 | yearBuf.append("19"); |
269 | |
} |
270 | 0 | yearBuf.append(util.group(3)); |
271 | 0 | return new DateComponent(yearBuf.toString(), util.group(1), util.group(2)); |
272 | |
} else { |
273 | 0 | LOG.warn("formatDate(String,List) Date string given '" + date + "' is not valid according to Workflow defaults. Returning null value."); |
274 | 0 | return null; |
275 | |
} |
276 | |
} |
277 | |
|
278 | |
public static Calendar convertTimestamp(Timestamp timestamp) { |
279 | 0 | if (timestamp == null) { |
280 | 0 | return null; |
281 | |
} |
282 | 0 | Calendar calendar = Calendar.getInstance(); |
283 | 0 | calendar.setTime(timestamp); |
284 | 0 | return calendar; |
285 | |
} |
286 | |
|
287 | |
public static Timestamp convertCalendar(Calendar calendar) { |
288 | 0 | if (calendar == null) { |
289 | 0 | return null; |
290 | |
} |
291 | 0 | return new Timestamp(calendar.getTimeInMillis()); |
292 | |
} |
293 | |
|
294 | |
public static String cleanDate(String string) { |
295 | 0 | for (LogicalOperator op : LogicalOperator.RANGE_CHARACTERS) { |
296 | 0 | string = StringUtils.replace(string, op.op(), ""); |
297 | |
} |
298 | 0 | return string; |
299 | |
} |
300 | |
|
301 | |
public static String cleanNumericOfValidOperators(String string){ |
302 | 0 | for (LogicalOperator op : LogicalOperator.RANGE_CHARACTERS) { |
303 | 0 | string = StringUtils.replace(string, op.op(), ""); |
304 | |
} |
305 | 0 | string = StringUtils.replace(string, LogicalOperator.OR.op(), ""); |
306 | 0 | string = StringUtils.replace(string, LogicalOperator.AND.op(), ""); |
307 | 0 | string = StringUtils.replace(string, LogicalOperator.NOT.op(), ""); |
308 | |
|
309 | 0 | return string; |
310 | |
} |
311 | |
|
312 | |
|
313 | |
|
314 | |
|
315 | |
|
316 | |
|
317 | |
|
318 | |
public static String cleanString(String string) { |
319 | 0 | for (LogicalOperator op : LogicalOperator.QUERY_CHARACTERS) { |
320 | 0 | string = StringUtils.replace(string, op.op(), ""); |
321 | |
} |
322 | 0 | return string; |
323 | |
} |
324 | |
|
325 | |
|
326 | |
|
327 | |
|
328 | |
|
329 | |
|
330 | |
|
331 | |
|
332 | |
public static List<String> getCleanedSearchableValues(String valueEntered, String propertyDataType) { |
333 | 0 | List<String> lRet = null; |
334 | 0 | List<String> lTemp = getSearchableValues(valueEntered); |
335 | 0 | if(lTemp != null && !lTemp.isEmpty()){ |
336 | 0 | lRet = new ArrayList<String>(); |
337 | 0 | for(String val: lTemp){ |
338 | |
|
339 | 0 | if (KNSConstants.DATA_TYPE_STRING.equals(propertyDataType)) { |
340 | 0 | lRet.add(clean(val)); |
341 | 0 | } else if (KNSConstants.DATA_TYPE_FLOAT.equals(propertyDataType) || KNSConstants.DATA_TYPE_LONG.equals(propertyDataType)) { |
342 | 0 | lRet.add(SQLUtils.cleanNumericOfValidOperators(val)); |
343 | 0 | } else if (KNSConstants.DATA_TYPE_DATE.equals(propertyDataType)) { |
344 | 0 | lRet.add(SQLUtils.cleanDate(val)); |
345 | |
} else { |
346 | 0 | lRet.add(clean(val)); |
347 | |
} |
348 | |
} |
349 | |
} |
350 | 0 | return lRet; |
351 | |
} |
352 | |
|
353 | |
|
354 | |
|
355 | |
|
356 | |
|
357 | |
|
358 | |
|
359 | |
private static List<String> getSearchableValues(String valueEntered) { |
360 | 0 | List<String> lRet = new ArrayList<String>(); |
361 | 0 | getSearchableValueRecursive(valueEntered, lRet); |
362 | 0 | return lRet; |
363 | |
} |
364 | |
|
365 | |
private static void getSearchableValueRecursive(String valueEntered, List lRet) { |
366 | 0 | if(valueEntered == null) { |
367 | 0 | return; |
368 | |
} |
369 | |
|
370 | 0 | valueEntered = valueEntered.trim(); |
371 | |
|
372 | 0 | if(lRet == null){ |
373 | 0 | throw new NullPointerException("The list passed in is by reference and should never be null."); |
374 | |
} |
375 | |
|
376 | 0 | if (StringUtils.contains(valueEntered, LogicalOperator.BETWEEN.op())) { |
377 | 0 | List<String> l = Arrays.asList(valueEntered.split("\\.\\.")); |
378 | 0 | for(String value : l){ |
379 | 0 | getSearchableValueRecursive(value,lRet); |
380 | |
} |
381 | 0 | return; |
382 | |
} |
383 | 0 | if (StringUtils.contains(valueEntered, LogicalOperator.OR.op())) { |
384 | 0 | List<String> l = Arrays.asList(StringUtils.split(valueEntered, LogicalOperator.OR.op())); |
385 | 0 | for(String value : l){ |
386 | 0 | getSearchableValueRecursive(value,lRet); |
387 | |
} |
388 | 0 | return; |
389 | |
} |
390 | 0 | if (StringUtils.contains(valueEntered, LogicalOperator.AND.op())) { |
391 | |
|
392 | 0 | List<String> l = Arrays.asList(StringUtils.split(valueEntered, LogicalOperator.AND.op())); |
393 | 0 | for(String value : l){ |
394 | 0 | getSearchableValueRecursive(value,lRet); |
395 | |
} |
396 | 0 | return; |
397 | |
} |
398 | |
|
399 | |
|
400 | 0 | lRet.add(valueEntered); |
401 | 0 | } |
402 | |
|
403 | |
|
404 | |
|
405 | |
|
406 | |
|
407 | |
|
408 | |
|
409 | |
private static String clean(String string) { |
410 | 0 | for (int i = 0; i < KNSConstants.QUERY_CHARACTERS.length; i++) { |
411 | 0 | string = StringUtils.replace(string, KNSConstants.QUERY_CHARACTERS[i], KNSConstants.EMPTY_STRING); |
412 | |
} |
413 | 0 | return string; |
414 | |
} |
415 | |
} |