001 /** 002 * Copyright 2005-2013 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 }