]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5728: Further work toward retrieving a list of related Movement records, for...
authorAron Roberts <aron@socrates.berkeley.edu>
Tue, 8 Jan 2013 04:50:58 +0000 (20:50 -0800)
committerAron Roberts <aron@socrates.berkeley.edu>
Tue, 8 Jan 2013 04:50:58 +0000 (20:50 -0800)
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/batch-update-object-loc.xml
services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/movement1-with-relation.xml [new file with mode: 0644]
services/batch/service/pom.xml
services/batch/service/src/main/java/org/collectionspace/services/batch/nuxeo/UpdateObjectLocationBatchJob.java

index dccb500b2de7418ed78a9421d8e20117124db976..9e45a6277d723cdb2c5904a6d736161cf61be8ac 100644 (file)
@@ -7,7 +7,7 @@
         \r
     <!-- This tests the UpdateObjectLocationBatchJob -->\r
         \r
-    <testGroup ID="testSingleRecordBatchUpdate" autoDeletePOSTS="true">\r
+    <testGroup ID="testSingleRecordBatchUpdate" autoDeletePOSTS="false">\r
             \r
         <test ID="createBatchRecord">\r
             <method>POST</method>\r
             <filename>batch/collObj1.xml</filename>\r
         </test>\r
         \r
+        <test ID="createMovement1WithRelationToCollectionObject">\r
+            <method>POST</method>\r
+            <uri>/cspace-services/movements</uri>\r
+            <filename>batch/movement1-with-relation.xml</filename>\r
+            <vars>\r
+                <var ID="currentLocation">location-1</var>\r
+                <var ID="locationDate">1900-01-01</var>\r
+                <var ID="relatedCollectionObjectCSID">${createCollectionObject.CSID}</var>\r
+            </vars>\r
+        </test>\r
+        \r
+        <test ID="createMovement2WithRelationToCollectionObject">\r
+            <method>POST</method>\r
+            <uri>/cspace-services/movements</uri>\r
+            <filename>batch/movement1-with-relation.xml</filename>\r
+            <vars>\r
+                <var ID="currentLocation">location-2</var>\r
+                <var ID="locationDate">2000-01-01</var>\r
+                <var ID="relatedCollectionObjectCSID">${createCollectionObject.CSID}</var>\r
+            </vars>\r
+        </test>\r
+        \r
         <!-- This post of a batch job invocation request doesn't create a new record, -->\r
         <!-- so we need to exclude it from the post-run auto-deletion of records. -->\r
         <test ID="invokeBatch" auth="test" autoDeletePOSTS="false">\r
diff --git a/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/movement1-with-relation.xml b/services/IntegrationTests/src/test/resources/test-data/xmlreplay/batch/movement1-with-relation.xml
new file mode 100644 (file)
index 0000000..416bce6
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<document name="movements">
+
+    <ns2:movements_common
+        xmlns:ns2="http://collectionspace.org/services/movement">
+        <currentLocation>${currentLocation}</currentLocation>
+        <locationDate>${locationDate}</locationDate>
+    </ns2:movements_common>
+
+    <ns3:relations-common-list xmlns:ns3="http://collectionspace.org/services/relation"
+                               xmlns:ns2="http://collectionspace.org/services/jaxb">
+        <!-- 
+             ${itemCSID} is a convention understood by the Relations service,
+             which is replaced by the CSID of the item being created.  (This
+             applies to all items, including object and procedural records,
+             not just to authority item records).
+             
+             As such, ${itemCSID} does NOT get expanded by XmlReplay. 
+             It passes through, and then the service deals with it.
+        -->
+        <relation-list-item>
+            <!-- The item being created, above ... -->
+            <subject>
+                <csid>${itemCSID}</csid>
+                <documentType>Movement</documentType>
+            </subject>
+            <!-- ... has an 'affects' relationship to ... -->
+            <predicate>affects</predicate>
+            <!-- ... its related item -->
+            <object>
+                <csid>${relatedCollectionObjectCSID}</csid>
+                <documentType>CollectionObject</documentType>
+            </object>
+        </relation-list-item>
+        
+    </ns3:relations-common-list>
+</document>
+
+
index 0942dac4ba3359a28b66100a84495c77e3ab8a00..49bebb0f201ccfd4fa113394b0dc3b5f460335de 100644 (file)
             <artifactId>org.collectionspace.services.batch.client</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.batch.jaxb</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.collectionspace.services</groupId>
             <artifactId>org.collectionspace.services.collectionobject.client</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.collectionspace.services</groupId>
