001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package edu.iu.uis.eden.docsearch;
018:
019: import java.sql.Date;
020: import java.sql.Timestamp;
021: import java.util.ArrayList;
022: import java.util.Arrays;
023: import java.util.Calendar;
024: import java.util.HashMap;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.regex.Matcher;
029: import java.util.regex.Pattern;
030:
031: import org.apache.commons.lang.StringUtils;
032: import org.kuali.rice.definition.ObjectDefinition;
033: import org.kuali.rice.resourceloader.ObjectDefinitionResolver;
034:
035: import edu.iu.uis.eden.EdenConstants;
036: import edu.iu.uis.eden.util.ClassLoaderUtils;
037: import edu.iu.uis.eden.util.Utilities;
038:
039: /**
040: * Various static utility methods for helping with Searcha.
041: *
042: * @author delyea
043: */
044: public class DocSearchUtils {
045: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
046: .getLogger(DocSearchUtils.class);
047:
048: // private static final String DATE_REGEX_PASS = "^\\d{2}/\\d{2}/\\d{4}$|^\\d{2}-\\d{2}-\\d{4}$"; // matches MM/dd/yyyy or MM-dd-yyyy
049: // private static final String DATE_REGEX_PASS_SPLIT = "(\\d{2})[/|-](\\d{2})[/|-](\\d{4})";
050: 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}$"; // matches M/d/yy or MM/dd/yy or M-d-yy or MM-dd-yy
051: private static final String DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT = "(\\d{1,2})[/,-](\\d{1,2})[/,-](\\d{2})";
052: 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}$"; // matches M/d/yyyy or MM/dd/yyyy or M-d-yyyy or MM-dd-yyyy
053: private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT = "(\\d{1,2})[/,-](\\d{1,2})[/,-](\\d{4})";
054:
055: 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}$"; // matches yyyy/M/d or yyyy/MM/dd or yyyy-M-d or yyyy-MM-dd
056: private static final String DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT = "(\\d{4})[/,-](\\d{1,2})[/,-](\\d{1,2})";
057:
058: private static final String DATE_REGEX_WHOLENUM_SMALL = "^\\d{6}$"; // matches MMddyy
059: private static final String DATE_REGEX_WHOLENUM_SMALL_SPLIT = "(\\d{2})(\\d{2})(\\d{2})";
060: private static final String DATE_REGEX_WHOLENUM_LARGE = "^\\d{8}$"; // matches MMddyyyy
061: private static final String DATE_REGEX_WHOLENUM_LARGE_SPLIT = "(\\d{2})(\\d{2})(\\d{4})";
062:
063: private static final Map REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION = new HashMap();
064: static {
065: // REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(DATE_REGEX_PASS, DATE_REGEX_PASS_SPLIT);
066: REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(
067: DATE_REGEX_SMALL_TWO_DIGIT_YEAR,
068: DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT);
069: REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(
070: DATE_REGEX_SMALL_FOUR_DIGIT_YEAR,
071: DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT);
072: REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(
073: DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST,
074: DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT);
075: REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(
076: DATE_REGEX_WHOLENUM_SMALL,
077: DATE_REGEX_WHOLENUM_SMALL_SPLIT);
078: REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION.put(
079: DATE_REGEX_WHOLENUM_LARGE,
080: DATE_REGEX_WHOLENUM_LARGE_SPLIT);
081: }
082:
083: public static final List DOCUMENT_SEARCH_DATE_VALIDATION_REGEX_EXPRESSIONS = Arrays
084: .asList(new String[] { DATE_REGEX_SMALL_FOUR_DIGIT_YEAR,
085: DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST });
086:
087: public static List<SearchableAttributeValue> getSearchableAttributeValueObjectTypes() {
088: List<SearchableAttributeValue> searchableAttributeValueClasses = new ArrayList<SearchableAttributeValue>();
089: for (Iterator iter = SearchableAttribute.SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST
090: .iterator(); iter.hasNext();) {
091: Class searchAttributeValueClass = (Class) iter.next();
092: ObjectDefinition objDef = new ObjectDefinition(
093: searchAttributeValueClass);
094: SearchableAttributeValue attributeValue = (SearchableAttributeValue) ObjectDefinitionResolver
095: .createObject(objDef, ClassLoaderUtils
096: .getDefaultClassLoader(), false);
097: searchableAttributeValueClasses.add(attributeValue);
098: }
099: return searchableAttributeValueClasses;
100: }
101:
102: public static SearchableAttributeValue getSearchableAttributeValueByDataTypeString(
103: String dataType) {
104: SearchableAttributeValue returnableValue = null;
105: if (StringUtils.isBlank(dataType)) {
106: return returnableValue;
107: }
108: for (Iterator iter = getSearchableAttributeValueObjectTypes()
109: .iterator(); iter.hasNext();) {
110: SearchableAttributeValue attValue = (SearchableAttributeValue) iter
111: .next();
112: if (dataType.equalsIgnoreCase(attValue
113: .getAttributeDataType())) {
114: if (returnableValue != null) {
115: String errorMsg = "Found two SearchableAttributeValue objects with same data type string ('"
116: + dataType
117: + "' while ignoring case): "
118: + returnableValue.getClass().getName()
119: + " and " + attValue.getClass().getName();
120: LOG
121: .error("getSearchableAttributeValueByDataTypeString() "
122: + errorMsg);
123: throw new RuntimeException(errorMsg);
124: }
125: LOG
126: .debug("getSearchableAttributeValueByDataTypeString() SearchableAttributeValue class name is "
127: + attValue.getClass().getName()
128: + "... ojbConcreteClassName is "
129: + attValue.getOjbConcreteClass());
130: ObjectDefinition objDef = new ObjectDefinition(attValue
131: .getClass());
132: returnableValue = (SearchableAttributeValue) ObjectDefinitionResolver
133: .createObject(objDef, ClassLoaderUtils
134: .getDefaultClassLoader(), false);
135: }
136: }
137: //construtorutils
138: return returnableValue;
139: }
140:
141: /**
142: * A method to format any variety of date strings into a common format
143: *
144: * @param date A string date in one of a few different formats
145: * @return A string representing a date in the format yyyy/MM/dd or null if date is invalid
146: */
147: public static String getSqlFormattedDate(String date) {
148: DateComponent dc = formatDateToDateComponent(date, Arrays
149: .asList(REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION
150: .keySet().toArray()));
151: if (dc == null) {
152: return null;
153: }
154: return dc.getYear() + "/" + dc.getMonth() + "/" + dc.getDate();
155: }
156:
157: // TODO Version 2.4 - Remove this and update DocSearchGenerator to use Platform
158: public static String getDateSQL(String date, String time) {
159: // SQL 92 date literal syntax:
160: // http://www.stanford.edu/dept/itss/docs/oracle/9i/java.920/a96654/ref.htm#1005145
161: String d = date.replace('/', '-');
162: if (time == null) {
163: return "{d '" + d + "'}";
164: } else {
165: return "{ts '" + d + " " + time + "'}";
166: }
167: }
168:
169: /**
170: * A method to format any variety of date strings into a common format
171: *
172: * @param date A string date in one of a few different formats
173: * @return A string representing a date in the format MM/dd/yyyy or null if date is invalid
174: */
175: public static String getEntryFormattedDate(String date) {
176: DateComponent dc = formatDateToDateComponent(date,
177: DOCUMENT_SEARCH_DATE_VALIDATION_REGEX_EXPRESSIONS);
178: if (dc == null) {
179: return null;
180: }
181: return dc.getMonth() + "/" + dc.getDate() + "/" + dc.getYear();
182: }
183:
184: private static DateComponent formatDateToDateComponent(String date,
185: List regularExpressionList) {
186: String matchingRegexExpression = null;
187: for (Iterator iter = regularExpressionList.iterator(); iter
188: .hasNext();) {
189: String matchRegex = (String) iter.next();
190: if (!REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION
191: .containsKey(matchRegex)) {
192: String errorMsg = "";
193: LOG.error("formatDateToDateComponent(String,List) "
194: + errorMsg);
195:
196: }
197: Pattern p = Pattern.compile(matchRegex);
198: if ((p.matcher(date)).matches()) {
199: matchingRegexExpression = matchRegex;
200: break;
201: }
202: }
203:
204: if (matchingRegexExpression == null) {
205: String errorMsg = "formatDate(String,List) Date string given '"
206: + date
207: + "' is not valid according to Workflow defaults. Returning null value.";
208: if (StringUtils.isNotBlank(date)) {
209: LOG.warn(errorMsg);
210: } else {
211: LOG.debug(errorMsg);
212: }
213: return null;
214: }
215: String regexSplitExpression = (String) REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION
216: .get(matchingRegexExpression);
217:
218: // Check date formats and reformat to yyyy/MM/dd
219: // well formed MM/dd/yyyy
220: Pattern p = Pattern.compile(regexSplitExpression);
221: Matcher util = p.matcher(date);
222: util.matches();
223: // if (regexSplitExpression.equals(DATE_REGEX_PASS_SPLIT)) {
224: // return new DateComponent(util.group(3),util.group(1),util.group(2));
225: //
226: // // small date format M/d/yy | 1-2d/1-2m/2y
227: // } else
228: if (regexSplitExpression
229: .equals(DATE_REGEX_SMALL_TWO_DIGIT_YEAR_SPLIT)) {
230: StringBuffer yearBuf = new StringBuffer();
231: StringBuffer monthBuf = new StringBuffer();
232: StringBuffer dateBuf = new StringBuffer();
233: Integer year = new Integer(util.group(3));
234:
235: if (year.intValue() <= 50) {
236: yearBuf.append("20").append(util.group(3));
237: } else if (util.group(3).length() < 3) {
238: yearBuf.append("19").append(util.group(3));
239: } else {
240: yearBuf.append(util.group(3));
241: }
242:
243: if (util.group(1).length() < 2) {
244: monthBuf.append("0").append(util.group(1));
245: } else {
246: monthBuf.append(util.group(1));
247: }
248:
249: if (util.group(2).length() < 2) {
250: dateBuf.append("0").append(util.group(2));
251: } else {
252: dateBuf.append(util.group(2));
253: }
254:
255: return new DateComponent(yearBuf.toString(), monthBuf
256: .toString(), dateBuf.toString());
257:
258: // small date format M/d/yyyy | MM/dd/yyyy | M-d-yyyy | MM-dd-yyyy
259: } else if (regexSplitExpression
260: .equals(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_SPLIT)) {
261: StringBuffer yearBuf = new StringBuffer(util.group(3));
262: StringBuffer monthBuf = new StringBuffer();
263: StringBuffer dateBuf = new StringBuffer();
264:
265: if (util.group(1).length() < 2) {
266: monthBuf.append("0").append(util.group(1));
267: } else {
268: monthBuf.append(util.group(1));
269: }
270:
271: if (util.group(2).length() < 2) {
272: dateBuf.append("0").append(util.group(2));
273: } else {
274: dateBuf.append(util.group(2));
275: }
276:
277: return new DateComponent(yearBuf.toString(), monthBuf
278: .toString(), dateBuf.toString());
279:
280: // small date format yyyy/M/d | yyyy/MM/dd | yyyy-M-d | yyyy-MM-dd
281: } else if (regexSplitExpression
282: .equals(DATE_REGEX_SMALL_FOUR_DIGIT_YEAR_FIRST_SPLIT)) {
283: StringBuffer yearBuf = new StringBuffer(util.group(1));
284: StringBuffer monthBuf = new StringBuffer();
285: StringBuffer dateBuf = new StringBuffer();
286:
287: if (util.group(2).length() < 2) {
288: monthBuf.append("0").append(util.group(2));
289: } else {
290: monthBuf.append(util.group(2));
291: }
292:
293: if (util.group(3).length() < 2) {
294: dateBuf.append("0").append(util.group(3));
295: } else {
296: dateBuf.append(util.group(3));
297: }
298:
299: return new DateComponent(yearBuf.toString(), monthBuf
300: .toString(), dateBuf.toString());
301:
302: // large number MMddyyyy
303: } else if (regexSplitExpression
304: .equals(DATE_REGEX_WHOLENUM_LARGE_SPLIT)) {
305: return new DateComponent(util.group(3), util.group(1), util
306: .group(2));
307:
308: // small number MMddyy
309: } else if (regexSplitExpression
310: .equals(DATE_REGEX_WHOLENUM_SMALL_SPLIT)) {
311: StringBuffer yearBuf = new StringBuffer();
312: Integer year = new Integer(util.group(3));
313:
314: if (year.intValue() < 50) {
315: yearBuf.append("20");
316: } else {
317: yearBuf.append("19");
318: }
319: yearBuf.append(util.group(3));
320: return new DateComponent(yearBuf.toString(), util.group(1),
321: util.group(2));
322: } else {
323: LOG
324: .warn("formatDate(String,List) Date string given '"
325: + date
326: + "' is not valid according to Workflow defaults. Returning null value.");
327: return null;
328: }
329: }
330:
331: public static String getDisplayValueWithDateOnly(Timestamp value) {
332: return EdenConstants.getDefaultDateFormat().format(
333: new Date(value.getTime()));
334: }
335:
336: public static String getDisplayValueWithDateTime(Timestamp value) {
337: return EdenConstants.getDefaultDateAndTimeFormat().format(
338: new Date(value.getTime()));
339: }
340:
341: public static Timestamp convertStringDateToTimestamp(
342: String dateWithoutTime) {
343: DateComponent formattedDate = formatDateToDateComponent(
344: dateWithoutTime,
345: Arrays
346: .asList(REGEX_EXPRESSION_MAP_TO_REGEX_SPLIT_EXPRESSION
347: .keySet().toArray()));
348: if (formattedDate == null) {
349: return null;
350: }
351: Calendar c = Calendar.getInstance();
352: c.clear();
353: c.set(Calendar.MONTH, Integer.valueOf(formattedDate.getMonth())
354: .intValue() - 1);
355: c.set(Calendar.DATE, Integer.valueOf(formattedDate.getDate())
356: .intValue());
357: c.set(Calendar.YEAR, Integer.valueOf(formattedDate.getYear())
358: .intValue());
359: return Utilities.convertCalendar(c);
360: }
361:
362: public static class DateComponent {
363: protected String month;
364: protected String date;
365: protected String year;
366:
367: public DateComponent(String year, String month, String date) {
368: this .month = month;
369: this .date = date;
370: this .year = year;
371: }
372:
373: public String getDate() {
374: return date;
375: }
376:
377: public String getMonth() {
378: return month;
379: }
380:
381: public String getYear() {
382: return year;
383: }
384: }
385: }
|