]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-4234, CSPACE-4106 Added support to filter Reports by doctype and invocation...
authorPatrick Schmitz <pschmitz@berkeley.edu>
Tue, 19 Jul 2011 00:58:21 +0000 (00:58 +0000)
committerPatrick Schmitz <pschmitz@berkeley.edu>
Tue, 19 Jul 2011 00:58:21 +0000 (00:58 +0000)
services/IntegrationTests/src/test/resources/test-data/xmlreplay/xml-replay-master.xml
services/client/src/main/java/org/collectionspace/services/client/IQueryManager.java
services/common/src/main/java/org/collectionspace/services/common/invocable/InvocableUtils.java [new file with mode: 0644]
services/common/src/main/java/org/collectionspace/services/common/query/QueryManager.java
services/common/src/main/java/org/collectionspace/services/common/query/nuxeo/QueryManagerNuxeoImpl.java
services/report/client/src/main/java/org/collectionspace/services/client/ReportClient.java
services/report/client/src/main/java/org/collectionspace/services/client/ReportProxy.java
services/report/client/src/test/java/org/collectionspace/services/client/test/ReportServiceTest.java
services/report/service/src/main/java/org/collectionspace/services/report/ReportResource.java

index 48d1af5f401283e0a952527cfe05398a22f37fda..d6fb9eface981c9fe7170cfc489ee6db40227efd 100755 (executable)
@@ -47,6 +47,7 @@
     <run controlFile="location/location-hierarchy.xml" testGroup="HierarchicLocation" />\r
     <run controlFile="organization/organization-hierarchy.xml" testGroup="HierarchicOrganization" />\r
     <run controlFile="batch/batch.xml" />\r
+    <run controlFile="report/report.xml" />\r
     <run controlFile="vocabulary/vocabulary.xml" testGroup="TestOrder" />\r
     \r
 </xmlReplayMaster>\r
