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