From fa2a5a43c82cd35cca9e7d4b51f83ce70e1e3e59 Mon Sep 17 00:00:00 2001 From: Daniel Cruz Date: Thu, 14 Feb 2019 00:42:45 -0600 Subject: Add Nested JSON Filtering 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 --- .../drools/controller/DroolsControllerFactory.java | 78 +---- .../drools/protocol/coders/JsonProtocolFilter.java | 388 ++++----------------- .../protocol/coders/ProtocolCoderToolset.java | 31 +- .../policy/drools/server/restful/RestManager.java | 314 ++++++----------- 4 files changed, 203 insertions(+), 608 deletions(-) (limited to 'policy-management/src/main/java') diff --git a/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java b/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java index 24fc6de9..16daa947 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java +++ b/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java @@ -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 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> 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 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(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) { diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/JsonProtocolFilter.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/JsonProtocolFilter.java index f65efaed..2ccc010f 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/JsonProtocolFilter.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/JsonProtocolFilter.java @@ -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. @@ -20,378 +20,120 @@ 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 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 filters) { - List 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> rawFilters) { - - if (rawFilters == null) { - throw new IllegalArgumentException("No raw filters provided"); - } - - List filters = new ArrayList<>(); - for (Pair 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 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 getRules(String name) { - if (name == null || name.isEmpty()) { - throw new IllegalArgumentException(MISSING_RULE_NAME); - } - - ArrayList temp = new ArrayList<>(); - for (FilterRule rule : this.rules) { - if (rule.getName().equals(name)) { - temp.add(rule); - } - } - return temp; + public List 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 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 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 filter(String json, String expression) { + if (json == null || json.isEmpty()) { + throw new IllegalArgumentException("a json string must be provided"); } - List 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 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(); - } - } diff --git a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java index f125c134..394e73af 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java +++ b/policy-management/src/main/java/org/onap/policy/drools/protocol/coders/ProtocolCoderToolset.java @@ -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. */ diff --git a/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java b/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java index 64fd6823..cbe2b339 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java +++ b/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java @@ -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 -- cgit 1.2.3-korg