View Javadoc

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