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