]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
5afc85d2ec9c463031e72979cffb1c85141bb699
[tmp/jakarta-migration.git] /
1 /**
2  * This document is a part of the source code and related artifacts
3  * for CollectionSpace, an open source collections management system
4  * for museums and related institutions:
5  *
6  * http://www.collectionspace.org
7  * http://wiki.collectionspace.org
8  *
9  * Copyright © 2009 Regents of the University of California
10  *
11  * Licensed under the Educational Community License (ECL), Version 2.0.
12  * You may not use this file except in compliance with this License.
13  *
14  * You may obtain a copy of the ECL 2.0 License at
15  * https://source.collectionspace.org/collection-space/LICENSE.txt
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23 package org.collectionspace.services.client.test;
24
25 import java.util.Arrays;
26 import java.util.ArrayList;
27 import java.util.List;
28 import javax.ws.rs.core.MediaType;
29 import javax.ws.rs.core.Response;
30
31 import org.collectionspace.services.CollectionObjectJAXBSchema;
32 import org.collectionspace.services.client.CollectionObjectClient;
33 import org.collectionspace.services.client.CollectionSpaceClient;
34 import org.collectionspace.services.client.PayloadOutputPart;
35 import org.collectionspace.services.client.PoxPayloadOut;
36 import org.collectionspace.services.collectionobject.CollectionobjectsCommon;
37 import org.collectionspace.services.common.AbstractCommonListUtils;
38 import org.collectionspace.services.jaxb.AbstractCommonList;
39
40 import org.jboss.resteasy.client.ClientResponse;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.testng.Assert;
44 import org.testng.annotations.AfterClass;
45 import org.testng.annotations.BeforeClass;
46 import org.testng.annotations.Test;
47
48 /**
49  * CollectionObjectSearchTest, carries out tests of keyword search functionality
50  * against a deployed and running CollectionObject Service.
51  * 
52  * $LastChangedRevision: 1327 $ $LastChangedDate: 2010-02-12 10:35:11 -0800
53  * (Fri, 12 Feb 2010) $
54  */
55 public class CollectionObjectSearchTest extends BaseServiceTest {
56
57         /** The logger. */
58         private final String CLASS_NAME = CollectionObjectSearchTest.class
59                         .getName();
60         private final Logger logger = LoggerFactory.getLogger(CLASS_NAME);
61         final static String IDENTIFIER = getSystemTimeIdentifier();
62         final static String KEYWORD_SEPARATOR = " ";
63         final long numNoiseWordResources = 10;
64         final double pctNonNoiseWordResources = 0.5;
65         // Use this to keep track of resources to delete
66         private List<String> allResourceIdsCreated = new ArrayList<String>();
67
68         // Constants for data used in search testing
69
70         // Test keywords unlikely to be encountered in actual collections data,
71         // consisting of the names of mythical creatures in a 1970s role-playing
72         // game, which result in very few 'hits' in Google searches.
73         final static String KEYWORD = "Tsolyani" + IDENTIFIER;
74         final static List<String> TWO_KEYWORDS = Arrays.asList(new String[] {
75                         "Cheggarra" + IDENTIFIER, "Ahoggya" + IDENTIFIER });
76         final static List<String> TWO_MORE_KEYWORDS = Arrays.asList(new String[] {
77                         "Karihaya" + IDENTIFIER, "Hlikku" + IDENTIFIER });
78         final static String NOISE_WORD = "Mihalli + IDENTIFIER";
79         // Test Unicode UTF-8 term for keyword searching: a random sequence,
80         // unlikely to be encountered in actual collections data, of two USASCII
81         // characters followed by four non-USASCII range Unicode UTF-8 characters:
82         //
83         // Δ : Greek capital letter Delta (U+0394)
84         // Ж : Cyrillic capital letter Zhe with breve (U+04C1)
85         // Ŵ : Latin capital letter W with circumflex (U+0174)
86         // Ω : Greek capital letter Omega (U+03A9)
87         final String UTF8_KEYWORD = "to" + '\u0394' + '\u04C1' + '\u0174'
88                         + '\u03A9';
89         // Non-existent term unlikely to be encountered in actual collections
90         // data, consisting of two back-to-back sets of the first letters of
91         // each of the words in a short pangram for the English alphabet.
92         final static String NON_EXISTENT_KEYWORD = "jlmbsoqjlmbsoq";
93
94         @Override
95         protected String getServiceName() {
96                 throw new UnsupportedOperationException(); // FIXME: REM - See
97                                                                                                         // http://issues.collectionspace.org/browse/CSPACE-3498
98         }
99
100         @Override
101         protected String getServicePathComponent() {
102                 // TODO Auto-generated method stub
103                 throw new UnsupportedOperationException(); // FIXME: REM - See
104                                                                                                         // http://issues.collectionspace.org/browse/CSPACE-3498
105         }
106
107         // /* (non-Javadoc)
108         // * @see
109         // org.collectionspace.services.client.test.BaseServiceTest#getServicePathComponent()
110         // */
111         // @Override
112         // protected String getServicePathComponent() {
113         // return new CollectionObjectClient().getServicePathComponent(); //FIXME:
114         // REM = Remove all refs to this method.
115         // }
116
117         /*
118          * (non-Javadoc)
119          * 
120          * @see
121          * org.collectionspace.services.client.test.BaseServiceTest#getClientInstance
122          * ()
123          */
124         @Override
125         protected CollectionSpaceClient getClientInstance() {
126                 return new CollectionObjectClient();
127         }
128
129         /*
130          * (non-Javadoc)
131          * 
132          * @see org.collectionspace.services.client.test.BaseServiceTest#
133          * getAbstractCommonList(org.jboss.resteasy.client.ClientResponse)
134          */
135         @Override
136         protected AbstractCommonList getAbstractCommonList(
137                         ClientResponse<AbstractCommonList> response) {
138                 return response.getEntity(AbstractCommonList.class);
139         }
140
141         /**
142          * Creates one or more resources containing a "noise" keyword, which should
143          * NOT be retrieved by keyword searches.
144          * 
145          * This also helps ensure that searches will not fail, due to a
146          * database-specific constraint or otherwise, if the number of records
147          * containing a particular keyword represent too high a proportion of the
148          * total number of records.
149          */
150         @BeforeClass(alwaysRun = true)
151         public void setup() {
152                 if (logger.isDebugEnabled()) {
153                         logger.debug("Creating " + numNoiseWordResources
154                                         + " 'noise word' resources ...");
155                 }
156                 createCollectionObjects(numNoiseWordResources, NOISE_WORD);
157         }
158
159         // ---------------------------------------------------------------
160         // Search tests
161         // ---------------------------------------------------------------
162         // Success outcomes
163
164         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, groups = { "advancedSearch" })
165         public void advancedSearch(String testName) throws Exception {
166
167                 if (logger.isDebugEnabled()) {
168                         logger.debug(testBanner(testName, CLASS_NAME));
169                 }
170
171                 // Create one or more keyword retrievable resources, each containing
172                 // a specified keyword.
173                 String theKeyword = KEYWORD + "COW";
174                 long numKeywordRetrievableResources = 1;
175                 createCollectionObjects(numKeywordRetrievableResources, theKeyword);
176
177                 // Set the expected status code and group of valid status codes
178                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
179
180                 // Send the search request and receive a response
181                 String propertyName = CollectionObjectClient.SERVICE_COMMON_PART_NAME + ":" +
182                         CollectionObjectJAXBSchema.DISTINGUISHING_FEATURES;
183                 String propertyValue = theKeyword;
184                 ClientResponse<AbstractCommonList> res = doAdvancedSearch(propertyName, propertyValue, "=");
185                 int statusCode = res.getStatus();
186
187                 // Check the status code of the response: does it match
188                 // the expected response(s)?
189                 if (logger.isDebugEnabled()) {
190                         logger.debug(testName + ": status = " + statusCode);
191                 }
192                 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
193                                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
194                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
195
196                 // Verify that the number of resources matched by the search
197                 // is identical to the expected result
198                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
199                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
200                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
201         }
202
203         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, groups = { "oneKeyword" })
204         public void searchWithOneKeyword(String testName) throws Exception {
205
206                 if (logger.isDebugEnabled()) {
207                         logger.debug(testBanner(testName, CLASS_NAME));
208                 }
209
210                 // Create one or more keyword retrievable resources, each containing
211                 // a specified keyword.
212                 long numKeywordRetrievableResources = (long) (numNoiseWordResources * pctNonNoiseWordResources);
213                 if (logger.isDebugEnabled()) {
214                         logger.debug("Creating " + numKeywordRetrievableResources
215                                         + " keyword-retrievable resources ...");
216                 }
217                 createCollectionObjects(numKeywordRetrievableResources, KEYWORD);
218
219                 // Set the expected status code and group of valid status codes
220                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
221
222                 // Send the search request and receive a response
223                 ClientResponse<AbstractCommonList> res = doSearch(KEYWORD);
224                 int statusCode = res.getStatus();
225
226                 // Check the status code of the response: does it match
227                 // the expected response(s)?
228                 if (logger.isDebugEnabled()) {
229                         logger.debug(testName + ": status = " + statusCode);
230                 }
231                 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
232                                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
233                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
234
235                 // Verify that the number of resources matched by the search
236                 // is identical to the expected result
237                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
238                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
239                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
240         }
241
242         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
243         public void searchWithTwoKeywordsInSameField(String testName)
244                         throws Exception {
245
246                 if (logger.isDebugEnabled()) {
247                         logger.debug(testBanner(testName, CLASS_NAME));
248                 }
249
250                 // Create one or more keyword retrievable resources, each containing
251                 // two specified keywords.
252                 long numKeywordRetrievableResources = (long) (numNoiseWordResources * pctNonNoiseWordResources);
253                 if (logger.isDebugEnabled()) {
254                         logger.debug("Creating " + numKeywordRetrievableResources
255                                         + " keyword-retrievable resources ...");
256                 }
257                 boolean keywordsInSameField = true;
258                 createCollectionObjects(numKeywordRetrievableResources, TWO_KEYWORDS,
259                                 keywordsInSameField);
260
261                 // Set the expected status code and group of valid status codes
262                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
263
264                 // Search using both terms
265
266                 // Send the search request and receive a response
267                 ClientResponse<AbstractCommonList> res = doSearch(TWO_KEYWORDS);
268                 int statusCode = res.getStatus();
269
270                 // Check the status code of the response: does it match
271                 // the expected response(s)?
272                 if (logger.isDebugEnabled()) {
273                         logger.debug(testName + ": status = " + statusCode);
274                 }
275                 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
276                                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
277                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
278
279                 // Verify that the number of resources matched by the search
280                 // is identical to the expected result
281                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
282                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
283                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
284
285                 // Search using a single term
286
287                 // Send the search request and receive a response
288                 res = doSearch(TWO_KEYWORDS.get(0));
289                 statusCode = res.getStatus();
290
291                 // Check the status code of the response: does it match
292                 // the expected response(s)?
293                 if (logger.isDebugEnabled()) {
294                         logger.debug(testName + ": status = " + statusCode);
295                 }
296                 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
297                                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
298                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
299
300                 // Verify that the number of resources matched by the search
301                 // is identical to the expected result
302                 NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
303                 numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
304                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
305
306         }
307
308         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
309         public void searchWithTwoKeywordsAcrossTwoFields(String testName)
310                         throws Exception {
311
312                 if (logger.isDebugEnabled()) {
313                         logger.debug(testBanner(testName, CLASS_NAME));
314                 }
315
316                 // Create one or more keyword retrievable resources, each containing
317                 // two specified keywords.
318                 long numKeywordRetrievableResources = 5;
319                 if (logger.isDebugEnabled()) {
320                         logger.debug("Creating " + numKeywordRetrievableResources
321                                         + " keyword-retrievable resources ...");
322                 }
323                 boolean keywordsInSameField = false;
324                 createCollectionObjects(numKeywordRetrievableResources,
325                                 TWO_MORE_KEYWORDS, keywordsInSameField);
326
327                 // Set the expected status code and group of valid status codes
328                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
329
330                 // Search using both terms
331
332                 // Send the search request and receive a response
333                 ClientResponse<AbstractCommonList> res = doSearch(TWO_MORE_KEYWORDS);
334                 int statusCode = res.getStatus();
335
336                 // Check the status code of the response: does it match
337                 // the expected response(s)?
338                 if (logger.isDebugEnabled()) {
339                         logger.debug(testName + ": status = " + statusCode);
340                 }
341                 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
342                                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
343                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
344
345                 // Verify that the number of resources matched by the search
346                 // is identical to the expected result
347                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
348                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
349                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
350
351                 // Search using a single term
352
353                 // Send the search request and receive a response
354                 res = doSearch(TWO_MORE_KEYWORDS.get(0));
355                 statusCode = res.getStatus();
356
357                 // Check the status code of the response: does it match
358                 // the expected response(s)?
359                 if (logger.isDebugEnabled()) {
360                         logger.debug(testName + ": status = " + statusCode);
361                 }
362                 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
363                                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
364                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
365
366                 // Verify that the number of resources matched by the search
367                 // is identical to the expected result
368                 NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
369                 numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
370                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
371
372         }
373
374         // @Test(dataProvider="testName",
375         // dataProviderClass=AbstractServiceTestImpl.class)
376         // public void searchWithOneKeywordInRepeatableScalarField(String testName)
377         // throws Exception {
378         // BriefDescriptionList descriptionList = new BriefDescriptionList();
379         // List<String> descriptions = descriptionList.getBriefDescription();
380         // if (TWO_KEYWORDS.size() >= 2) {
381         // descriptions.add(TWO_KEYWORDS.get(0));
382         // descriptions.add(TWO_KEYWORDS.get(1));
383         // }
384         // }
385         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class, groups = { "utf8" })
386         public void searchWithUTF8Keyword(String testName) {
387
388                 if (logger.isDebugEnabled()) {
389                         logger.debug(testBanner(testName, CLASS_NAME));
390                 }
391
392                 // Create one or more keyword retrievable resources, each containing
393                 // two specified keywords.
394                 long numKeywordRetrievableResources = 2;
395                 if (logger.isDebugEnabled()) {
396                         logger.debug("Creating " + numKeywordRetrievableResources
397                                         + " keyword-retrievable resources ...");
398                 }
399                 createCollectionObjects(numKeywordRetrievableResources, UTF8_KEYWORD);
400
401                 // Set the expected status code and group of valid status codes
402                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
403
404                 // Send the search request and receive a response
405                 ClientResponse<AbstractCommonList> res = doSearch(UTF8_KEYWORD);
406                 int statusCode = res.getStatus();
407
408                 // Check the status code of the response: does it match
409                 // the expected response(s)?
410                 if (logger.isDebugEnabled()) {
411                         logger.debug(testName + ": status = " + statusCode);
412                 }
413                 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
414                                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
415                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
416
417                 // Verify that the number of resources matched by the search
418                 // is identical to the expected result
419                 long NUM_MATCHES_EXPECTED = numKeywordRetrievableResources;
420                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
421                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
422         }
423
424         // Failure outcomes
425         // FIXME: Rename to searchWithNonExistentKeyword
426         @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class)
427         public void keywordSearchNonExistentKeyword(String testName)
428                         throws Exception {
429
430                 if (logger.isDebugEnabled()) {
431                         logger.debug(testBanner(testName, CLASS_NAME));
432                 }
433
434                 // Set the expected status code and group of valid status codes
435                 testSetup(STATUS_OK, ServiceRequestType.SEARCH);
436
437                 // Send the search request and receive a response
438                 ClientResponse<AbstractCommonList> res = doSearch(NON_EXISTENT_KEYWORD);
439                 int statusCode = res.getStatus();
440
441                 // Check the status code of the response: does it match
442                 // the expected response(s)?
443                 if (logger.isDebugEnabled()) {
444                         logger.debug(testName + ": status = " + statusCode);
445                 }
446                 Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
447                                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
448                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
449
450                 // Verify that the number of resources matched by the search
451                 // is identical to the expected result
452                 long NUM_MATCHES_EXPECTED = 0;
453                 long numMatched = getNumMatched(res, NUM_MATCHES_EXPECTED, testName);
454                 Assert.assertEquals(numMatched, NUM_MATCHES_EXPECTED);
455
456         }
457
458         // ---------------------------------------------------------------
459         // Cleanup of resources created during testing
460         // ---------------------------------------------------------------
461         /**
462          * Deletes all resources created by setup and tests, after all tests have
463          * been run.
464          * 
465          * This cleanup method will always be run, even if one or more tests fail.
466          * For this reason, it attempts to remove all resources created at any point
467          * during testing, even if some of those resources may be expected to be
468          * deleted by certain tests.
469          */
470         @AfterClass(alwaysRun = true)
471         public void cleanUp() {
472                 String noTest = System.getProperty("noTestCleanup");
473                 if (Boolean.TRUE.toString().equalsIgnoreCase(noTest)) {
474                         if (logger.isDebugEnabled()) {
475                                 logger.debug("Skipping Cleanup phase ...");
476                         }
477                         return;
478                 }
479                 if (logger.isDebugEnabled()) {
480                         logger.debug("Cleaning up temporary resources created for testing ...");
481                 }
482                 CollectionObjectClient collectionObjectClient = new CollectionObjectClient();
483                 for (String resourceId : allResourceIdsCreated) {
484                         // Note: Any non-success responses are ignored and not reported.
485                         collectionObjectClient.delete(resourceId).releaseConnection();
486                 }
487         }
488
489         // ---------------------------------------------------------------
490         // Utility methods used by tests above
491         // ---------------------------------------------------------------
492         private void createCollectionObjects(long numToCreate, String keyword) {
493                 List keywords = new ArrayList<String>();
494                 keywords.add(keyword);
495                 boolean keywordsInSameField = true;
496                 createCollectionObjects(numToCreate, keywords, keywordsInSameField);
497         }
498
499         private void createCollectionObjects(long numToCreate,
500                         List<String> keywords, boolean keywordsInSameField) {
501                 testSetup(STATUS_CREATED, ServiceRequestType.CREATE);
502                 CollectionObjectClient client = new CollectionObjectClient();
503                 for (long i = 0; i < numToCreate; i++) {
504                         PoxPayloadOut multipart = createCollectionObjectInstance(i,
505                                         keywords, keywordsInSameField);
506                         ClientResponse<Response> res = client.create(multipart);
507                         try {
508                                 int statusCode = res.getStatus();
509                                 Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
510                                 String id = extractId(res);
511                                 allResourceIdsCreated.add(id);
512                                 if (logger.isDebugEnabled()) {
513                                         logger.debug("Created new resource [" + i + "] with ID "
514                                                         + id);
515                                 }
516                         } finally {
517                                 res.releaseConnection();
518                         }
519                 }
520         }
521
522         private PoxPayloadOut createCollectionObjectInstance(long i,
523                         List<String> keywords, boolean keywordsInSameField) {
524                 CollectionobjectsCommon collectionObject = new CollectionobjectsCommon();
525                 collectionObject.setObjectNumber(createIdentifier());
526                 if (keywordsInSameField) {
527                         collectionObject.setDistinguishingFeatures(listToString(keywords,
528                                         KEYWORD_SEPARATOR));
529                 } else {
530                         if (keywords.size() == 1) {
531                                 collectionObject.setDistinguishingFeatures(keywords.get(0));
532                         } else if (keywords.size() == 2) {
533                                 collectionObject.setDistinguishingFeatures(keywords.get(0));
534                                 collectionObject.setPhysicalDescription(keywords.get(1));
535                         } else {
536                                 Assert.fail("List of keywords must have exactly one or two members.");
537                         }
538                 }
539                 PoxPayloadOut multipart = new PoxPayloadOut(
540                                 CollectionObjectClient.SERVICE_PAYLOAD_NAME);
541                 PayloadOutputPart commonPart = multipart.addPart(collectionObject,
542                                 MediaType.APPLICATION_XML_TYPE);
543                 commonPart.setLabel(new CollectionObjectClient().getCommonPartName());
544                 return multipart;
545         }
546
547         private static String listToString(List<String> list, String separator) {
548                 StringBuffer sb = new StringBuffer();
549                 if (list.size() > 0) {
550                         sb.append(list.get(0));
551                         for (int i = 1; i < list.size(); i++) {
552                                 sb.append(separator);
553                                 sb.append(list.get(i));
554                         }
555                 }
556                 return sb.toString();
557         }
558
559         private ClientResponse<AbstractCommonList> doSearch(List<String> keywords) {
560                 String searchParamValue = listToString(keywords, KEYWORD_SEPARATOR);
561                 return doSearch(searchParamValue);
562         }
563
564         private ClientResponse<AbstractCommonList> doAdvancedSearch(
565                         String propertyName, String propertyValue, String operator) {
566                 if (logger.isDebugEnabled()) {
567                         logger.debug("Searching on property: " + propertyName + "="
568                                         + "'" + propertyValue + "'");
569                 }
570                 String whereClause = propertyName + operator +
571                         "'" + propertyValue + "'";
572                 CollectionObjectClient client = new CollectionObjectClient();
573                 ClientResponse<AbstractCommonList> res = client
574                                 .advancedSearchIncludeDeleted(whereClause, false); // NOT_INCLUDING_DELETED_RESOURCES
575                 return res;
576         }
577
578         private ClientResponse<AbstractCommonList> doSearch(String keyword) {
579                 String searchParamValue = keyword;
580                 if (logger.isDebugEnabled()) {
581                         logger.debug("Searching on keyword(s): " + searchParamValue
582                                         + " ...");
583                 }
584                 CollectionObjectClient client = new CollectionObjectClient();
585                 final boolean NOT_INCLUDING_DELETED_RESOURCES = false;
586                 ClientResponse<AbstractCommonList> res = client
587                                 .keywordSearchIncludeDeleted(searchParamValue,
588                                                 NOT_INCLUDING_DELETED_RESOURCES);
589                 return res;
590         }
591
592         private long getNumMatched(ClientResponse<AbstractCommonList> res,
593                         long numExpectedMatches, String testName) {
594                 AbstractCommonList list = (AbstractCommonList) res
595                                 .getEntity(AbstractCommonList.class);
596                 long numMatched = list.getTotalItems();
597                 if (logger.isDebugEnabled()) {
598                         logger.debug("Keyword search matched " + numMatched
599                                         + " resources, expected to match " + numExpectedMatches);
600                 }
601
602                 // Optionally output additional data about list members for debugging.
603                 if (logger.isTraceEnabled()) {
604                         AbstractCommonListUtils.ListItemsInAbstractCommonList(list, logger,
605                                         testName);
606                 }
607
608                 return numMatched;
609         }
610
611         private void itemizeListItems(AbstractCommonList list) {
612                 List<AbstractCommonList.ListItem> items = list.getListItem();
613                 int i = 0;
614                 for (AbstractCommonList.ListItem item : items) {
615                         logger.debug("list-item["
616                                         + i
617                                         + "] title="
618                                         + AbstractCommonListUtils.ListItemGetElementValue(item,
619                                                         "title"));
620                         logger.debug("list-item["
621                                         + i
622                                         + "] URI="
623                                         + AbstractCommonListUtils.ListItemGetElementValue(item,
624                                                         "uri"));
625                         i++;
626                 }
627         }
628
629         public static String getSystemTimeIdentifier() {
630                 return Long.toString(System.currentTimeMillis());
631         }
632 }