]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-5727: Added resources directory for listener, to store database function to...
authorAron Roberts <aron@socrates.berkeley.edu>
Thu, 6 Dec 2012 04:02:05 +0000 (20:02 -0800)
committerAron Roberts <aron@socrates.berkeley.edu>
Thu, 6 Dec 2012 04:02:05 +0000 (20:02 -0800)
3rdparty/nuxeo/nuxeo-platform-listener/updateobjectlocationonmove/src/main/java/org/collectionspace/services/listener/UpdateObjectLocationOnMove.java
3rdparty/nuxeo/nuxeo-platform-listener/updateobjectlocationonmove/src/main/resources/db/postgresql/computecurrentlocation.sql [new file with mode: 0644]

index 0b6b6914f9f4dab031b0ced5142ac41260ece5bc..3eb0290e7af058e55f2aff862d279b8ef296c902 100644 (file)
@@ -1,10 +1,22 @@
 package org.collectionspace.services.listener;
 
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+import javax.sql.DataSource;
+
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+
 import org.collectionspace.services.client.workflow.WorkflowClient;
 import org.collectionspace.services.common.api.Tools;
+import org.collectionspace.services.common.storage.DatabaseProductType;
+import org.collectionspace.services.common.storage.JDBCTools;
 import org.collectionspace.services.movement.nuxeo.MovementConstants;
+
 import org.nuxeo.ecm.core.api.ClientException;
 import org.nuxeo.ecm.core.api.DocumentModel;
 import org.nuxeo.ecm.core.event.Event;