+            <artifactId>org.collectionspace.services.collectionobject.jaxb</artifactId> <!-- FIXME: REM - Is this really a required dependency? -->
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.collectionspace.services</groupId>
             <artifactId>org.collectionspace.services.loanout.client</artifactId>
         </dependency>
         <dependency>
             <groupId>org.collectionspace.services</groupId>
-            <artifactId>org.collectionspace.services.relation.client</artifactId>
+            <artifactId>org.collectionspace.services.movement.client</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
             <groupId>org.collectionspace.services</groupId>
-            <artifactId>org.collectionspace.services.batch.jaxb</artifactId>
+            <artifactId>org.collectionspace.services.movement.service</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
             <groupId>org.collectionspace.services</groupId>
-            <artifactId>org.collectionspace.services.collectionobject.jaxb</artifactId> <!-- FIXME: REM - Is this really a required dependency? -->
+            <artifactId>org.collectionspace.services.relation.client</artifactId>
             <version>${project.version}</version>
         </dependency>
         <!-- External dependencies -->        
@@ -66,7 +76,7 @@
             <artifactId>testng</artifactId>
         </dependency>
         
-      <!-- javax -->
+        <!-- javax -->
 
         <dependency>
             <groupId>javax.security</groupId>
index 66d94d929594716e2517d0d8a1e53d6537230d08..def2a3d0bc15538d3d125bed4f6ef5ea276324a0 100644 (file)
@@ -9,23 +9,30 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import javax.ws.rs.core.PathSegment;
-import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriInfo;
 import org.collectionspace.services.batch.AbstractBatchInvocable;
 import org.collectionspace.services.client.CollectionObjectClient;
-import org.collectionspace.services.client.CollectionSpaceClientUtils;
+import org.collectionspace.services.client.MovementClient;
 import org.collectionspace.services.client.PayloadOutputPart;
 import org.collectionspace.services.client.PoxPayloadOut;
+import org.collectionspace.services.client.RelationClient;
 import org.collectionspace.services.common.ResourceBase;
 import org.collectionspace.services.common.ResourceMap;
 import org.collectionspace.services.common.api.Tools;
 import org.collectionspace.services.common.invocable.InvocationResults;
+import org.collectionspace.services.jaxb.AbstractCommonList;
+import org.collectionspace.services.movement.nuxeo.MovementConstants;
+import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;
+import org.collectionspace.services.nuxeo.util.NuxeoUtils;
+
 import org.dom4j.DocumentException;
 import org.dom4j.DocumentHelper;
 import org.dom4j.Element;
 import org.dom4j.Node;
 import org.dom4j.XPath;
 import org.jboss.resteasy.specimpl.UriInfoImpl;
+import org.nuxeo.ecm.core.api.DocumentModel;
+import org.nuxeo.ecm.core.api.DocumentModelList;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -34,6 +41,17 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
     // FIXME; Get from existing constants and replace these local declarations
     final static String COLLECTIONOBJECTS_COMMON_SCHEMA_NAME = "collectionobjects_common";
     final static String OBJECT_NUMBER_FIELD_NAME = "objectNumber";
+    private final static String RELATIONS_COMMON_SCHEMA = "relations_common"; // FIXME: Get from external constant
+    private final static String RELATION_DOCTYPE = "Relation"; // FIXME: Get from external constant
+    private final static String SUBJECT_CSID_PROPERTY = "subjectCsid"; // FIXME: Get from external constant
+    private final static String OBJECT_CSID_PROPERTY = "objectCsid"; // FIXME: Get from external constant
+    private final static String SUBJECT_DOCTYPE_PROPERTY = "subjectDocumentType"; // FIXME: Get from external constant
+    private final static String OBJECT_DOCTYPE_PROPERTY = "objectDocumentType"; // FIXME: Get from external constant
+    protected final static String COLLECTIONOBJECTS_COMMON_SCHEMA = "collectionobjects_common"; // FIXME: Get from external constant
+    private final static String COLLECTIONOBJECT_DOCTYPE = "CollectionObject"; // FIXME: Get from external constant
+    protected final static String COMPUTED_CURRENT_LOCATION_PROPERTY = "computedCurrentLocation"; // FIXME: Create and then get from external constant
+    protected final static String MOVEMENTS_COMMON_SCHEMA = "movements_common"; // FIXME: Get from external constant
+    private final static String MOVEMENT_DOCTYPE = MovementConstants.NUXEO_DOCTYPE;
     private InvocationResults results = new InvocationResults();
     final String CLASSNAME = this.getClass().getSimpleName();
     final Logger logger = LoggerFactory.getLogger(UpdateObjectLocationBatchJob.class);
