1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.kew.impl.document.search;
17
18 import org.apache.commons.beanutils.PropertyUtils;
19 import org.apache.commons.lang.ObjectUtils;
20 import org.apache.commons.lang.StringUtils;
21 import org.apache.log4j.Logger;
22 import org.joda.time.DateTime;
23 import org.kuali.rice.kew.api.KEWPropertyConstants;
24 import org.kuali.rice.kew.api.document.DocumentStatus;
25 import org.kuali.rice.kew.api.document.DocumentStatusCategory;
26 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
27 import org.kuali.rice.kew.api.document.search.RouteNodeLookupLogic;
28 import org.kuali.rice.kew.docsearch.DocumentSearchInternalUtils;
29 import org.kuali.rice.kew.api.KewApiConstants;
30
31 import java.lang.reflect.InvocationTargetException;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collection;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.List;
38 import java.util.Map;
39 import java.util.Set;
40
41
42
43
44
45
46 public class DocumentSearchCriteriaTranslatorImpl implements DocumentSearchCriteriaTranslator {
47
48 private static final Logger LOG = Logger.getLogger(DocumentSearchCriteriaTranslatorImpl.class);
49
50 private static final String DOCUMENT_STATUSES = "documentStatuses";
51 private static final String ROUTE_NODE_LOOKUP_LOGIC = "routeNodeLookupLogic";
52
53
54
55
56 private static final String[] DIRECT_TRANSLATE_FIELD_NAMES = {
57 "documentId",
58 "applicationDocumentId",
59 "applicationDocumentStatus",
60 "initiatorPrincipalName",
61 "viewerPrincipalName",
62 "approverPrincipalName",
63 "routeNodeName",
64 "documentTypeName",
65 "saveName"
66 };
67 private static final Set<String> DIRECT_TRANSLATE_FIELD_NAMES_SET =
68 new HashSet<String>(Arrays.asList(DIRECT_TRANSLATE_FIELD_NAMES));
69
70 private static final String[] DATE_RANGE_TRANSLATE_FIELD_NAMES = {
71 "dateCreated",
72 "dateLastModified",
73 "dateApproved",
74 "dateFinalized"
75 };
76 private static final Set<String> DATE_RANGE_TRANSLATE_FIELD_NAMES_SET =
77 new HashSet<String>(Arrays.asList(DATE_RANGE_TRANSLATE_FIELD_NAMES));
78
79 @Override
80 public DocumentSearchCriteria translateFieldsToCriteria(Map<String, String> fieldValues) {
81
82 DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create();
83 for (Map.Entry<String, String> field : fieldValues.entrySet()) {
84 try {
85 if (StringUtils.isNotBlank(field.getValue())) {
86 if (DIRECT_TRANSLATE_FIELD_NAMES_SET.contains(field.getKey())) {
87 PropertyUtils.setNestedProperty(criteria, field.getKey(), field.getValue());
88 } else if (DATE_RANGE_TRANSLATE_FIELD_NAMES_SET.contains(field.getKey())) {
89 applyDateRangeField(criteria, field.getKey(), field.getValue());
90 } else if (field.getKey().startsWith(KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX)) {
91 String documentAttributeName = field.getKey().substring(KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX.length());
92 applyDocumentAttribute(criteria, documentAttributeName, field.getValue());
93 }
94
95 }
96 } catch (Exception e) {
97 throw new IllegalStateException("Failed to set document search criteria field: " + field.getKey(), e);
98 }
99 }
100
101 String routeNodeLookupLogic = fieldValues.get(ROUTE_NODE_LOOKUP_LOGIC);
102 if (StringUtils.isNotBlank(routeNodeLookupLogic)) {
103 criteria.setRouteNodeLookupLogic(RouteNodeLookupLogic.valueOf(routeNodeLookupLogic));
104 }
105
106 String documentStatusesValue = fieldValues.get(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_STATUS_CODE);
107 if (StringUtils.isNotBlank(documentStatusesValue)) {
108 String[] documentStatuses = documentStatusesValue.split(",");
109 for (String documentStatus : documentStatuses) {
110 if (documentStatus.startsWith("category:")) {
111 String categoryCode = StringUtils.remove(documentStatus, "category:");
112 criteria.getDocumentStatusCategories().add(DocumentStatusCategory.fromCode(categoryCode));
113 } else {
114 criteria.getDocumentStatuses().add(DocumentStatus.fromCode(documentStatus));
115 }
116 }
117 }
118
119 return criteria.build();
120 }
121
122
123
124
125
126
127 public Map<String, String[]> translateCriteriaToFields(DocumentSearchCriteria criteria) {
128 Map<String, String[]> values = new HashMap<String, String[]>();
129
130 for (String property: DIRECT_TRANSLATE_FIELD_NAMES) {
131 convertCriteriaPropertyToField(criteria, property, values);
132 }
133
134 for (String property: DATE_RANGE_TRANSLATE_FIELD_NAMES) {
135 convertCriteriaPropertyToField(criteria, property + "From", values);
136 convertCriteriaPropertyToField(criteria, property + "To", values);
137 }
138
139 Map<String, List<String>> docAttrValues = criteria.getDocumentAttributeValues();
140 for (Map.Entry<String, List<String>> entry: docAttrValues.entrySet()) {
141 values.put(KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + entry.getKey(), entry.getValue().toArray(new String[0]));
142 }
143
144 RouteNodeLookupLogic lookupLogic = criteria.getRouteNodeLookupLogic();
145 if (lookupLogic != null) {
146 values.put(ROUTE_NODE_LOOKUP_LOGIC, new String[]{lookupLogic.name()});
147 }
148
149 Collection<String> statuses = new ArrayList<String>();
150 for (DocumentStatus status: criteria.getDocumentStatuses()) {
151 statuses.add(status.getCode());
152 }
153 for (DocumentStatusCategory category: criteria.getDocumentStatusCategories()) {
154 statuses.add("category:" + category.getCode());
155 }
156 values.put(KEWPropertyConstants.DOC_SEARCH_RESULT_PROPERTY_NAME_STATUS_CODE, statuses.toArray(new String[0]));
157
158 return values;
159 }
160
161
162
163
164
165
166
167 protected static void convertCriteriaPropertyToField(DocumentSearchCriteria criteria, String property, Map<String, String[]> values) {
168 try {
169 Object val = PropertyUtils.getProperty(criteria, property);
170 if (val != null) {
171 values.put(property, new String[] { ObjectUtils.toString(val) });
172 }
173 } catch (NoSuchMethodException nsme) {
174 LOG.error("Error reading property '" + property + "' of criteria", nsme);
175 } catch (InvocationTargetException ite) {
176 LOG.error("Error reading property '" + property + "' of criteria", ite);
177 } catch (IllegalAccessException iae) {
178 LOG.error("Error reading property '" + property + "' of criteria", iae);
179
180 }
181 }
182
183 protected void applyDateRangeField(DocumentSearchCriteria.Builder criteria, String fieldName, String fieldValue) throws Exception {
184 DateTime lowerDateTime = DocumentSearchInternalUtils.getLowerDateTimeBound(fieldValue);
185 DateTime upperDateTime = DocumentSearchInternalUtils.getUpperDateTimeBound(fieldValue);
186 if (lowerDateTime != null) {
187 PropertyUtils.setNestedProperty(criteria, fieldName + "From", lowerDateTime);
188 }
189 if (upperDateTime != null) {
190 PropertyUtils.setNestedProperty(criteria, fieldName + "To", upperDateTime);
191 }
192 }
193
194 protected void applyDocumentAttribute(DocumentSearchCriteria.Builder criteria, String documentAttributeName, String attributeValue) {
195 criteria.addDocumentAttributeValue(documentAttributeName, attributeValue);
196 }
197
198 }