@@ -17,12 +29,30 @@ public class UpdateObjectLocationOnMove implements EventListener {
     // FIXME: We might experiment here with using log4j instead of Apache Commons Logging;
     // am using the latter to follow Ray's pattern for now
     final Log logger = LogFactory.getLog(UpdateObjectLocationOnMove.class);
+    private final String DATABASE_RESOURCE_DIRECTORY_NAME = "db";
+    // FIXME: Currently hard-coded; get this from JDBC utilities or equivalent
+    private final String DATABASE_SYSTEM_NAME = "postgresql";
+    private final String STORED_FUNCTION_NAME = "computecurrentlocation";
 
+    // ####################################################################
+    // FIXME: Per Rick, what happens if a relation record is updated,
+    // that either adds or removes a relation between a Movement
+    // record and a CollectionObject record?  Do we need to listen
+    // for that event as well and update the CollectionObject record's
+    // computedCurrentLocation accordingly?
+    //
+    // The following code is currently checking only for creates or
+    // updates to Movement records.
+    // ####################################################################
     @Override
     public void handleEvent(Event event) throws ClientException {
 
         logger.trace("In handleEvent in UpdateObjectLocationOnMove ...");
 
+        // FIXME: Check for database product type here.
+        // If our database type is one for which we don't yet
+        // have tested SQL code to perform this operation, return here.
+
         EventContext eventContext = event.getContext();
         if (eventContext == null) {
             return;
@@ -31,51 +61,77 @@ public class UpdateObjectLocationOnMove implements EventListener {
         DocumentModel docModel = docEventContext.getSourceDocument();
         if (isMovementDocument(docModel) && isActiveDocument(docModel)) {
             logger.debug("A create or update event for an active Movement document was received by UpdateObjectLocationOnMove ...");
-            
+
             // Pseudocode:
+
+            // Test whether a SQL function exists to supply the computed
+            // current location of a CollectionObject.
+            if (storedFunctionExists(STORED_FUNCTION_NAME)) {
+                logger.debug("Stored function " + STORED_FUNCTION_NAME + "exists.");
+            } else {
+                logger.debug("Stored function " + STORED_FUNCTION_NAME + "does NOT exist.");
+            }
             
-            // Use a JDBC call to test whether a SQL function exists to
-            // supply the last identified location of a CollectionObject.
-            // If it does not, bail.
-            
-            // At the moment, that function is named lastIdentifiedLocation(),
-            // resides in the resources of the collectionobject.services module,
-            // and will be created in the database via the Ant 'create_nuxeo_db'
-            // target.
+            // FIXME: For incremental debugging, as we work through implementing
+            // this pseudocode.
+            return;
+
+            // If it does not, load the function from the resources available
+            // to this class, and run a JDBC command to create that function.
+
+            // At the moment, that function is named computeCurrentLocation(),
+            // and resides in the resources of the current module.
             //
             // For now, assume this function will exist in the 'nuxeo' database;
             // future work to create per-tenant repositories will likely require that
             // our JDBC statements connect to the appropriate tenant-specific database.
-            
+
+            // It doesn't appear we can create this function via 'ant create_nuxeo db'
+            // during the build process, because there's a substantial likelihood at
+            // that point that tables referred to by the function (movements_common
+            // and collectionobjects_common) will not exist, and PostgreSQL will not
+            // permit the function to be created if that is the case.
+
+            /*
+            ClassLoader classLoader = getClass().getClassLoader();
+            String functionResourcePath =
+                    DATABASE_RESOURCE_DIRECTORY_NAME + "/"
+                    + DATABASE_SYSTEM_NAME + "/"
+                    + STORED_FUNCTION_NAME + ".sql";
+            classLoader.getResourceAsStream(functionResourcePath);
+            */
+
+            // If the create attempt fails, bail (return) from this method.
+
             // Get this Movement record's CSID via the document model.
-            
+
             // Find every CollectionObject record related to this Movement record:
             //
             // Via an NXQL query, get a list of (non-deleted) relation records where:
             // * This movement record's CSID is the subject CSID of the relation.
             // * The object document type is a CollectionObject doctype.
-            
+
             // Iterate through that list of Relation records and build a list of
             // CollectionObject CSIDs, by extracting the object CSIDs of those records.
-            
+
             // For each such CollectionObject:
-            
+
             // Verify that the CollectionObject record is active (use isActiveDocument(), below).
-           
+
             // Via a JDBC call, invoke the SQL function to supply the last
             // identified location of that CollectionObject, giving it the CSID
             // of the CollectionObject record as an argument.
-            
+
             // Check that the SQL function's returned value, which is expected
             // to be a reference (refName) to a storage location authority term,
             // is at a minimum:
             // * Non-null
             // * Capable of being successfully parsed by an authority item parser,
             //   returning a non-null parse result.
-            
+
             // Compare that returned value to the value in the
             // lastIdentifiedLocation field of that CollectionObject
-            
+
             // If the two values differ, update the CollectionObject record,
             // setting the value of the lastIdentifiedLocation field of that
             // CollectionObject record to the value returned from the SQL function.
@@ -92,19 +148,18 @@ public class UpdateObjectLocationOnMove implements EventListener {
     private boolean isMovementDocument(DocumentModel docModel) {
         return documentMatchesType(docModel, MovementConstants.NUXEO_DOCTYPE);
     }
-    
+
     // FIXME: Generic methods like the following might be split off
     // into an event utilities class. - ADR 2012-12-05
-    
     // FIXME: Identify whether the equivalent of this utility method is
     // already implemented and substitute a call to the latter if so.
-    
     /**
      * Identifies whether a document matches a supplied document type.
      *
      * @param docModel a document model.
      * @param docType a document type string.
-     * @return true if the document matches the supplied document type; false if it does not.
+     * @return true if the document matches the supplied document type; false if
+     * it does not.
      */
     private boolean documentMatchesType(DocumentModel docModel, String docType) {
         if (docModel == null || Tools.isBlank(docType)) {
@@ -145,4 +200,45 @@ public class UpdateObjectLocationOnMove implements EventListener {
         }
         return isActiveDocument;
     }
-}
+
+    private boolean storedFunctionExists(String functionname) {
+        if (Tools.isBlank(functionname)) {
+            return false;
+        }
+
+        boolean storedFunctionExists = false;
+        String sql = "SELECT proname FROM pg_proc WHERE proname='" + functionname + "'";
+        Connection conn = null;
+        Statement stmt = null;
+        ResultSet rs = null;
+
+        try {
+            conn = JDBCTools.getConnection(JDBCTools.getDataSource(JDBCTools.NUXEO_REPOSITORY_NAME));
+            stmt = conn.createStatement();
+            rs = stmt.executeQuery(sql);
+            if (rs.next()) {
+                storedFunctionExists = true;
+            }
+            rs.close();
+            stmt.close();
+            conn.close();
+        } catch (Exception e) {
+            logger.debug("Error when identifying whether stored function " + functionname + "exists :", e);
+        } finally {
+            try {
+                if (rs != null) {
+                    rs.close();
+                }
+                if (stmt != null) {
+                    stmt.close();
+                }
+                if (conn != null) {
+                    conn.close();
+                }
+            } catch (SQLException sqle) {
+                logger.debug("SQL Exception closing statement/connection in UpdateObjectLocationOnMove.storedFunctionExists: " + sqle.getLocalizedMessage());
+            }
+        }
+        return storedFunctionExists;
+    }
+}
\ No newline at end of file
diff --git a/3rdparty/nuxeo/nuxeo-platform-listener/updateobjectlocationonmove/src/main/resources/db/postgresql/computecurrentlocation.sql b/3rdparty/nuxeo/nuxeo-platform-listener/updateobjectlocationonmove/src/main/resources/db/postgresql/computecurrentlocation.sql
new file mode 100644 (file)
index 0000000..d48e8b8
--- /dev/null
@@ -0,0 +1,24 @@
+CREATE OR REPLACE FUNCTION computecurrentlocation(character varying) RETURNS character varying
+    AS 'select m.currentlocation as computedcurrentlocation
+from movements_common m,
+hierarchy h1, 
+relations_common r, 
+hierarchy h2,
+collectionobjects_common c,
+misc misc
+where m.id=h1.id
+and r.subjectcsid=h1.name
+and r.subjectdocumenttype=''Movement''
+and r.objectdocumenttype=''CollectionObject''
+and r.objectcsid=h2.name 
+and h2.id=c.id
+and misc.id = c.id
+and misc.lifecyclestate <> ''deleted''
+and m.currentlocation is not null
+and m.locationdate is not null
+and h2.name=$1
+order by m.locationdate desc,row_number() over(order by locationdate)
+limit 1'
+LANGUAGE SQL
+    IMMUTABLE
+    RETURNS NULL ON NULL INPUT;