2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2024 Ericsson
4 * Modifications Copyright (C) 2024 OpenInfra Foundation Europe
5 * ================================================================================
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
21 package org.oran.smo.yangtools.parser.findings;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Objects;
26 import java.util.regex.Pattern;
28 import org.oran.smo.yangtools.parser.model.ModuleIdentity;
29 import org.oran.smo.yangtools.parser.model.yangdom.YangDomElement;
32 * A predicate that takes one or more modules, one or more finding types, and one or more
35 * @author Mark Hollmann
37 public class ModuleAndFindingTypeAndSchemaNodePathFilterPredicate implements FindingFilterPredicate {
40 * Parses the supplied string into an instance of ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.
42 * Module names are separated from finding types, and from the node path, by the ";" character.
44 * Module names are separated by the "," character. Finding types are likewise separated by
45 * the "," character. Only one path may be supplied at most. A value must be supplied for module
46 * names, finding types and path.
48 * The only allowable wildcard character is a "*", denoting any "character sequence".
50 * Example 1: The following will suppress all P114 findings in any IETF and IANA modules:
51 * "ietf-*,iana-*;P114_TYPEDEF_NOT_USED;*"
53 * Example 2: The following will suppress all findings within the "modules-state" container
54 * within the IETF yang library: "ietf-yang-library;*;/container=modules-state"
56 * Example 3: The following will suppress all P115 findings, in all modules: "*;P115_*;*"
58 public static ModuleAndFindingTypeAndSchemaNodePathFilterPredicate fromString(final String s) {
60 final String[] split = s.split(";");
61 if (split.length != 3) {
62 throw new RuntimeException("Invalid string format for ModuleAndFindingTypeAndSchemaNodePathFilterPredicate.");
65 final List<Pattern> moduleNames = new ArrayList<>();
66 if (!split[0].equals("*")) {
67 final String[] moduleNamesSplit = split[0].contains(",") ? split[0].split(",") : new String[] { split[0] };
68 for (final String stringPattern : moduleNamesSplit) {
69 moduleNames.add(Pattern.compile(stringPattern.trim().replace(".", "[.]").replace("*", ".*")));
73 final List<Pattern> findingTypes = new ArrayList<>();
74 if (!split[1].equals("*")) {
75 final String[] findingTypesSplit = split[1].contains(",") ? split[1].split(",") : new String[] { split[1] };
76 for (final String stringPattern : findingTypesSplit) {
77 findingTypes.add(Pattern.compile(stringPattern.trim().replace(".", "[.]").replace("*", ".*")));
81 final String schemaNodePath = split[2].equals("*") ? null : split[2];
83 return new ModuleAndFindingTypeAndSchemaNodePathFilterPredicate(moduleNames, findingTypes, schemaNodePath);
86 private final List<Pattern> moduleNames;
87 private final List<Pattern> findingTypes;
88 private final String schemaNodePath;
91 * A finding will be filtered if the statement is part of any of the supplied modules,
92 * and if the finding is of any of the supplied types, and if the path to the statement
93 * is a sub-path of the supplied paths.
95 * More formally, the name of the module in which the offending statement sits must be
96 * matchable against any of the module name patterns, and the type of the finding must
97 * be matchable against any of the finding type patterns, and the schema node path of
98 * the offending statement must be the same, or a sub-path, of the supplied path.
100 * Supplying an empty list for module names or finding types will match-all for that
101 * parameter. Supplying null as schema node path will match-all paths.
103 public ModuleAndFindingTypeAndSchemaNodePathFilterPredicate(final List<Pattern> moduleNames,
104 final List<Pattern> findingTypes, final String schemaNodePath) {
105 this.moduleNames = Objects.requireNonNull(moduleNames);
106 this.findingTypes = Objects.requireNonNull(findingTypes);
107 this.schemaNodePath = schemaNodePath;
111 public boolean test(final Finding f) {
112 return matchOnModule(f) && matchOnFindingType(f) && matchOnSchemaNode(f);
115 private boolean matchOnModule(final Finding finding) {
117 if (moduleNames.isEmpty()) {
122 * If the finding does not relate to a YAM then obviously we cannot match.
124 if (finding.getYangModel() == null) {
129 * It can happen that we don't have a module identity yet, because a finding was found
130 * before we actually got a chance to extract the module name. In this case we use the
131 * name of the input. This is not foolproof, of course.
133 final ModuleIdentity moduleIdentity = finding.getYangModel().getModuleIdentity();
134 final String moduleOrSubModuleName = moduleIdentity == null ?
135 finding.getYangModel().getYangInput().getName() :
136 moduleIdentity.getModuleName();
138 for (final Pattern pattern : moduleNames) {
139 if (pattern.matcher(moduleOrSubModuleName).matches()) {
147 private boolean matchOnFindingType(final Finding finding) {
149 if (findingTypes.isEmpty()) {
153 final String findingType = finding.getFindingType();
155 for (final Pattern pattern : findingTypes) {
156 if (pattern.matcher(findingType).matches()) {
164 private boolean matchOnSchemaNode(final Finding finding) {
166 if (schemaNodePath == null) {
170 if (finding.getStatement() == null) {
174 final YangDomElement domElement = finding.getStatement().getDomElement();
175 if (domElement == null) {
179 return domElement.getSimplifiedPath().startsWith(schemaNodePath);