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