1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.docsearch;
17
18 import org.apache.commons.lang.StringUtils;
19 import org.apache.log4j.Logger;
20 import org.codehaus.jackson.map.ObjectMapper;
21 import org.codehaus.jackson.map.annotate.JsonSerialize;
22 import org.joda.time.DateTime;
23 import org.joda.time.MutableDateTime;
24 import org.kuali.rice.core.api.CoreApiServiceLocator;
25 import org.kuali.rice.core.api.reflect.ObjectDefinition;
26 import org.kuali.rice.core.api.search.SearchOperator;
27 import org.kuali.rice.core.api.uif.AttributeLookupSettings;
28 import org.kuali.rice.core.api.uif.DataType;
29 import org.kuali.rice.core.api.uif.RemotableAttributeField;
30 import org.kuali.rice.core.api.util.ClassLoaderUtils;
31 import org.kuali.rice.core.api.util.RiceConstants;
32 import org.kuali.rice.core.framework.resourceloader.ObjectDefinitionResolver;
33 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
34
35 import java.io.IOException;
36 import java.sql.Date;
37 import java.sql.Timestamp;
38 import java.text.ParseException;
39 import java.util.ArrayList;
40 import java.util.EnumSet;
41 import java.util.List;
42
43
44
45
46
47
48 public class DocumentSearchInternalUtils {
49
50 private static final Logger LOG = Logger.getLogger(DocumentSearchInternalUtils.class);
51
52 private static final boolean CASE_SENSITIVE_DEFAULT = false;
53
54 private static final String STRING_ATTRIBUTE_TABLE_NAME = "KREW_DOC_HDR_EXT_T";
55 private static final String DATE_TIME_ATTRIBUTE_TABLE_NAME = "KREW_DOC_HDR_EXT_DT_T";
56 private static final String DECIMAL_ATTRIBUTE_TABLE_NAME = "KREW_DOC_HDR_EXT_FLT_T";
57 private static final String INTEGER_ATTRIBUTE_TABLE_NAME = "KREW_DOC_HDR_EXT_LONG_T";
58
59 private static final List<SearchableAttributeConfiguration> CONFIGURATIONS =
60 new ArrayList<SearchableAttributeConfiguration>();
61 public static final List<Class<? extends SearchableAttributeValue>> SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST =
62 new ArrayList<Class<? extends SearchableAttributeValue>>();
63 static {
64 SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST.add(SearchableAttributeStringValue.class);
65 SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST.add(SearchableAttributeFloatValue.class);
66 SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST.add(SearchableAttributeLongValue.class);
67 SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST.add(SearchableAttributeDateTimeValue.class);
68 }
69
70 static {
71
72 CONFIGURATIONS.add(new SearchableAttributeConfiguration(
73 STRING_ATTRIBUTE_TABLE_NAME,
74 EnumSet.of(DataType.BOOLEAN, DataType.STRING, DataType.MARKUP),
75 String.class));
76
77 CONFIGURATIONS.add(new SearchableAttributeConfiguration(
78 DATE_TIME_ATTRIBUTE_TABLE_NAME,
79 EnumSet.of(DataType.DATE, DataType.TRUNCATED_DATE),
80 Timestamp.class));
81
82 CONFIGURATIONS.add(new SearchableAttributeConfiguration(
83 DECIMAL_ATTRIBUTE_TABLE_NAME,
84 EnumSet.of(DataType.FLOAT, DataType.DOUBLE),
85 Float.TYPE));
86
87 CONFIGURATIONS.add(new SearchableAttributeConfiguration(
88 INTEGER_ATTRIBUTE_TABLE_NAME,
89 EnumSet.of(DataType.INTEGER, DataType.LONG),
90 Long.TYPE));
91
92 }
93
94 public static boolean isLookupCaseSensitive(RemotableAttributeField remotableAttributeField) {
95 if (remotableAttributeField == null) {
96 throw new IllegalArgumentException("remotableAttributeField was null");
97 }
98 AttributeLookupSettings lookupSettings = remotableAttributeField.getAttributeLookupSettings();
99 if (lookupSettings != null) {
100 if (lookupSettings.isCaseSensitive() != null) {
101 return lookupSettings.isCaseSensitive().booleanValue();
102 }
103 }
104 return CASE_SENSITIVE_DEFAULT;
105 }
106
107 public static String getAttributeTableName(RemotableAttributeField attributeField) {
108 return getConfigurationForField(attributeField).getTableName();
109 }
110
111 public static Class<?> getDataTypeClass(RemotableAttributeField attributeField) {
112 return getConfigurationForField(attributeField).getDataTypeClass();
113 }
114
115 private static SearchableAttributeConfiguration getConfigurationForField(RemotableAttributeField attributeField) {
116 for (SearchableAttributeConfiguration configuration : CONFIGURATIONS) {
117 DataType dataType = attributeField.getDataType();
118 if (dataType == null) {
119 dataType = DataType.STRING;
120 }
121 if (configuration.getSupportedDataTypes().contains(dataType)) {
122 return configuration;
123 }
124 }
125 throw new IllegalArgumentException("Failed to determine proper searchable attribute configuration for given data type of '" + attributeField.getDataType() + "'");
126 }
127
128 public static List<SearchableAttributeValue> getSearchableAttributeValueObjectTypes() {
129 List<SearchableAttributeValue> searchableAttributeValueClasses = new ArrayList<SearchableAttributeValue>();
130 for (Class<? extends SearchableAttributeValue> searchAttributeValueClass : SEARCHABLE_ATTRIBUTE_BASE_CLASS_LIST) {
131 ObjectDefinition objDef = new ObjectDefinition(searchAttributeValueClass);
132 SearchableAttributeValue attributeValue = (SearchableAttributeValue) ObjectDefinitionResolver.createObject(
133 objDef, ClassLoaderUtils.getDefaultClassLoader(), false);
134 searchableAttributeValueClasses.add(attributeValue);
135 }
136 return searchableAttributeValueClasses;
137 }
138
139 public static SearchableAttributeValue getSearchableAttributeValueByDataTypeString(String dataType) {
140 SearchableAttributeValue returnableValue = null;
141 if (StringUtils.isBlank(dataType)) {
142 return returnableValue;
143 }
144 for (SearchableAttributeValue attValue : getSearchableAttributeValueObjectTypes())
145 {
146 if (dataType.equalsIgnoreCase(attValue.getAttributeDataType()))
147 {
148 if (returnableValue != null)
149 {
150 String errorMsg = "Found two SearchableAttributeValue objects with same data type string ('" + dataType + "' while ignoring case): " + returnableValue.getClass().getName() + " and " + attValue.getClass().getName();
151 LOG.error("getSearchableAttributeValueByDataTypeString() " + errorMsg);
152 throw new RuntimeException(errorMsg);
153 }
154 LOG.debug("getSearchableAttributeValueByDataTypeString() SearchableAttributeValue class name is " + attValue.getClass().getName() + "... ojbConcreteClassName is " + attValue.getOjbConcreteClass());
155 ObjectDefinition objDef = new ObjectDefinition(attValue.getClass());
156 returnableValue = (SearchableAttributeValue) ObjectDefinitionResolver.createObject(objDef, ClassLoaderUtils.getDefaultClassLoader(), false);
157 }
158 }
159 return returnableValue;
160 }
161
162 public static String getDisplayValueWithDateOnly(DateTime value) {
163 return getDisplayValueWithDateOnly(new Timestamp(value.getMillis()));
164 }
165
166 public static String getDisplayValueWithDateOnly(Timestamp value) {
167 return RiceConstants.getDefaultDateFormat().format(new Date(value.getTime()));
168 }
169
170 public static DateTime getLowerDateTimeBound(String dateRange) throws ParseException {
171 Range range = parseRange(dateRange);
172 if (range == null) {
173 throw new IllegalArgumentException("Failed to parse date range from given string: " + dateRange);
174 }
175 if (range.getLowerBoundValue() != null) {
176 java.util.Date lowerRangeDate = CoreApiServiceLocator.getDateTimeService().convertToDate(range.getLowerBoundValue());
177 MutableDateTime dateTime = new MutableDateTime(lowerRangeDate);
178 dateTime.setMillisOfDay(0);
179 return dateTime.toDateTime();
180 }
181 return null;
182 }
183
184 public static DateTime getUpperDateTimeBound(String dateRange) throws ParseException {
185 Range range = parseRange(dateRange);
186 if (range == null) {
187 throw new IllegalArgumentException("Failed to parse date range from given string: " + dateRange);
188 }
189 if (range.getUpperBoundValue() != null) {
190 java.util.Date upperRangeDate = CoreApiServiceLocator.getDateTimeService().convertToDate(range.getUpperBoundValue());
191 MutableDateTime dateTime = new MutableDateTime(upperRangeDate);
192
193 dateTime.setMillisOfDay((24 * 60 * 60 * 1000) - 1);
194 return dateTime.toDateTime();
195 }
196 return null;
197 }
198
199 public static Range parseRange(String rangeString) {
200 if (StringUtils.isBlank(rangeString)) {
201 throw new IllegalArgumentException("rangeString was null or blank");
202 }
203 Range range = new Range();
204 rangeString = rangeString.trim();
205 if (rangeString.startsWith(SearchOperator.LESS_THAN_EQUAL.op())) {
206 rangeString = StringUtils.remove(rangeString, SearchOperator.LESS_THAN_EQUAL.op()).trim();
207 range.setUpperBoundValue(rangeString);
208 range.setUpperBoundInclusive(true);
209 } else if (rangeString.startsWith(SearchOperator.LESS_THAN.op())) {
210 rangeString = StringUtils.remove(rangeString, SearchOperator.LESS_THAN.op()).trim();
211 range.setUpperBoundValue(rangeString);
212 range.setUpperBoundInclusive(false);
213 } else if (rangeString.startsWith(SearchOperator.GREATER_THAN_EQUAL.op())) {
214 rangeString = StringUtils.remove(rangeString, SearchOperator.GREATER_THAN_EQUAL.op()).trim();
215 range.setLowerBoundValue(rangeString);
216 range.setLowerBoundInclusive(true);
217 } else if (rangeString.startsWith(SearchOperator.GREATER_THAN.op())) {
218 rangeString = StringUtils.remove(rangeString, SearchOperator.GREATER_THAN.op()).trim();
219 range.setLowerBoundValue(rangeString);
220 range.setLowerBoundInclusive(false);
221 } else if (rangeString.contains(SearchOperator.BETWEEN_EXCLUSIVE_UPPER.op())) {
222 String[] rangeBounds = StringUtils.split(rangeString, SearchOperator.BETWEEN_EXCLUSIVE_UPPER.op());
223 range.setLowerBoundValue(rangeBounds[0]);
224 range.setLowerBoundInclusive(true);
225 range.setUpperBoundValue(rangeBounds[1]);
226 range.setUpperBoundInclusive(false);
227 } else if (rangeString.contains(SearchOperator.BETWEEN.op())) {
228 String[] rangeBounds = StringUtils.split(rangeString, SearchOperator.BETWEEN.op());
229 range.setLowerBoundValue(rangeBounds[0]);
230 range.setLowerBoundInclusive(true);
231 range.setUpperBoundValue(rangeBounds[1]);
232 range.setUpperBoundInclusive(true);
233 } else {
234
235 return null;
236 }
237 return range;
238 }
239
240 public static class SearchableAttributeConfiguration {
241
242 private final String tableName;
243 private final EnumSet<DataType> supportedDataTypes;
244 private final Class<?> dataTypeClass;
245
246 public SearchableAttributeConfiguration(String tableName,
247 EnumSet<DataType> supportedDataTypes,
248 Class<?> dataTypeClass) {
249 this.tableName = tableName;
250 this.supportedDataTypes = supportedDataTypes;
251 this.dataTypeClass = dataTypeClass;
252 }
253
254 public String getTableName() {
255 return tableName;
256 }
257
258 public EnumSet<DataType> getSupportedDataTypes() {
259 return supportedDataTypes;
260 }
261
262 public Class<?> getDataTypeClass() {
263 return dataTypeClass;
264 }
265
266 }
267
268
269
270
271
272
273
274 public static DocumentSearchCriteria unmarshalDocumentSearchCriteria(String string) throws IOException {
275 ObjectMapper jsonMapper = new ObjectMapper();
276 jsonMapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
277 DocumentSearchCriteria.Builder builder = (DocumentSearchCriteria.Builder) jsonMapper.readValue(string, DocumentSearchCriteria.Builder.class);
278
279 builder.normalizeDateTimes();
280
281 return builder.build();
282 }
283
284
285
286
287
288
289
290 public static String marshalDocumentSearchCriteria(DocumentSearchCriteria criteria) throws IOException {
291 ObjectMapper jsonMapper = new ObjectMapper();
292 jsonMapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
293
294
295
296
297
298
299 return jsonMapper.writeValueAsString(criteria);
300 }
301 }