index 7775b8363d52fe65333e884531bd0c7c44746de9..a117cbe5e9193a908d8650f8015292d483eb45a0 100644 (file)
@@ -37,6 +37,7 @@ public interface IQueryManager {
     final static String SEARCH_TYPE_KEYWORDS_KW = "kw";\r
     final static String SEARCH_TYPE_PARTIALTERM = "pt";\r
     final static String SEARCH_TYPE_DOCTYPE = "doctype";\r
+    final static String SEARCH_TYPE_INVCOATION_MODE = "mode";\r
     final static String SEARCH_TYPE_INVOCATION = "inv";\r
        final static String SEARCH_QUALIFIER_AND = SEARCH_TERM_SEPARATOR + "AND" + SEARCH_TERM_SEPARATOR;\r
        final static String SEARCH_QUALIFIER_OR = SEARCH_TERM_SEPARATOR + "OR" + SEARCH_TERM_SEPARATOR;\r
@@ -62,4 +63,24 @@ public interface IQueryManager {
         */\r
        public String createWhereClauseForPartialMatch(String field, String partialTerm);\r
 \r
+       /**\r
+        * Creates a filtering where clause from docType, for invocables.\r
+        * \r
+        * @param schema the schema name for this invocable type\r
+        * @param docType the docType\r
+        * \r
+        * @return the string\r
+        */\r
+       public String createWhereClauseForInvocableByDocType(String schema, String docType);\r
+       \r
+       /**\r
+        * Creates a filtering where clause from invocation mode, for invocables.\r
+        * \r
+        * @param schema the schema name for this invocable type\r
+        * @param mode the mode\r
+        * \r
+        * @return the string\r
+        */\r
+       public String createWhereClauseForInvocableByMode(String schema, String mode);\r
+       \r
 }\r
diff --git a/services/common/src/main/java/org/collectionspace/services/common/invocable/InvocableUtils.java b/services/common/src/main/java/org/collectionspace/services/common/invocable/InvocableUtils.java
new file mode 100644 (file)
index 0000000..3f8d969
--- /dev/null
@@ -0,0 +1,32 @@
+package org.collectionspace.services.common.invocable;\r
+\r
+import org.collectionspace.services.jaxb.InvocableJAXBSchema;\r
+\r
+public class InvocableUtils {\r
+\r
+       /**\r
+        * Returns the standard property name for an invocable schema, given\r
+        * and invocation mode string.\r
+        * @param schema If not null, the returned property name will be qualified with\r
+        *                                      this schema name.\r
+        * @param invocationMode one of Invocable.INVOCATION_MODE_*\r
+        * @return\r
+        */\r
+       public static String getPropertyNameForInvocationMode(String schema, String invocationMode) {\r
+               String modeProperty = null;\r
+               if(Invocable.INVOCATION_MODE_SINGLE.equalsIgnoreCase(invocationMode)) {\r
+                       modeProperty = InvocableJAXBSchema.SUPPORTS_SINGLE_DOC;\r
+               } else if(Invocable.INVOCATION_MODE_LIST.equalsIgnoreCase(invocationMode)) {\r
+                       modeProperty = InvocableJAXBSchema.SUPPORTS_DOC_LIST;\r
+               } else if(Invocable.INVOCATION_MODE_GROUP.equalsIgnoreCase(invocationMode)) {\r
+                       modeProperty = InvocableJAXBSchema.SUPPORTS_GROUP;\r
+               } else if(Invocable.INVOCATION_MODE_NO_CONTEXT.equalsIgnoreCase(invocationMode)) {\r
+                       modeProperty = InvocableJAXBSchema.SUPPORTS_NO_CONTEXT;\r
+               } else {\r
+                       throw new IllegalArgumentException("QueryManagerNuxeoImpl: unknown Invocation Mode: "\r
+                               +invocationMode);\r
+               }\r
+               return (schema!=null)? (schema+":"+modeProperty):modeProperty;\r
+       }\r
+\r
+}\r
index ee76beb4834280f8a1a7c53ef22745e94ebc4f32..cf88207f09108ff40c634e34c0043fc197122b8d 100644 (file)
@@ -59,4 +59,28 @@ public class QueryManager {
                return queryManager.createWhereClauseForPartialMatch(field, partialTerm);\r
        }\r
        \r
+       /**\r
+        * Creates a filtering where clause from docType, for invocables.\r
+        * \r
+        * @param schema the schema name for this invocable type\r
+        * @param docType the docType\r
+        * \r
+        * @return the string\r
+        */\r
+       static public String createWhereClauseForInvocableByDocType(String schema, String docType) {\r
+               return queryManager.createWhereClauseForInvocableByDocType(schema, docType);\r
+       }\r
+       \r
+       /**\r
+        * Creates a filtering where clause from invocation mode, for invocables.\r
+        * \r
+        * @param schema the schema name for this invocable type\r
+        * @param mode the mode\r
+        * \r
+        * @return the string\r
+        */\r
+       static public String createWhereClauseForInvocableByMode(String schema, String mode) {\r
+               return queryManager.createWhereClauseForInvocableByMode(schema, mode);\r
+       }\r
+       \r
 }\r
index 9d268b0f3d3acba484c91800110a0eb5ab471af4..5117e8d90547f3ca7665ce6ca86a463418edad6f 100644 (file)
@@ -36,9 +36,11 @@ import org.nuxeo.ecm.core.api.DocumentModelList;
 import org.nuxeo.ecm.core.api.repository.RepositoryInstance;\r
 import org.nuxeo.ecm.core.client.NuxeoClient;\r
 \r
+import org.collectionspace.services.jaxb.InvocableJAXBSchema;\r
 import org.collectionspace.services.nuxeo.client.java.NuxeoConnector;\r
-import org.collectionspace.services.nuxeo.client.java.RepositoryJavaClientImpl;\r
 import org.collectionspace.services.client.IQueryManager;\r
