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 {
114 PoxPayloadOut taxonPayload = findTaxonByCsid(taxonCsid);
115 String taxonRefName = getFieldValue(taxonPayload, TaxonConstants.REFNAME_SCHEMA_NAME, TaxonConstants.REFNAME_FIELD_NAME);
117 RefName.AuthorityItem item = RefName.AuthorityItem.parse(taxonRefName);
118 String vocabularyShortId = item.getParentShortIdentifier();
120 List<String> collectionObjectCsids = findReferencingCollectionObjects(TaxonomyAuthorityClient.SERVICE_NAME, vocabularyShortId, taxonCsid,
121 CollectionObjectBotGardenConstants.TAXON_SCHEMA_NAME + ":" + TAXON_FIELD_NAME_WITHOUT_PATH);
123 long numAffected = 0;
125 for (String collectionObjectCsid : collectionObjectCsids) {
126 // Filter out results where the taxon is referenced in the correct field, but isn't the primary value.
128 PoxPayloadOut collectionObjectPayload = findCollectionObjectByCsid(collectionObjectCsid);
129 String primaryTaxonRefName = getFieldValue(collectionObjectPayload, CollectionObjectBotGardenConstants.TAXON_SCHEMA_NAME,
130 CollectionObjectBotGardenConstants.TAXON_FIELD_NAME);
132 if (primaryTaxonRefName.equals(taxonRefName)) {
135 InvocationResults itemResults = updateRareFlag(collectionObjectPayload);
136 numAffected += itemResults.getNumAffected();
140 InvocationResults results = new InvocationResults();
141 results.setNumAffected(numAffected);
142 results.setUserNote(numFound + " referencing cataloging " + (numFound == 1 ? "record" : "records") + " found, " + numAffected + " updated");
147 public InvocationResults updateReferencingRareFlags(String taxonCsid) throws URISyntaxException, DocumentException, Exception {
148 return updateReferencingRareFlags(taxonCsid, null);
152 * Updates the rare flag of the specified collectionobject.
154 * @param collectionObjectCsid The csid of the collectionobject
156 * @throws URISyntaxException
157 * @throws DocumentException
159 public InvocationResults updateRareFlag(String collectionObjectCsid) throws URISyntaxException, DocumentException {
160 PoxPayloadOut collectionObjectPayload = findCollectionObjectByCsid(collectionObjectCsid);
162 return updateRareFlag(collectionObjectPayload);
166 * Updates the rare flag of the specified collectionobject. The rare flag is determined by looking at
167 * the taxon record that is referenced by the primary taxonomic determination of the collectionobject.
168 * If the taxon record has a conservation category that is considered rare in its primary plant attributes
169 * group, the rare flag is set to true. Otherwise, it is set to false.
171 * @param collectionObjectPayload The payload representing the collectionobject
173 * @throws URISyntaxException
174 * @throws DocumentException
176 public InvocationResults updateRareFlag(PoxPayloadOut collectionObjectPayload) throws URISyntaxException, DocumentException {
177 InvocationResults results = new InvocationResults();
179 String uri = this.getFieldValue(collectionObjectPayload, CollectionObjectBotGardenConstants.URI_SCHEMA_NAME,
180 CollectionObjectBotGardenConstants.URI_FIELD_NAME);
181 String[] uriParts = uri.split("\\/");
182 String collectionObjectCsid = uriParts[uriParts.length-1];
184 String workflowState = getFieldValue(collectionObjectPayload, CollectionObjectConstants.WORKFLOW_STATE_SCHEMA_NAME,
185 CollectionObjectConstants.WORKFLOW_STATE_FIELD_NAME);
187 if (workflowState.equals(WorkflowClient.WORKFLOWSTATE_DELETED)) {
188 logger.debug("skipping deleted collectionobject: " + collectionObjectCsid);
191 String taxonRefName = getFieldValue(collectionObjectPayload, CollectionObjectBotGardenConstants.TAXON_SCHEMA_NAME,
192 CollectionObjectBotGardenConstants.TAXON_FIELD_NAME);
193 String oldIsRare = getFieldValue(collectionObjectPayload, CollectionObjectBotGardenConstants.RARE_FLAG_SCHEMA_NAME,
194 CollectionObjectBotGardenConstants.RARE_FLAG_FIELD_NAME);
196 if (oldIsRare == null) {
200 String newIsRare = "false";
202 if (StringUtils.isNotBlank(taxonRefName)) {
203 PoxPayloadOut taxonPayload = null;
206 taxonPayload = findTaxonByRefName(taxonRefName);
208 catch (WebApplicationException e) {
209 logger.error("Error finding taxon: refName=" + taxonRefName, e);
212 if (taxonPayload != null) {
213 // UCBG-369: Changing this so that it only checks the primary conservation category.
215 String conservationCategory = getFieldValue(taxonPayload, TaxonBotGardenConstants.CONSERVATION_CATEGORY_SCHEMA_NAME,
216 TaxonBotGardenConstants.CONSERVATION_CATEGORY_FIELD_NAME);
218 if (isRare(conservationCategory)) {
224 if (!newIsRare.equals(oldIsRare)) {
225 logger.debug("setting rare flag: collectionObjectCsid=" + collectionObjectCsid + " oldIsRare=" + oldIsRare +" newIsRare=" + newIsRare);
227 setRareFlag(collectionObjectCsid, newIsRare);
229 results.setNumAffected(1);
230 results.setUserNote("rare flag set to " + newIsRare);
233 logger.debug("not setting rare flag: collectionObjectCsid=" + collectionObjectCsid + " oldIsRare=" + oldIsRare +" newIsRare=" + newIsRare);
235 results.setNumAffected(0);
236 results.setUserNote("rare flag not changed");
243 public static boolean isRare(String conservationCategoryRefName) {
244 boolean isRare = false;
246 if (StringUtils.isNotEmpty(conservationCategoryRefName)) {
247 // The conservation category is non-empty, so it's rare...
250 // ...unless it's one of the non-rare ones.
252 // Check if the display name starts with a prefix that
253 // indicates that it isn't rare.
255 RefName.AuthorityItem item = RefName.AuthorityItem.parse(conservationCategoryRefName);
256 String displayName = item.getDisplayName();
258 for (String prefix : NON_RARE_CONSERVATION_CATEGORY_PREFIXES) {
259 if (displayName.startsWith(prefix)) {
270 * Updates the rare flags of the specified collectionobjects.
272 * @param collectionObjectCsids The csids of the collectionobjects
274 * @throws URISyntaxException
275 * @throws DocumentException
277 public InvocationResults updateRareFlags(List<String> collectionObjectCsids) throws URISyntaxException, DocumentException {
278 int numSubmitted = collectionObjectCsids.size();
279 long numAffected = 0;
282 for (String collectionObjectCsid : collectionObjectCsids) {
283 InvocationResults itemResults = updateRareFlag(collectionObjectCsid);
285 numAffected += itemResults.getNumAffected();
288 InvocationResults results = new InvocationResults();
289 results.setNumAffected(numAffected);
290 results.setUserNote("updated " + numAffected + " of " + numSubmitted + " cataloging records");
296 * Updates the rare flags of all collectionobjects.
299 * @throws URISyntaxException
300 * @throws DocumentException
302 public InvocationResults updateAllRareFlags() throws URISyntaxException, DocumentException {
304 long numAffected = 0;
308 List<String> csids = Collections.emptyList();
311 csids = findAllCollectionObjects(pageSize, pageNum);
312 logger.debug("pageNum=" + pageNum + " pageSize=" + pageSize + " result size=" + csids.size());
314 InvocationResults pageResults = updateRareFlags(csids);
316 numAffected += pageResults.getNumAffected();
317 numFound += csids.size();
321 while (csids.size() == pageSize);
323 InvocationResults results = new InvocationResults();
324 results.setNumAffected(numAffected);
325 results.setUserNote("updated " + numAffected + " of " + numFound + " cataloging records");
331 * Sets the rare flag of the specified collectionobject to the specified value.
333 * @param collectionObjectCsid The csid of the collectionobject
334 * @param rareFlag The value of the rare flag
335 * @throws URISyntaxException
337 private void setRareFlag(String collectionObjectCsid, String rareFlag) throws URISyntaxException {
338 String updatePayload =
339 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
340 "<document name=\"collectionobjects\">" +
341 "<ns2:collectionobjects_naturalhistory xmlns:ns2=\"http://collectionspace.org/services/collectionobject/domain/naturalhistory\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
342 getFieldXml("rare", rareFlag) +
343 "</ns2:collectionobjects_naturalhistory>" +
344 "<ns2:collectionobjects_common xmlns:ns2=\"http://collectionspace.org/services/collectionobject\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" +
345 "</ns2:collectionobjects_common>" +
348 NuxeoBasedResource resource = (NuxeoBasedResource) getResourceMap().get(CollectionObjectClient.SERVICE_NAME);
349 resource.update(getResourceMap(), createUriInfo(), collectionObjectCsid, updatePayload);