Add Nested JSON Filtering 09/78509/8
authorDaniel Cruz <dc443y@att.com>
Thu, 14 Feb 2019 06:42:45 +0000 (00:42 -0600)
committerDaniel Cruz <dc443y@att.com>
Thu, 21 Feb 2019 22:36:38 +0000 (16:36 -0600)
The refactoring of the JsonProtocolFilter allows for complex filter
queries for JSON events coming in on network topics. The underlying
library used is json-path, which supports path based searching and
ruby regex filtering at any level of the JSON document.

The JsonProtocolFilter no longer requires a FilterRule class as one
json-path filter can contain multiple constraints using "&&" or "||".
This eliminates the need to identify the field name as a key with a
regex associated with it in the controller properties file (see the
original FilterRule implementation). It also simplifies the parsing
needed in the DroolsControllerFactory when extracting the filter
property and creating the JsonProtocolFilter.

JUnit coverage is 100% and all sonar flags were addressed related to
the JsonProtocolFilter class. Tested and verified working with the
telemetry API in a locally deployed PDP-D.

Change-Id: I8bd63db4e497c1ba0b5044b5449ccb7a9e4dbdbc
Issue-ID: POLICY-1489
Signed-off-by: Daniel Cruz <dc443y@att.com>
policy-management/pom.xml
policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java
policy-management/src/main/java/org/onap/policy/drools/protocol/coders/JsonProtocolFilter.java
policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java
policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java
policy-management/src/test/java/org/onap/policy/drools/protocol/coders/JsonProtocolFilterTest.java
policy-management/src/test/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolsetTest.java
pom.xml

index 81edf7a..d48d3ff 100644 (file)
             <artifactId>gson-javatime-serialisers</artifactId>
             <version>1.1.1</version>
         </dependency>
+        
+        <dependency>
+            <groupId>com.jayway.jsonpath</groupId>
+            <artifactId>json-path</artifactId>
+        </dependency>
 
         <dependency>
             <groupId>org.apache.commons</groupId>
index 24fc6de..16daa94 100644 (file)
@@ -7,9 +7,9 @@
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -25,7 +25,6 @@ import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Properties;
-
 import org.onap.policy.common.endpoints.event.comm.Topic;
 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
 import org.onap.policy.common.endpoints.event.comm.TopicSink;
@@ -38,7 +37,6 @@ import org.onap.policy.drools.protocol.coders.JsonProtocolFilter;
 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration;
 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.PotentialCoderFilter;