@@ -48,20 +66,20 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
      */
     @Override
     public void run() {
-        
+
         setCompletionStatus(STATUS_MIN_PROGRESS);
-        
+
         try {
             // FIXME: Placeholder during early development
             if (logger.isInfoEnabled()) {
                 logger.info("Invoking " + CLASSNAME + " ...");
                 logger.info("Invocation context is: " + getInvocationContext().getMode());
             }
-            
+
             if (!requestedInvocationModeIsSupported()) {
                 setInvocationModeNotSupportedResult();
             }
-            
+
             List<String> csids = new ArrayList<String>();
             if (requestIsForInvocationModeSingle()) {
                 String singleCsid = getInvocationContext().getSingleCSID();
@@ -79,7 +97,7 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
                 // FIXME: Get individual CSIDs from the group
                 // and add them to the list
             }
-            
+
             if (csids.isEmpty()) {
                 throw new Exception(CSID_VALUES_NOT_PROVIDED_IN_INVOCATION_CONTEXT_MESSAGE);
             }
@@ -87,12 +105,12 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
             // Update the current computed location field for each CollectionObject
             setResults(updateComputedCurrentLocations(csids));
             setCompletionStatus(STATUS_COMPLETE);
-            
+
         } catch (Exception e) {
             String errMsg = "Error encountered in " + CLASSNAME + ": " + e.getLocalizedMessage();
             setErrorResult(errMsg);
         }
-        
+
     }
 
     // Ray's convenience methods from his AbstractBatchJob class for the UC Berkeley Botanical Garden v2.4 implementation.
@@ -100,107 +118,190 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
         ResourceBase resource = getResourceMap().get(serviceName);
         return findByCsid(resource, csid);
     }
-    
+
     protected PoxPayloadOut findByCsid(ResourceBase resource, String csid) throws URISyntaxException, DocumentException {
         byte[] response = resource.get(null, createUriInfo(), csid);
         PoxPayloadOut payload = new PoxPayloadOut(response);
         return payload;
     }
-    
+
     protected UriInfo createUriInfo() throws URISyntaxException {
         return createUriInfo("");
     }
-    
+
     protected UriInfo createUriInfo(String queryString) throws URISyntaxException {
         URI absolutePath = new URI("");
         URI baseUri = new URI("");
         return new UriInfoImpl(absolutePath, baseUri, "", queryString, Collections.<PathSegment>emptyList());
     }
 
+    protected UriInfo createRelationSearchUriInfo(String subjectCsid, String objType) throws URISyntaxException {
+        String queryString = "sbj=" + subjectCsid + "&objType=" + objType;
+        URI uri = new URI(null, null, null, queryString, null);
+        return createUriInfo(uri.getRawQuery());
+    }
+
     /**
-     * Get a field value from a PoxPayloadOut, given a part name and namespace-qualified xpath
-     * expression.
+     * Get a field value from a PoxPayloadOut, given a part name and
+     * namespace-qualified xpath expression.
      */
     protected String getFieldValue(PoxPayloadOut payload, String partLabel, String namespacePrefix, String namespace, String fieldPath) {
         String value = null;
         PayloadOutputPart part = payload.getPart(partLabel);
-        
+
         if (part != null) {
             Element element = part.asElement();
             logger.info(partLabel + " part element =" + element.asXML());
 
-            Map<String, String> namespaceUris = new HashMap<String, String>();            
-            namespaceUris.put(namespacePrefix, namespace);          
-            
-            XPath xPath = DocumentHelper.createXPath(fieldPath);            
-            xPath.setNamespaceURIs(namespaceUris);            
-            
+            Map<String, String> namespaceUris = new HashMap<String, String>();
+            namespaceUris.put(namespacePrefix, namespace);
+
+            XPath xPath = DocumentHelper.createXPath(fieldPath);
+            xPath.setNamespaceURIs(namespaceUris);
+
             Node node = xPath.selectSingleNode(element);
             // Node node = element.selectSingleNode(fieldPath);
-            
+
             if (node != null) {
                 value = node.getText();
             }
         }
-        
+
         return value;
     }
