summaryrefslogtreecommitdiffstats
path: root/feature-mdc-filters/src/main
diff options
context:
space:
mode:
authorDaniel Cruz <dc443y@att.com>2019-03-22 08:33:29 -0500
committerDaniel Cruz <dc443y@att.com>2019-03-25 09:11:29 -0500
commit89d3441bb04047d63ff8f4f586773d7c287e1deb (patch)
treef61cce38bf849e6ba71aeaf4b83db6999cd46162 /feature-mdc-filters/src/main
parentd0715ca90465d0f7b3d090234f6b0098194f0101 (diff)
Add MDC Topic Filtering
A feature to provide configurable properties for network topics to extrac fields from JSON strings and place them in a mapped diagnostic context. Issue-ID: POLICY-1499 Change-Id: Icfca0be3b263ccf1612b79ed617e2b1ffb0317e6 Signed-off-by: Daniel Cruz <dc443y@att.com>
Diffstat (limited to 'feature-mdc-filters/src/main')
-rwxr-xr-xfeature-mdc-filters/src/main/feature/config/feature-mdc-filters.properties54
-rwxr-xr-xfeature-mdc-filters/src/main/feature/install/disable32
-rwxr-xr-xfeature-mdc-filters/src/main/feature/install/enable32
-rwxr-xr-xfeature-mdc-filters/src/main/java/org/onap/policy/drools/mdc/filters/MdcFilterFeature.java201
-rwxr-xr-xfeature-mdc-filters/src/main/java/org/onap/policy/drools/mdc/filters/MdcTopicFilter.java337
-rwxr-xr-xfeature-mdc-filters/src/main/resources/META-INF/services/org.onap.policy.common.endpoints.features.NetLoggerFeatureApi1
-rwxr-xr-xfeature-mdc-filters/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureAPI1
7 files changed, 658 insertions, 0 deletions
diff --git a/feature-mdc-filters/src/main/feature/config/feature-mdc-filters.properties b/feature-mdc-filters/src/main/feature/config/feature-mdc-filters.properties
new file mode 100755
index 00000000..0a53a9f5
--- /dev/null
+++ b/feature-mdc-filters/src/main/feature/config/feature-mdc-filters.properties
@@ -0,0 +1,54 @@
+###
+# ============LICENSE_START=======================================================
+# feature-mdc-filters
+# ================================================================================
+# Copyright (C) 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+# The properties keys follow the controller topic configurations followed by a
+# a new topic property, 'mdcFilters'.
+#<protocol>.<type>.topics.<topic-name>.mdcFilters
+
+# The value of the property is broken down to the MDC key name to be used by the
+# feature followed by the path(s) to the desired field's value.
+#dmaap.sink.topics.example.mdcFilters=sampleKey=$.path.to.sample.key
+
+# The path always begins with '$' as this signifies the root of the JSON document.
+# The underlying library used is Jayway JsonPath. The library's query syntax is
+# supported for searching a JSON document. The query syntax and some examples
+# can be found at: https://github.com/json-path/JsonPath
+
+# Multiple fields can be found for a given JSON document by a comma separated list
+# of <mdcKey,jsonPath> pairs.
+#dmaap.sink.topics.example.mdcFilters=field1=$.field1,field2=$.field2
+
+# If a given topic supports multiple message types that have fields with the same
+# name, a '|' separated list can define multiple paths to a field. The feature
+# will loop through each path until it finds a match and returns it.
+#dmaap.sink.topics.example.mdcFilters=field1=$.field1|$.body.field1
+
+# dmaap source filters
+dmaap.source.topics.PDPD-CONFIGURATION.mdcFilters=requestID=$.requestID
+dmaap.source.topics.DCAE_TOPIC.mdcFilters=requestID=$.requestID
+dmaap.source.topics.APPC-CL.mdcFilters=requestID=$.CommonHeader.RequestID
+dmaap.source.topics.APPC-LCM-WRITE.mdcFilters=requestID=$.body.output.common-header.request-id
+dmaap.source.topics.SDNR-CL-RSP.mdcFilters=requestID=$.body.CommonHeader.RequestID
+
+# dmaap sink filters
+dmaap.sink.topics.POLICY-CL-MGT.mdcFilters=requestID=$.requestID
+dmaap.sink.topics.APPC-CL.mdcFilters=requestID=$.CommonHeader.RequestID
+dmaap.sink.topics.APPC-LCM-READ.mdcFilters=requestID=$.body.input.common-header.request-id
+dmaap.sink.topics.SDNR-CL.mdcFilters=requestID=$.body.CommonHeader.RequestID
diff --git a/feature-mdc-filters/src/main/feature/install/disable b/feature-mdc-filters/src/main/feature/install/disable
new file mode 100755
index 00000000..25d57374
--- /dev/null
+++ b/feature-mdc-filters/src/main/feature/install/disable
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+###
+# ============LICENSE_START=======================================================
+# feature-mdc-filters
+# ================================================================================
+# Copyright (C) 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+##
+
+if [[ "${DEBUG}" == "y" ]]; then
+ set -x
+fi
+
+CONFIG_DIR="${POLICY_HOME}"/config
+for mainConfig in ${CONFIG_DIR}/logback.xml ${CONFIG_DIR}/logback-eelf.xml; do
+ if [ -e "${mainConfig}" ]; then
+ sed -i --follow-symlinks 's/${abstractNetworkPattern}/${networkPattern}/' "${mainConfig}"
+ fi
+done
diff --git a/feature-mdc-filters/src/main/feature/install/enable b/feature-mdc-filters/src/main/feature/install/enable
new file mode 100755
index 00000000..57c7cc4a
--- /dev/null
+++ b/feature-mdc-filters/src/main/feature/install/enable
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+###
+# ============LICENSE_START=======================================================
+# feature-mdc-filters
+# ================================================================================
+# Copyright (C) 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+##
+
+if [[ "${DEBUG}" == "y" ]]; then
+ set -x
+fi
+
+CONFIG_DIR="${POLICY_HOME}"/config
+for mainConfig in ${CONFIG_DIR}/logback.xml ${CONFIG_DIR}/logback-eelf.xml; do
+ if [ -e "${mainConfig}" ]; then
+ sed -i --follow-symlinks 's/${networkPattern}/${abstractNetworkPattern}/' "${mainConfig}"
+ fi
+done
diff --git a/feature-mdc-filters/src/main/java/org/onap/policy/drools/mdc/filters/MdcFilterFeature.java b/feature-mdc-filters/src/main/java/org/onap/policy/drools/mdc/filters/MdcFilterFeature.java
new file mode 100755
index 00000000..369c0aa0
--- /dev/null
+++ b/feature-mdc-filters/src/main/java/org/onap/policy/drools/mdc/filters/MdcFilterFeature.java
@@ -0,0 +1,201 @@
+/*
+ * ============LICENSE_START=======================================================
+ * feature-mdc-filters
+ * ================================================================================
+ * Copyright (C) 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.mdc.filters;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+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.features.NetLoggerFeatureApi;
+import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
+import org.onap.policy.drools.features.PolicyControllerFeatureAPI;
+import org.onap.policy.drools.persistence.SystemPersistence;
+import org.onap.policy.drools.system.PolicyController;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+public class MdcFilterFeature implements NetLoggerFeatureApi, PolicyControllerFeatureAPI {
+
+ /**
+ * Logger.
+ */
+ private static final Logger logger = LoggerFactory.getLogger(MdcFilterFeature.class);
+
+ /**
+ * Feature properties.
+ */
+ public static final String FEATURE_NAME = "feature-mdc-filters";
+ public static final String SOURCE = "source";
+ public static final String SINK = "sink";
+ public static final String MDC_FILTERS = ".mdcFilters";
+
+ /**
+ * Mapping of 'protocol:type:topic' key to a 'MdcTopicFilter' object.
+ */
+ private Map<String, MdcTopicFilter> topicFilters = new HashMap<>();
+
+ /**
+ * Feature properties map obtained from the feature properties file.
+ */
+ private Properties featureProps = null;
+
+ /**
+ * Constructor.
+ */
+ public MdcFilterFeature() {
+ super();
+ featureProps = getFeatureProps();
+ }
+
+ /**
+ * Gets the feature properties.
+ *
+ * @return the properties for this feature.
+ */
+ protected Properties getFeatureProps() {
+ return SystemPersistence.manager.getProperties(FEATURE_NAME);
+ }
+
+ /**
+ * Sequence number to be used for order of feature implementer execution.
+ */
+ @Override
+ public int getSequenceNumber() {
+ return 1;
+ }
+
+ /**
+ * Loops through all source and sink topics to find which topics have mdc filters and
+ * inserts an MdcTopicFilter in to the topicFilters map.
+ */
+ @Override
+ public boolean afterCreate(PolicyController controller) {
+ createSourceTopicFilters(controller);
+ createSinkTopicFilters(controller);
+ return false;
+ }
+
+ /**
+ * Extracts the fields in a JSON string that are to be logged in an abbreviated
+ * message. The event delivery infrastructure details are put in the MDC as well using
+ * the keys networkEventType (IN/OUT), networkProtocol (UEB/DMAAP/NOOP/REST), and
+ * networkTopic.
+ */
+ @Override
+ public boolean beforeLog(Logger eventLogger, EventType type, CommInfrastructure protocol, String topic,
+ String message) {
+
+ String filterKey = null;
+ if (type == EventType.IN) {
+ filterKey = getTopicKey(protocol.name().toLowerCase(), SOURCE, topic);
+ } else {
+ filterKey = getTopicKey(protocol.name().toLowerCase(), SINK, topic);
+ }
+
+ MDC.put("networkEventType", type.name());
+ MDC.put("networkProtocol", protocol.name());
+ MDC.put("networkTopic", topic);
+
+ MdcTopicFilter filter = topicFilters.get(filterKey);
+ if (filter != null) {
+ for (Map.Entry<String, List<String>> entry : filter.find(message).entrySet()) {
+ String mdcKey = entry.getKey();
+ List<String> results = entry.getValue();
+ if (results.isEmpty()) {
+ logger.debug("No results found for key {}", mdcKey);
+ } else if (results.size() > 1) {
+ logger.debug("Multple results found for key {}, returning list as a string", mdcKey);
+ MDC.put(mdcKey, results.toString());
+ } else {
+ MDC.put(mdcKey, results.get(0));
+ }
+ }
+ } else {
+ logger.debug("No mdc topic filters exist for key {}", filterKey);
+ }
+
+ return false;
+ }
+
+ /**
+ * Clears the MDC mapping after a message is logged.
+ */
+ @Override
+ public boolean afterLog(Logger eventLogger, EventType type, CommInfrastructure protocol, String topic,
+ String message) {
+ MDC.clear();
+ return false;
+ }
+
+ /**
+ * Creates a key using the protocol, type, and topic name.
+ *
+ * @param protocol defined as ueb, dmaap, noop
+ * @param type defined as source or sink
+ * @param topic name of the topic
+ * @return a key that is the concatenation of the protocol, type, and topic name
+ */
+ private String getTopicKey(String protocol, String type, String topic) {
+ return protocol + ":" + type + ":" + topic;
+ }
+
+ /**
+ * Creates MdcTopicFilters for a source/sink topic based on the type.
+ *
+ * @param topic the topic name
+ * @param type 'source' or 'sink'
+ */
+ private void createTopicFilter(Topic topic, String type) {
+ String protocol = topic.getTopicCommInfrastructure().name().toLowerCase();
+ String topicName = topic.getTopic();
+
+ String propertyKey = protocol + "." + type + ".topics." + topicName + MDC_FILTERS;
+ String propertyValue = featureProps.getProperty(propertyKey);
+ if (propertyValue != null) {
+ String topicKey = getTopicKey(protocol, type, topicName);
+ if (!topicFilters.containsKey(topicKey)) {
+ logger.debug("MdcTopicFilter created for {} {} topic {}", protocol, type, topicName);
+ topicFilters.put(topicKey, new MdcTopicFilter(propertyValue));
+ } else {
+ logger.debug("An MdcTopicFilter already exists for key {}", topicKey);
+ }
+ } else {
+ logger.debug("No MDC filters defined for {} {} topic {}", protocol, type, topicName);
+ }
+ }
+
+ /**
+ * Creates MdcTopicFilters for the controller's source topics.
+ */
+ private void createSourceTopicFilters(PolicyController controller) {
+ controller.getTopicSources().forEach(sourceTopic -> createTopicFilter(sourceTopic, SOURCE));
+ }
+
+ /**
+ * Creates MdcTopicFilters for the controller's sink topics.
+ */
+ private void createSinkTopicFilters(PolicyController controller) {
+ controller.getTopicSinks().forEach(sinkTopic -> createTopicFilter(sinkTopic, SINK));
+ }
+}
diff --git a/feature-mdc-filters/src/main/java/org/onap/policy/drools/mdc/filters/MdcTopicFilter.java b/feature-mdc-filters/src/main/java/org/onap/policy/drools/mdc/filters/MdcTopicFilter.java
new file mode 100755
index 00000000..d0813a93
--- /dev/null
+++ b/feature-mdc-filters/src/main/java/org/onap/policy/drools/mdc/filters/MdcTopicFilter.java
@@ -0,0 +1,337 @@
+/*
+ * ============LICENSE_START=======================================================
+ * feature-mdc-filters
+ * ================================================================================
+ * Copyright (C) 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.mdc.filters;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.onap.policy.drools.protocol.coders.JsonProtocolFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MdcTopicFilter {
+
+ private static final Logger logger = LoggerFactory.getLogger(MdcTopicFilter.class);
+
+ public static final String MDC_KEY_ERROR = "mdcKey must be provided";
+ public static final String JSON_PATH_ERROR = "json path(s) must be provided";
+
+ private Map<String, FilterRule> rules = new HashMap<>();
+
+ public static class FilterRule {
+ private String mdcKey;
+ private List<String> paths;
+
+ public FilterRule(String mdcKey, String path) {
+ this.mdcKey = mdcKey;
+ this.paths = Arrays.asList(path);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param mdcKey the key to the filter rule
+ * @param paths the list of potential paths to the key
+ */
+ public FilterRule(String mdcKey, List<String> paths) {
+ this.mdcKey = mdcKey;
+ this.paths = paths;
+ }
+
+ public String getMdcKey() {
+ return mdcKey;
+ }
+
+ public List<String> getPaths() {
+ return paths;
+ }
+
+ protected void setMdcKey(String mdcKey) {
+ if (mdcKey == null || mdcKey.isEmpty()) {
+ throw new IllegalArgumentException(MDC_KEY_ERROR);
+ }
+ this.mdcKey = mdcKey;
+ }
+
+ protected void setPaths(List<String> paths) {
+ if (paths == null || paths.isEmpty()) {
+ throw new IllegalArgumentException(JSON_PATH_ERROR);
+ }
+ this.paths = paths;
+ }
+
+ protected void addPaths(List<String> paths) {
+ if (paths == null || paths.isEmpty()) {
+ throw new IllegalArgumentException(JSON_PATH_ERROR);
+ }
+ this.paths.addAll(paths);
+ }
+
+ protected void addPath(String path) {
+ if (path == null || path.isEmpty()) {
+ throw new IllegalArgumentException(JSON_PATH_ERROR);
+ }
+ this.paths.add(path);
+ }
+ }
+
+ protected MdcTopicFilter(String rawFilters) {
+ for (String filter : rawFilters.split("\\s*,\\s*")) {
+ FilterRule rule = createFilterRule(filter);
+ rules.put(rule.mdcKey, rule);
+ }
+ }
+
+ private FilterRule createFilterRule(String filter) {
+ String[] filterKeyPaths = filter.split("\\s*=\\s*");
+ if (filterKeyPaths.length != 2) {
+ throw new IllegalArgumentException("could not parse filter rule");
+ }
+
+ String filterKey = filterKeyPaths[0];
+ String paths = filterKeyPaths[1];
+ List<String> filterPaths = new ArrayList<>(Arrays.asList(paths.split("(?<!\\|)\\|(?!\\|)")));
+ return new FilterRule(filterKey, filterPaths);
+ }
+
+ /**
+ * Gets all the filter rules for the topic.
+ *
+ * @return an array list of the rules for the topic
+ */
+ protected List<FilterRule> getFilterRule() {
+ return new ArrayList<>(rules.values());
+ }
+
+ /**
+ * Gets the filter rule for the specified key.
+ *
+ * @param mdcKey the key to the filter rule
+ * @return the filter rule associated with the key
+ */
+ protected FilterRule getFilterRule(String mdcKey) {
+ if (mdcKey == null || mdcKey.isEmpty()) {
+ throw new IllegalArgumentException(MDC_KEY_ERROR);
+ }
+ return rules.get(mdcKey);
+ }
+
+ /**
+ * Adds a filter rule for the specified key and path.
+ *
+ * @param mdcKey the key to the filter rule
+ * @param path the json path to the key
+ * @return the filter rule that was added for the topic
+ */
+ protected FilterRule addFilterRule(String mdcKey, String path) {
+ if (path == null || path.isEmpty()) {
+ throw new IllegalArgumentException(JSON_PATH_ERROR);
+ }
+ return addFilterRule(mdcKey, Arrays.asList(path));
+ }
+
+ /**
+ * Adds a filter rule for the specified key and paths.
+ *
+ * @param mdcKey the key to the filter rule
+ * @param paths the list of potential paths to the key
+ * @return the filter rule that was added for the topic
+ */
+ protected FilterRule addFilterRule(String mdcKey, List<String> paths) {
+ if (mdcKey == null || mdcKey.isEmpty()) {
+ throw new IllegalArgumentException(MDC_KEY_ERROR);
+ }
+
+ if (paths == null || paths.isEmpty()) {
+ throw new IllegalArgumentException(JSON_PATH_ERROR);
+ }
+
+ if (rules.containsKey(mdcKey)) {
+ throw new IllegalArgumentException("a filter rule already exists for key: " + mdcKey);
+ }
+
+ FilterRule rule = new FilterRule(mdcKey, paths);
+ rules.put(mdcKey, rule);
+ return rule;
+ }
+
+ /**
+ * Modifies an existing filter rule by adding the specified path.
+ *
+ * @param mdcKey the key to the filter rule
+ * @param path the path to the key
+ * @return the filter rule that was modified
+ */
+ protected FilterRule modifyFilterRule(String mdcKey, String path) {
+ if (path == null || path.isEmpty()) {
+ throw new IllegalArgumentException(JSON_PATH_ERROR);
+ }
+ return modifyFilterRule(mdcKey, Arrays.asList(path));
+ }
+
+ /**
+ * Modifies an existing filter rule by adding the specified paths.
+ *
+ * @param mdcKey the key to the filter rule
+ * @param paths the list of potential paths to the key
+ * @return the filter rule that was modified
+ */
+ protected FilterRule modifyFilterRule(String mdcKey, List<String> paths) {
+ if (mdcKey == null || mdcKey.isEmpty()) {
+ throw new IllegalArgumentException(MDC_KEY_ERROR);
+ }
+
+ if (paths == null || paths.isEmpty()) {
+ throw new IllegalArgumentException(JSON_PATH_ERROR);
+ }
+
+ if (!rules.containsKey(mdcKey)) {
+ throw new IllegalArgumentException("a filter rule doesn't exist for key: " + mdcKey);
+ }
+
+ FilterRule rule = rules.get(mdcKey);
+ rule.addPaths(paths);
+ return rule;
+ }
+
+ /**
+ * Modifies an existing filter rule's key and replaces the paths with the specified
+ * paths.
+ *
+ * @param oldMdcKey the old key to the filter rule
+ * @param newMdcKey the new key to the filter rule
+ * @param paths the list of potential paths to the key
+ * @return the filter rule that was modified
+ */
+ protected FilterRule modifyFilterRule(String oldMdcKey, String newMdcKey, List<String> paths) {
+ if (oldMdcKey == null || oldMdcKey.isEmpty()) {
+ throw new IllegalArgumentException("current mdcKey must be provided");
+ }
+
+ if (newMdcKey == null || newMdcKey.isEmpty()) {
+ throw new IllegalArgumentException("new mdcKey must be provided");
+ }
+
+ if (oldMdcKey.equals(newMdcKey)) {
+ throw new IllegalArgumentException("the old and new mdcKey are equivalent");
+ }
+ if (paths == null || paths.isEmpty()) {
+ throw new IllegalArgumentException(JSON_PATH_ERROR);
+ }
+
+ if (rules.containsKey(newMdcKey)) {
+ throw new IllegalArgumentException("a filter rule already exists for key: " + newMdcKey);
+ }
+
+ FilterRule rule = rules.remove(oldMdcKey);
+ if (rule == null) {
+ throw new IllegalArgumentException("a filter rule doesn't exist for key: " + oldMdcKey);
+ }
+
+ rule.setMdcKey(newMdcKey);
+ rule.setPaths(paths);
+ rules.put(newMdcKey, rule);
+ return rule;
+ }
+
+ /**
+ * Deletes all filter rules for the topic filter.
+ */
+ protected void deleteFilterRule() {
+ rules.clear();
+ }
+
+ /**
+ * Deletes an existing filter rule.
+ *
+ * @param mdcKey the key to the filter rule
+ * @return the filter rule that was deleted
+ */
+ protected FilterRule deleteFilterRule(String mdcKey) {
+ if (mdcKey == null || mdcKey.isEmpty()) {
+ throw new IllegalArgumentException(MDC_KEY_ERROR);
+ }
+ return rules.remove(mdcKey);
+ }
+
+ /**
+ * Finds all fields for each topic filter rule. The results are stored in a map that
+ * is indexed by the MDC key. Each MDC key has a list of results as multiple
+ * occurrences of a key can be found in a JSON document.
+ *
+ * @param json the json string to be parsed
+ * @return a map of mdc keys and list of results for each key
+ */
+ protected Map<String, List<String>> find(String json) {
+ Map<String, List<String>> results = new HashMap<>();
+ for (FilterRule rule : rules.values()) {
+ List<String> matches = new ArrayList<>();
+ for (String path : rule.getPaths()) {
+
+ try {
+ matches = JsonProtocolFilter.filter(json, path);
+ } catch (Exception e) {
+ logger.debug("Could not filter on path {} because of {}", path, e.getMessage(), e);
+ }
+
+ if (!matches.isEmpty()) {
+ break;
+ } else {
+ logger.error("Could not find path {} in json {}", path, json);
+ }
+
+ }
+ results.put(rule.getMdcKey(), matches);
+ }
+ return results;
+ }
+
+ /**
+ * Finds all occurrences of a field in a JSON document based on the filter rule paths.
+ *
+ * @param json the json string to be parsed
+ * @return a list of matches from the JSON document
+ */
+ protected List<String> find(String json, String mdcKey) {
+ List<String> matches = new ArrayList<>();
+ for (String path : rules.get(mdcKey).getPaths()) {
+
+ try {
+ matches = JsonProtocolFilter.filter(json, path);
+ } catch (Exception e) {
+ logger.debug("Could not filter on path {} because of {}", path, e.getMessage(), e);
+ }
+
+ if (!matches.isEmpty()) {
+ break;
+ }
+
+ }
+
+ if (matches.isEmpty()) {
+ logger.error("Could not find any matches for key {} in json {}", mdcKey, json);
+ }
+
+ return matches;
+ }
+}
diff --git a/feature-mdc-filters/src/main/resources/META-INF/services/org.onap.policy.common.endpoints.features.NetLoggerFeatureApi b/feature-mdc-filters/src/main/resources/META-INF/services/org.onap.policy.common.endpoints.features.NetLoggerFeatureApi
new file mode 100755
index 00000000..f2fdb402
--- /dev/null
+++ b/feature-mdc-filters/src/main/resources/META-INF/services/org.onap.policy.common.endpoints.features.NetLoggerFeatureApi
@@ -0,0 +1 @@
+org.onap.policy.drools.mdc.filters.MdcFilterFeature
diff --git a/feature-mdc-filters/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureAPI b/feature-mdc-filters/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureAPI
new file mode 100755
index 00000000..f2fdb402
--- /dev/null
+++ b/feature-mdc-filters/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyControllerFeatureAPI
@@ -0,0 +1 @@
+org.onap.policy.drools.mdc.filters.MdcFilterFeature