+import org.collectionspace.services.common.invocable.Invocable;\r
+import org.collectionspace.services.common.invocable.InvocableUtils;\r
 import org.collectionspace.services.common.storage.DatabaseProductType;\r
 import org.collectionspace.services.common.storage.JDBCTools;\r
 \r
@@ -55,6 +57,8 @@ public class QueryManagerNuxeoImpl implements IQueryManager {
        private static Pattern nonWordChars = Pattern.compile("[^\\p{L}\\p{M}\\p{N}_']");\r
        private static Pattern unescapedDblQuotes = Pattern.compile("(?<!\\\\)\"");\r
        private static Pattern unescapedSingleQuote = Pattern.compile("(?<!\\\\)'");\r
+       private static Pattern kwdSearchProblemChars = Pattern.compile("[\\:\\(\\)]");\r
+       private static Pattern kwdSearchHyphen = Pattern.compile(" - ");\r
        \r
        private static String getLikeForm() {\r
                if(SEARCH_LIKE_FORM == null) {\r
@@ -135,11 +139,16 @@ public class QueryManagerNuxeoImpl implements IQueryManager {
                        // and escaping single quotes. Can return a boolean for anything stripped,\r
                        // which triggers the back-up search. We can think about whether stripping\r
                        // short words not in a quoted phrase should trigger the backup.\r
-                       fullTextWhereClause.append(unescapedSingleQuote.matcher(trimmed).replaceAll("\\\\'"));\r
+                       trimmed = unescapedSingleQuote.matcher(trimmed).replaceAll("\\\\'");\r
                        // If there are non-word chars in the phrase, we need to match the\r
                        // phrase exactly against the fulltext table for this object\r
                        //if(nonWordChars.matcher(trimmed).matches()) {\r
                        //}\r
+                       // Replace problem chars with spaces. Patches CSPACE-4147, CSPACE-4106 \r
+                       trimmed = kwdSearchProblemChars.matcher(trimmed).replaceAll(" ");\r
+                       trimmed = kwdSearchHyphen.matcher(trimmed).replaceAll(" ");\r
+\r
+                       fullTextWhereClause.append(trimmed);\r
                        if (logger.isTraceEnabled() == true) {\r
                                logger.trace("Current built whereClause is: " + fullTextWhereClause.toString());\r
                        }\r
@@ -180,7 +189,46 @@ public class QueryManagerNuxeoImpl implements IQueryManager {
                return ptClause;\r
        }\r
 \r
-\r
+       /**\r
+        * Creates a filtering where clause from docType, for invocables.\r
+        * \r
+        * @param docType the docType\r
+        * \r
+        * @return the string\r
+        */\r
+       public String createWhereClauseForInvocableByDocType(String schema, String docType) {\r
+               String trimmed = (docType == null)?"":docType.trim(); \r
+               if (trimmed.isEmpty()) {\r
+                       throw new RuntimeException("No docType specified.");\r
+               }\r
+               if (schema==null || schema.isEmpty()) {\r
+                       throw new RuntimeException("No match schema specified.");\r
+               }\r
+               String wClause = schema+":"+InvocableJAXBSchema.FOR_DOC_TYPE + " = '" + trimmed + "'";\r
+               return wClause;\r
+       }\r
+       \r
+       /**\r
+        * Creates a filtering where clause from invocation mode, for invocables.\r
+        * \r
+        * @param mode the mode\r
+        * \r
+        * @return the string\r
+        */\r
+       public String createWhereClauseForInvocableByMode(String schema, String mode) {\r
+               String trimmed = (mode == null)?"":mode.trim(); \r
+               if (trimmed.isEmpty()) {\r
+                       throw new RuntimeException("No docType specified.");\r
+               }\r
+               if (schema==null || schema.isEmpty()) {\r
+                       throw new RuntimeException("No match schema specified.");\r
+               }\r
+               String wClause = \r
+                       InvocableUtils.getPropertyNameForInvocationMode(schema, trimmed)\r
+                       + " != 0";\r
+               return wClause;\r
+       }\r
+       \r
        \r
        /**\r
         * @param input\r
index bcd845086100dd29647ea6ea2f8ca299e236cf20..d919d307a9dcda22b7f775631819ec89f17d2b4b 100644 (file)
@@ -27,6 +27,8 @@
 package org.collectionspace.services.client;
 
 //import org.collectionspace.services.common.context.ServiceContext;
+import javax.ws.rs.QueryParam;
+
 import org.collectionspace.services.report.ReportsCommonList;
 import org.jboss.resteasy.client.ClientResponse;
 
@@ -69,4 +71,13 @@ public class ReportClient extends AbstractPoxServiceClientImpl<ReportsCommonList
         return getProxy().readList();
     }
     
+    /**
+     * @return
+     * @see org.collectionspace.services.client.ReportProxy#getReport()
+     */
+    public ClientResponse<ReportsCommonList> readListFiltered(
+                       String docType, String mode) {
+        return getProxy().readListFiltered(docType, mode);
+    }
+    
 }
index 11a8d1baee0c9c5bcb88a8ddf77779d865ad7ff6..908e78a613a9922bee8438ee7c7537305136b3b7 100644 (file)
@@ -54,6 +54,12 @@ public interface ReportProxy extends CollectionSpacePoxProxy<ReportsCommonList>
     @Produces({"application/xml"})
     ClientResponse<ReportsCommonList> readList();
     
+    @GET
+    @Produces({"application/xml"})
+    ClientResponse<ReportsCommonList> readListFiltered(
+               @QueryParam(IQueryManager.SEARCH_TYPE_DOCTYPE) String docType,
+               @QueryParam(IQueryManager.SEARCH_TYPE_INVCOATION_MODE) String mode);
+    
     @Override
        @GET
     @Produces({"application/xml"})
index 220a318d34a5af1b491f163b5d7d1f1574144f94..7f22bd1cdfc9dd7ba4207c76f1e4e7b7aa32ed4c 100644 (file)
@@ -62,6 +62,8 @@ public class ReportServiceTest extends AbstractServiceTestImpl {
     // Instance variables specific to this test.
     /** The known resource id. */
     private String knownResourceId = null;
+    
+    private String testDocType = "Acquisition";
 
     /* (non-Javadoc)
      * @see org.collectionspace.services.client.test.BaseServiceTest#getClientInstance()
@@ -292,11 +294,11 @@ public class ReportServiceTest extends AbstractServiceTestImpl {
                 invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
         Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
 
+        List<ReportsCommonList.ReportListItem> items =
+            list.getReportListItem();
         // Optionally output additional data about list members for debugging.
         boolean iterateThroughList = false;
         if (iterateThroughList && logger.isDebugEnabled()) {
-            List<ReportsCommonList.ReportListItem> items =
-                    list.getReportListItem();
             int i = 0;
             for (ReportsCommonList.ReportListItem item : items) {
                 logger.debug(testName + ": list-item[" + i + "] csid="
@@ -310,7 +312,87 @@ public class ReportServiceTest extends AbstractServiceTestImpl {
                 i++;
             }
         }
+    }
 
+    @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
+               dependsOnMethods = {"readList"})
+    public void readListFiltered(String testName) throws Exception {
+       if (logger.isDebugEnabled()) {
+               logger.debug(testBanner(testName, CLASS_NAME));
+       }
+       // Perform setup.
+       setupReadList();
+
+       // Submit the request to the service and store the response.
+       ReportClient client = new ReportClient();
+       ClientResponse<ReportsCommonList> res = client.readListFiltered(
+                       testDocType, "single");
+       ReportsCommonList list = res.getEntity();
+       int statusCode = res.getStatus();
+
+       // Check the status code of the response: does it match
+       // the expected response(s)?
+       if (logger.isDebugEnabled()) {
+               logger.debug(testName + ": status = " + statusCode);
+       }
+       Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+                       invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+       Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
+
+       List<ReportsCommonList.ReportListItem> items =
+               list.getReportListItem();
+       // We must find the basic one we created
+       boolean fFoundBaseItem = false;
+               for (ReportsCommonList.ReportListItem item : items) {
+                       if(knownResourceId.equalsIgnoreCase(item.getCsid())) {
+                               fFoundBaseItem = true;
+                               break;
+                       }
+               }
+               if(!fFoundBaseItem)
+                       Assert.fail("readListFiltered failed to return base item");
+               
+               // Now filter for something else, and ensure it is NOT returned
+       res = client.readListFiltered("Intake", "single");
+       list = res.getEntity();
+       statusCode = res.getStatus();
+
+       // Check the status code of the response: does it match
+       // the expected response(s)?
+       if (logger.isDebugEnabled()) {
+               logger.debug(testName + ": status = " + statusCode);
+       }
+       Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+                       invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+       Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
+
+       items = list.getReportListItem();
+       // We must NOT find the basic one we created
+               for (ReportsCommonList.ReportListItem item : items) {
+                       Assert.assertNotSame(item.getCsid(), knownResourceId, 
+                               "readListFiltered(\"Intake\", \"single\") incorrectly returned base item");
+               }
+               
+               // Now filter for something else, and ensure it is NOT returned
+       res = client.readListFiltered(testDocType, "group");
+       list = res.getEntity();
+       statusCode = res.getStatus();
+
+       // Check the status code of the response: does it match
+       // the expected response(s)?
+       if (logger.isDebugEnabled()) {
+               logger.debug(testName + ": status = " + statusCode);
+       }
+       Assert.assertTrue(REQUEST_TYPE.isValidStatusCode(statusCode),
+                       invalidStatusCodeMessage(REQUEST_TYPE, statusCode));
+       Assert.assertEquals(statusCode, EXPECTED_STATUS_CODE);
+
+       items = list.getReportListItem();
+       // We must NOT find the basic one we created
+               for (ReportsCommonList.ReportListItem item : items) {
+                       Assert.assertNotSame(item.getCsid(), knownResourceId, 
+                               "readListFiltered(\""+testDocType+"\", \"group\") incorrectly returned base item");
+               }
     }
 
     // ---------------------------------------------------------------
@@ -322,7 +404,7 @@ public class ReportServiceTest extends AbstractServiceTestImpl {
      */
     @Override
     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
-    dependsOnMethods = {"read"})
+    dependsOnMethods = {"read", "readListFiltered"})
     public void update(String testName) throws Exception {
 
         if (logger.isDebugEnabled()) {
@@ -475,7 +557,7 @@ public class ReportServiceTest extends AbstractServiceTestImpl {
      */
     @Override
     @Test(dataProvider = "testName", dataProviderClass = AbstractServiceTestImpl.class,
-    dependsOnMethods = {"create", "readList", "testSubmitRequest", "update", "readWorkflow"})
+    dependsOnMethods = {"create", "readListFiltered", "testSubmitRequest", "update", "readWorkflow"})
     public void delete(String testName) throws Exception {
 
         if (logger.isDebugEnabled()) {
@@ -581,8 +663,9 @@ public class ReportServiceTest extends AbstractServiceTestImpl {
      */
     private PoxPayloadOut createReportInstance(String identifier) {
         return createReportInstance(
-                "name-" + identifier,
-                "persAuthTermCountsTest.jasper",
+                "Acquisition Summary", 
+                testDocType, true, false, false, true,
+                "acq_basic.jasper",
                 "application/pdf");
     }
 
@@ -595,10 +678,18 @@ public class ReportServiceTest extends AbstractServiceTestImpl {
      * @return the multipart output
      */
     private PoxPayloadOut createReportInstance(String name,
+               String forDocType,
+               boolean supportsSingle, boolean supportsList, 
+               boolean supportsGroup, boolean supportsNoContext, 
             String filename,
             String outputMIME) {
         ReportsCommon reportCommon = new ReportsCommon();
         reportCommon.setName(name);
+        reportCommon.setForDocType(forDocType);
+        reportCommon.setSupportsSingleDoc(supportsSingle);
+        reportCommon.setSupportsDocList(supportsList);
+        reportCommon.setSupportsGroup(supportsGroup);
+        reportCommon.setSupportsNoContext(supportsNoContext);
         reportCommon.setFilename(filename);
         reportCommon.setOutputMIME(outputMIME);
         reportCommon.setNotes(getUTF8DataFragment()); // For UTF-8 tests
index c17ee3dcfb9486aaa65ba4d0eb03faaa84af29b4..f65005d998e3adf4d2760537ea95517a86864a96 100644 (file)
@@ -31,6 +31,7 @@ import net.sf.jasperreports.engine.JasperPrint;
 import org.collectionspace.services.jaxb.AbstractCommonList;
 import org.collectionspace.services.jaxb.InvocableJAXBSchema;
 import org.collectionspace.services.ReportJAXBSchema;
+import org.collectionspace.services.client.IQueryManager;
 import org.collectionspace.services.client.PoxPayloadIn;
 import org.collectionspace.services.client.PoxPayloadOut;
 import org.collectionspace.services.client.ReportClient;
@@ -41,6 +42,7 @@ import org.collectionspace.services.common.ServiceMessages;
 import org.collectionspace.services.common.config.ConfigReader;
 import org.collectionspace.services.common.context.ServiceContext;
 import org.collectionspace.services.common.document.BadRequestException;
+import org.collectionspace.services.common.document.DocumentFilter;
 import org.collectionspace.services.common.document.DocumentHandler;
 import org.collectionspace.services.common.document.DocumentNotFoundException;
 import org.collectionspace.services.common.document.DocumentWrapper;
@@ -48,6 +50,7 @@ import org.collectionspace.services.common.invocable.Invocable;
 import org.collectionspace.services.common.invocable.InvocationContext;
 import org.collectionspace.services.common.invocable.InvocationResults;
 import org.collectionspace.services.common.invocable.Invocable.InvocationError;
+import org.collectionspace.services.common.query.QueryManager;
 import org.collectionspace.services.common.security.UnauthorizedException;
 import org.jboss.resteasy.spi.ResteasyProviderFactory;
 import org.nuxeo.ecm.core.api.DocumentModel;
@@ -107,6 +110,26 @@ public class ReportResource extends ResourceBase {
         try {
             ServiceContext<PoxPayloadIn, PoxPayloadOut> ctx = createServiceContext(queryParams);
             DocumentHandler handler = createDocumentHandler(ctx);
+            String docType = queryParams.getFirst(IQueryManager.SEARCH_TYPE_DOCTYPE);
+            String mode = queryParams.getFirst(IQueryManager.SEARCH_TYPE_INVCOATION_MODE);
+            String whereClause = null;
+            DocumentFilter documentFilter = null;
+            String common_part =ctx.getCommonPartLabel(); 
+            if (docType != null && !docType.isEmpty()) {
+                whereClause = QueryManager.createWhereClauseForInvocableByDocType(
+                               common_part, docType);
+                documentFilter = handler.getDocumentFilter();
+                documentFilter.appendWhereClause(whereClause, IQueryManager.SEARCH_QUALIFIER_AND);
+            }
+            if (mode != null && !mode.isEmpty()) {
+                whereClause = QueryManager.createWhereClauseForInvocableByMode(
+                               common_part, mode);
+                documentFilter = handler.getDocumentFilter();
+                documentFilter.appendWhereClause(whereClause, IQueryManager.SEARCH_QUALIFIER_AND);
+            }
+            if (whereClause !=null && logger.isDebugEnabled()) {
+                logger.debug("The WHERE clause is: " + documentFilter.getWhereClause());
+            }
             getRepositoryClient(ctx).getFiltered(ctx, handler);
             AbstractCommonList list = (AbstractCommonList) handler.getCommonPartList();
             return list;