-    
+
     protected List<String> getFieldValues(PoxPayloadOut payload, String partLabel, String fieldPath) {
         List<String> values = new ArrayList<String>();
         PayloadOutputPart part = payload.getPart(partLabel);
-        
+
         if (part != null) {
             Element element = part.asElement();
             List<Node> nodes = element.selectNodes(fieldPath);
-            
+
             if (nodes != null) {
                 for (Node node : nodes) {
                     values.add(node.getText());
                 }
             }
         }
-        
+
         return values;
     }
-    
+
     private InvocationResults updateComputedCurrentLocations(List<String> csids) {
-        
+
         ResourceMap resourcemap = getResourceMap();
         ResourceBase collectionObjectResource = resourcemap.get(CollectionObjectClient.SERVICE_NAME);
+        ResourceBase movementResource = resourcemap.get(MovementClient.SERVICE_NAME);
         PoxPayloadOut collectionObjectPayload;
         String objectNumber;
         String computedCurrentLocation;
         int numAffected = 0;
         // FIXME: Temporary during testing/development
         final String COMPUTED_CURRENT_LOCATION = "FOO_COMPUTED_CURRENT_LOCATION";
-        
+
         try {
 
             // For each CollectionObject record:
             for (String csid : csids) {
+
                 // Get the movement records related to this record
+
+                // FIXME: Create a convenience method for constructing queries like the following
+                String queryString = "rtObj=" + csid;
+                URI uri = new URI(null, null, null, queryString, null);
+                UriInfo uriInfo = createUriInfo(uri.getRawQuery());
+
+                AbstractCommonList relatedMovements = movementResource.getList(uriInfo);
+                if (logger.isInfoEnabled()) {
+                    logger.info("Identified " + relatedMovements.getTotalItems()
+                            + " movement records related to CollectionObject record " + csid);
+                }
+                if (relatedMovements.getTotalItems() == 0) {
+                    // continue;
+                }
+                
+                /*
+                 * Query resulting from the above:
+                 * Executing CMIS query: SELECT DOC.nuxeo:pathSegment, DOC.dc:title,
+                 * REL.dc:title, REL.relations_common:objectCsid, REL.relations_common:subjectCsid
+                 * FROM Movement DOC JOIN Relation REL ON REL.relations_common:subjectCsid = DOC.nuxeo:pathSegment
+                 * WHERE REL.relations_common:objectCsid = 'c0bdd018-01c1-412a-bc21' AND
+                 * DOC.nuxeo:isVersion = false ORDER BY DOC.collectionspace_core:updatedAt
+                 */
+
+                // FIXME: Get the reciprocal relation records, via rtSbj=, as well,
+                // and remove duplicates
+
+                // FIXME Temporary for testing
+                queryString = "rtSbj=" + csid;
+                uri = new URI(null, null, null, queryString, null);
+                uriInfo = createUriInfo(uri.getRawQuery());
+
+                relatedMovements = movementResource.getList(uriInfo);
+                if (logger.isInfoEnabled()) {
+                    logger.info("Identified " + relatedMovements.getTotalItems()
+                            + " movement records related to CollectionObject record " + csid);
+                }
+                if (relatedMovements.getTotalItems() == 0) {
+                    continue;
+                }
+                
+                /*
+                 * Query resulting from the above:
+                 * Executing CMIS query: SELECT DOC.nuxeo:pathSegment, DOC.dc:title,
+                 * REL.dc:title, REL.relations_common:objectCsid, REL.relations_common:subjectCsid
+                 * FROM Movement DOC JOIN Relation REL ON REL.relations_common:objectCsid = DOC.nuxeo:pathSegment
+                 * WHERE REL.relations_common:subjectCsid = '7db3c206-3a3c-4f5c-8155' AND
+                 * DOC.nuxeo:isVersion = false ORDER BY DOC.collectionspace_core:updatedAt DESC
+                 */
+
+
+                /*
+                 // FIXME: Similar to RelationsUtils.buildWhereClause()
+                 // We might consider adding a 'bidirectional where clause' like the following there.
+
+                 String query = String.format(
+                 "SELECT * FROM %1$s WHERE " // collectionspace_core:tenantId =  "
+                 + "("
+                 + "  (%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, csid, MOVEMENT_DOCTYPE);
+
+                 relationResource.getList(uriInfo);
+                 query = NuxeoUtils.buildNXQLQuery(csids, null);
+                 DocumentModelList relationDocModels = coreSession.query(query);
+                 */
+
                 // Get the latest movement record from among those
+
                 // Extract its current location value
+
                 // FIXME: Temporary during testing/development
                 computedCurrentLocation = COMPUTED_CURRENT_LOCATION;
+
                 // Update the computed current location value in the CollectionObject record
                 collectionObjectPayload = findByCsid(collectionObjectResource, csid);
                 if (Tools.notBlank(collectionObjectPayload.toXML())) {
                     if (logger.isInfoEnabled()) {
                         logger.info("Payload: " + "\n" + collectionObjectPayload);
                     }
-                    // Silenly fails at various places in dom4j calls (selectSingleNode, selectNode,
+                    // Silently fails at various places in dom4j calls (selectSingleNode, selectNode,
                     // createXpath) in any of the methods tried above, without throwing an Exception
                     /*
-                    objectNumber = getFieldValue(collectionObjectPayload,
-                            COLLECTIONOBJECTS_COMMON_SCHEMA_NAME,
-                            "ns2", "http://collectionspace.org/services/collectionobject",
-                            OBJECT_NUMBER_FIELD_NAME);
-                    if (logger.isInfoEnabled()) {
-                        logger.info("Object number: " + objectNumber);
-                    }
-                    */
+                     objectNumber = getFieldValue(collectionObjectPayload,
+                     COLLECTIONOBJECTS_COMMON_SCHEMA_NAME,
+                     "ns2", "http://collectionspace.org/services/collectionobject",
+                     OBJECT_NUMBER_FIELD_NAME);
+                     if (logger.isInfoEnabled()) {
+                     logger.info("Object number: " + objectNumber);
+                     }
+                     */
                     objectNumber = "BAR"; // FIXME
                     if (Tools.notBlank(objectNumber)) {
                         String collectionObjectUpdatePayload =
@@ -214,26 +315,25 @@ public class UpdateObjectLocationBatchJob extends AbstractBatchInvocable {
                             logger.info("Update payload: " + "\n" + collectionObjectUpdatePayload);
                         }
                         byte[] response = collectionObjectResource.update(resourcemap, null, csid, collectionObjectUpdatePayload);
-                        /*
-                         * if (response.getStatus() != OK_STATUS) {
-                         String errMsg = "Error encountered in " + CLASSNAME + ": " + "Updating CollectionObject failed.";
-                         setErrorResult(errMsg);
-                         } else {
-                         results.setUserNote("Computed current location value for CollectionObject " + csid + " set to " + computedCurrentLocation);
-                         numAffected++;
-                         }
-                         */
+                        numAffected++;
+                        if (logger.isTraceEnabled()) {
+                            logger.trace("Computed current location value for CollectionObject " + csid + " set to " + computedCurrentLocation);
+
+                        }
                     }
-                    
+
                 }
             }
         } catch (Exception e) {
-            String errMsg = "Error encountered in " + CLASSNAME + ": " + e.getLocalizedMessage();
+            String errMsg = "Error encountered in " + CLASSNAME + ": " + e.getLocalizedMessage() + " ";
+            errMsg = errMsg + "Successfully updated " + numAffected + " CollectionObject record(s) prior to error.";
             setErrorResult(errMsg);
             getResults().setNumAffected(numAffected);
             return getResults();
         }
-        getResults().setNumAffected(numAffected);
+
+        getResults()
+                .setNumAffected(numAffected);
         return getResults();
     }
 }