View Javadoc
1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.kew.docsearch;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.junit.Test;
20  import org.kuali.rice.core.api.uif.RemotableAttributeError;
21  import org.kuali.rice.core.api.uif.RemotableAttributeField;
22  import org.kuali.rice.kew.api.KewApiServiceLocator;
23  import org.kuali.rice.kew.api.WorkflowDocument;
24  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
25  import org.kuali.rice.kew.api.document.DocumentStatus;
26  import org.kuali.rice.kew.api.document.DocumentWithContent;
27  import org.kuali.rice.kew.api.document.attribute.DocumentAttribute;
28  import org.kuali.rice.kew.api.document.attribute.DocumentAttributeDataType;
29  import org.kuali.rice.kew.api.document.attribute.DocumentAttributeFactory;
30  import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
31  import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
32  import org.kuali.rice.kew.api.document.search.DocumentSearchResult;
33  import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
34  import org.kuali.rice.kew.api.extension.ExtensionDefinition;
35  import org.kuali.rice.kew.doctype.bo.DocumentType;
36  import org.kuali.rice.kew.framework.document.attribute.SearchableAttribute;
37  import org.kuali.rice.kew.framework.document.search.DocumentSearchCustomizerBase;
38  import org.kuali.rice.kew.framework.document.search.DocumentSearchResultValue;
39  import org.kuali.rice.kew.framework.document.search.DocumentSearchResultValues;
40  import org.kuali.rice.kew.service.KEWServiceLocator;
41  import org.kuali.rice.kew.test.KEWTestCase;
42  
43  import java.util.ArrayList;
44  import java.util.Collections;
45  import java.util.List;
46  
47  import static org.junit.Assert.*;
48  
49  /**
50   * An integration test for the DocumentSearchCustomizer class.  Includes tests on various aspects of the customzations
51   * that class provides, attempting to use the high-level document search apis to exercise it.
52   *
53   * @author Kuali Rice Team (rice.collab@kuali.org)
54   */
55  public class DocumentSearchCustomizerTest extends KEWTestCase {
56  
57      @Override
58  	protected void loadTestData() throws Exception {
59      	loadXmlFile("DocumentSearchCustomizerTest.xml");
60      }
61  
62      @Test
63      public void testCustomizeCriteria() throws Exception {
64  
65          String ewestfal = getPrincipalIdForName("ewestfal");
66          DocumentSearchCriteria.Builder builder = DocumentSearchCriteria.Builder.create();
67  
68          // first check a full doc search, should return no results
69          DocumentSearchResults results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(ewestfal, builder.build());
70          assertTrue(results.getSearchResults().isEmpty());
71          assertFalse(results.getCriteria().getDocumentStatuses().contains(DocumentStatus.FINAL));
72  
73          // now check a document search against the "DocumentSearchCustomizerTest" document type, it is configured with the
74          // CustomizeCriteria customizer
75          builder.setDocumentTypeName("DocumentSearchCustomizerTest");
76  
77          results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(ewestfal, builder.build());
78          assertTrue(results.getSearchResults().isEmpty());
79          DocumentSearchCriteria resultCriteria = results.getCriteria();
80          assertTrue("Document Statuses should have contained FINAL, instead contains: " + resultCriteria
81                  .getDocumentStatuses(), resultCriteria.getDocumentStatuses().contains(DocumentStatus.FINAL));
82  
83          // now route an instance of the CustomizeCriteria document type to FINAL
84          WorkflowDocument document = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("ewestfal"),
85                  "DocumentSearchCustomizerTest");
86          document.route("");
87          assertTrue(document.isFinal());
88  
89          // now run another search, we should get back one result this time
90          results = KewApiServiceLocator.getWorkflowDocumentService().documentSearch(ewestfal, builder.build());
91          assertEquals(1, results.getSearchResults().size());
92          assertEquals(document.getDocumentId(), results.getSearchResults().get(0).getDocument().getDocumentId());
93      }
94  
95      @Test
96      public void testCustomizeClearCriteria() throws Exception {
97  
98          // grab a couple of document types, the first is the TestDocumentType which has no DocumentSearchCustomizer
99          // 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 }