]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
36ef17097ffcad8c017a08f19ca42d781bcd0aee
[tmp/jakarta-migration.git] /
1 package org.collectionspace.services.batch.nuxeo;
2
3 import java.io.StringReader;
4 import java.net.URI;
5 import java.net.URISyntaxException;
6 import java.util.ArrayList;
7 import java.util.Arrays;
8 import java.util.Collections;
9 import java.util.HashSet;
10 import java.util.List;
11 import java.util.Set;
12 import javax.ws.rs.core.PathSegment;
13 import javax.ws.rs.core.UriInfo;
14 import org.collectionspace.services.batch.AbstractBatchInvocable;
15 import org.collectionspace.services.client.AbstractCommonListUtils;
16 import org.collectionspace.services.client.CollectionObjectClient;
17 import org.collectionspace.services.client.IQueryManager;
18 import org.collectionspace.services.client.MovementClient;
19 import org.collectionspace.services.client.PoxPayloadOut;
20 import org.collectionspace.services.client.workflow.WorkflowClient;
21 import org.collectionspace.services.common.ResourceBase;
22 import org.collectionspace.services.common.ResourceMap;
23 import org.collectionspace.services.common.api.Tools;
24 import org.collectionspace.services.common.invocable.InvocationResults;
25 import org.collectionspace.services.jaxb.AbstractCommonList;
26 import org.dom4j.DocumentException;
27 import org.jboss.resteasy.specimpl.UriInfoImpl;
28 import org.jdom.Document;
29 import org.jdom.Element;
30 import org.jdom.Namespace;
31 import org.jdom.input.SAXBuilder;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
36
37     // FIXME: Where appropriate, get from existing constants rather than local declarations
38     private final static String COMPUTED_CURRENT_LOCATION_ELEMENT_NAME = "computedCurrentLocation";
39     private final static String CSID_ELEMENT_NAME = "csid";
40     private final static String CURRENT_LOCATION_ELEMENT_NAME = "currentLocation";
41     private final static String LIFECYCLE_STATE_ELEMENT_NAME = "currentLifeCycleState";
42     private final static String LOCATION_DATE_ELEMENT_NAME = "locationDate";
43     private final static String OBJECT_NUMBER_ELEMENT_NAME = "objectNumber";
44     private final static String WORKFLOW_COMMON_SCHEMA_NAME = "workflow_common";
45     private final static String WORKFLOW_COMMON_NAMESPACE_PREFIX = "ns2";
46     private final static String WORKFLOW_COMMON_NAMESPACE_URI =
47             "http://collectionspace.org/services/workflow";
48     private final static Namespace WORKFLOW_COMMON_NAMESPACE =
49             Namespace.getNamespace(
50             WORKFLOW_COMMON_NAMESPACE_PREFIX,
51             WORKFLOW_COMMON_NAMESPACE_URI);
52     private final static String COLLECTIONOBJECTS_COMMON_SCHEMA_NAME = "collectionobjects_common";
53     private final static String COLLECTIONOBJECTS_COMMON_NAMESPACE_PREFIX = "ns2";
54     private final static String COLLECTIONOBJECTS_COMMON_NAMESPACE_URI =
55             "http://collectionspace.org/services/collectionobject";
56     private final static Namespace COLLECTIONOBJECTS_COMMON_NAMESPACE =
57             Namespace.getNamespace(
58             COLLECTIONOBJECTS_COMMON_NAMESPACE_PREFIX,
59             COLLECTIONOBJECTS_COMMON_NAMESPACE_URI);
60     private final boolean EXCLUDE_DELETED = true;
61     private final String CLASSNAME = this.getClass().getSimpleName();
62     private final Logger logger = LoggerFactory.getLogger(this.getClass());
63
64     // Initialization tasks
65     public UpdateObjectLocationBatchJob() {
66         setSupportedInvocationModes(Arrays.asList(INVOCATION_MODE_SINGLE, INVOCATION_MODE_LIST,
67                 INVOCATION_MODE_GROUP, INVOCATION_MODE_NO_CONTEXT));
68     }
69
70     /**
71      * The main work logic of the batch job. Will be called after setContext.
72      */
73     @Override
74     public void run() {
75
76         setCompletionStatus(STATUS_MIN_PROGRESS);
77
78         try {
79
80             List<String> csids = new ArrayList<String>();
81
82             // Build a list of CollectionObject records to process via this
83             // batch job, depending on the invocation mode requested.
84             if (requestIsForInvocationModeSingle()) {
85                 String singleCsid = getInvocationContext().getSingleCSID();
86                 if (Tools.isBlank(singleCsid)) {
87                     throw new Exception(CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT);
88                 } else {
89                     csids.add(singleCsid);
90                 }
91             } else if (requestIsForInvocationModeList()) {
92                 List<String> listCsids = getListCsids();
93                 if (listCsids.isEmpty()) {
94                     throw new Exception(CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT);
95                 }
96                 csids.addAll(listCsids);
97             } else if (requestIsForInvocationModeGroup()) {
98                 String groupCsid = getInvocationContext().getGroupCSID();
99                 if (Tools.isBlank(groupCsid)) {
100                     throw new Exception(CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT);
101                 }
102                 List<String> groupMemberCsids = getMemberCsidsFromGroup(CollectionObjectClient.SERVICE_NAME, groupCsid);
103                 if (groupMemberCsids.isEmpty()) {
104                     throw new Exception(CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT);
105                 }
106                 csids.addAll(groupMemberCsids);
107             } else if (requestIsForInvocationModeNoContext()) {
108                 List<String> noContextCsids = getNoContextCsids();
109                 if (noContextCsids.isEmpty()) {
110                     throw new Exception(CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT);
111                 }
112                 csids.addAll(noContextCsids);
113             }
114             if (logger.isInfoEnabled()) {
115                 logger.info("Identified " + csids.size() + " total CollectionObject(s) to be processed via the " + CLASSNAME + " batch job");
116             }
117
118             // Update the value of the computed current location field for each CollectionObject
119             setResults(updateComputedCurrentLocations(csids));
120             setCompletionStatus(STATUS_COMPLETE);
121
122         } catch (Exception e) {
123             String errMsg = "Error encountered in " + CLASSNAME + ": " + e.getLocalizedMessage();
124             setErrorResult(errMsg);
125         }
126
127     }
128
129     private InvocationResults updateComputedCurrentLocations(List<String> csids) {
130         ResourceMap resourcemap = getResourceMap();
131         ResourceBase collectionObjectResource = resourcemap.get(CollectionObjectClient.SERVICE_NAME);
132         ResourceBase movementResource = resourcemap.get(MovementClient.SERVICE_NAME);
133         String computedCurrentLocation;
134         int numUpdated = 0;
135
136         try {
137
138             // For each CollectionObject record
139             for (String collectionObjectCsid : csids) {
140
141                 // FIXME: Optionally set competition status here to
142                 // indicate what percentage of records have been processed.
143
144                 // Skip over soft-deleted CollectionObject records
145                 //
146                 // (Invocations using the 'no context' mode have already
147                 // filtered out soft-deleted records.)
148                 if (!requestIsForInvocationModeNoContext()) {
149                     if (isRecordDeleted(collectionObjectResource, collectionObjectCsid)) {
150                         if (logger.isTraceEnabled()) {
151                             logger.trace("Skipping soft-deleted CollectionObject record with CSID " + collectionObjectCsid);
152                         }
153                         continue;
154                     }
155                 }
156                 // Get the Movement records related to this CollectionObject record
157                 AbstractCommonList relatedMovements =
158                         getRelatedRecords(movementResource, collectionObjectCsid, EXCLUDE_DELETED);
159                 // Skip over CollectionObject records that have no related Movement records
160                 if (relatedMovements.getListItem().isEmpty()) {
161                     continue;
162                 }
163                 // Get the most recent 'suitable' Movement record, one which
164                 // contains both a location date and a current location value
165                 AbstractCommonList.ListItem mostRecentMovement = getMostRecentMovement(relatedMovements);
166                 // Skip over CollectionObject records where no suitable
167                 // most recent Movement record can be identified.
168                 //
169                 // FIXME: Clarify: it ever necessary to 'unset' a computed
170                 // current location value, by setting it to a null or empty value,
171                 // if that value is no longer obtainable from related Movement
172                 // records, if any?
173                 if (mostRecentMovement == null) {
174                     continue;
175                 }
176                 // Update the value of the computed current location field
177                 // (and, via subclasses, this and/or other relevant fields)
178                 // in the CollectionObject record
179                 numUpdated = updateCollectionObjectValues(collectionObjectResource,
180                         collectionObjectCsid, mostRecentMovement, resourcemap, numUpdated);
181             }
182
183         } catch (Exception e) {
184             String errMsg = "Error encountered in " + CLASSNAME + ": " + e.getLocalizedMessage() + " ";
185             errMsg = errMsg + "Successfully updated " + numUpdated + " CollectionObject record(s) prior to error.";
186             logger.error(errMsg);
187             setErrorResult(errMsg);
188             getResults().setNumAffected(numUpdated);
189             return getResults();
190         }
191
192         logger.info("Updated computedCurrentLocation values in " + numUpdated + " CollectionObject record(s).");
193         getResults().setNumAffected(numUpdated);
194         return getResults();
195     }
196
197     private AbstractCommonList.ListItem getMostRecentMovement(AbstractCommonList relatedMovements) {
198         Set<String> alreadyProcessedMovementCsids = new HashSet<String>();
199         AbstractCommonList.ListItem mostRecentMovement = null;
200         String movementCsid;
201         String currentLocation;
202         String locationDate;
203         String mostRecentLocationDate = "";
204         for (AbstractCommonList.ListItem movementListItem : relatedMovements.getListItem()) {
205             movementCsid = AbstractCommonListUtils.ListItemGetElementValue(movementListItem, CSID_ELEMENT_NAME);
206             if (Tools.isBlank(movementCsid)) {
207                 continue;
208             }
209             // Skip over any duplicates in the list, such as records that might
210             // appear as the subject of one relation record and the object of
211             // its reciprocal relation record
212             if (alreadyProcessedMovementCsids.contains(movementCsid)) {
213                 continue;
214             } else {
215                 alreadyProcessedMovementCsids.add(movementCsid);
216             }
217             locationDate = AbstractCommonListUtils.ListItemGetElementValue(movementListItem, LOCATION_DATE_ELEMENT_NAME);
218             if (Tools.isBlank(locationDate)) {
219                 continue;
220             }
221             currentLocation = AbstractCommonListUtils.ListItemGetElementValue(movementListItem, CURRENT_LOCATION_ELEMENT_NAME);
222             if (Tools.isBlank(currentLocation)) {
223                 continue;
224             }
225             // FIXME: Add optional validation here that this Movement record's
226             // currentLocation value parses successfully as an item refName,
227             // before identifying that record as the most recent Movement.
228             // Consider making this optional validation, in turn dependent on the
229             // value of a parameter passed in during batch job invocation.
230             if (logger.isTraceEnabled()) {
231                 logger.trace("Location date value = " + locationDate);
232                 logger.trace("Current location value = " + currentLocation);
233             }
234             // If this record's location date value is more recent than that of other
235             // Movement records processed so far, set the current Movement record
236             // as the most recent Movement.
237             //
238             // The following comparison assumes that all values for this element/field
239             // will be consistent ISO 8601 date/time representations, each of which can
240             // be ordered via string comparison.
241             //
242             // If this is *not* the case, we should instead parse and convert these values
243             // to date/time objects.
244             if (locationDate.compareTo(mostRecentLocationDate) > 0) {
245                 mostRecentLocationDate = locationDate;
246                 mostRecentMovement = movementListItem;
247             }
248
249         }
250         return mostRecentMovement;
251     }
252
253     // This method can be overridden and extended to update a custom set of
254     // values in the CollectionObject record by pulling in values from its
255     // most recent related Movement record.
256     //
257     // Note: any such values must first be exposed in Movement list items,
258     // in turn via configuration in Services tenant bindings ("listResultsField").
259     protected int updateCollectionObjectValues(ResourceBase collectionObjectResource,
260             String collectionObjectCsid, AbstractCommonList.ListItem mostRecentMovement,
261             ResourceMap resourcemap, int numUpdated)
262             throws DocumentException, URISyntaxException {
263         PoxPayloadOut collectionObjectPayload;
264         String computedCurrentLocation;
265         String objectNumber;
266         String previousComputedCurrentLocation;
267
268         collectionObjectPayload = findByCsid(collectionObjectResource, collectionObjectCsid);
269         if (Tools.isBlank(collectionObjectPayload.toXML())) {
270             return numUpdated;
271         } else {
272             if (logger.isTraceEnabled()) {
273                 logger.trace("Payload: " + "\n" + collectionObjectPayload);
274             }
275         }
276         // Perform the update only if the computed current location value will change
277         // as a result of the update
278         computedCurrentLocation =
279                 AbstractCommonListUtils.ListItemGetElementValue(mostRecentMovement, CURRENT_LOCATION_ELEMENT_NAME);
280         previousComputedCurrentLocation = getFieldElementValue(collectionObjectPayload,
281                 COLLECTIONOBJECTS_COMMON_SCHEMA_NAME, COLLECTIONOBJECTS_COMMON_NAMESPACE,
282                 COMPUTED_CURRENT_LOCATION_ELEMENT_NAME);
283         if (!shouldUpdateLocation(previousComputedCurrentLocation, computedCurrentLocation)) {
284             return numUpdated;
285         }
286     
287         // Perform the update only if there is a non-blank object number available.
288         //
289         // In the default CollectionObject validation handler, the object number
290         // is a required field and its (non-blank) value must be present in update
291         // payloads to successfully perform an update.
292         objectNumber = getFieldElementValue(collectionObjectPayload,
293                 COLLECTIONOBJECTS_COMMON_SCHEMA_NAME, COLLECTIONOBJECTS_COMMON_NAMESPACE,
294                 OBJECT_NUMBER_ELEMENT_NAME);
295         if (logger.isTraceEnabled()) {
296             logger.trace("Object number: " + objectNumber);
297         }
298         // FIXME: Consider making the requirement that a non-blank object number
299         // be present dependent on the value of a parameter passed in during
300         // batch job invocation, as some implementations may have turned off that
301         // validation requirement.
302         if (Tools.isBlank(objectNumber)) {
303             return numUpdated;
304         }
305
306         // Update the location.
307         // (Updated location values can legitimately be blank, to 'null out' existing locations.)  
308         if (computedCurrentLocation == null) {
309             computedCurrentLocation = "";
310         }
311
312         String collectionObjectUpdatePayload =
313                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
314                 + "<document name=\"collectionobject\">"
315                 + "  <ns2:collectionobjects_common "
316                 + "      xmlns:ns2=\"http://collectionspace.org/services/collectionobject\">"
317                 + "    <objectNumber>" + objectNumber + "</objectNumber>"
318                 + "    <computedCurrentLocation>" + computedCurrentLocation + "</computedCurrentLocation>"
319                 + "  </ns2:collectionobjects_common>"
320                 + "</document>";
321         if (logger.isTraceEnabled()) {
322             logger.trace("Update payload: " + "\n" + collectionObjectUpdatePayload);
323         }
324         byte[] response = collectionObjectResource.update(resourcemap, null, collectionObjectCsid,
325                 collectionObjectUpdatePayload);
326         numUpdated++;
327         if (logger.isTraceEnabled()) {
328             logger.trace("Computed current location value for CollectionObject " + collectionObjectCsid
329                     + " was set to " + computedCurrentLocation);
330
331         }
332         return numUpdated;
333     }
334     
335     protected boolean shouldUpdateLocation(String previousLocation, String currentLocation) {
336         boolean shouldUpdate = true;
337         if (Tools.isBlank(previousLocation) && Tools.isBlank(currentLocation)) {
338             shouldUpdate = false;
339         } else if (Tools.notBlank(previousLocation) && previousLocation.equals(currentLocation)) {
340             shouldUpdate = false;
341         }
342         return shouldUpdate;
343     }
344
345     // #################################################################
346     // Ray Lee's convenience methods from his AbstractBatchJob class for the
347     // UC Berkeley Botanical Garden v2.4 implementation.
348     // #################################################################
349     protected PoxPayloadOut findByCsid(String serviceName, String csid) throws URISyntaxException, DocumentException {
350         ResourceBase resource = getResourceMap().get(serviceName);
351         return findByCsid(resource, csid);
352     }
353
354     protected PoxPayloadOut findByCsid(ResourceBase resource, String csid) throws URISyntaxException, DocumentException {
355         byte[] response = resource.get(null, createUriInfo(), csid);
356         PoxPayloadOut payload = new PoxPayloadOut(response);
357         return payload;
358     }
359
360     protected UriInfo createUriInfo() throws URISyntaxException {
361         return createUriInfo("");
362     }
363
364     protected UriInfo createUriInfo(String queryString) throws URISyntaxException {
365         URI absolutePath = new URI("");
366         URI baseUri = new URI("");
367         return new UriInfoImpl(absolutePath, baseUri, "", queryString, Collections.<PathSegment>emptyList());
368     }
369
370     // #################################################################
371     // Other convenience methods
372     // #################################################################
373     protected UriInfo createRelatedRecordsUriInfo(String queryString) throws URISyntaxException {
374         URI uri = new URI(null, null, null, queryString, null);
375         return createUriInfo(uri.getRawQuery());
376     }
377
378     protected String getFieldElementValue(PoxPayloadOut payload, String partLabel, Namespace partNamespace, String fieldPath) {
379         String value = null;
380         SAXBuilder builder = new SAXBuilder();
381         try {
382             Document document = builder.build(new StringReader(payload.toXML()));
383             Element root = document.getRootElement();
384             // The part element is always expected to have an explicit namespace.
385             Element part = root.getChild(partLabel, partNamespace);
386             // Try getting the field element both with and without a namespace.
387             // Even though a field element that lacks a namespace prefix
388             // may yet inherit its namespace from a parent, JDOM may require that
389             // the getChild() call be made without a namespace.
390             Element field = part.getChild(fieldPath, partNamespace);
391             if (field == null) {
392                 field = part.getChild(fieldPath);
393             }
394             if (field != null) {
395                 value = field.getText();
396             }
397         } catch (Exception e) {
398             logger.error("Error getting value from field path " + fieldPath
399                     + " in schema part " + partLabel);
400             return null;
401         }
402         return value;
403     }
404
405     private boolean isRecordDeleted(ResourceBase resource, String collectionObjectCsid)
406             throws URISyntaxException, DocumentException {
407         boolean isDeleted = false;
408         byte[] workflowResponse = resource.getWorkflow(createUriInfo(), collectionObjectCsid);
409         if (workflowResponse != null) {
410             PoxPayloadOut payloadOut = new PoxPayloadOut(workflowResponse);
411             String workflowState =
412                     getFieldElementValue(payloadOut, WORKFLOW_COMMON_SCHEMA_NAME,
413                     WORKFLOW_COMMON_NAMESPACE, LIFECYCLE_STATE_ELEMENT_NAME);
414             if (Tools.notBlank(workflowState) && workflowState.equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
415                 isDeleted = true;
416             }
417         }
418         return isDeleted;
419     }
420
421     private UriInfo addFilterToExcludeSoftDeletedRecords(UriInfo uriInfo) throws URISyntaxException {
422         if (uriInfo == null) {
423             uriInfo = createUriInfo();
424         }
425         uriInfo.getQueryParameters().add(WorkflowClient.WORKFLOW_QUERY_NONDELETED, Boolean.FALSE.toString());
426         return uriInfo;
427     }
428
429     private AbstractCommonList getRecordsRelatedToCsid(ResourceBase resource, String csid,
430             String relationshipDirection, boolean excludeDeletedRecords) throws URISyntaxException {
431         UriInfo uriInfo = createUriInfo();
432         uriInfo.getQueryParameters().add(relationshipDirection, csid);
433         if (excludeDeletedRecords) {
434             uriInfo = addFilterToExcludeSoftDeletedRecords(uriInfo);
435         }
436         // The 'resource' type used here identifies the record type of the
437         // related records to be retrieved
438         AbstractCommonList relatedRecords = resource.getList(uriInfo);
439         if (logger.isTraceEnabled()) {
440             logger.trace("Identified " + relatedRecords.getTotalItems()
441                     + " record(s) related to the object record via direction " + relationshipDirection + " with CSID " + csid);
442         }
443         return relatedRecords;
444     }
445
446     /**
447      * Returns the records of a specified type that are related to a specified
448      * record, where that record is the object of the relation.
449      *
450      * @param resource a resource. The type of this resource determines the type
451      * of related records that are returned.
452      * @param csid a CSID identifying a record
453      * @param excludeDeletedRecords true if 'soft-deleted' records should be
454      * excluded from results; false if those records should be included
455      * @return a list of records of a specified type, related to a specified
456      * record
457      * @throws URISyntaxException
458      */
459     private AbstractCommonList getRecordsRelatedToObjectCsid(ResourceBase resource, String csid, boolean excludeDeletedRecords) throws URISyntaxException {
460         return getRecordsRelatedToCsid(resource, csid, IQueryManager.SEARCH_RELATED_TO_CSID_AS_OBJECT, excludeDeletedRecords);
461     }
462
463     /**
464      * Returns the records of a specified type that are related to a specified
465      * record, where that record is the subject of the relation.
466      *
467      * @param resource a resource. The type of this resource determines the type
468      * of related records that are returned.
469      * @param csid a CSID identifying a record
470      * @param excludeDeletedRecords true if 'soft-deleted' records should be
471      * excluded from results; false if those records should be included
472      * @return a list of records of a specified type, related to a specified
473      * record
474      * @throws URISyntaxException
475      */
476     private AbstractCommonList getRecordsRelatedToSubjectCsid(ResourceBase resource, String csid, boolean excludeDeletedRecords) throws URISyntaxException {
477         return getRecordsRelatedToCsid(resource, csid, IQueryManager.SEARCH_RELATED_TO_CSID_AS_SUBJECT, excludeDeletedRecords);
478     }
479
480     private AbstractCommonList getRelatedRecords(ResourceBase resource, String csid, boolean excludeDeletedRecords)
481             throws URISyntaxException, DocumentException {
482         AbstractCommonList relatedRecords = new AbstractCommonList();
483         AbstractCommonList recordsRelatedToObjectCSID = getRecordsRelatedToObjectCsid(resource, csid, excludeDeletedRecords);
484         AbstractCommonList recordsRelatedToSubjectCSID = getRecordsRelatedToSubjectCsid(resource, csid, excludeDeletedRecords);
485         // If either list contains any related records, merge in its items
486         if (recordsRelatedToObjectCSID.getListItem().size() > 0) {
487             relatedRecords.getListItem().addAll(recordsRelatedToObjectCSID.getListItem());
488         }
489         if (recordsRelatedToSubjectCSID.getListItem().size() > 0) {
490             relatedRecords.getListItem().addAll(recordsRelatedToSubjectCSID.getListItem());
491         }
492         if (logger.isTraceEnabled()) {
493             logger.trace("Identified a total of " + relatedRecords.getListItem().size()
494                     + " record(s) related to the record with CSID " + csid);
495         }
496         return relatedRecords;
497     }
498
499     private List<String> getCsidsList(AbstractCommonList list) {
500         List<String> csids = new ArrayList<String>();
501         for (AbstractCommonList.ListItem listitem : list.getListItem()) {
502             csids.add(AbstractCommonListUtils.ListItemGetCSID(listitem));
503         }
504         return csids;
505     }
506
507     private List<String> getMemberCsidsFromGroup(String serviceName, String groupCsid) throws URISyntaxException, DocumentException {
508         ResourceMap resourcemap = getResourceMap();
509         ResourceBase resource = resourcemap.get(serviceName);
510         return getMemberCsidsFromGroup(resource, groupCsid);
511     }
512
513     private List<String> getMemberCsidsFromGroup(ResourceBase resource, String groupCsid) throws URISyntaxException, DocumentException {
514         // The 'resource' type used here identifies the record type of the
515         // related records to be retrieved
516         AbstractCommonList relatedRecords =
517                 getRelatedRecords(resource, groupCsid, EXCLUDE_DELETED);
518         List<String> memberCsids = getCsidsList(relatedRecords);
519         return memberCsids;
520     }
521
522     private List<String> getNoContextCsids() throws URISyntaxException {
523         ResourceMap resourcemap = getResourceMap();
524         ResourceBase collectionObjectResource = resourcemap.get(CollectionObjectClient.SERVICE_NAME);
525         UriInfo uriInfo = createUriInfo();
526         uriInfo = addFilterToExcludeSoftDeletedRecords(uriInfo);
527         AbstractCommonList collectionObjects = collectionObjectResource.getList(uriInfo);
528         List<String> noContextCsids = getCsidsList(collectionObjects);
529         return noContextCsids;
530     }
531 }