View Javadoc

1   /*
2    * Copyright 2005-2007 The Kuali Foundation
3    *
4    *
5    * Licensed under the Educational Community License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.opensource.org/licenses/ecl2.php
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.kuali.rice.kew.docsearch.xml;
18  
19  import java.io.BufferedReader;
20  import java.io.StringReader;
21  import java.sql.Timestamp;
22  import java.util.Calendar;
23  import java.util.HashMap;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.xml.parsers.DocumentBuilderFactory;
29  import javax.xml.xpath.XPath;
30  import javax.xml.xpath.XPathConstants;
31  import javax.xml.xpath.XPathFactory;
32  
33  import org.junit.Ignore;
34  import org.junit.Test;
35  import org.kuali.rice.kew.docsearch.DocSearchCriteriaDTO;
36  import org.kuali.rice.kew.docsearch.DocSearchUtils;
37  import org.kuali.rice.kew.docsearch.DocumentSearchContext;
38  import org.kuali.rice.kew.docsearch.DocumentSearchResult;
39  import org.kuali.rice.kew.docsearch.DocumentSearchResultComponents;
40  import org.kuali.rice.kew.docsearch.DocumentSearchTestBase;
41  import org.kuali.rice.kew.docsearch.SearchableAttributeDateTimeValue;
42  import org.kuali.rice.kew.docsearch.SearchableAttributeFloatValue;
43  import org.kuali.rice.kew.docsearch.SearchableAttributeLongValue;
44  import org.kuali.rice.kew.docsearch.SearchableAttributeStringValue;
45  import org.kuali.rice.kew.docsearch.SearchableAttributeValue;
46  import org.kuali.rice.kew.docsearch.TestXMLSearchableAttributeDateTime;
47  import org.kuali.rice.kew.docsearch.TestXMLSearchableAttributeFloat;
48  import org.kuali.rice.kew.docsearch.TestXMLSearchableAttributeLong;
49  import org.kuali.rice.kew.docsearch.TestXMLSearchableAttributeString;
50  import org.kuali.rice.kew.docsearch.service.DocumentSearchService;
51  import org.kuali.rice.kew.doctype.bo.DocumentType;
52  import org.kuali.rice.kew.doctype.service.DocumentTypeService;
53  import org.kuali.rice.kew.dto.NetworkIdDTO;
54  import org.kuali.rice.kew.dto.WorkflowAttributeDefinitionDTO;
55  import org.kuali.rice.kew.exception.WorkflowException;
56  import org.kuali.rice.kew.exception.WorkflowServiceErrorException;
57  import org.kuali.rice.kew.routeheader.DocumentRouteHeaderValue;
58  import org.kuali.rice.kew.routeheader.service.RouteHeaderService;
59  import org.kuali.rice.kew.rule.WorkflowAttributeValidationError;
60  import org.kuali.rice.kew.service.KEWServiceLocator;
61  import org.kuali.rice.kew.service.WorkflowDocument;
62  import org.kuali.rice.kew.test.TestUtilities;
63  import org.kuali.rice.kew.web.KeyValueSort;
64  import org.kuali.rice.kim.bo.Person;
65  import org.kuali.rice.kim.service.KIMServiceLocator;
66  import org.kuali.rice.kns.web.ui.Field;
67  import org.kuali.rice.kns.web.ui.Row;
68  import org.w3c.dom.Element;
69  import org.xml.sax.InputSource;
70  
71  
72  /**
73   * Tests the StandardGenericXMLSearchableAttribute.
74   *
75   * KULWF-654: Tests the resolution to this issue by configuring a CustomActionListAttribute as well as a
76   * searchable attribute.
77   */
78  public class StandardGenericXMLSearchableAttributeTest extends DocumentSearchTestBase {
79  
80      protected void loadTestData() throws Exception {
81          loadXmlFile("XmlConfig.xml");
82      }
83  
84      @Test public void testXMLStandardSearchableAttributeWithInvalidValue() throws Exception {
85          String documentTypeName = "SearchDocTypeStandardSearchDataType";
86          String userNetworkId = "rkirkend";
87          WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO(userNetworkId), documentTypeName);
88  
89          /*
90           *   Below we are using the keys and values from the custom searchable attribute classes' static constants but
91           *   this is only for convenience as those should always be valid values to test for.
92           */
93          // adding string value in what should be a long searchable attribute
94          WorkflowAttributeDefinitionDTO longXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttributeStdLong");
95          longXMLDef.addProperty(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, "123x23");
96          workflowDocument.addSearchableDefinition(longXMLDef);
97  
98          workflowDocument.setTitle("Routing style");
99          try {
100             workflowDocument.routeDocument("routing this document.");
101             fail("Document should be unroutable with invalid searchable attribute value");
102         } catch (Exception e) {
103             e.printStackTrace();
104             /*
105              * The call to TestUtilities below is needed because when exception routing spawns a new thread (see
106              * TestExceptionRoutingServiceImpl class) the next test will begin before the exception thread is complete and
107              * cause errors. This was originally discovered because the test method
108              * testXMLStandardSearchableAttributesWithDataType() would run and get errors loading xml data for workgroups
109              * perhaps because the exception thread was keeping the cache around and now allowing it to be cleared?
110              */
111             TestUtilities.waitForExceptionRouting();
112         }
113         TestUtilities.waitForExceptionRouting();
114     }
115 
116     @Test public void testXMLStandardSearchableAttributesWithDataType() throws Exception {
117         String documentTypeName = "SearchDocTypeStandardSearchDataType";
118     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
119         String userNetworkId = "rkirkend";
120         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO(userNetworkId), documentTypeName);
121 
122         /*
123          *   Below we are using the keys and values from the custom searchable attribute classes' static constants but
124          *   this is only for convenience as those should always be valid values to test for.
125          */
126         int i = 0;
127         // adding string searchable attribute
128         i++;
129         WorkflowAttributeDefinitionDTO stringXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
130         stringXMLDef.addProperty(TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeString.SEARCH_STORAGE_VALUE);
131         workflowDocument.addSearchableDefinition(stringXMLDef);
132         // adding long searchable attribute
133         i++;
134         WorkflowAttributeDefinitionDTO longXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttributeStdLong");
135         longXMLDef.addProperty(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE.toString());
136         workflowDocument.addSearchableDefinition(longXMLDef);
137         // adding float searchable attribute
138         i++;
139         WorkflowAttributeDefinitionDTO floatXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttributeStdFloat");
140         floatXMLDef.addProperty(TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeFloat.SEARCH_STORAGE_VALUE.toString());
141         workflowDocument.addSearchableDefinition(floatXMLDef);
142         // adding string searchable attribute
143         i++;
144         WorkflowAttributeDefinitionDTO dateXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttributeStdDateTime");
145         dateXMLDef.addProperty(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, DocSearchUtils.getDisplayValueWithDateOnly(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_VALUE));
146         workflowDocument.addSearchableDefinition(dateXMLDef);
147 
148         workflowDocument.setTitle("Routing style");
149         workflowDocument.routeDocument("routing this document.");
150 
151         workflowDocument = new WorkflowDocument(new NetworkIdDTO(userNetworkId), workflowDocument.getRouteHeaderId());
152         DocumentRouteHeaderValue doc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(workflowDocument.getRouteHeaderId());
153         /*
154         assertEquals("Wrong number of searchable attributes", i, doc.getSearchableAttributeValues().size());
155         for (Iterator iter = doc.getSearchableAttributeValues().iterator(); iter.hasNext();) {
156             SearchableAttributeValue attributeValue = (SearchableAttributeValue) iter.next();
157             if (attributeValue instanceof SearchableAttributeStringValue) {
158                 SearchableAttributeStringValue realValue = (SearchableAttributeStringValue) attributeValue;
159                 assertEquals("The only String attribute that should have been added has key '" + TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY + "'", TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY, realValue.getSearchableAttributeKey());
160                 assertEquals("The only String attribute that should have been added has value '" + TestXMLSearchableAttributeString.SEARCH_STORAGE_VALUE + "'", TestXMLSearchableAttributeString.SEARCH_STORAGE_VALUE, realValue.getSearchableAttributeValue());
161             } else if (attributeValue instanceof SearchableAttributeLongValue) {
162                 SearchableAttributeLongValue realValue = (SearchableAttributeLongValue) attributeValue;
163                 assertEquals("The only Long attribute that should have been added has key '" + TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY + "'", TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, realValue.getSearchableAttributeKey());
164                 assertEquals("The only Long attribute that should have been added has value '" + TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE + "'", TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE, realValue.getSearchableAttributeValue());
165             } else if (attributeValue instanceof SearchableAttributeFloatValue) {
166                 SearchableAttributeFloatValue realValue = (SearchableAttributeFloatValue) attributeValue;
167                 assertEquals("The only Float attribute that should have been added has key '" + TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY + "'", TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY, realValue.getSearchableAttributeKey());
168                 assertTrue("The only Float attribute that should have been added has value '" + TestXMLSearchableAttributeFloat.SEARCH_STORAGE_VALUE + "'", 0 == TestXMLSearchableAttributeFloat.SEARCH_STORAGE_VALUE.compareTo(realValue.getSearchableAttributeValue()));
169             } else if (attributeValue instanceof SearchableAttributeDateTimeValue) {
170                 SearchableAttributeDateTimeValue realValue = (SearchableAttributeDateTimeValue) attributeValue;
171                 assertEquals("The only DateTime attribute that should have been added has key '" + TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY + "'", TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, realValue.getSearchableAttributeKey());
172                 Calendar testDate = Calendar.getInstance();
173                 testDate.setTimeInMillis(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_VALUE_IN_MILLS);
174                 testDate.set(Calendar.SECOND, 0);
175                 testDate.set(Calendar.MILLISECOND, 0);
176                 Calendar attributeDate = Calendar.getInstance();
177                 attributeDate.setTimeInMillis(realValue.getSearchableAttributeValue().getTime());
178                 attributeDate.set(Calendar.SECOND, 0);
179                 attributeDate.set(Calendar.MILLISECOND, 0);
180                 assertEquals("The month value for the searchable attribute is wrong",testDate.get(Calendar.MONTH),attributeDate.get(Calendar.MONTH));
181                 assertEquals("The date value for the searchable attribute is wrong",testDate.get(Calendar.DATE),attributeDate.get(Calendar.DATE));
182                 assertEquals("The year value for the searchable attribute is wrong",testDate.get(Calendar.YEAR),attributeDate.get(Calendar.YEAR));
183             } else {
184                 fail("Searchable Attribute Value base class should be one of the four checked always");
185             }
186         }
187         */
188 
189         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
190         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName(userNetworkId);
191 
192         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
193         criteria.setDocTypeFullName(documentTypeName);
194         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeString.SEARCH_STORAGE_VALUE, docType));
195         DocumentSearchResultComponents result = docSearchService.getList(user.getPrincipalId(), criteria);
196         List searchResults = result.getSearchResults();
197 
198         assertEquals("Search results should have one document.", 1, searchResults.size());
199 
200         DocSearchCriteriaDTO criteria2 = new DocSearchCriteriaDTO();
201         criteria2.setDocTypeFullName(documentTypeName);
202         criteria2.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY, "fred", docType));
203         DocumentSearchResultComponents result2 = docSearchService.getList(user.getPrincipalId(), criteria2);
204         List searchResults2 = result2.getSearchResults();
205 
206         assertEquals("Search results should be empty.", 0, searchResults2.size());
207 
208         DocSearchCriteriaDTO criteria3 = new DocSearchCriteriaDTO();
209         criteria3.setDocTypeFullName(documentTypeName);
210         criteria3.addSearchableAttribute(createSearchAttributeCriteriaComponent("fakeproperty", "doesntexist", docType));
211         DocumentSearchResultComponents result3 = null;
212         try {
213             result3 = docSearchService.getList(user.getPrincipalId(), criteria3);
214             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
215         } catch (WorkflowServiceErrorException e) {}
216 
217         criteria = null;
218         searchResults = null;
219         criteria = new DocSearchCriteriaDTO();
220         criteria.setDocTypeFullName(documentTypeName);
221         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE.toString(), docType));
222         result = docSearchService.getList(user.getPrincipalId(), criteria);
223         searchResults = result.getSearchResults();
224         assertEquals("Search results should have one document.", 1, searchResults.size());
225 
226         criteria2 = null;
227         searchResults2 = null;
228         criteria2 = new DocSearchCriteriaDTO();
229         criteria2.setDocTypeFullName(documentTypeName);
230         criteria2.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, "1111111", docType));
231         result2 = docSearchService.getList(user.getPrincipalId(), criteria2);
232         searchResults2 = result2.getSearchResults();
233         assertEquals("Search results should be empty.", 0, searchResults2.size());
234 
235         criteria3 = null;
236         result3 = null;
237         criteria3 = new DocSearchCriteriaDTO();
238         criteria3.setDocTypeFullName(documentTypeName);
239         criteria3.addSearchableAttribute(createSearchAttributeCriteriaComponent("fakeymcfakefake", "99999999", docType));
240         try {
241             result3 = docSearchService.getList(user.getPrincipalId(), criteria3);
242             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
243         } catch (WorkflowServiceErrorException e) {}
244 
245         criteria = null;
246         searchResults = null;
247         criteria = new DocSearchCriteriaDTO();
248         criteria.setDocTypeFullName(documentTypeName);
249         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeFloat.SEARCH_STORAGE_VALUE.toString(), docType));
250         result = docSearchService.getList(user.getPrincipalId(), criteria);
251         searchResults = result.getSearchResults();
252         assertEquals("Search results should have one document.", 1, searchResults.size());
253 
254         criteria2 = null;
255         searchResults2 = null;
256         criteria2 = new DocSearchCriteriaDTO();
257         criteria2.setDocTypeFullName(documentTypeName);
258         criteria2.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY, "215.3548", docType));
259         result2 = docSearchService.getList(user.getPrincipalId(), criteria2);
260         searchResults2 = result2.getSearchResults();
261         assertEquals("Search results should be empty.", 0, searchResults2.size());
262 
263         criteria3 = null;
264         result3 = null;
265         criteria3 = new DocSearchCriteriaDTO();
266         criteria3.setDocTypeFullName(documentTypeName);
267         criteria3.addSearchableAttribute(createSearchAttributeCriteriaComponent("fakeylostington", "9999.9999", docType));
268         try {
269             result3 = docSearchService.getList(user.getPrincipalId(), criteria3);
270             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
271         } catch (WorkflowServiceErrorException e) {}
272 
273         criteria = null;
274         searchResults = null;
275         criteria = new DocSearchCriteriaDTO();
276         criteria.setDocTypeFullName(documentTypeName);
277         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, DocSearchUtils.getDisplayValueWithDateOnly(new Timestamp(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_VALUE_IN_MILLS)), docType));
278         result = docSearchService.getList(user.getPrincipalId(), criteria);
279         searchResults = result.getSearchResults();
280         assertEquals("Search results should have one document.", 1, searchResults.size());
281 
282         criteria2 = null;
283         searchResults2 = null;
284         criteria2 = new DocSearchCriteriaDTO();
285         criteria2.setDocTypeFullName(documentTypeName);
286         criteria2.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, "07/06/1979", docType));
287         result2 = docSearchService.getList(user.getPrincipalId(), criteria2);
288         searchResults2 = result2.getSearchResults();
289         assertEquals("Search results should be empty.", 0, searchResults2.size());
290 
291         criteria3 = null;
292         result3 = null;
293         criteria3 = new DocSearchCriteriaDTO();
294         criteria3.setDocTypeFullName(documentTypeName);
295         criteria3.addSearchableAttribute(createSearchAttributeCriteriaComponent("lastingsfakerson", "07/06/2007", docType));
296         try {
297             result3 = docSearchService.getList(user.getPrincipalId(), criteria3);
298             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
299         } catch (WorkflowServiceErrorException e) {}
300     }
301 
302     @Test public void testRouteDocumentWithSearchableAttribute() throws Exception {
303     	String documentTypeName = "SearchDocType";
304     	String key = "givenname";
305     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
306         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), documentTypeName);
307         WorkflowAttributeDefinitionDTO givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
308 
309         workflowDocument.setApplicationContent("<test></test>");
310 
311         givennameXMLDef.addProperty(key, "jack");
312         workflowDocument.addSearchableDefinition(givennameXMLDef);
313 
314         workflowDocument.setTitle("Routing style");
315         workflowDocument.routeDocument("routing this document.");
316 
317         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
318 
319         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName("rkirkend");
320         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
321         criteria.setDocTypeFullName(documentTypeName);
322         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jack", docType));
323         DocumentSearchResultComponents result = docSearchService.getList(user.getPrincipalId(), criteria);
324         List searchResults = result.getSearchResults();
325 
326         assertEquals("Search results should have one document.", 1, searchResults.size());
327 
328         criteria = null;
329         searchResults = null;
330         criteria = new DocSearchCriteriaDTO();
331         criteria.setDocTypeFullName(documentTypeName);
332         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "fred", docType));
333         result = docSearchService.getList(user.getPrincipalId(), criteria);
334         searchResults = result.getSearchResults();
335 
336         assertEquals("Search results should be empty.", 0, searchResults.size());
337 
338         criteria = null;
339         searchResults = null;
340         criteria = new DocSearchCriteriaDTO();
341         criteria.setDocTypeFullName(documentTypeName);
342         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent("fakeproperty", "doesntexist", docType));
343         try {
344             result = docSearchService.getList(user.getPrincipalId(), criteria);
345             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
346         } catch (WorkflowServiceErrorException wsee) {}
347     }
348 
349     @Test public void testDocumentSearchAttributeWildcarding() throws Exception {
350         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
351 
352     	String documentTypeName = "SearchDocType";
353     	String key = "givenname";
354     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
355         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), documentTypeName);
356         WorkflowAttributeDefinitionDTO givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
357 
358         workflowDocument.setApplicationContent("<test></test>");
359 
360         givennameXMLDef.addProperty(key, "jack");
361         workflowDocument.addSearchableDefinition(givennameXMLDef);
362 
363         workflowDocument.setTitle("Routing style");
364         workflowDocument.routeDocument("routing this document.");
365 
366         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName("rkirkend");
367         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
368         criteria.setDocTypeFullName(documentTypeName);
369         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jack", docType));
370         DocumentSearchResultComponents result = docSearchService.getList(user.getPrincipalId(), criteria);
371         List searchResults = result.getSearchResults();
372 
373         assertEquals("Search results should have one document.", 1, searchResults.size());
374 
375         criteria = new DocSearchCriteriaDTO();
376         criteria.setDocTypeFullName(documentTypeName);
377         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "ja*", docType));
378         result = docSearchService.getList(user.getPrincipalId(), criteria);
379         searchResults = result.getSearchResults();
380 
381         assertEquals("Search results should have one document.", 1, searchResults.size());
382 
383         criteria = new DocSearchCriteriaDTO();
384         criteria.setDocTypeFullName(documentTypeName);
385         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "ja", docType));
386         result = docSearchService.getList(user.getPrincipalId(), criteria);
387         searchResults = result.getSearchResults();
388 
389         assertEquals("Search results should have one document.", 0, searchResults.size());
390 
391         criteria = new DocSearchCriteriaDTO();
392         criteria.setDocTypeFullName(documentTypeName);
393         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "*ack", docType));
394         result = docSearchService.getList(user.getPrincipalId(), criteria);
395         searchResults = result.getSearchResults();
396 
397         assertEquals("Search results should have one document.", 1, searchResults.size());
398     }
399 
400     @Test public void testDocumentSearchAttributeWildcardingDisallow() throws Exception {
401         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
402 
403         String documentTypeName = "SearchDocTypeStandardSearchDataType";
404     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
405         String userNetworkId = "rkirkend";
406         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO(userNetworkId), documentTypeName);
407 
408         /*
409          *   Below we are using the keys and values from the custom searchable attribute classes' static constants but
410          *   this is only for convenience as those should always be valid values to test for.
411          */
412         WorkflowAttributeDefinitionDTO longXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttributeStdLong");
413         longXMLDef.addProperty(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE.toString());
414         workflowDocument.addSearchableDefinition(longXMLDef);
415         workflowDocument.setTitle("Routing style");
416         workflowDocument.routeDocument("routing this document.");
417 
418         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName(userNetworkId);
419 
420         String validSearchValue = TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE.toString();
421         DocSearchCriteriaDTO criteria = null;
422         List searchResults = null;
423         DocumentSearchResultComponents result = null;
424         criteria = new DocSearchCriteriaDTO();
425         criteria.setDocTypeFullName(documentTypeName);
426         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, validSearchValue, docType));
427         result = docSearchService.getList(user.getPrincipalId(), criteria);
428         searchResults = result.getSearchResults();
429         assertEquals("Search results should have one document.", 1, searchResults.size());
430 
431         criteria = null;
432         searchResults = null;
433         criteria = new DocSearchCriteriaDTO();
434         criteria.setDocTypeFullName(documentTypeName);
435         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, "*" + validSearchValue.substring(2), docType));
436 
437         if ((new SearchableAttributeLongValue()).allowsWildcards()) {
438             result = docSearchService.getList(user.getPrincipalId(), criteria);
439             searchResults = result.getSearchResults();
440             assertEquals("Search results should be empty using wildcard '*' value.", 0, searchResults.size());
441         } else {
442             try {
443                 result = docSearchService.getList(user.getPrincipalId(), criteria);
444                 searchResults = result.getSearchResults();
445                 fail("Search results should be throwing a validation exception for use of the character '*' without allowing wildcards");
446             } catch (WorkflowServiceErrorException wsee) {}
447         }
448 
449         criteria = null;
450         searchResults = null;
451         criteria = new DocSearchCriteriaDTO();
452         criteria.setDocTypeFullName(documentTypeName);
453         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, validSearchValue.substring(0, (validSearchValue.length() - 2)), docType));
454         result = docSearchService.getList(user.getPrincipalId(), criteria);
455         searchResults = result.getSearchResults();
456         assertEquals("Search results should be empty trying to use assumed ending wildcard.", 0, searchResults.size());
457     }
458 
459     @Test public void testDocumentSearchAttributeCaseSensitivity() throws Exception {
460         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
461     	String documentTypeName = "SearchDocTypeCaseSensitivity";
462     	String networkId = "rkirkend";
463     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
464 
465     	String key = "givenname";
466     	WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO(networkId), documentTypeName);
467         WorkflowAttributeDefinitionDTO givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
468         givennameXMLDef.addProperty(key, "jack");
469         workflowDocument.addSearchableDefinition(givennameXMLDef);
470         workflowDocument.setTitle("Routing style");
471         workflowDocument.routeDocument("routing this document.");
472 
473         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName(networkId);
474         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
475         criteria.setDocTypeFullName(documentTypeName);
476         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jack", docType));
477         DocumentSearchResultComponents result = docSearchService.getList(user.getPrincipalId(), criteria);
478         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
479 
480         criteria = new DocSearchCriteriaDTO();
481         criteria.setDocTypeFullName(documentTypeName);
482         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "JACK", docType));
483         result = docSearchService.getList(user.getPrincipalId(), criteria);
484         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
485 
486         criteria = new DocSearchCriteriaDTO();
487         criteria.setDocTypeFullName(documentTypeName);
488         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jAck", docType));
489         result = docSearchService.getList(user.getPrincipalId(), criteria);
490         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
491 
492         criteria = new DocSearchCriteriaDTO();
493         criteria.setDocTypeFullName(documentTypeName);
494         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jacK", docType));
495         result = docSearchService.getList(user.getPrincipalId(), criteria);
496         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
497 
498     	key = "givenname_nocase";
499         workflowDocument = new WorkflowDocument(new NetworkIdDTO(networkId), documentTypeName);
500         WorkflowAttributeDefinitionDTO givenname_nocaseXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute_CaseInsensitive");
501         givenname_nocaseXMLDef.addProperty(key, "jaCk");
502         workflowDocument.addSearchableDefinition(givenname_nocaseXMLDef);
503         workflowDocument.setTitle("Routing style");
504         workflowDocument.routeDocument("routing this document.");
505 
506         criteria = new DocSearchCriteriaDTO();
507         criteria.setDocTypeFullName(documentTypeName);
508         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jack", docType));
509         result = docSearchService.getList(user.getPrincipalId(), criteria);
510         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
511 
512         criteria = new DocSearchCriteriaDTO();
513         criteria.setDocTypeFullName(documentTypeName);
514         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "JACK", docType));
515         result = docSearchService.getList(user.getPrincipalId(), criteria);
516         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
517 
518         criteria = new DocSearchCriteriaDTO();
519         criteria.setDocTypeFullName(documentTypeName);
520         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jaCk", docType));
521         result = docSearchService.getList(user.getPrincipalId(), criteria);
522         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
523 
524         criteria = new DocSearchCriteriaDTO();
525         criteria.setDocTypeFullName(documentTypeName);
526         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jacK", docType));
527         result = docSearchService.getList(user.getPrincipalId(), criteria);
528         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
529 
530         criteria = new DocSearchCriteriaDTO();
531         criteria.setDocTypeFullName(documentTypeName);
532         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jAc", docType));
533         result = docSearchService.getList(user.getPrincipalId(), criteria);
534         assertEquals("Search results should have one document.", 0, result.getSearchResults().size());
535 
536         criteria = new DocSearchCriteriaDTO();
537         criteria.setDocTypeFullName(documentTypeName);
538         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jA*", docType));
539         result = docSearchService.getList(user.getPrincipalId(), criteria);
540         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
541 
542         criteria = new DocSearchCriteriaDTO();
543         criteria.setDocTypeFullName(documentTypeName);
544         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "*aCk", docType));
545         result = docSearchService.getList(user.getPrincipalId(), criteria);
546         assertEquals("Search results should have one document.", 1, result.getSearchResults().size());
547     }
548 
549     /**
550      * Tests searching with client-generated documentContent which is just malformed XML.
551      * @throws WorkflowException
552      */
553     @Test public void testRouteDocumentWithMalformedSearchableAttributeContent() throws WorkflowException {
554         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), "SearchDocType");
555 
556         workflowDocument.setApplicationContent("hey, <I'm Not ] Even & XML");
557 
558         workflowDocument.setTitle("Routing style");
559         try {
560             workflowDocument.routeDocument("routing this document.");
561             fail("routeDocument succeeded with malformed XML");
562         } catch (WorkflowException we) {
563             // An exception is thrown in DTOConverter/XmlUtils.appendXml at the time of this writing
564             // so I will just assume that is the expected behavior
565         }
566         TestUtilities.waitForExceptionRouting();
567     }
568 
569     /**
570      * Tests searching with client-generated documentContent which will not match what the SearchableAttribute
571      * is configured to look for.  This should pass with zero search results, but should not throw an exception.
572      * @throws Exception
573      */
574     @Test public void testRouteDocumentWithInvalidSearchableAttributeContent() throws Exception {
575     	String documentTypeName = "SearchDocType";
576     	String key = "givenname";
577     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
578         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), documentTypeName);
579 
580         workflowDocument.setApplicationContent("<documentContent><searchableContent><garbage>" +
581                                                "<blah>not going to match anything</blah>" +
582                                                "</garbage></searchableContent></documentContent>");
583 
584         workflowDocument.setTitle("Routing style");
585         workflowDocument.routeDocument("routing this document.");
586 
587         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
588 
589         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName("rkirkend");
590         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
591         criteria.setDocTypeFullName(documentTypeName);
592         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jack", docType));
593         DocumentSearchResultComponents result = docSearchService.getList(user.getPrincipalId(), criteria);
594         List searchResults = result.getSearchResults();
595 
596         assertEquals("Search results should be empty.", 0, searchResults.size());
597 
598         criteria = new DocSearchCriteriaDTO();
599         criteria.setDocTypeFullName(documentTypeName);
600         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "fred", docType));
601         result = docSearchService.getList(user.getPrincipalId(), criteria);
602         searchResults = result.getSearchResults();
603 
604         assertEquals("Search results should be empty.", 0, searchResults.size());
605 
606         criteria = new DocSearchCriteriaDTO();
607         criteria.setDocTypeFullName(documentTypeName);
608         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent("fakeproperty", "doesntexist", docType));
609         try {
610             result = docSearchService.getList(user.getPrincipalId(), criteria);
611             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
612         } catch (WorkflowServiceErrorException wsee) {}
613     }
614 
615     /**
616      * Tests searching with client-generated documentContent which will not match what the SearchableAttribute
617      * is configured to look for.  This should pass with zero search results, but should not throw an exception.
618      * @throws Exception
619      */
620     @Test public void testRouteDocumentWithMoreInvalidSearchableAttributeContent() throws Exception {
621     	String documentTypeName = "SearchDocType";
622     	String key = "givenname";
623     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
624         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), documentTypeName);
625 
626         workflowDocument.setApplicationContent("<documentContent><NOTsearchableContent><garbage>" +
627                                                "<blah>not going to match anything</blah>" +
628                                                "</garbage></NOTsearchableContent></documentContent>");
629 
630         workflowDocument.setTitle("Routing style");
631         workflowDocument.routeDocument("routing this document.");
632 
633         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
634 
635         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName("rkirkend");
636         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
637         criteria.setDocTypeFullName(documentTypeName);
638         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jack", docType));
639         DocumentSearchResultComponents result = docSearchService.getList(user.getPrincipalId(), criteria);
640         List searchResults = result.getSearchResults();
641 
642         assertEquals("Search results should be empty.", 0, searchResults.size());
643 
644         criteria = new DocSearchCriteriaDTO();
645         criteria.setDocTypeFullName(documentTypeName);
646         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "fred", docType));
647         result = docSearchService.getList(user.getPrincipalId(), criteria);
648         searchResults = result.getSearchResults();
649 
650         assertEquals("Search results should be empty.", 0, searchResults.size());
651 
652         criteria = new DocSearchCriteriaDTO();
653         criteria.setDocTypeFullName(documentTypeName);
654         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent("fakeproperty", "doesntexist", docType));
655         try {
656             result = docSearchService.getList(user.getPrincipalId(), criteria);
657             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
658         } catch (WorkflowServiceErrorException wsee) {}
659     }
660 
661     /*
662     @Test public void testAppendingSeachContentWithSearchableAttribute() throws Exception {
663         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), "SearchDocType");
664         WorkflowAttributeDefinitionDTO givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
665 
666         givennameXMLDef.addProperty("givenname", "jack");
667         workflowDocument.addSearchableDefinition(givennameXMLDef);
668 
669         workflowDocument.setTitle("Routing Rowdy Piper");
670         workflowDocument.routeDocument("routing this document.");
671 
672         // look up document and verify the search valu is there
673         DocumentRouteHeaderValue doc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(workflowDocument.getRouteHeaderId());
674         assertEquals("Wrong number of searchable attributes", 1, doc.getSearchableAttributeValues().size());
675 
676         workflowDocument = new WorkflowDocument(new NetworkIdDTO("jhopf"), workflowDocument.getRouteHeaderId());
677         givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
678 
679         givennameXMLDef.addProperty("givenname", "jill");
680         workflowDocument.addSearchableDefinition(givennameXMLDef);
681         workflowDocument.approve("");
682 
683         doc = KEWServiceLocator.getRouteHeaderService().getRouteHeader(workflowDocument.getRouteHeaderId());
684         assertEquals("Wrong number of searchable attributes", 2, doc.getSearchableAttributeValues().size());
685 
686         // check for jack and jill
687         boolean foundJack = false;
688         boolean foundJill = false;
689         for (Iterator iter = doc.getSearchableAttributeValues().iterator(); iter.hasNext();) {
690             SearchableAttributeValue searchableValue = (SearchableAttributeValue) iter.next();
691             if (searchableValue.getSearchableAttributeDisplayValue().equals("jack")) {
692                 foundJack = true;
693             } else if (searchableValue.getSearchableAttributeDisplayValue().equals("jill")) {
694                 foundJill = true;
695             }
696         }
697 
698         assertTrue("Didn't find searchable attribute value 'jack'", foundJack);
699         assertTrue("Didn't find searchable attribute value 'jill'", foundJill);
700     }
701     */
702 
703     /*
704     @Test public void testNoSearchableContentAction() throws Exception {
705     	RouteHeaderService routeHeaderService = KEWServiceLocator.getRouteHeaderService();
706     	WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), "SearchDocType");
707     	workflowDocument.saveDocument("");
708 
709     	//verify that a searchable attribute exists even though
710     	DocumentRouteHeaderValue document = routeHeaderService.getRouteHeader(workflowDocument.getRouteHeaderId());
711     	assertEquals("Should have a searchable attribute key", 1, document.getSearchableAttributeValues().size());
712     	assertEquals("Searchable attribute key should be givenname", "givenname", ((SearchableAttributeValue)document.getSearchableAttributeValues().get(0)).getSearchableAttributeKey());
713 
714 
715     	WorkflowDocument workflowDocument2 = new WorkflowDocument(new NetworkIdDTO("rkirkend"), "SearchDocType2");
716     	workflowDocument2.saveDocument("");
717 
718     	DocumentRouteHeaderValue document2 = routeHeaderService.getRouteHeader(workflowDocument2.getRouteHeaderId());
719     	assertEquals("Should have a searchable attribute key", 1, document2.getSearchableAttributeValues().size());
720     	assertEquals("Searchable attribute key should be givenname", "givenname", ((SearchableAttributeValue)document2.getSearchableAttributeValues().get(0)).getSearchableAttributeKey());
721     }
722     */
723 
724 //    protected String getAltAppContextFile() {
725 //    	if (this.getName().equals("testIndexingRequeue")) {
726 //    		return "org/kuali/rice/kew/docsearch/xml/SearchableAttributeProcessorSpring.xml";
727 //    	} else {
728 //    		return null;
729 //    	}
730 //
731 //    }
732 
733     //this is testing that the code being called in the event of an OptimisticLockException happening in the
734     //SearchableAttributeProcessor is working.  An actual OptimisticLockException is not being created because it's
735     //too much of a pain in this single threaded testing env.
736 //    public void testIndexingRequeue() throws Exception {
737 //    	Long routeHeaderId = new Long(1);
738 //
739 //        PersistedMessage searchIndexingWork = new PersistedMessage();
740 //        searchIndexingWork.setProcessorClassName(SearchableAttributeProcessor.class.getName());
741 //        searchIndexingWork.setRouteHeaderId(routeHeaderId);
742 //        searchIndexingWork.setQueuePriority(new Integer(6));
743 //        searchIndexingWork.setQueueStatus("Q");
744 //        searchIndexingWork.setQueueDate(new Timestamp(System.currentTimeMillis()));
745 //        SpringServiceLocator.getRouteQueueService().save(searchIndexingWork);
746 //
747 //        new SearchableAttributeProcessor().requeueIndexing(searchIndexingWork);
748 //
749 //        Collection queueEntries = SpringServiceLocator.getRouteQueueService().findAll();
750 //        assertEquals("should have 2 queue entries", 2, queueEntries.size());
751 //        for (Iterator iter = queueEntries.iterator(); iter.hasNext();) {
752 //			PersistedMessage queueEntry = (PersistedMessage) iter.next();
753 //			//all entries should have certain similarities
754 //			assertEquals("Wrong routeHeaderid", searchIndexingWork.getRouteHeaderId(), queueEntry.getRouteHeaderId());
755 //			assertEquals("Wrong queue status", searchIndexingWork.getQueueStatus(), queueEntry.getQueueStatus());
756 //			assertEquals("Wrong queue priority", searchIndexingWork.getQueuePriority(), queueEntry.getQueuePriority());
757 //		}
758 //    }
759 
760     /*
761     @Test public void testClearingSearchContentWithSearchableAttribute() throws Exception {
762     	RouteHeaderService routeHeaderService = KEWServiceLocator.getRouteHeaderService();
763 
764     	WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), "SearchDocType");
765         WorkflowAttributeDefinitionDTO givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
766 
767         givennameXMLDef.addProperty("givenname", "jack");
768         workflowDocument.addSearchableDefinition(givennameXMLDef);
769 
770         workflowDocument.setTitle("Routing Rowdy Piper");
771         workflowDocument.routeDocument("routing this document.");
772 
773         // look up document and verify the search valu is there
774         DocumentRouteHeaderValue doc = routeHeaderService.getRouteHeader(workflowDocument.getRouteHeaderId());
775         assertEquals("Wrong number of searchable attributes", 1, doc.getSearchableAttributeValues().size());
776 
777         workflowDocument = new WorkflowDocument(new NetworkIdDTO("jhopf"), workflowDocument.getRouteHeaderId());
778         workflowDocument.clearSearchableContent();
779 
780         givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
781         givennameXMLDef.addProperty("givenname", "dukeboys");
782         workflowDocument.addSearchableDefinition(givennameXMLDef);
783 
784         givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
785         givennameXMLDef.addProperty("givenname", "luke duke");
786         workflowDocument.addSearchableDefinition(givennameXMLDef);
787 
788         givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLSearchableAttribute");
789         givennameXMLDef.addProperty("givenname", "bo duke");
790         workflowDocument.addSearchableDefinition(givennameXMLDef);
791 
792         workflowDocument.approve("");
793 
794         doc = routeHeaderService.getRouteHeader(workflowDocument.getRouteHeaderId());
795         assertEquals("Wrong number of searchable attributes", 3, doc.getSearchableAttributeValues().size());
796 
797         // check for jack and jill
798         boolean foundLuke = false;
799         boolean foundBo = false;
800         boolean foundDukeBoys = false;
801         for (Iterator iter = doc.getSearchableAttributeValues().iterator(); iter.hasNext();) {
802             SearchableAttributeValue searchableValue = (SearchableAttributeValue) iter.next();
803             if (searchableValue.getSearchableAttributeDisplayValue().equals("dukeboys")) {
804                 foundDukeBoys = true;
805             } else if (searchableValue.getSearchableAttributeDisplayValue().equals("luke duke")) {
806                 foundLuke = true;
807             } else if (searchableValue.getSearchableAttributeDisplayValue().equals("bo duke")) {
808                 foundBo = true;
809             }
810         }
811 
812         assertTrue("Didn't find searchable attribute value 'luke duke'", foundLuke);
813         assertTrue("Didn't find searchable attribute value 'bo duke'", foundBo);
814         assertTrue("Didn't find searchable attribute value 'dukeboys'", foundDukeBoys);
815     }
816     */
817 
818     /*
819      * Test method for 'org.kuali.rice.kew.docsearch.xml.StandardGenericXMLSearchableAttribute.getSearchContent()'
820      */
821     @Test public void testGetSearchContent() throws Exception {
822         StandardGenericXMLSearchableAttribute attribute = getAttribute("XMLSearchableAttribute");
823         String keyName = "givenname";
824         String value = "jack";
825         Map paramMap = new HashMap();
826         paramMap.put(keyName, value);
827         attribute.setParamMap(paramMap);
828         //Filling in a random document type name... Revisit
829         String documentTypeName = "SearchDocType";
830         DocumentSearchContext context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, "");
831         String searchContent = attribute.getSearchContent(context);
832         assertTrue("searchContent was not found.", searchContent != null && searchContent.length() > 0);
833         XPath xpath = XPathFactory.newInstance().newXPath();
834         Element foundDocContent = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(searchContent)))).getDocumentElement();
835         String findStuff = "//putWhateverWordsIwantInsideThisTag/" + keyName + "/value";
836         assertTrue("Search content does not contain correct value for field '" + keyName + "'.", value.equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
837 
838         attribute = getAttribute("XMLSearchableAttributeStdLong");
839         keyName = "testLongKey";
840         value = "123458";
841         paramMap = new HashMap();
842         paramMap.put(keyName, value);
843         attribute.setParamMap(paramMap);
844         searchContent = attribute.getSearchContent(context);
845         assertTrue("searchContent was not found.", searchContent != null && searchContent.length() > 0);
846         xpath = XPathFactory.newInstance().newXPath();
847         foundDocContent = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(searchContent)))).getDocumentElement();
848         findStuff = "//putWhateverWordsIwantInsideThisTag/" + keyName + "/value";
849         assertTrue("Search content does not contain correct value for field '" + keyName + "'.", value.equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
850 
851         attribute = getAttribute("XMLSearchableAttributeStdFloat");
852         keyName = "testFloatKey";
853         value = "2568.204";
854         paramMap = new HashMap();
855         paramMap.put(keyName, value);
856         attribute.setParamMap(paramMap);
857         searchContent = attribute.getSearchContent(context);
858         assertTrue("searchContent was not found.", searchContent != null && searchContent.length() > 0);
859         xpath = XPathFactory.newInstance().newXPath();
860         foundDocContent = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(searchContent)))).getDocumentElement();
861         findStuff = "//putWhateverWordsIwantInsideThisTag/" + keyName + "/value";
862         assertTrue("Search content does not contain correct value for field '" + keyName + "'.", value.equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
863 
864         attribute = getAttribute("XMLSearchableAttributeStdCurrency");
865         keyName = "testCurrencyKey";
866         value = "2248.20";
867         paramMap = new HashMap();
868         paramMap.put(keyName, value);
869         attribute.setParamMap(paramMap);
870         searchContent = attribute.getSearchContent(context);
871         assertTrue("searchContent was not found.", searchContent != null && searchContent.length() > 0);
872         xpath = XPathFactory.newInstance().newXPath();
873         foundDocContent = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(searchContent)))).getDocumentElement();
874         findStuff = "//putWhateverWordsIwantInsideThisTag/" + keyName + "/value";
875         assertTrue("Search content does not contain correct value for field '" + keyName + "'.", value.equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
876 
877         attribute = getAttribute("XMLSearchableAttributeStdDateTime");
878         keyName = "testDateTimeKey";
879         value = DocSearchUtils.getDisplayValueWithDateOnly(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_VALUE);
880         paramMap = new HashMap();
881         paramMap.put(keyName, value);
882         attribute.setParamMap(paramMap);
883         searchContent = attribute.getSearchContent(context);
884         assertTrue("searchContent was not found.", searchContent != null && searchContent.length() > 0);
885         xpath = XPathFactory.newInstance().newXPath();
886         foundDocContent = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new BufferedReader(new StringReader(searchContent)))).getDocumentElement();
887         findStuff = "//putWhateverWordsIwantInsideThisTag/" + keyName + "/value";
888         assertTrue("Search content does not contain correct value for field '" + keyName + "'.", value.equals(xpath.evaluate(findStuff, foundDocContent, XPathConstants.STRING)));
889     }
890 
891     /*
892      * Test method for 'org.kuali.rice.kew.docsearch.xml.StandardGenericXMLSearchableAttribute.getSearchStorageValues(String)'
893      */
894     @Test public void testGetSearchStorageValues() {
895     	String attributeName = "XMLSearchableAttribute";
896     	String keyName = "givenname";
897     	String value = "jack";
898     	String documentcontent = "<documentContent>" + "<searchableContent>" + "<putWhateverWordsIwantInsideThisTag>" + "<" + keyName + ">" + "<value>" + value + "</value>" + "</" + keyName + ">" + "</putWhateverWordsIwantInsideThisTag>" + "</searchableContent>" + "</documentContent>";
899         StandardGenericXMLSearchableAttribute attribute = getAttribute(attributeName);
900         //Filling in a random document type name... Revisit
901         String documentTypeName = "SearchDocType";
902         DocumentSearchContext context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, documentcontent);
903         List values = attribute.getSearchStorageValues(context);
904         assertEquals("Number of search attribute values is wrong",1,values.size());
905         for (Iterator iter = values.iterator(); iter.hasNext();) {
906             SearchableAttributeValue searchAttValue = (SearchableAttributeValue) iter.next();
907             assertEquals("Key of attribute is wrong",keyName,searchAttValue.getSearchableAttributeKey());
908             assertEquals("Value of attribute is wrong",value,searchAttValue.getSearchableAttributeDisplayValue());
909         }
910 
911         // test general operation
912         attributeName = "XMLSearchableAttributeStdLong";
913         keyName = "testLongKey";
914         value = "123458";
915         documentcontent = "<documentContent>" + "<searchableContent>" + "<putWhateverWordsIwantInsideThisTag>" + "<" + keyName + ">" + "<value>" + value + "</value>" + "</" + keyName + ">" + "</putWhateverWordsIwantInsideThisTag>" + "</searchableContent>" + "</documentContent>";
916         context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, documentcontent);
917         attribute = getAttribute(attributeName);
918         values = attribute.getSearchStorageValues(context);
919         assertEquals("Number of search attribute values is wrong",1,values.size());
920         for (Iterator iter = values.iterator(); iter.hasNext();) {
921             SearchableAttributeValue searchAttValue = (SearchableAttributeValue) iter.next();
922             assertEquals("Key of attribute is wrong",keyName,searchAttValue.getSearchableAttributeKey());
923             assertEquals("Value of attribute is wrong",value,searchAttValue.getSearchableAttributeDisplayValue());
924         }
925 
926         // test operation with leading and trailing spaces in xml doc content
927         attributeName = "XMLSearchableAttributeStdLong";
928         keyName = "testLongKey";
929         value = "123458";
930         documentcontent = "<documentContent>" + "<searchableContent>" + "<putWhateverWordsIwantInsideThisTag>" + "<" + keyName + ">" + "<value>" + " " + value + " " + "</value>" + "</" + keyName + ">" + "</putWhateverWordsIwantInsideThisTag>" + "</searchableContent>" + "</documentContent>";
931         context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, documentcontent);
932         attribute = getAttribute(attributeName);
933         values = attribute.getSearchStorageValues(context);
934         assertEquals("Number of search attribute values is wrong",1,values.size());
935         for (Iterator iter = values.iterator(); iter.hasNext();) {
936             SearchableAttributeValue searchAttValue = (SearchableAttributeValue) iter.next();
937             assertEquals("Key of attribute is wrong",keyName,searchAttValue.getSearchableAttributeKey());
938             assertEquals("Value of attribute is wrong",value,searchAttValue.getSearchableAttributeDisplayValue());
939         }
940 
941         attributeName = "XMLSearchableAttributeStdFloat";
942         keyName = "testFloatKey";
943         value = "2568.204154796";
944         documentcontent = "<documentContent>" + "<searchableContent>" + "<putWhateverWordsIwantInsideThisTag>" + "<" + keyName + ">" + "<value>" + value + "</value>" + "</" + keyName + ">" + "</putWhateverWordsIwantInsideThisTag>" + "</searchableContent>" + "</documentContent>";
945         context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, documentcontent);
946         attribute = getAttribute(attributeName);
947         values = attribute.getSearchStorageValues(context);
948         assertEquals("Number of search attribute values is wrong",1,values.size());
949         for (Iterator iter = values.iterator(); iter.hasNext();) {
950             SearchableAttributeValue searchAttValue = (SearchableAttributeValue) iter.next();
951             assertEquals("Key of attribute is wrong",keyName,searchAttValue.getSearchableAttributeKey());
952             assertEquals("Value of attribute is wrong",insertCommasIfNeeded(value, 3),searchAttValue.getSearchableAttributeDisplayValue());
953         }
954 
955     	attributeName = "XMLSearchableAttributeStdDateTime";
956         keyName = "testDateTimeKey";
957         value = DocSearchUtils.getDisplayValueWithDateOnly(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_VALUE);
958         documentcontent = "<documentContent>" + "<searchableContent>" + "<putWhateverWordsIwantInsideThisTag>" + "<" + keyName + ">" + "<value>" + value + "</value>" + "</" + keyName + ">" + "</putWhateverWordsIwantInsideThisTag>" + "</searchableContent>" + "</documentContent>";
959         context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, documentcontent);
960         attribute = getAttribute(attributeName);
961         values = attribute.getSearchStorageValues(context);
962         assertEquals("Number of search attribute values is wrong",1,values.size());
963         for (Iterator iter = values.iterator(); iter.hasNext();) {
964             SearchableAttributeValue searchAttValue = (SearchableAttributeValue) iter.next();
965             assertEquals("Key of attribute is wrong",keyName,searchAttValue.getSearchableAttributeKey());
966             assertEquals("Value of attribute is wrong",value,searchAttValue.getSearchableAttributeDisplayValue());
967         }
968 
969         // test for kuali xstream formatted dates
970         value = "02/20/2007";
971         String returnValue = "02/20/2007";
972         documentcontent = "<documentContent>" + "<searchableContent>" + "<putWhateverWordsIwantInsideThisTag>" + "<" + keyName + ">" + "<value>" + value + "</value>" + "</" + keyName + ">" + "</putWhateverWordsIwantInsideThisTag>" + "</searchableContent>" + "</documentContent>";
973         context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, documentcontent);
974         attribute = getAttribute(attributeName);
975         values = attribute.getSearchStorageValues(context);
976         assertEquals("Number of search attribute values is wrong",1,values.size());
977         for (Iterator iter = values.iterator(); iter.hasNext();) {
978             SearchableAttributeValue searchAttValue = (SearchableAttributeValue) iter.next();
979             assertEquals("Key of attribute is wrong",keyName,searchAttValue.getSearchableAttributeKey());
980             assertEquals("Value of attribute is wrong",returnValue,searchAttValue.getSearchableAttributeDisplayValue());
981         }
982     }
983 
984     private String insertCommasIfNeeded(String value, int interval) {
985         int indexOfDecimal = value.indexOf(".");
986         String decimalPointOn = value.substring(indexOfDecimal);
987         String temp = value.substring(0, indexOfDecimal);
988         StringBuffer builtValue = new StringBuffer();
989         if (temp.length() <= interval) {
990             builtValue.append(temp);
991         } else {
992             int counter = 0;
993             for (int i = temp.length() - 1; (i >= 0); i--) {
994                 if (counter == interval) {
995                     builtValue.insert(0, ",");
996                     counter = 0;
997                 }
998                 counter++;
999                 builtValue.insert(0, temp.substring(i, i+1));
1000             }
1001         }
1002         return (builtValue.append(decimalPointOn)).toString();
1003     }
1004 
1005     /*
1006      * Test method for 'org.kuali.rice.kew.docsearch.xml.StandardGenericXMLSearchableAttribute.getSearchingRows()'
1007      */
1008     @Test public void testGetSearchingRows() {
1009         StandardGenericXMLSearchableAttribute searchAttribute = getAttribute(null);
1010         //Filling in a random document type name... Revisit
1011         String documentTypeName = "SearchDocType";
1012         DocumentSearchContext context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, "");
1013         assertTrue("Invalid number of search rows", searchAttribute.getSearchingRows(context).size() == 1);
1014 
1015         //we really just want this to load without exploding
1016         List searchRows = getAttribute("BlankDropDownSearchAttribute").getSearchingRows(context);
1017         assertEquals("Invalid number of search rows", 1, searchRows.size());
1018         Row row = (Row) searchRows.get(0);
1019         Field field = row.getField(0);
1020         assertEquals("Should be 5 valid values", 5, field.getFieldValidValues().size());
1021 
1022         assertEquals("Default value is not correct", "AMST", field.getPropertyValue());
1023     }
1024 
1025     /*
1026      * Test method for 'org.kuali.rice.kew.docsearch.xml.StandardGenericXMLSearchableAttribute.validateUserSearchInputs(Map)'
1027      */
1028     @Test  public void testValidateUserSearchInputs() {
1029         StandardGenericXMLSearchableAttribute searchAttribute = getAttribute("XMLSearchableAttribute");
1030         Map paramMap = new HashMap();
1031         paramMap.put(TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY, "jack");
1032         String documentTypeName = "SearchDocType";
1033         //TODO: put document content here?
1034         DocumentSearchContext context = DocSearchUtils.getDocumentSearchContext("", documentTypeName, "");
1035         List validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1036         assertEquals("Validation should not have returned an error.", 0, validationErrors.size());
1037         paramMap.clear();
1038         paramMap.put(TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY, "jack.jack");
1039         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1040         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1041         WorkflowAttributeValidationError error = (WorkflowAttributeValidationError) validationErrors.get(0);
1042         assertEquals("Validation error should match xml attribute message", "Invalid first name", error.getMessage());
1043         paramMap.clear();
1044         paramMap.put(TestXMLSearchableAttributeString.SEARCH_STORAGE_KEY, "jack*jack");
1045         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1046         assertEquals("Validation should return a single error message.", 0, validationErrors.size());
1047 
1048         searchAttribute = getAttribute("XMLSearchableAttributeStdLong");
1049         paramMap = new HashMap();
1050         paramMap.put(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE.toString());
1051         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1052         assertEquals("Validation should not have returned an error.", 0, validationErrors.size());
1053         paramMap.clear();
1054         paramMap.put(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeLong.SEARCH_STORAGE_VALUE.toString() + ".33");
1055         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1056         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1057         error = (WorkflowAttributeValidationError) validationErrors.get(0);
1058         assertTrue("Validation error is incorrect", error.getMessage().endsWith("does not conform to standard validation for field type."));
1059         paramMap.clear();
1060         paramMap.put(TestXMLSearchableAttributeLong.SEARCH_STORAGE_KEY, "jack*jack");
1061         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1062         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1063         error = (WorkflowAttributeValidationError) validationErrors.get(0);
1064         assertTrue("Validation error is incorrect", error.getMessage().endsWith("does not conform to standard validation for field type."));
1065 
1066         searchAttribute = getAttribute("XMLSearchableAttributeStdFloat");
1067         paramMap = new HashMap();
1068         paramMap.put(TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeFloat.SEARCH_STORAGE_VALUE.toString());
1069         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1070         assertEquals("Validation should not have returned an error.", 0, validationErrors.size());
1071         paramMap.clear();
1072         paramMap.put(TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeFloat.SEARCH_STORAGE_VALUE.toString() + "a");
1073         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1074         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1075         error = (WorkflowAttributeValidationError) validationErrors.get(0);
1076         assertTrue("Validation error is incorrect", error.getMessage().endsWith("does not conform to standard validation for field type."));
1077         paramMap.clear();
1078         paramMap.put(TestXMLSearchableAttributeFloat.SEARCH_STORAGE_KEY, TestXMLSearchableAttributeFloat.SEARCH_STORAGE_VALUE.toString() + "*");
1079         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1080         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1081         error = (WorkflowAttributeValidationError) validationErrors.get(0);
1082         assertTrue("Validation error is incorrect", error.getMessage().endsWith("does not conform to standard validation for field type."));
1083 
1084         searchAttribute = getAttribute("XMLSearchableAttributeStdCurrency");
1085         String key = "testCurrencyKey";
1086         Float value = Float.valueOf("5486.25");
1087         paramMap = new HashMap();
1088         paramMap.put(key, value.toString());
1089         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1090         assertEquals("Validation should not have returned an error.", 0, validationErrors.size());
1091         paramMap.clear();
1092         paramMap.put(key, value.toString() + "a");
1093         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1094         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1095         error = (WorkflowAttributeValidationError) validationErrors.get(0);
1096         assertTrue("Validation error is incorrect", error.getMessage().endsWith("does not conform to standard validation for field type."));
1097         paramMap.clear();
1098         paramMap.put(key, value.toString() + "*");
1099         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1100         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1101         error = (WorkflowAttributeValidationError) validationErrors.get(0);
1102         assertTrue("Validation error is incorrect", error.getMessage().endsWith("does not conform to standard validation for field type."));
1103 
1104         searchAttribute = getAttribute("XMLSearchableAttributeStdDateTime");
1105         paramMap = new HashMap();
1106         paramMap.put(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, DocSearchUtils.getDisplayValueWithDateOnly(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_VALUE));
1107         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1108         assertEquals("Validation should not have returned an error.", 0, validationErrors.size());
1109         paramMap.clear();
1110         paramMap.put(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, "001/5/08");
1111         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1112         assertEquals("Validation should not have returned an error.", 0, validationErrors.size());
1113         paramMap.clear();
1114         paramMap.put(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, "41/5/08");
1115         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1116         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1117         error = (WorkflowAttributeValidationError) validationErrors.get(0);
1118         assertTrue("Validation error is incorrect", error.getMessage().endsWith("does not conform to standard validation for field type."));
1119         paramMap.clear();
1120         paramMap.put(TestXMLSearchableAttributeDateTime.SEARCH_STORAGE_KEY, "01/02/20*");
1121         validationErrors = searchAttribute.validateUserSearchInputs(paramMap, context);
1122         assertEquals("Validation should return a single error message.", 1, validationErrors.size());
1123         error = (WorkflowAttributeValidationError) validationErrors.get(0);
1124         assertTrue("Validation error is incorrect", error.getMessage().endsWith("does not conform to standard validation for field type."));
1125     }
1126 
1127     /**
1128      * Tests the XStreamSafeEvaluator against searchable attributes to resolve EN-63 and KULWF-723.
1129      *
1130      * This test is pretty much just a copy of testRouteDocumentWithSearchableAttribute using a
1131      * different document type which defines the same xpath expression, only with embedded
1132      * XStream "reference" attributes in the XML.
1133      */
1134     @Test public void testRouteDocumentWithXStreamSearchableAttribute() throws Exception {
1135     	String documentTypeName = "SearchDocType";
1136     	String key = "givenname";
1137     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
1138 
1139         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), "SearchDocTypeXStream");
1140         WorkflowAttributeDefinitionDTO givennameXMLDef = new WorkflowAttributeDefinitionDTO("XMLXStreamSearchableAttribute");
1141 
1142         workflowDocument.setApplicationContent("<test></test>");
1143 
1144         givennameXMLDef.addProperty("givenname", "jack");
1145         workflowDocument.addSearchableDefinition(givennameXMLDef);
1146 
1147         workflowDocument.setTitle("Routing style");
1148         workflowDocument.routeDocument("routing this document.");
1149 
1150         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
1151 
1152         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName("rkirkend");
1153         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
1154         criteria.setDocTypeFullName(documentTypeName);
1155         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jack", docType));
1156         DocumentSearchResultComponents result = docSearchService.getList(user.getPrincipalId(), criteria);
1157         List searchResults = result.getSearchResults();
1158 
1159         assertEquals("Search results should be empty.", 0, searchResults.size());
1160 
1161         criteria = new DocSearchCriteriaDTO();
1162         criteria.setDocTypeFullName(documentTypeName);
1163         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "fred", docType));
1164         result = docSearchService.getList(user.getPrincipalId(), criteria);
1165         searchResults = result.getSearchResults();
1166 
1167         assertEquals("Search results should be empty.", 0, searchResults.size());
1168 
1169         criteria = new DocSearchCriteriaDTO();
1170         criteria.setDocTypeFullName(documentTypeName);
1171         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent("fakeproperty", "doesntexist", docType));
1172         try {
1173             result = docSearchService.getList(user.getPrincipalId(), criteria);
1174             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
1175         } catch (WorkflowServiceErrorException wsee) {}
1176     }
1177 
1178 
1179     /**
1180      * Tests the resolution to issues EN-95, KULWF-757, KULOWF-52 whereby the use of a quickfinder is causing
1181      * NullPointers when searching for documents.
1182      */
1183     @Test public void testSearchableAttributeWithQuickfinder() throws Exception {
1184     	String documentTypeName = "AttributeWithQuickfinderDocType";
1185     	String key = "chart";
1186     	DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
1187     	 WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("rkirkend"), documentTypeName);
1188 
1189     	 // define the chart for the searchable attribute
1190     	 WorkflowAttributeDefinitionDTO chartDef = new WorkflowAttributeDefinitionDTO("SearchableAttributeWithQuickfinder");
1191          chartDef.addProperty(key, "BL");
1192          document.addSearchableDefinition(chartDef);
1193 
1194          // save the document
1195          document.setTitle("Routin' with style");
1196          document.saveDocument("Savin' this document.");
1197 
1198          // prepare to search
1199          DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
1200          Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName("rkirkend");
1201 
1202          // execute the search by our chart, we should see one result
1203          DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
1204          criteria.setDocTypeFullName(documentTypeName);
1205          criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "BL", docType));
1206          DocumentSearchResultComponents results = docSearchService.getList(user.getPrincipalId(), criteria);
1207          List searchResults = results.getSearchResults();
1208          assertEquals("Search results should have one document.", 1, searchResults.size());
1209          DocumentSearchResult result = (DocumentSearchResult)searchResults.get(0);
1210          KeyValueSort kvs = result.getResultContainer(DocumentSearchResult.PROPERTY_NAME_ROUTE_HEADER_ID);
1211          assertEquals("Wrong document in search results.", document.getRouteHeaderId(), kvs.getSortValue());
1212 
1213          // search with no searchable attribute criteria, should return our document as well
1214          criteria = new DocSearchCriteriaDTO();
1215          criteria.setDocTypeFullName(documentTypeName);
1216          results = docSearchService.getList(user.getPrincipalId(), criteria);
1217          searchResults = results.getSearchResults();
1218          assertEquals("Search results should have one document.", 1, searchResults.size());
1219          result = (DocumentSearchResult)searchResults.get(0);
1220          kvs = result.getResultContainer(DocumentSearchResult.PROPERTY_NAME_ROUTE_HEADER_ID);
1221          assertEquals("Wrong document in search results.", document.getRouteHeaderId(), kvs.getSortValue());
1222 
1223     }
1224 
1225     /**
1226      * Tests that the hidding of fields and columns works properly to resolve EN-53.
1227      *
1228      * TODO this is currently commented out because we can't test this properly through the unit
1229      * test since the filtering of the column actually happens in the web-tier.  Shoudl this be
1230      * the case?  Maybe we need to re-examine when we refactor document search.
1231      */
1232     @Test public void testSearchableAttributeWithHiddens() throws Exception {
1233     	// for the following document, the chart field should not show up in the result set and the org field
1234     	// should not show up in the criteriaw
1235     	String docType = "AttributeWithHiddensDocType";
1236     	DocumentType documentType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(docType);
1237 
1238     	String attributeName = "SearchableAttributeWithHiddens";
1239     	WorkflowDocument document = new WorkflowDocument(new NetworkIdDTO("rkirkend"), docType);
1240 
1241    	 	// define the chart for the searchable attribute
1242    	 	WorkflowAttributeDefinitionDTO chartDef = new WorkflowAttributeDefinitionDTO(attributeName);
1243         chartDef.addProperty("chart", "BL");
1244         chartDef.addProperty("org", "ARSC");
1245         chartDef.addProperty("dollar", "24");
1246         document.addSearchableDefinition(chartDef);
1247 
1248         // save the document
1249         document.setTitle("Routin' with style");
1250         document.saveDocument("Savin' this document.");
1251 
1252         // prepare to search
1253         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
1254         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName("rkirkend");
1255 
1256         // execute the search by our chart, we should see one result
1257         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
1258         criteria.setDocTypeFullName(docType);
1259         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent("chart", "BL", documentType));
1260         DocumentSearchResultComponents results = docSearchService.getList(user.getPrincipalId(), criteria);
1261         List searchResults = results.getSearchResults();
1262         assertEquals("Search results should have one document.", 1, searchResults.size());
1263         DocumentSearchResult result = (DocumentSearchResult)searchResults.get(0);
1264         KeyValueSort kvs = result.getResultContainer(DocumentSearchResult.PROPERTY_NAME_ROUTE_HEADER_ID);
1265         assertEquals("Wrong document in search results.", document.getRouteHeaderId(), kvs.getSortValue());
1266         // also check that the chart field is not in the result set and the org field is
1267         kvs = null;
1268         kvs = result.getResultContainer("chart");
1269         assertNull("The chart column should not be in the result set!",kvs.getValue());
1270         kvs = null;
1271         kvs = result.getResultContainer("org");
1272         assertNotNull("The org column should be in the result set", kvs);
1273         assertEquals("Wrong org code.", "ARSC", kvs.getValue());
1274         kvs = null;
1275         kvs = result.getResultContainer("dollar");
1276         assertNotNull("The dollar column should be in the result set", kvs);
1277         assertEquals("Wrong dollar code.", "24", kvs.getValue());
1278     }
1279 
1280     @Test public void testSetApplicationContentXMLRoutedDocument() throws Exception {
1281         String documentTypeName = "SearchDocType";
1282         String key = "givenname";
1283         DocumentType docType = ((DocumentTypeService)KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_TYPE_SERVICE)).findByName(documentTypeName);
1284         WorkflowDocument workflowDocument = new WorkflowDocument(new NetworkIdDTO("rkirkend"), documentTypeName);
1285         workflowDocument.setApplicationContent("<documentContent><searchableContent><putWhateverWordsIwantInsideThisTag>" +
1286                                                "<givenname><value>jack</value></givenname>" +
1287                                                "</putWhateverWordsIwantInsideThisTag></searchableContent></documentContent>");
1288 
1289         workflowDocument.setTitle("Routing style");
1290         workflowDocument.routeDocument("routing this document.");
1291 
1292         DocumentSearchService docSearchService = (DocumentSearchService) KEWServiceLocator.getService(KEWServiceLocator.DOCUMENT_SEARCH_SERVICE);
1293 
1294         Person user = KIMServiceLocator.getPersonService().getPersonByPrincipalName("rkirkend");
1295         DocSearchCriteriaDTO criteria = new DocSearchCriteriaDTO();
1296         criteria.setDocTypeFullName(documentTypeName);
1297         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "jack", docType));
1298         DocumentSearchResultComponents result = docSearchService.getList(user.getPrincipalId(), criteria);
1299         List searchResults = result.getSearchResults();
1300 
1301         assertEquals("Search results should be empty.", 1, searchResults.size());
1302 
1303         criteria = new DocSearchCriteriaDTO();
1304         criteria.setDocTypeFullName(documentTypeName);
1305         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent(key, "fred", docType));
1306         result = docSearchService.getList(user.getPrincipalId(), criteria);
1307         searchResults = result.getSearchResults();
1308 
1309         assertEquals("Search results should be empty.", 0, searchResults.size());
1310 
1311         criteria = new DocSearchCriteriaDTO();
1312         criteria.setDocTypeFullName(documentTypeName);
1313         criteria.addSearchableAttribute(createSearchAttributeCriteriaComponent("fakeproperty", "doesntexist", docType));
1314         try {
1315             result = docSearchService.getList(user.getPrincipalId(), criteria);
1316             fail("Search results should be throwing a validation exception for use of non-existant searchable attribute");
1317         } catch (WorkflowServiceErrorException wsee) {}
1318     }
1319 
1320     /**
1321      * Tests that Field objects use correct KeyLabelPair instances when checks for blank valid values are performed
1322      * (such as when JSP renders drop-downs), to verify that KULRICE-3587 has been fixed.
1323      * 
1324      * @throws Exception
1325      */
1326     @Test public void testBlankValidValuesOnKeyLabelPairs() throws Exception {
1327     	boolean[] shouldHaveBlank = {true, false};
1328     	String[] attributesToTest = {"XMLSearchableAttributeWithBlank", "XMLSearchableAttributeWithoutBlank"};
1329         DocumentSearchContext docSearchContext = DocSearchUtils.getDocumentSearchContext("", "BlankValidValuesDocType", "");
1330         // Verify that the getHasBlankValidValue() method on each field returns the correct result and does not cause unexpected exceptions.
1331         for (int i = 0; i < shouldHaveBlank.length; i++) {
1332         	List<Row> rowList = getAttribute(attributesToTest[i]).getSearchingRows(docSearchContext);
1333             assertEquals("The searching rows list for " + attributesToTest[i] + " should have exactly one element", 1, rowList.size());
1334         	assertEquals("Searching row for " + attributesToTest[i] + " should have exactly one field", 1, rowList.get(0).getFields().size());
1335         	Field testField = rowList.get(0).getFields().get(0);
1336         	try {
1337         		assertEquals("The field for " + attributesToTest[i] + " does not have the expected getHasBlankValidValue() result",
1338         				shouldHaveBlank[i], testField.getHasBlankValidValue());
1339         	} catch (Exception ex) {
1340         		fail("An exception occurred while running getHasBlankValidValue() on " + attributesToTest[i] + ": " + ex.getMessage());
1341         	}
1342         }
1343         
1344         
1345     }
1346 }