1 package org.collectionspace.services.batch.nuxeo;
3 import java.net.URISyntaxException;
4 import java.util.Arrays;
5 import java.util.Collections;
8 import javax.ws.rs.WebApplicationException;
10 import org.apache.commons.lang.StringUtils;
11 import org.collectionspace.services.client.CollectionObjectClient;
12 import org.collectionspace.services.client.PoxPayloadOut;
13 import org.collectionspace.services.client.TaxonomyAuthorityClient;
14 import org.collectionspace.services.client.workflow.WorkflowClient;
15 import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectBotGardenConstants;
16 import org.collectionspace.services.collectionobject.nuxeo.CollectionObjectConstants;
17 import org.collectionspace.services.common.NuxeoBasedResource;
18 import org.collectionspace.services.common.api.RefName;
19 import org.collectionspace.services.common.invocable.InvocationContext.ListCSIDs;
20 import org.collectionspace.services.common.invocable.InvocationResults;
21 import org.collectionspace.services.taxonomy.nuxeo.TaxonBotGardenConstants;
22 import org.collectionspace.services.taxonomy.nuxeo.TaxonConstants;
23 import org.dom4j.DocumentException;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
27 public class UpdateRareFlagBatchJob extends AbstractBatchJob {
28 final Logger logger = LoggerFactory.getLogger(UpdateRareFlagBatchJob.class);
30 // All conservation categories are considered rare, except for ones that start with the following prefixes.
31 public static final List<String> NON_RARE_CONSERVATION_CATEGORY_PREFIXES = Arrays.asList("none", "DD ", "LC ", "LR (lc) ");
33 private static final String[] TAXON_FIELD_NAME_PARTS = CollectionObjectBotGardenConstants.TAXON_FIELD_NAME.split("\\/");
34 private static final String TAXON_FIELD_NAME_WITHOUT_PATH = TAXON_FIELD_NAME_PARTS[TAXON_FIELD_NAME_PARTS.length - 1];
36 public UpdateRareFlagBatchJob() {
37 this.setSupportedInvocationModes(Arrays.asList(INVOCATION_MODE_SINGLE, INVOCATION_MODE_LIST, INVOCATION_MODE_NO_CONTEXT));
42 setCompletionStatus(STATUS_MIN_PROGRESS);
45 String mode = getInvocationContext().getMode();
47 if (mode.equals(INVOCATION_MODE_SINGLE)) {
49 * In a single document context, the single csid must specify a collectionobject or a
50 * taxonomy record. If it's a collectionobject, the rare flag for the specified
51 * collectionobject will be updated. If it's a taxonomy record, the rare flag will be
52 * updated for each collectionobject with a primary determination that refers to the
53 * specified taxonomy record.
56 String csid = getInvocationContext().getSingleCSID();
58 if (StringUtils.isEmpty(csid)) {
59 throw new Exception("Missing context csid");
62 String docType = getInvocationContext().getDocType();
64 if (docType.equals(CollectionObjectConstants.NUXEO_DOCTYPE)) {
65 setResults(updateRareFlag(csid));
67 else if (docType.equals(TaxonConstants.NUXEO_DOCTYPE)) {
68 setResults(updateReferencingRareFlags(csid));
71 throw new Exception("Unsupported document type: " + docType);
74 else if (mode.equals(INVOCATION_MODE_LIST)) {
76 * In a list context, the csids must specify collectionobjects. The rare flag for
77 * each collectionobject will be updated.
79 ListCSIDs csids = getInvocationContext().getListCSIDs();
81 setResults(updateRareFlags(csids.getCsid()));
83 else if (mode.equals(INVOCATION_MODE_NO_CONTEXT)) {
85 * If there is no context, the rare flag will be updated for all (non-deleted)
89 setResults(updateAllRareFlags());
92 throw new Exception("Unsupported invocation mode: " + mode);
95 setCompletionStatus(STATUS_COMPLETE);
98 setCompletionStatus(STATUS_ERROR);
99 setErrorInfo(new InvocationError(INT_ERROR_STATUS, e.getMessage()));
104 * Updates the rare flags of collectionobjects that refer to the specified taxon record.
105 * A collectionobject is considered to refer to the taxon record if the refname of its
106 * primary taxonomic identification is the refname of the taxon record.
108 * @param taxonCsid The csid of the taxon record
110 * @throws URISyntaxException
111 * @throws DocumentException
113 public InvocationResults updateReferencingRareFlags(String taxonCsid, String vocabularyCsid) throws URISyntaxException, DocumentException, Exception {
114 PoxPayloadOut taxonPayload = vocabularyCsid == null
115 ? findTaxonByCsid(taxonCsid)
116 : findTaxonByCsid(taxonCsid, vocabularyCsid);
117 String taxonRefName = getFieldValue(taxonPayload, TaxonConstants.REFNAME_SCHEMA_NAME, TaxonConstants.REFNAME_FIELD_NAME);
119 RefName.AuthorityItem item = RefName.AuthorityItem.parse(taxonRefName);
120 String vocabularyShortId = item.getParentShortIdentifier();
122 List<String> collectionObjectCsids = findReferencingCollectionObjects(TaxonomyAuthorityClient.SERVICE_NAME, vocabularyShortId, taxonCsid,
123 CollectionObjectBotGardenConstants.TAXON_SCHEMA_NAME + ":" + TAXON_FIELD_NAME_WITHOUT_PATH);
125 long numAffected = 0;
127 for (String collectionObjectCsid : collectionObjectCsids) {
128 // Filter out results where the taxon is referenced in the correct field, but isn't the primary value.
130 PoxPayloadOut collectionObjectPayload = findCollectionObjectByCsid(collectionObjectCsid);
131 String primaryTaxonRefName = getFieldValue(collectionObjectPayload, CollectionObjectBotGardenConstants.TAXON_SCHEMA_NAME,
132 CollectionObjectBotGardenConstants.TAXON_FIELD_NAME);
134 if (primaryTaxonRefName.equals(taxonRefName)) {
137 InvocationResults itemResults = updateRareFlag(collectionObjectPayload);
138 numAffected += itemResults.getNumAffected();
142 InvocationResults results = new InvocationResults();
143 results.setNumAffected(numAffected);
144 results.setUserNote(numFound + " referencing cataloging " + (numFound == 1 ? "record" : "records") + " found, " + numAffected + " updated");
149 public InvocationResults updateReferencingRareFlags(String taxonCsid) throws URISyntaxException, DocumentException, Exception {
150 return updateReferencingRareFlags(taxonCsid, null);
154 * Updates the rare flag of the specified collectionobject.
156 * @param collectionObjectCsid The csid of the collectionobject
158 * @throws URISyntaxException
159 * @throws DocumentException
161 public InvocationResults updateRareFlag(String collectionObjectCsid) throws URISyntaxException, DocumentException, Exception {
162 PoxPayloadOut collectionObjectPayload = findCollectionObjectByCsid(collectionObjectCsid);
164 return updateRareFlag(collectionObjectPayload);
168 * Updates the rare flag of the specified collectionobject. The rare flag is determined by looking at
169 * the taxon record that is referenced by the primary taxonomic determination of the collectionobject.
170 * If the taxon record has a conservation category that is considered rare in its primary plant attributes
171 * group, the rare flag is set to true. Otherwise, it is set to false.
173 * @param collectionObjectPayload The payload representing the collectionobject
175 * @throws URISyntaxException
176 * @throws DocumentException
178 public InvocationResults updateRareFlag(PoxPayloadOut collectionObjectPayload) throws URISyntaxException, DocumentException, Exception {
179 InvocationResults results = new InvocationResults();
181 String uri = this.getFieldValue(collectionObjectPayload, CollectionObjectBotGardenConstants.URI_SCHEMA_NAME,
182 CollectionObjectBotGardenConstants.URI_FIELD_NAME);
183 String[] uriParts = uri.split("\\/");
184 String collectionObjectCsid = uriParts[uriParts.length-1];
186 String workflowState = getFieldValue(collectionObjectPayload, CollectionObjectConstants.WORKFLOW_STATE_SCHEMA_NAME,
187 CollectionObjectConstants.WORKFLOW_STATE_FIELD_NAME);
189 if (workflowState.equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
190 logger.debug("skipping deleted collectionobject: " + collectionObjectCsid);
193 String taxonRefName = getFieldValue(collectionObjectPayload, CollectionObjectBotGardenConstants.TAXON_SCHEMA_NAME,
194 CollectionObjectBotGardenConstants.TAXON_FIELD_NAME);
195 String oldIsRare = getFieldValue(collectionObjectPayload, CollectionObjectBotGardenConstants.RARE_FLAG_SCHEMA_NAME,
196 CollectionObjectBotGardenConstants.RARE_FLAG_FIELD_NAME);
198 if (oldIsRare == null) {
202 String newIsRare = "false";
204 if (StringUtils.isNotBlank(taxonRefName)) {
205 PoxPayloadOut taxonPayload = null;
208 taxonPayload = findTaxonByRefName(taxonRefName);
210 catch (WebApplicationException e) {
211 logger.error("Error finding taxon: refName=" + taxonRefName, e);
214 if (taxonPayload != null) {
215 // UCBG-369: Changing this so that it only checks the primary conservation category.
217 String conservationCategory = getFieldValue(taxonPayload, TaxonBotGardenConstants.CONSERVATION_CATEGORY_SCHEMA_NAME,
218 TaxonBotGardenConstants.CONSERVATION_CATEGORY_FIELD_NAME);
220 if (isRare(conservationCategory)) {
226 if (!newIsRare.equals(oldIsRare)) {
227 logger.debug("setting rare flag: collectionObjectCsid=" + collectionObjectCsid + " oldIsRare=" + oldIsRare +" newIsRare=" + newIsRare);
229 setRareFlag(collectionObjectCsid, newIsRare);
231 results.setNumAffected(1);
232 results.setUserNote("rare flag set to " + newIsRare);
235 logger.debug("not setting rare flag: collectionObjectCsid=" + collectionObjectCsid + " oldIsRare=" + oldIsRare +" newIsRare=" + newIsRare);
237 results.setNumAffected(0);
238 results.setUserNote("rare flag not changed");
245 public static boolean isRare(String conservationCategoryRefName) {
246 boolean isRare = false;
248 if (StringUtils.isNotEmpty(conservationCategoryRefName)) {
249 // The conservation category is non-empty, so it's rare...
252 // ...unless it's one of the non-rare ones.
254 // Check if the display name starts with a prefix that
255 // indicates that it isn't rare.
257 RefName.AuthorityItem item = RefName.AuthorityItem.parse(conservationCategoryRefName);
258 String displayName = item.getDisplayName();
260 for (String prefix : NON_RARE_CONSERVATION_CATEGORY_PREFIXES) {
261 if (displayName.startsWith(prefix)) {
272 * Updates the rare flags of the specified collectionobjects.
274 * @param collectionObjectCsids The csids of the collectionobjects
276 * @throws URISyntaxException
277 * @throws DocumentException
279 public InvocationResults updateRareFlags(List<String> collectionObjectCsids) throws URISyntaxException, DocumentException, Exception {
280 int numSubmitted = collectionObjectCsids.size();
281 long numAffected = 0;
284 for (String collectionObjectCsid : collectionObjectCsids) {
285 InvocationResults itemResults = updateRareFlag(collectionObjectCsid);
287 numAffected += itemResults.getNumAffected();
290 InvocationResults results = new InvocationResults();
291 results.setNumAffected(numAffected);
292 results.setUserNote("updated " + numAffected + " of " + numSubmitted + " cataloging records");
298 * Updates the rare flags of all collectionobjects.
301 * @throws URISyntaxException
302 * @throws DocumentException
304 public InvocationResults updateAllRareFlags() throws URISyntaxException, DocumentException, Exception {
306 long numAffected = 0;
310 List<String> csids = Collections.emptyList();
313 csids = findAllCollectionObjects(pageSize, pageNum);
314 logger.debug("pageNum=" + pageNum + " pageSize=" + pageSize + " result size=" + csids.size());
316 InvocationResults pageResults = updateRareFlags(csids);
318 numAffected += pageResults.getNumAffected();
319 numFound += csids.size();
323 while (csids.size() == pageSize);
325 InvocationResults results = new InvocationResults();
326 results.setNumAffected(numAffected);
327 results.setUserNote("updated " + numAffected + " of " + numFound + " cataloging records");
333 * Sets the rare flag of the specified collectionobject to the specified value.
335 * @param collectionObjectCsid The csid of the collectionobject
336 * @param rareFlag The value of the rare flag
337 * @throws URISyntaxException
339 private void setRareFlag(String collectionObjectCsid, String rareFlag) throws URISyntaxException {
340 String updatePayload =
341 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
342 "<document name=\"collectionobjects\">" +
343 "<ns2:collectionobjects_naturalhistory xmlns:ns2=\"http://collectionspace.org/services/collectionobject/domain/naturalhistory\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
344 getFieldXml("rare", rareFlag) +
345 "</ns2:collectionobjects_naturalhistory>" +
346 "<ns2:collectionobjects_common xmlns:ns2=\"http://collectionspace.org/services/collectionobject\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
347 "</ns2:collectionobjects_common>" +
350 NuxeoBasedResource resource = (NuxeoBasedResource) getResourceMap().get(CollectionObjectClient.SERVICE_NAME);
351 resource.update(getServiceContext(), getResourceMap(), createUriInfo(), collectionObjectCsid, updatePayload);