001 /**
002 * Copyright 2005-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.kuali.rice.kew.docsearch;
017
018 import org.apache.commons.lang.StringUtils;
019 import org.junit.Test;
020 import org.kuali.rice.core.api.uif.RemotableAttributeError;
021 import org.kuali.rice.core.api.uif.RemotableAttributeField;
022 import org.kuali.rice.kew.api.KewApiServiceLocator;
023 import org.kuali.rice.kew.api.WorkflowDocument;
024 import org.kuali.rice.kew.api.WorkflowDocumentFactory;
025 import org.kuali.rice.kew.api.document.DocumentStatus;
026 import org.kuali.rice.kew.api.document.DocumentWithContent;
027 import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
028 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDataType;
029 import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory;
030 import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
031 import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
032 import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
033 import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
034 import org.kuali.rice.kew.api.extension.ExtensionDefinition;
035 import org.kuali.rice.kew.doctype.bo.DocumentType;
036 import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute;
037 import org.kuali.rice.kew.framework.document.search.DocumentSearchCustomizerBase;
038 import org.kuali.rice.kew.framework.document.search.DocumentSearchResultValue;
039 import org.kuali.rice.kew.framework.document.search.DocumentSearchResultValues;
040 import org.kuali.rice.kew.service.KEWServiceLocator;
041 import org.kuali.rice.kew.test.KEWTestCase;
042
043 import java.util.ArrayList;
044 import java.util.Collections;
045 import java.util.List;
046
047 import static org.junit.Assert.*;
048
049 /**
050 * An integration test for the DocumentSearchCustomizer class. Includes tests on various aspects of the customzations
051 * that class provides, attempting to use the high-level document search apis to exercise it.
052 *
053 * @author Kuali Rice Team (rice.collab@kuali.org)
054 */
055 public class DocumentSearchCustomizerTest extends KEWTestCase {
056
057 @Override
058 protected void loadTestData() throws Exception {
059 loadXmlFile("DocumentSearchCustomizerTest.xml");
060 }
061
062 @Test
063 public void testCustomizeCriteria() throws Exception {
064
065 String ewestfal = getPrincipalIdForName("ewestfal");
066 DocumentSearchCriteria.Builder builder = DocumentSearchCriteria.Builder.create();
067
068 // first check a full doc search, should return no results
069 DocumentSearchResults results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(ewestfal, builder.build());
070 assertTrue(results.getSearchResults().isEmpty());
071 assertFalse(results.getCriteria().getDocumentStatuses().contains(DocumentStatus.FINAL));
072
073 // now check a document search against the "DocumentSearchCustomizerTest" document type, it is configured with the
074 // CustomizeCriteria customizer
075 builder.setDocumentTypeName("DocumentSearchCustomizerTest");
076
077 results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(ewestfal, builder.build());
078 assertTrue(results.getSearchResults().isEmpty());
079 DocumentSearchCriteria resultCriteria = results.getCriteria();
080 assertTrue("Document Statuses should have contained FINAL, instead contains: " + resultCriteria
081 .getDocumentStatuses(), resultCriteria.getDocumentStatuses().contains(DocumentStatus.FINAL));
082
083 // now route an instance of the CustomizeCriteria document type to FINAL
084 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"),
085 "DocumentSearchCustomizerTest");
086 document.route("");
087 assertTrue(document.isFinal());
088
089 // now run another search, we should get back one result this time
090 results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(ewestfal, builder.build());
091 assertEquals(1, results.getSearchResults().size());
092 assertEquals(document.getDocumentId(), results.getSearchResults().get(0).getDocument().getDocumentId());
093 }
094
095 @Test
096 public void testCustomizeClearCriteria() throws Exception {
097
098 // grab a couple of document types, the first is the TestDocumentType which has no DocumentSearchCustomizer
099 // configured on it, the second in our Document Type for this integration test which is configured with the
100 // Customizer
101
102 DocumentType testDocumentType = KEWServiceLocator.getDocumentTypeService().findByName("TestDocumentType");
103 assertNotNull(testDocumentType);
104 DocumentType customizedDocumentType = KEWServiceLocator.getDocumentTypeService().findByName("DocumentSearchCustomizerTest");
105 assertNotNull(customizedDocumentType);
106
107 // first set document id and application document id on a criteria and clear it using the TestDocumentType, it
108 // should clear out both
109
110 DocumentSearchCriteria.Builder builder = DocumentSearchCriteria.Builder.create();
111 builder.setDocumentId("12345");
112 builder.setApplicationDocumentId("54321");
113 DocumentSearchCriteria clearedCriteria = KEWServiceLocator.getDocumentSearchService().clearCriteria(testDocumentType, builder.build());
114 assertNull(clearedCriteria.getDocumentId());
115 assertNull(clearedCriteria.getApplicationDocumentId());
116
117 // now clear the same criteria with the customized document type, it should clear out the document id but
118 // preserve the application document id
119
120 clearedCriteria = KEWServiceLocator.getDocumentSearchService().clearCriteria(customizedDocumentType, builder.build());
121 assertNull(clearedCriteria.getDocumentId());
122 assertEquals("54321", clearedCriteria.getApplicationDocumentId());
123 }
124
125 @Test
126 public void testCustomizeResults() throws Exception {
127
128 // route an instance of the CustomizeCriteria document type to FINAL
129
130 String ewestfal = getPrincipalIdForName("ewestfal");
131 WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"),
132 "DocumentSearchCustomizerTest");
133 document.route("");
134 assertTrue(document.isFinal());
135
136 // check that the document attributes get indexed properly
137
138 List<String> attributeValues = KewApiServiceLocator.getWorkflowDocumentService().getSearchableAttributeStringValuesByKey(document.getDocumentId(), "myAttribute");
139 assertEquals(1, attributeValues.size());
140 assertEquals("myValue", attributeValues.get(0));
141 attributeValues = KewApiServiceLocator.getWorkflowDocumentService().getSearchableAttributeStringValuesByKey(document.getDocumentId(), "myMultiValuedAttribute");
142 assertEquals(2, attributeValues.size());
143 assertTrue(attributeValues.contains("value1"));
144 assertTrue(attributeValues.contains("value2"));
145
146 DocumentSearchCriteria.Builder builder = DocumentSearchCriteria.Builder.create();
147 DocumentSearchResults results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(ewestfal, builder.build());
148 assertEquals(1, results.getSearchResults().size());
149 DocumentSearchResult result = results.getSearchResults().get(0);
150
151 // TODO - the below assertions really should work, but they currently don't. Currently, unless you pass the
152 // specific document type as one of the criteria the document attributes are not returned with the search
153 // There should at least be an option on the search api to enable the returning of document attributes from
154 // the search API - see https://jira.kuali.org/browse/KULRICE-6764
155 /*assertEquals(1, result.getDocumentAttributes().size());
156 DocumentAttribute attribute = result.getDocumentAttributes().get(0);
157 assertEquals("myAttribute", attribute.getName());
158 assertEquals("myValue", attribute.getValue());
159 assertEquals(DocumentAttributeDataType.STRING, attribute.getDataType());*/
160
161 // now do a document search targeting the specific customizer document type, the result should be customized
162 // and the "myAttribute" attribute should have a customized value of "myCustomizedValue", also the
163 // "myMultiValuedAttribute" should now only have a single value of "value0"
164
165 builder.setDocumentTypeName("DocumentSearchCustomizerTest");
166 results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(ewestfal, builder.build());
167 assertEquals(1, results.getSearchResults().size());
168 result = results.getSearchResults().get(0);
169 assertEquals(3, result.getDocumentAttributes().size());
170 for (DocumentAttribute attribute : result.getDocumentAttributes()) {
171 if (attribute.getName().equals("myAttribute")) {
172 assertEquals("myAttribute", attribute.getName());
173 assertEquals("myCustomizedValue", attribute.getValue());
174 assertEquals(DocumentAttributeDataType.STRING, attribute.getDataType());
175 } else if (attribute.getName().equals("myMultiValuedAttribute")) {
176 assertEquals("myMultiValuedAttribute", attribute.getName());
177 assertEquals("value0", attribute.getValue());
178 assertEquals(DocumentAttributeDataType.STRING, attribute.getDataType());
179 } else if (attribute.getName().equals("criteriaUserId")) {
180 assertEquals("criteriaUserId", attribute.getName());
181 assertEquals(ewestfal, attribute.getValue());
182 }else {
183 fail("Encountered an attribute name which i didn't understand: " + attribute.getName());
184 }
185 }
186 }
187
188 /**
189 * An implementation of a DocumentSearchCustomizer which does some simple customizations to allow us to test that
190 * the customizer is functioning properly.
191 */
192 public static final class Customizer extends DocumentSearchCustomizerBase {
193
194 @Override
195 public DocumentSearchCriteria customizeCriteria(DocumentSearchCriteria documentSearchCriteria) {
196 DocumentSearchCriteria.Builder builder = DocumentSearchCriteria.Builder.create(documentSearchCriteria);
197 builder.setDocumentStatuses(Collections.singletonList(DocumentStatus.FINAL));
198 return builder.build();
199 }
200 @Override
201 public boolean isCustomizeCriteriaEnabled(String documentTypeName) {
202 return true;
203 }
204
205 @Override
206 public DocumentSearchCriteria customizeClearCriteria(DocumentSearchCriteria documentSearchCriteria) {
207 // preserver applicationDocumentId on clear, but clear out everything else
208 DocumentSearchCriteria.Builder builder = DocumentSearchCriteria.Builder.create();
209 builder.setApplicationDocumentId(documentSearchCriteria.getApplicationDocumentId());
210 return builder.build();
211 }
212 @Override
213 public boolean isCustomizeClearCriteriaEnabled(String documentTypeName) {
214 return true;
215 }
216
217 @Override
218 public DocumentSearchResultValues customizeResults(DocumentSearchCriteria documentSearchCriteria,
219 List<DocumentSearchResult> defaultResults) {
220 if (defaultResults.size() == 1) {
221 assertEquals(1, defaultResults.size());
222 DocumentSearchResultValues.Builder valuesBuilder = DocumentSearchResultValues.Builder.create();
223
224 DocumentSearchResultValue.Builder resultValueBuilder = DocumentSearchResultValue.Builder.create(defaultResults.get(0).getDocument().getDocumentId());
225 resultValueBuilder.getDocumentAttributes().add(DocumentAttributeFactory.loadContractIntoBuilder(DocumentAttributeFactory.createStringAttribute("myAttribute", "myCustomizedValue")));
226 resultValueBuilder.getDocumentAttributes().add(DocumentAttributeFactory.loadContractIntoBuilder(DocumentAttributeFactory.createStringAttribute("myMultiValuedAttribute", "value0")));
227
228 // Return if principal id was foudn in criteria
229 if(StringUtils.isNotBlank(documentSearchCriteria.getDocSearchUserId())) {
230 resultValueBuilder.getDocumentAttributes().add(DocumentAttributeFactory.loadContractIntoBuilder(DocumentAttributeFactory.createStringAttribute("criteriaUserId", documentSearchCriteria.getDocSearchUserId())));
231 }
232
233 valuesBuilder.getResultValues().add(resultValueBuilder);
234 return valuesBuilder.build();
235 } else {
236 return null;
237 }
238 }
239 @Override
240 public boolean isCustomizeResultsEnabled(String documentTypeName) {
241 return true;
242 }
243
244 }
245
246 public static final class CustomSearchAttribute implements SearchableAttribute {
247 @Override
248 public String generateSearchContent(ExtensionDefinition extensionDefinition,
249 String documentTypeName,
250 WorkflowAttributeDefinition attributeDefinition) {
251 return null;
252 }
253 @Override
254 public List<DocumentAttribute> extractDocumentAttributes(ExtensionDefinition extensionDefinition,
255 DocumentWithContent documentWithContent) {
256 List<DocumentAttribute> attributes = new ArrayList<DocumentAttribute>();
257 attributes.add(DocumentAttributeFactory.createStringAttribute("myAttribute", "myValue"));
258 attributes.add(DocumentAttributeFactory.createStringAttribute("myMultiValuedAttribute", "value1"));
259 attributes.add(DocumentAttributeFactory.createStringAttribute("myMultiValuedAttribute", "value2"));
260 attributes.add(DocumentAttributeFactory.createStringAttribute("criteriaUserId", "blank"));
261 return attributes;
262 }
263 @Override
264 public List<RemotableAttributeField> getSearchFields(ExtensionDefinition extensionDefinition,
265 String documentTypeName) {
266 List<RemotableAttributeField> searchFields = new ArrayList<RemotableAttributeField>();
267 RemotableAttributeField.Builder builder = RemotableAttributeField.Builder.create("myAttribute");
268 searchFields.add(builder.build());
269 builder = RemotableAttributeField.Builder.create("myMultiValuedAttribute");
270 searchFields.add(builder.build());
271 builder = RemotableAttributeField.Builder.create("criteriaUserId");
272 searchFields.add(builder.build());
273 return searchFields;
274 }
275 @Override
276 public List<RemotableAttributeError> validateDocumentAttributeCriteria(ExtensionDefinition extensionDefinition,
277 DocumentSearchCriteria documentSearchCriteria) {
278 return null;
279 }
280 }
281
282 }