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.joda.time.DateTime;
20  import org.junit.Ignore;
21  import org.junit.Test;
22  import org.kuali.rice.kew.api.KEWPropertyConstants;
23  import org.kuali.rice.kew.api.KewApiServiceLocator;
24  import org.kuali.rice.kew.api.WorkflowDocument;
25  import org.kuali.rice.kew.api.WorkflowDocumentFactory;
26  import org.kuali.rice.kew.api.document.DocumentContentUpdate;
27  import org.kuali.rice.kew.api.document.DocumentStatus;
28  import org.kuali.rice.kew.api.document.DocumentStatusCategory;
29  import org.kuali.rice.kew.api.document.attribute.WorkflowAttributeDefinition;
30  import org.kuali.rice.kew.api.document.search.DocumentSearchCriteria;
31  import org.kuali.rice.kew.api.document.search.DocumentSearchResults;
32  import org.kuali.rice.kew.api.extension.ExtensionDefinition;
33  import org.kuali.rice.kew.docsearch.service.DocumentSearchService;
34  import org.kuali.rice.kew.docsearch.xml.StandardGenericXMLSearchableAttribute;
35  import org.kuali.rice.kew.doctype.bo.DocumentType;
36  import org.kuali.rice.kew.doctype.service.DocumentTypeService;
37  import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
38  import org.kuali.rice.kew.framework.KewFrameworkServiceLocator;
39  import org.kuali.rice.kew.impl.document.search.DocumentSearchCriteriaTranslatorImpl;
40  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
41  import org.kuali.rice.kew.routeheader.dao.DocumentRouteHeaderDAO;
42  import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
43  import org.kuali.rice.kew.rule.bo.RuleAttribute;
44  import org.kuali.rice.kew.rule.service.RuleAttributeService;
45  import org.kuali.rice.kew.service.KEWServiceLocator;
46  import org.kuali.rice.kew.api.KewApiConstants;
47  import org.kuali.rice.kim.api.identity.Person;
48  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
49  import org.kuali.rice.krad.util.GlobalVariables;
50  import org.kuali.rice.krad.util.KRADConstants;
51  import org.kuali.rice.test.BaselineTestCase;
52  
53  import java.math.BigDecimal;
54  import java.sql.Timestamp;
55  import java.util.ArrayList;
56  import java.util.Arrays;
57  import java.util.Calendar;
58  import java.util.Collection;
59  import java.util.Collections;
60  import java.util.HashMap;
61  import java.util.HashSet;
62  import java.util.List;
63  import java.util.Map;
64  
65  import static org.junit.Assert.*;
66  import static org.junit.Assert.assertEquals;
67  
68  
69  
70  
71  
72  
73  
74  public class SearchableAttributeTest extends DocumentSearchTestBase {
75  
76      protected void loadTestData() throws Exception {
77          loadXmlFile("SearchAttributeConfig.xml");
78          loadXmlFile("SearchableTrimTest.xml");
79      }
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100 
101 
102 
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116     
117 
118 
119     @Test public void testSearchableAttributeSearch()throws Exception {
120     	String documentTypeName = "SearchDocType";
121         String userNetworkId = "rkirkend";
122         WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(getPrincipalId(userNetworkId), documentTypeName);
123         workflowDocument.setTitle("Routing style");
124         workflowDocument.route("routing this document.");
125 
126         workflowDocument = WorkflowDocumentFactory.loadDocument(getPrincipalId(userNetworkId), workflowDocument.getDocumentId());
127         DocumentRouteHeaderValue doc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(workflowDocument.getDocumentId());
128 
129         
130         DocumentRouteHeaderDAO dao = KEWServiceLocator.getBean("enDocumentRouteHeaderDAO");
131         Collection<SearchableAttributeValue> allValues = dao.findSearchableAttributeValues(workflowDocument.getDocumentId());
132         assertEquals("Wrong number of searchable attributes", 4, allValues.size());
133 
134         for (SearchableAttributeValue attributeValue: allValues) {
135             if (attributeValue instanceof SearchableAttributeStringValue) {
136                 SearchableAttributeStringValue realValue = (SearchableAttributeStringValue) attributeValue;
137 
138                 for(String value:getRouteHeaderService().getSearchableAttributeStringValuesByKey(doc.getDocumentId(), realValue.getSearchableAttributeKey())){
139                 	assertEquals("Assert that the values are the same", value, attributeValue.getSearchableAttributeValue());
140                 }
141 
142             } else if (attributeValue instanceof SearchableAttributeLongValue) {
143                 SearchableAttributeLongValue realValue = (SearchableAttributeLongValue) attributeValue;
144                 for(Long value:getRouteHeaderService().getSearchableAttributeLongValuesByKey(doc.getDocumentId(), realValue.getSearchableAttributeKey())){
145                 	assertEquals("Assert that the values are the same", value, attributeValue.getSearchableAttributeValue());
146                 }
147             } else if (attributeValue instanceof SearchableAttributeFloatValue) {
148                 SearchableAttributeFloatValue realValue = (SearchableAttributeFloatValue) attributeValue;
149                 for(BigDecimal value:getRouteHeaderService().getSearchableAttributeFloatValuesByKey(doc.getDocumentId(), realValue.getSearchableAttributeKey())){
150                 	assertEquals("Assert that the values are the same", value, attributeValue.getSearchableAttributeValue());
151                 }
152 
153             } else if (attributeValue instanceof SearchableAttributeDateTimeValue) {
154                 SearchableAttributeDateTimeValue realValue = (SearchableAttributeDateTimeValue) attributeValue;
155                 assertEquals("The only DateTime attribute that should have been added has key '" + TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY + "'", TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, realValue.getSearchableAttributeKey());
156 
157                 Calendar testDate = Calendar.getInstance();
158                 testDate.setTimeInMillis(realValue.getSearchableAttributeValue().getTime());
159                 testDate.set(Calendar.SECOND, 0);
160                 testDate.set(Calendar.MILLISECOND, 0);
161 
162                 for(Timestamp value:getRouteHeaderService().getSearchableAttributeDateTimeValuesByKey(doc.getDocumentId(), realValue.getSearchableAttributeKey())){
163                 	Calendar attributeDate = Calendar.getInstance();
164                     attributeDate.setTimeInMillis(value.getTime());
165                     attributeDate.set(Calendar.SECOND, 0);
166                     attributeDate.set(Calendar.MILLISECOND, 0);
167 
168                     assertEquals("The month value for the searchable attribute is wrong",testDate.get(Calendar.MONTH),attributeDate.get(Calendar.MONTH));
169                     assertEquals("The date value for the searchable attribute is wrong",testDate.get(Calendar.DATE),attributeDate.get(Calendar.DATE));
170                     assertEquals("The year value for the searchable attribute is wrong",testDate.get(Calendar.YEAR),attributeDate.get(Calendar.YEAR));
171                 }
172 
173             } else {
174                 fail("Searchable Attribute Value base class should be one of the four checked always");
175             }
176         }
177     }
178 
179     protected RouteHeaderService getRouteHeaderService(){
180     	RouteHeaderService rRet = KEWServiceLocator.getRouteHeaderService();
181     	return rRet;
182     }
183 
184     protected String getPrincipalId(String networkId){
185     	return KimApiServiceLocator.getPersonService().getPersonByPrincipalName(networkId).getPrincipalId();
186     }
187 
188     @Test public void testCustomSearchableAttributesWithDataType() throws Exception {
189         String documentTypeName = "SearchDocType";
190     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
191         String userNetworkId = "rkirkend";
192         WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(getPrincipalId(userNetworkId), documentTypeName);
193         workflowDocument.setTitle("Routing style");
194         workflowDocument.route("routing this document.");
195 
196         workflowDocument = WorkflowDocumentFactory.loadDocument(getPrincipalId(userNetworkId), workflowDocument.getDocumentId());
197         DocumentRouteHeaderValue doc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(workflowDocument.getDocumentId());
198 
199         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
200         Person user = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(userNetworkId);
201 
202         DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create();
203         criteria.setDocumentTypeName(documentTypeName);
204         addSearchableAttribute(criteria, TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY,
205                 TestXMLSearchableAttributeString.SEARCH_STORAGE_VALUE);
206         DocumentSearchResults results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
207         assertEquals("Search results should have one document.", 1, results.getSearchResults().size());
208 
209         criteria = DocumentSearchCriteria.Builder.create();
210         criteria.setDocumentTypeName(documentTypeName);
211         addSearchableAttribute(criteria, TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY, "fred");
212         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
213         assertEquals("Search results should be empty.", 0, results.getSearchResults().size());
214 
215         criteria = DocumentSearchCriteria.Builder.create();
216         criteria.setDocumentTypeName(documentTypeName);
217         addSearchableAttribute(criteria, "fakeproperty", "doesntexist");
218         try {
219             docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
220             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
221         } catch (RuntimeException e) {}
222 
223         criteria = DocumentSearchCriteria.Builder.create();
224         criteria.setDocumentTypeName(documentTypeName);
225         addSearchableAttribute(criteria, TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY,
226                 TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE.toString());
227         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
228         assertEquals("Search results should have one document.", 1, results.getSearchResults().size());
229 
230         criteria = DocumentSearchCriteria.Builder.create();
231         criteria.setDocumentTypeName(documentTypeName);
232         addSearchableAttribute(criteria, TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, "1111111");
233         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
234         assertEquals("Search results should be empty.", 0, results.getSearchResults().size());
235 
236         criteria = DocumentSearchCriteria.Builder.create();
237         criteria.setDocumentTypeName(documentTypeName);
238         addSearchableAttribute(criteria, "fakeymcfakefake", "99999999");
239         try {
240             docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
241             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
242         } catch (RuntimeException e) {}
243 
244         criteria = DocumentSearchCriteria.Builder.create();
245         criteria.setDocumentTypeName(documentTypeName);
246         addSearchableAttribute(criteria, TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY,
247                 TestXMLSearchableAttributeFloat.SEARCH_STORAGE_VALUE.toString());
248         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
249         assertEquals("Search results should have one document.", 1, results.getSearchResults().size());
250 
251         criteria = DocumentSearchCriteria.Builder.create();
252         criteria.setDocumentTypeName(documentTypeName);
253         addSearchableAttribute(criteria, TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY, "215.3548");
254         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
255         assertEquals("Search results should be empty.", 0, results.getSearchResults().size());
256 
257         criteria = DocumentSearchCriteria.Builder.create();
258         criteria.setDocumentTypeName(documentTypeName);
259         addSearchableAttribute(criteria, "fakeylostington", "9999.9999");
260         try {
261             docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
262             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
263         } catch (RuntimeException e) {}
264 
265         criteria = DocumentSearchCriteria.Builder.create();
266         criteria.setDocumentTypeName(documentTypeName);
267         addSearchableAttribute(criteria, TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY,
268                 DocumentSearchInternalUtils.getDisplayValueWithDateOnly(new Timestamp(
269                         TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_VALUE_IN_MILLS)));
270         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
271         assertEquals("Search results should have one document.", 1, results.getSearchResults().size());
272 
273         criteria = DocumentSearchCriteria.Builder.create();
274         criteria.setDocumentTypeName(documentTypeName);
275         addSearchableAttribute(criteria, TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, "07/06/1979");
276         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
277         assertEquals("Search results should be empty.", 0, results.getSearchResults().size());
278 
279         criteria = DocumentSearchCriteria.Builder.create();
280         criteria.setDocumentTypeName(documentTypeName);
281         addSearchableAttribute(criteria, "lastingsfakerson", "07/06/2007");
282         try {
283             docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
284             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
285         } catch (RuntimeException e) {}
286     }
287 
288     
289 
290 
291 
292     @Test public void testSearchAttributesAcrossDocumentTypeVersions() throws Exception {
293         
294         loadXmlFile("testdoc0.xml");
295 
296         String documentTypeName = "SearchDoc";
297         WorkflowDocument doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("arh14"), documentTypeName);
298         DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
299         doc.route("routing");
300 
301         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
302 
303         DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create();
304         criteria.setDocumentTypeName(documentTypeName);
305         criteria.setDateCreatedFrom(new DateTime(2004, 1, 1, 0, 0));
306 
307         Person user = KimApiServiceLocator.getPersonService().getPersonByPrincipalName("arh14");
308         DocumentSearchResults results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
309         assertEquals(1, results.getSearchResults().size());
310 
311         
312         loadXmlFile("testdoc1.xml");
313         docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
314 
315         
316         doc = WorkflowDocumentFactory.createDocument(getPrincipalIdForName("arh14"), documentTypeName);
317         doc.route("routing");
318 
319         
320         criteria = DocumentSearchCriteria.Builder.create();
321         criteria.setDocumentTypeName(documentTypeName);
322         criteria.setDateCreatedFrom(new DateTime(2004, 1, 1, 0, 0));
323 
324         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
325         assertEquals(2, results.getSearchResults().size());
326 
327         
328         criteria = DocumentSearchCriteria.Builder.create();
329         criteria.setDocumentTypeName(documentTypeName);
330         criteria.setDateCreatedFrom(new DateTime(2004, 1, 1, 0, 0));
331         addSearchableAttribute(criteria, "MockSearchableAttributeKey", "MockSearchableAttributeValue");
332 
333         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
334         assertEquals(1, results.getSearchResults().size());
335 
336         
337         criteria = DocumentSearchCriteria.Builder.create();
338         criteria.setDocumentTypeName(documentTypeName);
339         criteria.setDateCreatedFrom(new DateTime(2004, 1, 1, 0, 0));
340 
341         results = docSearchService.lookupDocuments(user.getPrincipalId(), criteria.build());
342 
343         assertEquals(2, results.getSearchResults().size());
344     }
345 
346     
347 
348 
349 
350 
351 
352     @Test public void testWildcardsOnSearchableAttributes() throws Exception {
353         String documentTypeName = "WildcardTestDocType";
354     	DocumentType docType = KEWServiceLocator.getDocumentTypeService().findByName(documentTypeName);
355         String principalName = "rkirkend";
356         String principalId = KimApiServiceLocator.getPersonService().getPersonByPrincipalName(principalName).getPrincipalId();
357         String[][] searchableAttributeValuesAsStrings = { {"testString", "9984", "38.1357", "06/24/2009"},
358         		{"anotherStr", "33", "80000.65432", "07/08/2010"}, {"MoreText", "432", "-0.765", "12/12/2012"} };
359 
360         
361         for (int i = 0; i < searchableAttributeValuesAsStrings.length; i++) {
362         	WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(principalId, documentTypeName);
363 
364         	
365         	WorkflowAttributeDefinition.Builder wcStringXMLDef = WorkflowAttributeDefinition.Builder.create("XMLSearchableAttributeWildcardString");
366         	wcStringXMLDef.addPropertyDefinition("xmlSearchableAttributeWildcardString", searchableAttributeValuesAsStrings[i][0]);
367         	workflowDocument.addSearchableDefinition(wcStringXMLDef.build());
368         	
369         	WorkflowAttributeDefinition.Builder wcLongXMLDef = WorkflowAttributeDefinition.Builder.create("XMLSearchableAttributeWildcardLong");
370         	wcLongXMLDef.addPropertyDefinition("xmlSearchableAttributeWildcardLong", searchableAttributeValuesAsStrings[i][1]);
371         	workflowDocument.addSearchableDefinition(wcLongXMLDef.build());
372         	
373         	WorkflowAttributeDefinition.Builder wcFloatXMLDef = WorkflowAttributeDefinition.Builder.create("XMLSearchableAttributeWildcardFloat");
374         	wcFloatXMLDef.addPropertyDefinition("xmlSearchableAttributeWildcardFloat", searchableAttributeValuesAsStrings[i][2]);
375         	workflowDocument.addSearchableDefinition(wcFloatXMLDef.build());
376         	
377         	WorkflowAttributeDefinition.Builder wcDatetimeXMLDef = WorkflowAttributeDefinition.Builder.create("XMLSearchableAttributeWildcardDatetime");
378         	wcDatetimeXMLDef.addPropertyDefinition("xmlSearchableAttributeWildcardDatetime", searchableAttributeValuesAsStrings[i][3]);
379         	workflowDocument.addSearchableDefinition(wcDatetimeXMLDef.build());
380 
381         	workflowDocument.setTitle("Search Def Test Doc " + i);
382         	workflowDocument.route("routing search def doc " + i);
383         }
384 
385         
386         
387         
388         assertSearchableAttributeWildcardsWork(docType, principalId, "xmlSearchableAttributeWildcardString",
389         		new String[]  {"TESTSTRING|moretext", "!MoreText"   , "!anotherStr!testString", "!anotherStr&&!MoreText"  , "!SomeString"      ,
390         					"*str*"                 , "More????"    , "*e*n?"                 , "???String"               , "*te*&&!????String", "!test??????"       , "anotherStr..MoreText",
391         					"testString..MoreText"  , ">=testString", "<=anotherStr|>MoreText", "<=testString&&!anotherStr", ">=abc"             , "<=anotherOne&&>=text",
392         					">=More????"             , "<=*test*"},
393         			new int[] {2                    , 2             , 1                       , 1                         , 3                  ,
394         					2                       , 1             , 1                       , 0                         , 1                  , 2                   , 2 
395         					-1                       , 1             , 2                       , 2                         , 3                  , 0                   ,
396         					2                       , 2});
397 
398         
399         assertSearchableAttributeMultiplesWork(docType, principalId, "xmlSearchableAttributeWildcardString",
400         		new String[][] { {"testString"}, {"anotherStr"}, {"MoreText"}, {"testString", "anotherStr"}, {"testString", "MoreText"}, {"anotherStr", "MoreText"}, {"testString", "anotherStr", "MoreText"}, {"monkey"}, {"monkey", "giraffe"}, {"monkey", "testString"} },
401         			new int[]  {  1,              1,              1,            2,                            2,                          2,                          3,                                        0,          0,                     1                       });
402 
403         
404         assertSearchableAttributeWildcardsWork(docType, principalId, "xmlSearchableAttributeWildcardLong",
405         		new String[]  {"99??", "*2"       , "!33"         , "<9984", ">=433", "<34", ">=432", ">=34&&<9984", "<100000&&>=20", ">=9984&&<33", "431..<9985",
406         					"9999..1", "<432|>432", ">=9000|<=100", "!", ">=-76"},
407         			new int[] {-1     , -1          , 2             , 2      , 1     , 1     , 2      , 1           , 3               , 0           , 2 
408         					-1        , 2          , 2             , -1 , 3});
409 
410         
411         assertSearchableAttributeMultiplesWork(docType, principalId, "xmlSearchableAttributeWildcardLong",
412         		new String[][] { {"9984"}, {"33"}, {"432"}, {"9984", "33"}, {"9984", "432"}, {"33", "432"}, {"9984", "33", "432"}, {"7"}, {"7", "4488"}, {"7", "9984"} },
413         			new int[]  {  1,              1,              1,            2,                            2,                          2,                          3,                                        0,          0,                     1                       });
414 
415         
416         assertSearchableAttributeWildcardsWork(docType, principalId, "xmlSearchableAttributeWildcardFloat",
417         		new String[]  {"38.1???", "!-0.765", "*80*"                , "<80000.65432"   , ">=0"                  , "<-0.763", ">=38.1357", "<38.1358", "<-0.5|>0.5", ">=-0.765&&<=-0.765", ">=38.1358&&<80000.65432",
418         					"-50..<50"   , "100..10", "<38.1358|>=38.1357" , ">=123.4567|<0.11", "-1.1..<38.1357&&<3.3"},
419         			new int[] {-1        , 2        , -1                     , 2                , 2                     , 1         , 2          , 2         , 3           , 1                   , 0                       ,
420         					2           , -1        , 3                     , 2                , 1});
421 
422         
423         assertSearchableAttributeMultiplesWork(docType, principalId, "xmlSearchableAttributeWildcardFloat",
424         		new String[][] { {"38.1357"}, {"80000.65432"}, {"-0.765"}, {"38.1357", "80000.65432"}, {"38.1357", "-0.765"}, {"80000.65432", "-0.765"}, {"38.1357", "80000.65432", "-0.765"}, {"3.1415928"}, {"3.1415928", "4488.0"}, {"3.1415928", "38.1357"} },
425         			new int[]  {  1,              1,              1,            2,                            2,                          2,                          3,                                        0,          0,                     1                       });
426 
427 
428         
429         
430         assertSearchableAttributeWildcardsWork(docType, principalId, "xmlSearchableAttributeWildcardDatetime",
431         		new String[]  {"??/??/20??"            , "12/12/20*"               , "!07/08/2010"           , ">=06/25/2009", "<07/08/2010", ">=12/12/2012", "<05/06/2011", ">=06/25/2009&&<07/09/2010",
432         					">=01/01/2001&&<06/24/2009", "11/29/1990..<12/31/2009"  , "12/13/2100..<08/09/1997",
433         					"<06/24/2009|>=12/12/2012" , "<06/25/2009|>=07/09/2010", ">02/31/2011"},
434         			new int[] {-1                      , -1                         , 2 
435         					0                          , 1                         , -1                       ,
436         					1                          , 2                         , -1});
437         
438         
439         assertSearchableAttributeMultiplesWork(docType, principalId, "xmlSearchableAttributeWildcardDatetime",
440         		new String[][] { {"06/24/2009"}, {"07/08/2010"}, {"12/12/2012"}, {"06/24/2009", "07/08/2010"}, {"06/24/2009", "12/12/2012"}, {"07/08/2010", "12/12/2012"}, {"06/24/2009", "07/08/2010", "12/12/2012"}, {"12/20/2012"}, {"12/20/2012", "11/09/2009"}, {"12/20/2012", "12/12/2012"} },
441         			new int[]  {  1,              1,              1,            2,                            2,                          2,                          3,                                        0,          0,                     1                       });
442 
443     }
444 
445     
446 
447 
448 
449 
450 
451 
452 
453 
454 
455     private void assertSearchableAttributeWildcardsWork(DocumentType docType, String principalId, String fieldDefKey, String[] searchValues,
456     		int[] resultSizes) throws Exception {
457     	DocumentSearchCriteria.Builder criteria = null;
458         DocumentSearchResults results = null;
459         DocumentSearchService docSearchService = KEWServiceLocator.getDocumentSearchService();
460         for (int i = 0; i < resultSizes.length; i++) {
461         	criteria = DocumentSearchCriteria.Builder.create();
462         	criteria.setDocumentTypeName(docType.getName());
463         	addSearchableAttribute(criteria, fieldDefKey, searchValues[i]);
464         	try {
465         		results = docSearchService.lookupDocuments(principalId, criteria.build());
466         		if (resultSizes[i] < 0) {
467         			fail(fieldDefKey + "'s search at loop index " + i + " should have thrown an exception");
468         		}
469         		if(resultSizes[i] != results.getSearchResults().size()){
470         			assertEquals(fieldDefKey + "'s search results at loop index " + i + " returned the wrong number of documents.", resultSizes[i], results.getSearchResults().size());
471         		}
472         	} catch (Exception ex) {
473         		if (resultSizes[i] >= 0) {
474                     ex.printStackTrace();
475         			fail(fieldDefKey + "'s search at loop index " + i + " should not have thrown an exception");
476         		}
477         	}
478         	GlobalVariables.clear();
479         }
480     }
481     
482     
483 
484 
485 
486 
487 
488 
489 
490 
491 
492     private void assertSearchableAttributeMultiplesWork(DocumentType docType, String principalId, String fieldDefKey, String[][] searchValues,
493     		int[] resultSizes) throws Exception {
494         DocumentSearchCriteria.Builder criteria = null;
495         DocumentSearchResults results = null;
496         DocumentSearchService docSearchService = KEWServiceLocator.getDocumentSearchService();
497         for (int i = 0; i < resultSizes.length; i++) {
498             criteria = DocumentSearchCriteria.Builder.create();
499         	criteria.setDocumentTypeName(docType.getName());
500         	addSearchableAttribute(criteria, fieldDefKey, searchValues[i]);
501         	try {
502                 results = docSearchService.lookupDocuments(principalId, criteria.build());
503                 if (resultSizes[i] < 0) {
504         			fail(fieldDefKey + "'s search at loop index " + i + " should have thrown an exception");
505         		}
506         		if(resultSizes[i] != results.getSearchResults().size()){
507         			assertEquals(fieldDefKey + "'s search results at loop index " + i + " returned the wrong number of documents.", resultSizes[i], results.getSearchResults().size());
508         		}
509         	} catch (Exception ex) {
510         		if (resultSizes[i] >= 0) {
511         			fail(fieldDefKey + "'s search at loop index " + i + " should not have thrown an exception");
512         		}
513         	}
514         	GlobalVariables.clear();
515         }
516     }
517     
518     
519     
520     
521 
522 
523     @Test
524     public void testValidateUserSearchInputsNoCast() {
525     	StandardGenericXMLSearchableAttribute searchableAttribute = new StandardGenericXMLSearchableAttribute();
526         ExtensionDefinition extensionDefinition = KewApiServiceLocator.getExtensionRepositoryService().getExtensionByName("SearchableAttributeVisible");
527 
528         DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create();
529     	Map<String, List<String>> simpleParamMap = new HashMap<String, List<String>>();
530     	simpleParamMap.put("givenname", Collections.singletonList("test"));
531         criteria.setDocumentAttributeValues(simpleParamMap);
532     	List errors = new ArrayList();
533     	Exception caughtException = null;
534     	try {
535     		errors = searchableAttribute.validateDocumentAttributeCriteria(extensionDefinition, criteria.build());
536     	} catch (RuntimeException re) {
537     		caughtException = re;
538     	}
539     	assertNull("Found exception "+caughtException, caughtException);
540     	assertTrue("Found errors "+errors, (errors.size() == 0));
541     	
542     	Map<String, List<String>> listParamMap = new HashMap<String, List<String>>();
543     	List<String> multipleValues = new ArrayList<String>();
544     	multipleValues.add("testone");
545     	multipleValues.add("testtwo");
546     	listParamMap.put("givenname", multipleValues);
547         criteria.setDocumentAttributeValues(listParamMap);
548     	errors = new ArrayList();
549     	caughtException = null;
550     	try {
551     		errors = searchableAttribute.validateDocumentAttributeCriteria(extensionDefinition, criteria.build());
552     	} catch (RuntimeException re) {
553     		caughtException = re;
554     	}
555     	assertNull("Found exception "+caughtException, caughtException);
556     	assertTrue("Found errors "+errors, (errors.size() == 0));
557     	
558     }
559     
560     @Test
561     public void testSearchableAttributeTrim() {
562     	RuleAttribute trimAttribute = KEWServiceLocator.getRuleAttributeService().findByName("TrimSearchableAttribute");
563     	assert(trimAttribute.getName().equals("TrimSearchableAttribute"));
564     	assert(trimAttribute.getResourceDescriptor().equals("org.kuali.rice.kew.docsearch.xml.StandardGenericXMLSearchableAttribute"));
565     	assert(trimAttribute.getLabel().equals("Unit111"));
566     	assert(trimAttribute.getType().equals("SearchableXmlAttribute"));
567     	assert(trimAttribute.getDescription().equals("Unit111"));
568     	assert(trimAttribute.getApplicationId().equals("NSTrimSearchableTest"));
569     	
570     }
571 
572     @Test
573     public void testXmlGeneration() {
574         loadXmlFile("testdoc1.xml");
575         WorkflowAttributeDefinition searchableDefinition = WorkflowAttributeDefinition.Builder.create("SearchAttribute").build();
576         DocumentContentUpdate.Builder documentContentUpdateBuilder = DocumentContentUpdate.Builder.create();
577         documentContentUpdateBuilder.getSearchableDefinitions().add(searchableDefinition);
578         WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(getPrincipalId("ewestfal"), "SearchDoc", null, documentContentUpdateBuilder.build());
579         workflowDocument.route("");
580         assertTrue(workflowDocument.isFinal());
581         assertEquals(StringUtils.deleteWhitespace("<" + KewApiConstants.SEARCHABLE_CONTENT_ELEMENT + ">" + MockSearchableAttribute.SEARCH_CONTENT + "</" + KewApiConstants.SEARCHABLE_CONTENT_ELEMENT + ">"),
582                 StringUtils.deleteWhitespace(workflowDocument.getDocumentContent().getSearchableContent()));
583     }
584 
585     @Test
586     public void testAttributeRangeFieldGeneration() {
587         String documentTypeName = "SearchDocType";
588         DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
589         String userNetworkId = "rkirkend";
590         WorkflowDocument workflowDocument = WorkflowDocumentFactory.createDocument(getPrincipalId(userNetworkId), documentTypeName);
591         workflowDocument.setTitle("Routing style");
592         workflowDocument.route("routing this document.");
593 
594         DocumentSearchCriteria.Builder criteria = DocumentSearchCriteria.Builder.create();
595         criteria.setDocumentTypeName(documentTypeName);
596         criteria.setDateApprovedFrom(new DateTime(2010, 1, 1, 0, 0));
597         criteria.setDateApprovedTo(new DateTime(2011, 1, 1, 0, 0));
598         String fieldValue = ">= " + DocumentSearchInternalUtils.getDisplayValueWithDateOnly(new Timestamp(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_VALUE_IN_MILLS));
599         addSearchableAttribute(criteria, TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, fieldValue);
600 
601         Map<String, String[]> fields = new DocumentSearchCriteriaTranslatorImpl().translateCriteriaToFields(criteria.build());
602         System.err.println(fields);
603         String lowerBoundField = KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + KRADConstants.LOOKUP_RANGE_LOWER_BOUND_PROPERTY_PREFIX + TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY;
604         String upperBoundField = KewApiConstants.DOCUMENT_ATTRIBUTE_FIELD_PREFIX + TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY;
605 
606         assertNotNull(fields.get(lowerBoundField));
607         assertNotNull(fields.get(upperBoundField));
608         assertNotNull(fields.get(lowerBoundField)[0]);
609         assertNull(fields.get(upperBoundField)[0]);
610 
611         assertEquals(DocumentSearchInternalUtils.getDisplayValueWithDateOnly(new Timestamp(new DateTime(2007, 3, 15, 0, 0).toDateTime().getMillis())), fields.get(lowerBoundField)[0]);
612     }
613     
614 }