-import org.onap.policy.drools.utils.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -50,11 +48,11 @@ public interface DroolsControllerFactory {
 
     /**
      * Constructs a Drools Controller based on properties.
-     * 
+     *
      * @param properties properties containing initialization parameters
      * @param eventSources list of event sources
      * @param eventSinks list of event sinks
-     * 
+     *
      * @return the instantiated Drools Controller
      * @throws IllegalArgumentException with invalid parameters
      * @throws LinkageError Failure to link rules and models in Drools Libraries
@@ -64,13 +62,13 @@ public interface DroolsControllerFactory {
 
     /**
      * Explicit construction of a Drools Controller.
-     * 
+     *
      * @param groupId maven group id of drools artifact
      * @param artifactId maven artifact id of drools artifact
      * @param version maven version id of drools artifact
      * @param decoderConfigurations list of decoder configurations
      * @param encoderConfigurations list of encoder configurations
-     * 
+     *
      * @return the instantiated Drools Controller
      * @throws IllegalArgumentException with invalid parameters
      * @throws LinkageError Failure to link rules and models in Drools Libraries
@@ -81,7 +79,7 @@ public interface DroolsControllerFactory {
 
     /**
      * Releases the Drools Controller from operation.
-     * 
+     *
      * @param controller the Drools Controller to shut down
      */
     public void shutdown(DroolsController controller);
@@ -93,7 +91,7 @@ public interface DroolsControllerFactory {
 
     /**
      * Destroys and releases resources for a Drools Controller.
-     * 
+     *
      * @param controller the Drools Controller to destroy
      */
     public void destroy(DroolsController controller);
@@ -105,11 +103,11 @@ public interface DroolsControllerFactory {
 
     /**
      * Gets the Drools Controller associated with the maven group and artifact id.
-     * 
+     *
      * @param groupId maven group id of drools artifact
      * @param artifactId maven artifact id of drools artifact
      * @param version maven version id of drools artifact
-     * 
+     *
      * @return the Drools Controller
      * @throws IllegalArgumentException with invalid parameters
      */
@@ -117,7 +115,7 @@ public interface DroolsControllerFactory {
 
     /**
      * returns the current inventory of Drools Controllers.
-     * 
+     *
      * @return a list of Drools Controllers
      */
     public List<DroolsController> inventory();
@@ -208,7 +206,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
             /*
              * The Null Drools Controller for no maven coordinates is always here so when no
              * coordinates present, this is the return point
-             * 
+             *
              * assert (controllerCopy instanceof NullDroolsController)
              */
             if (droolsControllers.containsKey(controllerId)) {
@@ -245,7 +243,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
 
     /**
      * find out decoder classes and filters.
-     * 
+     *
      * @param properties properties with information about decoders
      * @param topicEntities topic sources
      * @return list of topics, each with associated decoder classes, each with a list of associated
@@ -313,7 +311,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
             // 3. second the list of classes associated with each topic
 
             String eventClasses = properties
-                    .getProperty(propertyTopicEntityPrefix + firstTopic 
+                    .getProperty(propertyTopicEntityPrefix + firstTopic
                             + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX);
 
             if (eventClasses == null || eventClasses.isEmpty()) {
@@ -328,54 +326,14 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
             for (String theClass : topicClasses) {
 
 
-                // 4. third, for each coder class, get the list of field filters
+                // 4. third, for each coder class, get the filter expression
 
                 String filter = properties
-                        .getProperty(propertyTopicEntityPrefix + firstTopic 
+                        .getProperty(propertyTopicEntityPrefix + firstTopic
                                 + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX
                                 + "." + theClass + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_FILTER_SUFFIX);
 
-                List<Pair<String, String>> filters = new ArrayList<>();
-
-                if (filter == null || filter.isEmpty()) {
-                    // 4. topic -> class -> with no filters
-
-                    JsonProtocolFilter protocolFilter = JsonProtocolFilter.fromRawFilters(filters);
-                    PotentialCoderFilter class2Filters = new PotentialCoderFilter(theClass, protocolFilter);
-                    classes2Filters.add(class2Filters);
-                    continue;
-                }
-
-                // There are filters associated with the applicability of
-                // this class for decoding.
-                List<String> listOfFilters = new ArrayList<>(Arrays.asList(filter.split("\\s*,\\s*")));
-
-                for (String nameValue : listOfFilters) {
-                    String fieldName;
-                    String regexValue;
-
-                    String[] nameValueSplit = nameValue.split("\\s*=\\s*");
-                    if (nameValueSplit.length <= 0 || nameValueSplit.length > 2) {
-                        // TODO warn
-                        // skip
-                        continue;
-                    }
-
-                    if (nameValueSplit.length == 2) {
-                        fieldName = nameValueSplit[0];
-                        regexValue = nameValueSplit[1];
-                    } else if (nameValueSplit.length == 1) {
-                        fieldName = nameValueSplit[0];
-                        regexValue = null;
-                    } else {
-                        // unreachable
-                        continue;
-                    }
-
-                    filters.add(new Pair<String, String>(fieldName, regexValue));
-                }
-
-                JsonProtocolFilter protocolFilter = JsonProtocolFilter.fromRawFilters(filters);
+                JsonProtocolFilter protocolFilter = new JsonProtocolFilter(filter);
                 PotentialCoderFilter class2Filters = new PotentialCoderFilter(theClass, protocolFilter);
                 classes2Filters.add(class2Filters);
             }
@@ -408,7 +366,7 @@ class IndexedDroolsControllerFactory implements DroolsControllerFactory {
 
     /**
      * unmanage the drools controller.
-     * 
+     *
      * @param controller the controller
      */
     protected void unmanage(DroolsController controller) {
index f65efae..2ccc010 100644 (file)
@@ -2,14 +2,14 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
 package org.onap.policy.drools.protocol.coders;
 
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
+import com.jayway.jsonpath.Configuration;
+import com.jayway.jsonpath.DocumentContext;
+import com.jayway.jsonpath.JsonPath;
+import com.jayway.jsonpath.Option;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-import org.onap.policy.drools.utils.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**
- * JSON Protocol Filter.
- */
+/** JSON Protocol Filter. */
 public class JsonProtocolFilter {
 
-    private static final String MISSING_RULE_NAME = "no rule name provided";
-    /**
-     * Logger.
-     */
-    private static final Logger logger = LoggerFactory.getLogger(JsonProtocolFilter.class);
-
-    /**
-     * Helper class to collect Filter information.
-     */
-    public static class FilterRule {
-        /**
-         * Field name.
-         */
-        private String name;
-
-        /**
-         * Field Value regex.
-         */
-        private String regex;
-
-        /**
-         * Filter Constructor.
-         * 
-         * @param name field name
-         * @param regex field regex value
-         */
-        public FilterRule(String name, String regex) {
-            this.setName(name);
-            this.setRegex(regex);
-        }
-
-        /**
-         * Default constructor (for serialization only).
-         */
-        public FilterRule() {
-            super();
-        }
-
-        /**
-         * gets name.
-         * 
-         * @return name
-         */
-        public String getName() {
-            return name;
-        }
-
-        /**
-         * gets regex.
-         * 
-         * @return regular expression string
-         */
-        public String getRegex() {
-            return regex;
-        }
-
-        /**
-         * Sets field name.
-         * 
-         * @param name field name
-         */
-        public void setName(String name) {
-            if (name == null || name.isEmpty()) {
-                throw new IllegalArgumentException("filter field name must be provided");
-            }
-
-            this.name = name;
-        }
-
-        /**
-         * sets regex name.
-         * 
-         * @param regex expression
-         */
-        public void setRegex(String regex) {
-            if (regex == null || regex.isEmpty()) {
-                this.regex = ".*";
-            }
-
-            this.regex = regex;
-        }
+    /** Default filter to match anything. */
+    public static final String MATCH_ANY = "[?($ =~ /.*/)]";
 
-        @Override
-        public String toString() {
-            StringBuilder builder = new StringBuilder();
-            builder.append("Filter [name=").append(name).append(", regex=").append(regex).append("]");
-            return builder.toString();
-        }
-    }
+    /** Logger. */
+    private static final Logger logger = LoggerFactory.getLogger(JsonProtocolFilter.class);
 
-    /**
-     * all the filters to be applied.
-     */
-    protected List<FilterRule> rules = new CopyOnWriteArrayList<>();
+    /** A rule based on a JsonPath expression that is used for filtering. */
+    private String rule;
 
     /**
-     * Create a Protocol Filter.
-     * 
-     * @throws IllegalArgumentException an invalid input has been provided
+     * Default constructor (for serialization only).
      */
     public JsonProtocolFilter() {
         super();
+        this.setRule(null);
     }
 
     /**
      * Constructor.
-     * 
-     * @param filters filter list
-     * 
-     * @throws IllegalArgumentException an invalid input has been provided
-     */
-    public JsonProtocolFilter(List<FilterRule> filters) {
-        List<FilterRule> temp = new ArrayList<>();
-        for (FilterRule rule : filters) {
-            if (rule.getName() == null || rule.getName().isEmpty()) {
-                continue;
-            }
-
-            if (rule.getRegex() == null || rule.getRegex().isEmpty()) {
-                rule.setRegex(".*");
-            }
-
-            temp.add(rule);
-        }
-
-        this.rules.addAll(temp);
-    }
-
-    /**
-     * From raw filters.
-     * 
-     * @param rawFilters raw filter initialization
-     * 
+     *
+     * @param rule the JsonPath expression used for the filter rule
      * @throws IllegalArgumentException an invalid input has been provided
      */
-    public static JsonProtocolFilter fromRawFilters(List<Pair<String, String>> rawFilters) {
-
-        if (rawFilters == null) {
-            throw new IllegalArgumentException("No raw filters provided");
-        }
-
-        List<FilterRule> filters = new ArrayList<>();
-        for (Pair<String, String> filterPair: rawFilters) {
-            if  (filterPair.first() == null || filterPair.first().isEmpty()) {
-                continue;
-            }
-
-            filters.add(new FilterRule(filterPair.first(), filterPair.second()));
-        }
-        return new JsonProtocolFilter(filters);
+    public JsonProtocolFilter(String rule) {
+        this.setRule(rule);
     }
 
     /**
-     * are there any filters.
-     * 
-     * @return true if there are filters, false otherwise
+     * Gets the filter expression rule.
+     *
+     * @return the filter expression associated with this JsonProtocolFilter
      */
-    public boolean isRules() {
-        return !this.rules.isEmpty();
+    public String getRule() {
+        return this.rule;
     }
 
     /**
-     * accept a JSON string as conformant it if passes all filters.
-     * 
-     * @param json json is a JSON object
-     * @return true if json string is conformant
-     * 
-     * @throws IllegalArgumentException an invalid input has been provided
+     * Sets the filter expression rule.
+     *
+     * @param rule the JsonPath expression rule
      */
-    public boolean accept(JsonElement json) {
-        if (json == null) {
-            throw new IllegalArgumentException("no JSON provided");
-        }
-
-        if (!json.isJsonObject()) {
-            return false;
-        }
-
-        if (rules.isEmpty()) {
-            return true;
-        }
-
-        try {
-            JsonObject event = json.getAsJsonObject();
-            for (FilterRule filter: rules) {
-                if (filter.getRegex() == null
-                        || filter.getRegex().isEmpty()
-                        || ".*".equals(filter.getRegex())) {
-
-                    // Only check for presence
-                    if (!event.has(filter.getName())) {
-                        return false;
-                    }
-                } else {
-                    JsonElement field = event.get(filter.getName());
-                    if (field == null) {
-                        return false;
-                    }
-
-                    String fieldValue = field.getAsString();
-                    if (!fieldValue.matches(filter.getRegex())) {
-                        return false;
-                    }
-                }
-            }
-            return true;
-        } catch (Exception e) {
-            throw new IllegalArgumentException(e);
+    public void setRule(String rule) {
+        String ruleExpression = rule;
+        if (rule == null || rule.isEmpty()) {
+            ruleExpression = MATCH_ANY;
         }
+        this.rule = ruleExpression;
     }
 
     /**
-     * Accept a JSON string as conformant it if passes all filters.
-     * 
-     * @param json json string
-     * @return true if json string is conformant
-     * 
-     * @throws IllegalArgumentException an invalid input has been provided
+     * Accepts a JSON message if there is a match on the filter expression.
+     *
+     * @return true if a match is found or the rule uses the match any policy, false otherwise
      */
     public boolean accept(String json) {
-        if (json == null || json.isEmpty()) {
-            throw new IllegalArgumentException("no JSON provided");
-        }
-
-        if (rules.isEmpty()) {
+        if (MATCH_ANY.equals(this.rule)) {
             return true;
         }
-
-        try {
-            JsonElement element = new JsonParser().parse(json);
-            if (element == null || !element.isJsonObject()) {
-                return false;
-            }
-
-            return this.accept(element.getAsJsonObject());
-        } catch (IllegalArgumentException ile) {
-            throw ile;
-        } catch (Exception e) {
-            logger.info("{}: cannot accept {} because of {}", 
-                    this, json, e.getMessage(), e);
-            throw new IllegalArgumentException(e);
-        }
-    }
-
-    public List<FilterRule> getRules() {
-        return new ArrayList<>(this.rules);
+        return !filter(json).isEmpty();
     }
 
     /**
-     * Get rules.
-     * 
-     * @param name name
-     * @return list of filter rules
+     * Finds a field based on a path or a subset of the JSON if using an expression.
+     *
+     * @param json the JSON string to be parsed
+     * @return a list of strings that match the expression
      */
-    public List<FilterRule> getRules(String name) {
-        if (name == null || name.isEmpty()) {
-            throw new IllegalArgumentException(MISSING_RULE_NAME);
-        }
-
-        ArrayList<FilterRule> temp = new ArrayList<>();
-        for (FilterRule rule : this.rules) {
-            if (rule.getName().equals(name)) {
-                temp.add(rule);
-            }
-        }
-        return temp;
+    public List<String> filter(String json) {
+        return filter(json, this.rule);
     }
 
     /**
-     * Set Rules.
-     * 
-     * @param rulesFilters filters
+     * Finds all occurrences of a field in a JSON document based on the JsonPath
+     * expression.
+     *
+     * @param json the JSON string to be parsed
+     * @param expression the JsonPath expression
+     * @return a list of matches from the JSON document
      */
-    public void setRules(List<FilterRule> rulesFilters) {
-        if (rulesFilters == null) {
-            throw new IllegalArgumentException("no rules provided");
-        }
-
-        this.rules.clear();
-        this.rules.addAll(rulesFilters);
-    }
-
-    /**
-     * Delete rules.
-     * 
-     * @param name name
-     */
-    public void deleteRules(String name) {
-        if (name == null || name.isEmpty()) {
-            throw new IllegalArgumentException(MISSING_RULE_NAME);
-        }
-
-        List<FilterRule> temp = new ArrayList<>();
-        for (FilterRule rule : this.rules) {
-            if (rule.name.equals(name)) {
-                temp.add(rule);
-            }
-        }
-        this.rules.removeAll(temp);
-    }
-
-    /**
-     * Delete rule.
-     * 
-     * @param name name
-     * @param regex regex
-     */
-    public void deleteRule(String name, String regex) {
-        if (name == null || name.isEmpty()) {
-            throw new IllegalArgumentException(MISSING_RULE_NAME);
-        }
-
-        String nonNullRegex = regex;
-        if (regex == null || regex.isEmpty()) {
-            nonNullRegex = ".*";
+    public static List<String> filter(String json, String expression) {
+        if (json == null || json.isEmpty()) {
+            throw new IllegalArgumentException("a json string must be provided");
         }
 
-        List<FilterRule> temp = new ArrayList<>();
-        for (FilterRule rule : this.rules) {
-            if (rule.name.equals(name) && rule.getRegex().equals(nonNullRegex)) {
-                temp.add(rule);
-            }
+        if (expression == null || expression.isEmpty()) {
+            throw new IllegalArgumentException("an expression must be provided");
         }
 
-        this.rules.removeAll(temp);
-    }
-
-    /**
-     * Add rule.
-     * 
-     * @param name name
-     * @param regex regex
-     */
-    public void addRule(String name, String regex) {
-        if (name == null || name.isEmpty()) {
-            throw new IllegalArgumentException(MISSING_RULE_NAME);
-        }
+        Configuration conf = Configuration.defaultConfiguration().addOptions(Option.ALWAYS_RETURN_LIST);
+        DocumentContext document = JsonPath.using(conf).parse(json);
 
-        String nonNullRegex = regex;
-        if (regex == null || regex.isEmpty()) {
-            nonNullRegex = ".*";
+        List<String> matches = new ArrayList<>();
+        try {
+            matches = document.read(expression);
+        } catch (Exception e) {
+            logger.error("JsonPath couldn't read {} because of {}", expression, e.getMessage(), e);
         }
 
-        for (FilterRule rule : this.rules) {
-            if (rule.getName().equals(name) && rule.getRegex().equals(regex)) {
-                return;
-            }
+        if (matches.isEmpty()) {
+            logger.warn("Could not find any matches for rule {} in json {}", expression, json);
         }
 
-        this.rules.add(new FilterRule(name, nonNullRegex));
+        return matches;
     }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("JsonProtocolFilter [rules=").append(rules).append("]");
-        return builder.toString();
-    }
-
 }
index f125c13..394e73a 100644 (file)
@@ -31,7 +31,6 @@ import com.google.gson.JsonParser;
 import com.google.gson.JsonPrimitive;
 import com.google.gson.JsonSerializationContext;
 import com.google.gson.JsonSerializer;
-
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
 import java.lang.reflect.Type;
@@ -168,7 +167,7 @@ public abstract class ProtocolCoderToolset {
 
     /**
      * remove coder.
-     * 
+     *
      * @param eventClass event class
      */
     public void removeCoders(String eventClass) {
@@ -206,7 +205,7 @@ public abstract class ProtocolCoderToolset {
 
     /**
      * Get group id.
-     * 
+     *
      * @return the groupId
      */
     public String getGroupId() {
@@ -215,7 +214,7 @@ public abstract class ProtocolCoderToolset {
 
     /**
      * Get artifact id.
-     * 
+     *
      * @return the artifactId
      */
     public String getArtifactId() {
@@ -224,7 +223,7 @@ public abstract class ProtocolCoderToolset {
 
     /**
      * Get custom coder.
-     * 
+     *
      * @return the customCoder
      */
     public CustomCoder getCustomCoder() {
@@ -233,7 +232,7 @@ public abstract class ProtocolCoderToolset {
 
     /**
      * Set custom coder.
-     * 
+     *
      * @param customCoder the customCoder to set.
      */
     public void setCustomCoder(CustomCoder customCoder) {
@@ -262,28 +261,14 @@ public abstract class ProtocolCoderToolset {
             throw new IllegalStateException("No coders available");
         }
 
-        if (this.coders.size() == 1) {
-            final JsonProtocolFilter filter = this.coders.get(0).getFilter();
-            if (!filter.isRules()) {
-                return this.coders.get(0);
-            }
-        }
-
-        JsonElement event;
-        try {
-            event = this.filteringParser.parse(json);
-        } catch (final Exception e) {
-            throw new UnsupportedOperationException(e);
-        }
-
         for (final CoderFilters decoder : this.coders) {
             try {
-                final boolean accepted = decoder.getFilter().accept(event);
+                boolean accepted = decoder.getFilter().accept(json);
                 if (accepted) {
                     return decoder;
                 }
             } catch (final Exception e) {
-                logger.info("{}: unexpected failure accepting {} because of {}", this, event,
+                logger.info("{}: unexpected failure accepting {} because of {}", this, json,
                         e.getMessage(), e);
                 // continue
             }
@@ -325,8 +310,6 @@ public abstract class ProtocolCoderToolset {
     }
 }
 
-
-
 /**
  * Tools used for encoding/decoding using GSON.
  */
index 64fd682..cbe2b33 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * policy-management
  * ================================================================================
- * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -36,8 +36,6 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.UUID;
-import java.util.regex.Pattern;
-
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.DefaultValue;
@@ -51,7 +49,6 @@ import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
-
 import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
 import org.onap.policy.common.endpoints.event.comm.TopicSink;
 import org.onap.policy.common.endpoints.event.comm.TopicSource;
@@ -67,7 +64,6 @@ import org.onap.policy.drools.properties.DroolsProperties;
 import org.onap.policy.drools.protocol.coders.EventProtocolCoder;
 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
 import org.onap.policy.drools.protocol.coders.JsonProtocolFilter;
-import org.onap.policy.drools.protocol.coders.JsonProtocolFilter.FilterRule;
 import org.onap.policy.drools.protocol.coders.ProtocolCoderToolset;
 import org.onap.policy.drools.protocol.configuration.ControllerConfiguration;
 import org.onap.policy.drools.protocol.configuration.PdpdConfiguration;
@@ -77,7 +73,6 @@ import org.onap.policy.drools.utils.logging.LoggerUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-
 /**
  * Telemetry JAX-RS Interface to the PDP-D.
  */
@@ -98,7 +93,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -111,7 +106,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -132,7 +127,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -154,7 +149,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -175,7 +170,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -187,7 +182,7 @@ public class RestManager {
 
     /**
      * POST.
-     * 
+     *
      * @return response object
      */
     @POST
@@ -216,7 +211,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -229,7 +224,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -242,7 +237,7 @@ public class RestManager {
 
     /**
     * GET.
-    * 
+    *
     * @return response object
     */
     @GET
@@ -257,7 +252,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -274,7 +269,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -287,7 +282,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -315,7 +310,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -343,7 +338,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -364,7 +359,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -385,7 +380,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -398,7 +393,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -411,7 +406,7 @@ public class RestManager {
 
     /**
     * POST.
-    * 
+    *
     * @return response object
     */
     @POST
@@ -479,7 +474,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -492,7 +487,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -506,7 +501,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -528,7 +523,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -557,7 +552,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -604,7 +599,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -632,7 +627,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -644,7 +639,7 @@ public class RestManager {
 
     /**
      * POST.
-     * 
+     *
      * @return response object
      */
     @POST
@@ -688,7 +683,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -701,7 +696,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -724,7 +719,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -747,7 +742,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -775,7 +770,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -807,7 +802,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -836,7 +831,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -875,7 +870,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -928,7 +923,7 @@ public class RestManager {
 
     /**
      * POST.
-     * 
+     *
      * @return response object
      */
     @POST
@@ -985,7 +980,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -1027,7 +1022,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -1085,29 +1080,21 @@ public class RestManager {
 
     /**
      * POST.
-     * 
+     *
      * @return response object
      */
     @POST
-    @Path("engine/controllers/tools/coders/decoders/filters/rules/{ruleName}")
+    @Path("engine/controllers/tools/coders/decoders/filters/rule")
     @ApiOperation(value = "Produces a Decoder Rule Filter in a format that the Policy Controller can understand",
             notes = "The result can be used with other APIs to attach a filter to a decoder")
     public Response rules(
-            @ApiParam(value = "Negate regex?",
-                    required = true) @DefaultValue("false") @QueryParam("negate") boolean negate,
-            @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String name,
-            @ApiParam(value = "Regex expression", required = true) String regex) {
-        String literalRegex = Pattern.quote(regex);
-        if (negate) {
-            literalRegex = "^(?!" + literalRegex + "$).*";
-        }
-
-        return Response.status(Status.OK).entity(new JsonProtocolFilter.FilterRule(name, literalRegex)).build();
+            @ApiParam(value = "JsonPath expression", required = true) String expression) {
+        return Response.status(Status.OK).entity(new JsonProtocolFilter(expression)).build();
     }
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1142,7 +1129,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1178,7 +1165,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1215,7 +1202,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1258,7 +1245,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1303,7 +1290,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -1359,17 +1346,16 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
-    @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules")
-    @ApiOperation(value = "Gets the filter rules attached to a topic decoder of a controller",
+    @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rule")
+    @ApiOperation(value = "Gets the filter rule attached to a topic decoder of a controller",
             notes = "Decoders are associated with networked topics. A Policy Controller manages "
                     + "multiple topics and therefore its attached decoders. "
                     + "A Policy Controller uses filters to further specify the fact mapping.  "
-                    + "Filters are applied on a per fact type and are composed of field matching rules. ",
-            responseContainer = "List", response = FilterRule.class)
+                    + "Filters are applied on a per fact type using a jsonpath expression rule. ")
     @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller, topic, or fact type cannot be found"),
             @ApiResponse(code = 406,
                     message = "The system is an administrative state that prevents " + "this request to be fulfilled")})
@@ -1394,7 +1380,7 @@ public class RestManager {
                         .entity(new Error(controllerName + ":" + topic + ":" + factClass + "  no filters")).build();
             }
 
-            return Response.status(Response.Status.OK).entity(filter.getRules()).build();
+            return Response.status(Response.Status.OK).entity(filter.getRule()).build();
         } catch (final IllegalArgumentException e) {
             logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", this,
                     controllerName, topic, factClass, e.getMessage(), e);
@@ -1408,87 +1394,26 @@ public class RestManager {
         }
     }
 
-    /**
-     * GET.
-     * 
-     * @return response object
-     */
-    @GET
-    @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules/{ruleName}")
-    @ApiOperation(value = "Gets a filter rule by name attached to a topic decoder of a controller",
-            notes = "Decoders are associated with networked topics. A Policy Controller manages "
-                    + "multiple topics and therefore its attached decoders. "
-                    + "A Policy Controller uses filters to further specify the fact mapping.  "
-                    + "Filters are applied on a per fact type and are composed of field matching rules. ",
-            responseContainer = "List", response = FilterRule.class)
-    @ApiResponses(value = {
-            @ApiResponse(code = 404, message = "The controller, topic, fact type, or rule name cannot be found"),
-            @ApiResponse(code = 406,
-                    message = "The system is an administrative state that prevents " + "this request to be fulfilled")})
-    public Response decoderFilterRules(
-            @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName,
-            @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic,
-            @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass,
-            @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String ruleName) {
-        try {
-            final DroolsController drools = this.getDroolsController(controllerName);
-            final ProtocolCoderToolset decoder =
-                    EventProtocolCoder.manager.getDecoders(drools.getGroupId(), drools.getArtifactId(), topic);
-
-            final CoderFilters filters = decoder.getCoder(factClass);
-            if (filters == null) {
-                return Response.status(Response.Status.BAD_REQUEST)
-                        .entity(new Error(controllerName + ":" + topic + ":" + factClass + "  does not exist")).build();
-            }
-
-            final JsonProtocolFilter filter = filters.getFilter();
-            if (filter == null) {
-                return Response.status(Response.Status.BAD_REQUEST)
-                        .entity(new Error(controllerName + ":" + topic + ":" + factClass + "  no filters")).build();
-            }
-
-            return Response.status(Response.Status.OK).entity(filter.getRules(ruleName)).build();
-        } catch (final IllegalArgumentException e) {
-            logger.debug(
-                    "{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}",
-                    this, controllerName, topic, factClass, ruleName, e.getMessage(), e);
-            return Response.status(Response.Status.NOT_FOUND)
-                    .entity(new Error(controllerName + ":" + topic + ":" + factClass + ": " + ruleName + " not found"))
-                    .build();
-        } catch (final IllegalStateException e) {
-            logger.debug(
-                    "{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}",
-                    this, controllerName, topic, factClass, ruleName, e.getMessage(), e);
-            return Response.status(Response.Status.NOT_ACCEPTABLE)
-                    .entity(new Error(
-                            controllerName + ":" + topic + ":" + factClass + ":" + ruleName + " not acceptable"))
-                    .build();
-        }
-    }
-
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
-    @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules/{ruleName}")
-    @ApiOperation(value = "Deletes a filter rule by name attached to a topic decoder of a controller",
+    @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rule")
+    @ApiOperation(value = "Deletes the filter rule attached to a topic decoder of a controller",
             notes = "Decoders are associated with networked topics. A Policy Controller manages "
                     + "multiple topics and therefore its attached decoders. "
                     + "A Policy Controller uses filters to further specify the fact mapping.  "
-                    + "Filters are applied on a per fact type and are composed of field matching rules. ",
-            responseContainer = "List", response = FilterRule.class)
+                    + "Filters are applied on a per fact type using a jsonpath expression rule. ")
     @ApiResponses(value = {
-            @ApiResponse(code = 404, message = "The controller, topic, fact type, or rule name cannot be found"),
+            @ApiResponse(code = 404, message = "The controller, topic, or fact type cannot be found"),
             @ApiResponse(code = 406,
                     message = "The system is an administrative state that prevents " + "this request to be fulfilled")})
     public Response decoderFilterRuleDelete(
             @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName,
             @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic,
-            @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass,
-            @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String ruleName,
-            @ApiParam(value = "Filter Rule", required = true) FilterRule rule) {
+            @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass) {
 
         try {
             final DroolsController drools = this.getDroolsController(controllerName);
@@ -1507,50 +1432,38 @@ public class RestManager {
                         .entity(new Error(controllerName + ":" + topic + ":" + factClass + "  no filters")).build();
             }
 
-            if (rule == null) {
-                filter.deleteRules(ruleName);
-                return Response.status(Response.Status.OK).entity(filter.getRules()).build();
-            }
-
-            if (rule.getName() == null || !rule.getName().equals(ruleName)) {
-                return Response.status(Response.Status.BAD_REQUEST).entity(new Error(controllerName + ":" + topic + ":"
-                        + factClass + ":" + ruleName + " rule name request inconsistencies (" + rule.getName() + ")"))
-                        .build();
-            }
-
-            filter.deleteRule(ruleName, rule.getRegex());
-            return Response.status(Response.Status.OK).entity(filter.getRules()).build();
+            filter.setRule(null);
+            return Response.status(Response.Status.OK).entity(filter.getRule()).build();
         } catch (final IllegalArgumentException e) {
             logger.debug(
-                    "{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}",
-                    this, controllerName, topic, factClass, ruleName, e.getMessage(), e);
+                    "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}",
+                    this, controllerName, topic, factClass, e.getMessage(), e);
             return Response.status(Response.Status.NOT_FOUND)
-                    .entity(new Error(controllerName + ":" + topic + ":" + factClass + ": " + ruleName + " not found"))
+                    .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not found"))
                     .build();
         } catch (final IllegalStateException e) {
             logger.debug(
-                    "{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}",
-                    this, controllerName, topic, factClass, ruleName, e.getMessage(), e);
+                    "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}",
+                    this, controllerName, topic, factClass, e.getMessage(), e);
             return Response.status(Response.Status.NOT_ACCEPTABLE)
                     .entity(new Error(
-                            controllerName + ":" + topic + ":" + factClass + ":" + ruleName + " not acceptable"))
+                            controllerName + ":" + topic + ":" + factClass + " not acceptable"))
                     .build();
         }
     }
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
-    @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules")
+    @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rule")
     @ApiOperation(value = "Places a new filter rule in a topic decoder",
             notes = "Decoders are associated with networked topics. A Policy Controller manages "
                     + "multiple topics and therefore its attached decoders. "
                     + "A Policy Controller uses filters to further specify the fact mapping.  "
-                    + "Filters are applied on a per fact type and are composed of field matching rules. ",
-            responseContainer = "List", response = FilterRule.class)
+                    + "Filters are applied on a per fact type using a jsonpath expression rule. ")
     @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller, topic, or fact type cannot be found"),
             @ApiResponse(code = 406,
                     message = "The system is an administrative state that prevents " + "this request to be fulfilled")})
@@ -1558,8 +1471,7 @@ public class RestManager {
             @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName,
             @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic,
             @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass,
-            @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String ruleName,
-            @ApiParam(value = "Filter Rule", required = true) FilterRule rule) {
+            @ApiParam(value = "JsonPath filter expression", required = true) String rule) {
 
         try {
             final DroolsController drools = this.getDroolsController(controllerName);
@@ -1578,25 +1490,25 @@ public class RestManager {
                         .entity(new Error(controllerName + ":" + topic + ":" + factClass + "  no filters")).build();
             }
 
-            if (rule.getName() == null) {
+            if (rule == null || rule.isEmpty()) {
                 return Response.status(Response.Status.BAD_REQUEST).entity(new Error(controllerName + ":" + topic + ":"
-                        + factClass + " rule name request inconsistencies (" + rule.getName() + ")")).build();
+                        + factClass + " no filter rule provided")).build();
             }
 
-            filter.addRule(rule.getName(), rule.getRegex());
-            return Response.status(Response.Status.OK).entity(filter.getRules()).build();
+            filter.setRule(rule);
+            return Response.status(Response.Status.OK).entity(filter.getRule()).build();
         } catch (final IllegalArgumentException e) {
             logger.debug(
                     "{}: cannot access decoder filter rules for policy-controller {} "
-                            + "topic {} type {} rule {} because of {}",
-                            this, controllerName, topic, factClass, ruleName, e.getMessage(), e);
+                            + "topic {} type {} because of {}",
+                            this, controllerName, topic, factClass, e.getMessage(), e);
             return Response.status(Response.Status.NOT_FOUND)
-                    .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not found")).build();
+                    .entity(new Error(controllerName + ":" + topic + " not found")).build();
         } catch (final IllegalStateException e) {
             logger.debug(
                     "{}: cannot access decoder filter rules for policy-controller {} "
-                            + "topic {} type {} rule {} because of {}",
-                            this, controllerName, topic, factClass, ruleName, e.getMessage(), e);
+                            + "topic {} type {} because of {}",
+                            this, controllerName, topic, factClass, e.getMessage(), e);
             return Response.status(Response.Status.NOT_ACCEPTABLE)
                     .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not acceptable")).build();
         }
@@ -1604,7 +1516,7 @@ public class RestManager {
 
     /**
      * POST.
-     * 
+     *
      * @return response object
      */
     @POST
@@ -1665,7 +1577,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1715,7 +1627,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -1735,7 +1647,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -1755,7 +1667,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1768,7 +1680,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1781,7 +1693,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1794,7 +1706,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1807,7 +1719,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1820,7 +1732,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1833,7 +1745,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1847,7 +1759,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1861,7 +1773,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1876,7 +1788,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1890,7 +1802,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1905,7 +1817,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1920,7 +1832,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1936,7 +1848,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1951,7 +1863,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1964,7 +1876,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1977,7 +1889,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -1991,7 +1903,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -2004,7 +1916,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -2024,7 +1936,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -2048,7 +1960,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -2061,7 +1973,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -2081,7 +1993,7 @@ public class RestManager {
 
     /**
      * DELETE.
-     * 
+     *
      * @return response object
      */
     @DELETE
@@ -2102,7 +2014,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -2146,7 +2058,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
@@ -2190,7 +2102,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -2203,7 +2115,7 @@ public class RestManager {
 
     /**
     * GET.
-    * 
+    *
     * @return response object
     */
     @GET
@@ -2227,7 +2139,7 @@ public class RestManager {
 
     /**
      * GET.
-     * 
+     *
      * @return response object
      */
     @GET
@@ -2255,7 +2167,7 @@ public class RestManager {
 
     /**
      * PUT.
-     * 
+     *
      * @return response object
      */
     @PUT
index e83e588..e0baeb6 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,205 +24,140 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.junit.Test;
-import org.onap.policy.drools.protocol.coders.JsonProtocolFilter.FilterRule;
-import org.onap.policy.drools.utils.Pair;
-
 
 public class JsonProtocolFilterTest {
 
-    private static final String NAME1 = "name1";
-    private static final String REGEX1 = "regex1";
+    private static final String JSON =
+                    "{\"requestID\":\"38adde30-cc22-11e8-a8d5-f2801f1b9fd1\",\"entity\":\"controller\","
+                                    + "\"controllers\":[{\"name\":\"test-controller\","
+                                    + "\"drools\":{\"groupId\":\"org.onap.policy.drools.test\","
+                                    + "\"artifactId\":\"test\",\"version\":\"0.0.1\"},\"operation\":\"update\"}]}";
+
+    /**
+     * Tests getting the rule expression of the filter.
+     */
+    @Test
+    public void getRuleTest() {
+        assertEquals("$.test", new JsonProtocolFilter("$.test").getRule());
+    }
+
+    /**
+     * Tests setting the rule expression of the filter.
+     */
+    @Test
+    public void setRuleTest() {
+        JsonProtocolFilter filter = new JsonProtocolFilter();
+        assertEquals(JsonProtocolFilter.MATCH_ANY, filter.getRule());
+        filter.setRule("$.test");
+        assertEquals("$.test", filter.getRule());
+    }
+
+    /**
+     * Tests that the rule expression will be set to match anything if an empty string is passed.
+     */
+    @Test
+    public void setRuleEmptyTest() {
+        assertEquals(JsonProtocolFilter.MATCH_ANY, new JsonProtocolFilter("").getRule());
+    }
+
+    /**
+     * Tests that the rule expression will be set to match anything if a null string is passed.
+     */
+    @Test
+    public void setRuleNullTest() {
+        assertEquals(JsonProtocolFilter.MATCH_ANY, new JsonProtocolFilter(null).getRule());
+    }
+
+    /**
+     * Tests accepting a message if all filter rules pass.
+     */
+    @Test
+    public void acceptPassTest() {
+        assertTrue(new JsonProtocolFilter(
+                        "$.controllers[?(@.drools.version =~ /\\d\\.\\d\\.\\d/ && @.operation == 'update')]")
+                                        .accept(JSON));
+    }
+
+    /**
+     * Tests accepting a message without having to filter if the rule is set to match anything.
+     */
+    @Test
+    public void acceptAnyTest() {
+        assertTrue(new JsonProtocolFilter(null).accept(JSON));
+    }
 
-    private static final String NAME2 = "name2";
-    private static final String REGEX2 = "regex2";
+    /**
+     * Tests rejecting a message if one or more of the filter rules fail.
+     */
+    @Test
+    public void acceptFailTest() {
+        assertFalse(
+            new JsonProtocolFilter("$.controllers[?(@.drools.version =~ /\\\\d\\\\.\\\\d\\\\.2/)]")
+                .accept(JSON));
+    }
 
-    private static final String NAME3 = "name3";
-    private static final String REGEX3 = "regex3";
+    /**
+     * Tests finding field matches for a filter rule corresponding to a topic.
+     */
+    @Test
+    public void filterPassTest() {
+        assertEquals("38adde30-cc22-11e8-a8d5-f2801f1b9fd1", new JsonProtocolFilter("$.requestID").filter(JSON).get(0));
+    }
+
+    /**
+     * Tests that an empty list is returned when no matches are found.
+     */
+    @Test
+    public void filterFailTest() {
+        assertTrue(new JsonProtocolFilter("$.test").filter(JSON).isEmpty());
+    }
 
-    private static final String NAME4 = "name4";
-    private static final String REGEX4a = "^regex4a.*";
-    private static final String REGEX4b = ".*regex4b$";
-    
+    /**
+     * Tests static method for filtering a JSON string with an arbitrary expression.
+     */
+    @Test
+    public void staticFilterPassTest() {
+        assertEquals("controller", JsonProtocolFilter.filter(JSON, "$.entity").get(0));
+    }
 
+    /**
+     * Tests that an empty list is returned when the static filter() method does not find any matches.
+     */
     @Test
-    public void test() {
-        
-        //      ********************   D E F I N E   f i l t e r R u l e   O b j e c t s   ***************************
-        //      DEFINE one (1) filterRule object (using constructor without parms passed; instead use set methods
-        FilterRule filterRule1 = new FilterRule();
-        filterRule1.setName(NAME1);
-        filterRule1.setRegex(REGEX1);
-        assertEquals(filterRule1.getName(), NAME1);
-        assertEquals(filterRule1.getRegex(), REGEX1);
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      DEFINE four (4) filterRule objects (using constructor passing the field values
-        FilterRule filterRule2 = new FilterRule(NAME2, REGEX2);
-        assertEquals(filterRule2.getName(), NAME2);
-        assertEquals(filterRule2.getRegex(), REGEX2);
-
-        FilterRule filterRule3 = new FilterRule(NAME3, REGEX3);
-        assertEquals(filterRule3.getName(), NAME3);
-        assertEquals(filterRule3.getRegex(), REGEX3);
-
-        FilterRule filterRule4a = new FilterRule(NAME4, REGEX4a);
-        assertEquals(filterRule4a.getName(), NAME4);
-        assertEquals(filterRule4a.getRegex(), REGEX4a);
-
-        FilterRule filterRule4b = new FilterRule(NAME4, REGEX4b);
-        assertEquals(filterRule4b.getName(), NAME4);
-        assertEquals(filterRule4b.getRegex(), REGEX4b);
-
-
-
-        //      ************************   D E F I N E   f i l t e r   L i s t s  ************************************
-        //      DEFINE rawFiltersA
-        List<Pair<String,String>> rawFiltersA = new ArrayList<>();
-        rawFiltersA.add(new Pair<String,String>(filterRule1.getName(), filterRule1.getRegex()));
-        rawFiltersA.add(new Pair<String,String>(filterRule2.getName(), filterRule2.getRegex()));
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      DEFINE filtersA 
-        List<FilterRule> filtersA = new ArrayList<>();
-        for (Pair<String, String> filterPair: rawFiltersA) {
-            if  (filterPair.first() == null || filterPair.first().isEmpty()) {
-                continue;
-            }
-            filtersA.add(new FilterRule(filterPair.first(), filterPair.second()));
-        }
-
-
-
-        //      ***********   I N S T A N T I A T E   J s o n P r o t o c o l F i l t e r   O b j e c t s   **********
-        //      INSTANTIATE protocolFilterA  (passing raw filters to the 'fromRawFilters' constructor)
-        JsonProtocolFilter protocolFilterA = JsonProtocolFilter.fromRawFilters(rawFiltersA);
-        assertTrue(protocolFilterA.isRules());
-        assertEquals(protocolFilterA.getRules().toString(), filtersA.toString());
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      INSTANTIATE protocolFilterB  (passing filters list to constructor which accepts such)
-        JsonProtocolFilter protocolFilterB = new JsonProtocolFilter(filtersA);
-        assertTrue(protocolFilterB.isRules());
-        assertEquals(protocolFilterB.getRules(), filtersA);
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      INSTANTIATE protocolFilterC  (using constructor without parms; add instead using setRules() method
-        JsonProtocolFilter protocolFilterC = new JsonProtocolFilter();
-        protocolFilterC.setRules(filtersA);
-        assertTrue(protocolFilterC.isRules());
-        assertEquals(protocolFilterC.getRules(), filtersA);
-
-
-
-        //      ***   D E F I N E   o t h e r   f i l t e r   L i s t s   f o r   v a l i d a t i o n s   ************
-        //      DEFINE rawFiltersB
-        List<Pair<String,String>> rawFiltersB = new ArrayList<>();
-        rawFiltersB.add(new Pair<String,String>(filterRule1.getName(), filterRule1.getRegex()));
-        rawFiltersB.add(new Pair<String,String>(filterRule2.getName(), filterRule2.getRegex()));
-        rawFiltersB.add(new Pair<String,String>(filterRule3.getName(), filterRule3.getRegex()));
-        rawFiltersB.add(new Pair<String,String>(filterRule4a.getName(), filterRule4a.getRegex()));
-        rawFiltersB.add(new Pair<String,String>(filterRule4b.getName(), filterRule4b.getRegex()));
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      DEFINE filtersB
-        List<FilterRule> filtersB = new ArrayList<>();
-        for (Pair<String, String> filterPair: rawFiltersB) {
-            filtersB.add(new FilterRule(filterPair.first(), filterPair.second()));
-        }
-
-
-
-        //      ***********   A D D   T O   p r o t o c o l F i l t e r B   3   m o r e   f i l t e r s   ************
-        protocolFilterB.addRule(filterRule3.getName(), filterRule3.getRegex());
-        protocolFilterB.addRule(filterRule4a.getName(), filterRule4a.getRegex());
-        protocolFilterB.addRule(filterRule4b.getName(), filterRule4b.getRegex());
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      VALIDATE that protocolFilterB now contains filters passed using filtersA and the new ones just added
-        assertEquals(protocolFilterB.getRules().toString(), filtersB.toString());
-
-
-
-        //      ************   D E L E T E   f i l t e r s   f r o m   p r o t o c o l F i l t e r B       ***********
-        //      DELETE specific filter from protocolFilterB by passing both the name & regex values
-
-        assertTrue(protocolFilterB.getRules(NAME3).size() == 1);
-        assertTrue(protocolFilterB.getRules(NAME3).get(0).getName().equals(NAME3));
-        assertTrue(protocolFilterB.getRules(NAME3).get(0).getRegex().equals(REGEX3));
-
-        assertTrue(protocolFilterB.getRules(NAME4).size() == 2);
-        assertTrue(protocolFilterB.getRules(NAME4).get(0).getName().equals(NAME4));
-        assertTrue(protocolFilterB.getRules(NAME4).get(0).getRegex().equals(REGEX4a));
-        assertTrue(protocolFilterB.getRules(NAME4).get(1).getName().equals(NAME4));
-        assertTrue(protocolFilterB.getRules(NAME4).get(1).getRegex().equals(REGEX4b));
-
-        final String jsonA = "{ \"name1\":\"regex1\",\"name2\":\"regex2\","
-                        + "\"name3\":\"regex3\",\"name4\":\"regex4a\",\"name4\":\"regex4b\"}";
-        final String jsonB = "{ \"name1\":\"regex1\",\"name2\":\"regex2\","
-                        + "\"name3\":\"regex3\",\"name4\":\"regex4a-regex4b\"}";
-        final String jsonC = "{ \"name1\":\"regex1\",\"name2\":\"regex2\","
-                        + "\"name3\":\"regex3\",\"name4\":\"regex4a\"}";
-        final String jsonD = "{ \"name1\":\"regex1\",\"name2\":\"regex2\","
-                        + "\"name3\":\"regex3\",\"name4\":\"regex4b\"}";
-
-        assertFalse(protocolFilterB.accept(jsonA));
-        assertTrue(protocolFilterB.accept(jsonB));
-        assertFalse(protocolFilterB.accept(jsonC));
-        assertFalse(protocolFilterB.accept(jsonD));
-
-        protocolFilterB.deleteRule(NAME4, REGEX4a);
-
-        assertTrue(protocolFilterB.accept(jsonA));
-        assertTrue(protocolFilterB.accept(jsonB));
-        assertFalse(protocolFilterB.accept(jsonC));
-        assertTrue(protocolFilterB.accept(jsonD));
-
-        protocolFilterB.addRule(NAME4, REGEX4a);
-
-        assertTrue(protocolFilterB.getRules(NAME4).size() == 2);
-        assertTrue(protocolFilterB.getRules(NAME4).get(0).getName().equals(NAME4));
-        assertTrue(protocolFilterB.getRules(NAME4).get(0).getRegex().equals(REGEX4b));
-        assertTrue(protocolFilterB.getRules(NAME4).get(1).getName().equals(NAME4));
-        assertTrue(protocolFilterB.getRules(NAME4).get(1).getRegex().equals(REGEX4a));
-
-        assertFalse(protocolFilterB.accept(jsonA));
-        assertTrue(protocolFilterB.accept(jsonB));
-        assertFalse(protocolFilterB.accept(jsonC));
-        assertFalse(protocolFilterB.accept(jsonD));
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      DELETE all filters from protocolFilterB that have a match to the same name value
-        protocolFilterB.deleteRules(NAME4);
-
-        assertTrue(protocolFilterB.getRules(NAME4).isEmpty());
-        assertTrue(protocolFilterB.accept(jsonA));
-        assertTrue(protocolFilterB.accept(jsonB));
-        assertTrue(protocolFilterB.accept(jsonC));
-        assertTrue(protocolFilterB.accept(jsonD));
-
-        assertTrue(protocolFilterB.getRules(NAME3).size() == 1);
-        protocolFilterB.addRule(NAME3, REGEX3);
-        assertTrue(protocolFilterB.getRules(NAME3).size() == 1);
-        protocolFilterB.deleteRule(NAME3, REGEX3);
-        assertTrue(protocolFilterB.getRules(NAME3).isEmpty());
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      VALIDATE that protocolFilterB now only contains the filters that were originally passed using filtersA
-        assertEquals(protocolFilterB.getRules(), filtersA);
-
-        //      ************   A C C E P T   J S O N   I F   I T   P A S S E S   A L L   F I L T E R S     ***********
-        //      ACCEPT TRUE a JSON that passes all filters
-        String jsonE = "{ \"name1\":\"regex1\",\"name2\":\"regex2\"}";
-        assertTrue(protocolFilterA.accept(jsonE));
-
-        //      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-        //      ACCEPT FALSE a JSON that does NOT pass all filters
-        String jsonF = "{ \"name1\":\"regex1\"}";
-        assertFalse(protocolFilterA.accept(jsonF));
+    public void staticFilterFailTest() {
+        assertTrue(JsonProtocolFilter.filter(JSON, "$.test").isEmpty());
     }
 
+    /**
+     * Tests that an exception is thrown if a null JSON string is passed.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void staticFilterNullJsonTest() {
+        JsonProtocolFilter.filter(null, "[?($ =~ /.*/");
+    }
+
+    /**
+     * Tests that an exception is thrown if an empty JSON string is passed.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void staticFilterEmptyJsonTest() {
+        JsonProtocolFilter.filter("", "[?($ =~ /.*/");
+    }
+
+    /**
+     * Tests that an exception is thrown if a null expression string is passed.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void staticFilterNullExpressionTest() {
+        JsonProtocolFilter.filter("{\"hello\":\"world\"}", null);
+    }
+
+    /**
+     * Tests that an exception is thrown if an empty expression string is passed.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void staticFilterEmptyExpressionTest() {
+        JsonProtocolFilter.filter("{\"hello\":\"world\"}", "");
+    }
 }
\ No newline at end of file
index da49126..b7d72f3 100644 (file)
@@ -25,7 +25,6 @@ import com.google.gson.GsonBuilder;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
 import org.junit.Assert;
@@ -39,7 +38,6 @@ import org.onap.policy.drools.controller.DroolsController;
 import org.onap.policy.drools.controller.internal.MavenDroolsControllerTest;
 import org.onap.policy.drools.properties.DroolsProperties;
 import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
-import org.onap.policy.drools.protocol.coders.JsonProtocolFilter.FilterRule;
 import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
 import org.onap.policy.drools.util.KieUtils;
 import org.onap.policy.drools.utils.Triple;
@@ -64,7 +62,7 @@ public class ProtocolCoderToolsetTest {
 
     /**
      * Setup.
-     * 
+     *
      * @throws IOException throws IO Exception
      */
     @Before
@@ -96,7 +94,7 @@ public class ProtocolCoderToolsetTest {
 
     /**
      * Test the Gson toolset.
-     * 
+     *
      * @param protocolFilter protocol filter
      */
     public void testGsonToolset(JsonProtocolFilter protocolFilter) {
@@ -157,11 +155,9 @@ public class ProtocolCoderToolsetTest {
         CoderFilters coderFilters = coderToolset.getCoder(Triple.class.getCanonicalName());
         Assert.assertTrue(coderFilters.getCodedClass() == Triple.class.getCanonicalName());
         Assert.assertTrue(coderFilters.getFilter() == protocolFilter);
-        Assert.assertTrue(coderFilters.getFilter().getRules("second").size() == 1);
-        Assert.assertTrue(coderFilters.getFilter().getRules("third").size() == 1);
+        Assert.assertTrue(coderFilters.getFilter().getRule() != null);
 
-        coderFilters.getFilter().getRules("second").get(0).setRegex("^v2$");
-        coderFilters.getFilter().getRules("third").get(0).setRegex(".*v3.*");
+        coderFilters.getFilter().setRule("[?($.second =~ /^v2$/ && $.third =~ /.*v3.*/)]");
 
         tripleDecoded = (Triple<String, String, String>) coderToolset.decode(tripleEncoded);
 
@@ -169,8 +165,8 @@ public class ProtocolCoderToolsetTest {
         Assert.assertTrue(tripleDecoded.second().equals(triple.second()));
         Assert.assertTrue(tripleDecoded.third().equals(triple.third()));
 
-        coderFilters.getFilter().deleteRules("third");
-        Assert.assertTrue(coderFilters.getFilter().getRules("third").isEmpty());
+        coderFilters.getFilter().setRule(null);
+        Assert.assertEquals("[?($ =~ /.*/)]", coderFilters.getFilter().getRule());
 
         tripleDecoded = (Triple<String, String, String>) coderToolset.decode(tripleEncoded);
 
@@ -178,7 +174,7 @@ public class ProtocolCoderToolsetTest {
         Assert.assertTrue(tripleDecoded.second().equals(triple.second()));
         Assert.assertTrue(tripleDecoded.third().equals(triple.third()));
 
-        coderFilters.getFilter().addRule("third", ".*v3.*");
+        coderFilters.getFilter().setRule("[?($.third =~ /.*v3.*/)]");
     }
 
     private String encode(ProtocolCoderToolset coderToolset, Triple<String, String, String> triple) {
@@ -188,10 +184,8 @@ public class ProtocolCoderToolsetTest {
     }
 
     private void addRemoveCoder(ProtocolCoderToolset coderToolset) {
-        List<FilterRule> filters = new ArrayList<>();
-        filters.add(new FilterRule("second", ".*"));
-
-        coderToolset.addCoder(this.getClass().getCanonicalName(), new JsonProtocolFilter(filters), 654321);
+        coderToolset.addCoder(this.getClass().getCanonicalName(),
+                new JsonProtocolFilter("[?($.second =~ /.*/)]"), 654321);
         Assert.assertTrue(coderToolset.getCoders().size() == 2);
 
         coderToolset.removeCoders(this.getClass().getCanonicalName());
@@ -199,22 +193,18 @@ public class ProtocolCoderToolsetTest {
     }
 
     private void updateCoderFilterRule(ProtocolCoderToolset coderToolset) {
-        List<FilterRule> filters = new ArrayList<>();
-        filters.add(new FilterRule("third", ".*"));
-        coderToolset.addCoder(Triple.class.getCanonicalName(), new JsonProtocolFilter(filters), 654321);
+        coderToolset.addCoder(Triple.class.getCanonicalName(), new JsonProtocolFilter("[?($.third =~ /.*/)]"), 654321);
 
         Assert.assertTrue(coderToolset.getCoders().size() == 1);
 
         Assert.assertTrue(coderToolset.getCoder(Triple.class.getCanonicalName()).getModelClassLoaderHash() == 654321);
 
         Assert.assertTrue(
-                coderToolset.getCoder(Triple.class.getCanonicalName()).getFilter().getRules("third").size() == 1);
-
-        Assert.assertTrue(
-                coderToolset.getCoder(Triple.class.getCanonicalName()).getFilter().getRules("third").size() == 1);
+                coderToolset.getCoder(
+                        Triple.class.getCanonicalName()).getFilter().getRule() != null);
 
-        Assert.assertTrue(".*".equals(coderToolset.getCoder(Triple.class.getCanonicalName()).getFilter()
-                .getRules("third").get(0).getRegex()));
+        Assert.assertTrue("[?($.third =~ /.*/)]".equals(coderToolset.getCoder(Triple.class.getCanonicalName())
+                .getFilter().getRule()));
     }
 
     private void validateInitialization(JsonProtocolFilter protocolFilter, ProtocolCoderToolset coderToolset) {
@@ -254,11 +244,6 @@ public class ProtocolCoderToolsetTest {
     }
 
     private JsonProtocolFilter createFilterSet() {
-        List<FilterRule> filters = new ArrayList<>();
-        filters.add(new FilterRule("first", ".*"));
-        filters.add(new FilterRule("second", "^blah.*"));
-        filters.add(new FilterRule("third", "^hello$"));
-
-        return new JsonProtocolFilter(filters);
+        return new JsonProtocolFilter("[?($.first =~ /.*/ && $.second =~ /^blah.*/ && $.third =~ /^hello$/)]");
     }
 }
diff --git a/pom.xml b/pom.xml
index 9b8f650..ff9cdb7 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -57,6 +57,7 @@
 
         <!-- Project common dependency versions -->
         <jersey.version>2.25.1</jersey.version>
+        <json.path.version>2.4.0</json.path.version>
         <hibernate.core.version>5.2.10.Final</hibernate.core.version>
         <hibernate.commons.annotations.version>5.0.1.Final</hibernate.commons.annotations.version>
         <commons.io.version>2.5</commons.io.version>
                 <artifactId>javax.inject</artifactId>
                 <version>2.4.0-b31</version>
             </dependency>
+            <dependency>
+                <groupId>com.jayway.jsonpath</groupId>
+                <artifactId>json-path</artifactId>
+                <version>${json.path.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.glassfish.jersey.containers</groupId>
                 <artifactId>jersey-common</artifactId>