/** * Returns the CSIDs of CollectionObject records that are related to a Movement record. * * @param movementCsid the CSID of a Movement record. * @param coreSession a repository session. * @throws ClientException * @return the CSIDs of the CollectionObject records, if any, which are related to the Movement * record. */ private Set<String> getCollectionObjectCsidsRelatedToMovement( String movementCsid, CoreSession coreSession) throws ClientException { Set<String> csids = new HashSet<>(); // Via an NXQL query, get a list of active relation records where: // * This movement record's CSID is the subject CSID of the relation, // and its object document type is a CollectionObject doctype; // or // * This movement record's CSID is the object CSID of the relation, // and its subject document type is a CollectionObject doctype. // // Some values below are hard-coded for readability, rather than // being obtained from constants. String query = String.format( "SELECT * FROM %1$s WHERE " // collectionspace_core:tenantId = 1 " + "(" + " (%2$s:subjectCsid = '%3$s' " + " AND %2$s:objectDocumentType = '%4$s') " + " OR " + " (%2$s:objectCsid = '%3$s' " + " AND %2$s:subjectDocumentType = '%4$s') " + ")" + ACTIVE_DOCUMENT_WHERE_CLAUSE_FRAGMENT, RELATION_DOCTYPE, RELATIONS_COMMON_SCHEMA, movementCsid, COLLECTIONOBJECT_DOCTYPE); DocumentModelList relationDocModels = coreSession.query(query); if (relationDocModels == null || relationDocModels.isEmpty()) { // Encountering a Movement record that is not related to any // CollectionObject is potentially a normal occurrence, so no // error messages are logged here when we stop handling this event. return csids; } // Iterate through the list of Relation records found and build // a list of CollectionObject CSIDs, by extracting the relevant CSIDs // from those Relation records. String csid; for (DocumentModel relationDocModel : relationDocModels) { csid = getCsidForDesiredDocTypeFromRelation( relationDocModel, COLLECTIONOBJECT_DOCTYPE, MOVEMENT_DOCTYPE); if (Tools.notBlank(csid)) { csids.add(csid); } } return csids; }
/** * Returns a document model for a record identified by a CSID. * * @param session a repository session. * @param collectionObjectCsid a CollectionObject identifier (CSID) * @return a document model for the record identified by the supplied CSID. */ protected static DocumentModel getDocModelFromCsid( CoreSession session, String collectionObjectCsid) { DocumentModelList collectionObjectDocModels = null; try { final String query = "SELECT * FROM " + NuxeoUtils.BASE_DOCUMENT_TYPE + " WHERE " + NuxeoUtils.getByNameWhereClause(collectionObjectCsid); collectionObjectDocModels = session.query(query); } catch (Exception e) { logger.warn("Exception in query to get document model for CollectionObject: ", e); } if (collectionObjectDocModels == null || collectionObjectDocModels.isEmpty()) { logger.warn("Could not get document models for CollectionObject(s)."); return null; } else if (collectionObjectDocModels.size() != 1) { logger.debug("Found more than 1 document with CSID=" + collectionObjectCsid); return null; } return collectionObjectDocModels.get(0); }
/** * Returns the most recent Movement record related to a CollectionObject. * * <p>This method currently returns the related Movement record with the latest (i.e. most recent * in time) Location Date field value. * * @param session a repository session. * @param collectionObjectCsid a CollectionObject identifier (CSID) * @throws ClientException * @return the most recent Movement record related to the CollectionObject identified by the * supplied CSID. */ protected static DocumentModel getMostRecentMovement( CoreSession session, String collectionObjectCsid) throws ClientException { DocumentModel mostRecentMovementDocModel = null; // Get Relation records for Movements related to this CollectionObject. // // Some values below are hard-coded for readability, rather than // being obtained from constants. String query = String.format( "SELECT * FROM %1$s WHERE " // collectionspace_core:tenantId = 1 " + "(" + " (%2$s:subjectCsid = '%3$s' " + " AND %2$s:objectDocumentType = '%4$s') " + " OR " + " (%2$s:objectCsid = '%3$s' " + " AND %2$s:subjectDocumentType = '%4$s') " + ")" + ACTIVE_DOCUMENT_WHERE_CLAUSE_FRAGMENT, RELATION_DOCTYPE, RELATIONS_COMMON_SCHEMA, collectionObjectCsid, MOVEMENT_DOCTYPE); if (logger.isTraceEnabled()) { logger.trace("query=" + query); } DocumentModelList relationDocModels = session.query(query); if (relationDocModels == null || relationDocModels.isEmpty()) { logger.warn( "Unexpectedly found no relations to Movement records to/from to this CollectionObject record."); return mostRecentMovementDocModel; } else { if (logger.isTraceEnabled()) { logger.trace( "Found " + relationDocModels.size() + " relations to Movement records to/from this CollectionObject record."); } } // Iterate through related movement records, to find the related // Movement record with the most recent location date. GregorianCalendar mostRecentLocationDate = EARLIEST_COMPARISON_DATE; // Note: the following value is used to compare any two records, rather // than to identify the most recent value so far encountered. Thus, it may // occasionally be set backward or forward in time, within the loop below. GregorianCalendar comparisonCreationDate = EARLIEST_COMPARISON_DATE; DocumentModel movementDocModel; Set<String> alreadyProcessedMovementCsids = new HashSet<>(); String relatedMovementCsid; for (DocumentModel relationDocModel : relationDocModels) { // Due to the 'OR' operator in the query above, related Movement // record CSIDs may reside in either the subject or object CSID fields // of the relation record. Whichever CSID value doesn't match the // CollectionObject's CSID is inferred to be the related Movement record's CSID. relatedMovementCsid = (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, SUBJECT_CSID_PROPERTY); if (relatedMovementCsid.equals(collectionObjectCsid)) { relatedMovementCsid = (String) relationDocModel.getProperty(RELATIONS_COMMON_SCHEMA, OBJECT_CSID_PROPERTY); } if (Tools.isBlank(relatedMovementCsid)) { continue; } // Because of the OR clause used in the query above, there may be // two or more Relation records returned in the query results that // reference the same Movement record, as either the subject // or object of a relation to the same CollectionObject record; // we need to filter out those duplicates. if (alreadyProcessedMovementCsids.contains(relatedMovementCsid)) { continue; } else { alreadyProcessedMovementCsids.add(relatedMovementCsid); } if (logger.isTraceEnabled()) { logger.trace("Related movement CSID=" + relatedMovementCsid); } movementDocModel = getDocModelFromCsid(session, relatedMovementCsid); if (movementDocModel == null) { continue; } // Verify that the Movement record is active. This will also exclude // versioned Movement records from the computation of the current // location, for tenants that are versioning such records. if (!isActiveDocument(movementDocModel)) { if (logger.isTraceEnabled()) { logger.trace("Skipping this inactive Movement record ..."); } continue; } GregorianCalendar locationDate = (GregorianCalendar) movementDocModel.getProperty(MOVEMENTS_COMMON_SCHEMA, LOCATION_DATE_PROPERTY); // If the current Movement record lacks a location date, it cannot // be established as the most recent Movement record; skip over it. if (locationDate == null) { continue; } GregorianCalendar creationDate = (GregorianCalendar) movementDocModel.getProperty(COLLECTIONSPACE_CORE_SCHEMA, CREATED_AT_PROPERTY); if (locationDate.after(mostRecentLocationDate)) { mostRecentLocationDate = locationDate; if (creationDate != null) { comparisonCreationDate = creationDate; } mostRecentMovementDocModel = movementDocModel; // If the current Movement record's location date is identical // to that of the (at this time) most recent Movement record, then // instead compare the two records using their creation date values } else if (locationDate.compareTo(mostRecentLocationDate) == 0) { if (creationDate != null && creationDate.after(comparisonCreationDate)) { // The most recent location date value doesn't need to be // updated here, as the two records' values are identical comparisonCreationDate = creationDate; mostRecentMovementDocModel = movementDocModel; } } } return mostRecentMovementDocModel; }