• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pkiraly / metadata-qa-api / #717

28 Aug 2025 09:15AM UTC coverage: 86.426% (-0.1%) from 86.526%
#717

push

pkiraly
Add priorityOnFail

12 of 23 new or added lines in 4 files covered. (52.17%)

3 existing lines in 2 files now uncovered.

5654 of 6542 relevant lines covered (86.43%)

0.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.68
/src/main/java/de/gwdg/metadataqa/api/schema/SchemaUtils.java
1
package de.gwdg.metadataqa.api.schema;
2

3
import de.gwdg.metadataqa.api.configuration.schema.Rule;
4
import de.gwdg.metadataqa.api.json.DataElement;
5
import de.gwdg.metadataqa.api.rule.logical.AndChecker;
6
import de.gwdg.metadataqa.api.rule.logical.LogicalChecker;
7
import de.gwdg.metadataqa.api.rule.logical.NotChecker;
8
import de.gwdg.metadataqa.api.rule.logical.OrChecker;
9
import de.gwdg.metadataqa.api.rule.pairchecker.DisjointChecker;
10
import de.gwdg.metadataqa.api.rule.pairchecker.LessThanPairChecker;
11
import de.gwdg.metadataqa.api.rule.singlefieldchecker.ContentTypeChecker;
12
import de.gwdg.metadataqa.api.rule.singlefieldchecker.DependencyChecker;
13
import de.gwdg.metadataqa.api.rule.singlefieldchecker.EnumerationChecker;
14
import de.gwdg.metadataqa.api.rule.pairchecker.EqualityChecker;
15
import de.gwdg.metadataqa.api.rule.singlefieldchecker.HasChildrenChecker;
16
import de.gwdg.metadataqa.api.rule.singlefieldchecker.HasValueChecker;
17
import de.gwdg.metadataqa.api.rule.singlefieldchecker.ImageDimensionChecker;
18
import de.gwdg.metadataqa.api.rule.singlefieldchecker.LanguageTagChecker;
19
import de.gwdg.metadataqa.api.rule.singlefieldchecker.LinkValidityChecker;
20
import de.gwdg.metadataqa.api.rule.singlefieldchecker.MQAFPatternChecker;
21
import de.gwdg.metadataqa.api.rule.singlefieldchecker.MaxCountChecker;
22
import de.gwdg.metadataqa.api.rule.singlefieldchecker.MaxLengthChecker;
23
import de.gwdg.metadataqa.api.rule.singlefieldchecker.MaxWordsChecker;
24
import de.gwdg.metadataqa.api.rule.singlefieldchecker.MinCountChecker;
25
import de.gwdg.metadataqa.api.rule.singlefieldchecker.MinLengthChecker;
26
import de.gwdg.metadataqa.api.rule.singlefieldchecker.MinWordsChecker;
27
import de.gwdg.metadataqa.api.rule.singlefieldchecker.MultilingualChecker;
28
import de.gwdg.metadataqa.api.rule.singlefieldchecker.NumericValueChecker;
29
import de.gwdg.metadataqa.api.rule.singlefieldchecker.PatternChecker;
30
import de.gwdg.metadataqa.api.rule.RuleChecker;
31
import de.gwdg.metadataqa.api.rule.singlefieldchecker.UniquenessChecker;
32
import org.apache.commons.lang3.StringUtils;
33

34
import java.util.ArrayList;
35
import java.util.LinkedHashMap;
36
import java.util.List;
37
import java.util.Map;
38
import java.util.logging.Logger;
39
import java.util.stream.Collectors;
40

41
import static de.gwdg.metadataqa.api.rule.singlefieldchecker.NumericValueChecker.TYPE.MAX_EXCLUSIVE;
42
import static de.gwdg.metadataqa.api.rule.singlefieldchecker.NumericValueChecker.TYPE.MAX_INCLUSIVE;
43
import static de.gwdg.metadataqa.api.rule.singlefieldchecker.NumericValueChecker.TYPE.MIN_EXCLUSIVE;
44
import static de.gwdg.metadataqa.api.rule.singlefieldchecker.NumericValueChecker.TYPE.MIN_INCLUSIVE;
45

46
public class SchemaUtils {
×
47

48
  private static final Logger LOGGER = Logger.getLogger(SchemaUtils.class.getCanonicalName());
1✔
49
  static int id = 0;
1✔
50

51
  /**
52
   * Create rule checkers based on the schema
53
   *
54
   * @param schema
55
   * @return The list of rule checkers
56
   */
57
  public static List<RuleChecker> getRuleCheckers(Schema schema) {
58
    setSchemaForFields(schema);
1✔
59
    id = 0;
1✔
60
    List<RuleChecker> allRuleCheckers = new ArrayList<>();
1✔
61
    for (DataElement dataElement : schema.getPaths()) {
1✔
62
      if (dataElement.getRules() != null) {
1✔
63
        List<Rule> rules = dataElement.getRules();
1✔
64
        for (Rule rule : rules) {
1✔
65
          List<RuleChecker> ruleCheckers = processRule(schema, dataElement, rule);
1✔
66
          if (!ruleCheckers.isEmpty())
1✔
67
            allRuleCheckers.addAll(ruleCheckers);
1✔
68
        }
1✔
69
      }
70
    }
1✔
71
    return allRuleCheckers;
1✔
72
  }
73

74
  private static List<RuleChecker> processRule(Schema schema, DataElement dataElement, Rule rule) {
75
    List<RuleChecker> ruleCheckers = new ArrayList<>();
1✔
76
    if (rule.getSkip().equals(Boolean.TRUE))
1✔
77
      return ruleCheckers;
×
78

79
    if (StringUtils.isNotBlank(rule.getPattern()))
1✔
80
      ruleCheckers.add(new PatternChecker(dataElement, rule.getPattern()));
1✔
81

82
    if (rule.getMqafPattern() != null)
1✔
83
      ruleCheckers.add(new MQAFPatternChecker(dataElement, rule.getMqafPattern()));
×
84

85
    if (StringUtils.isNotBlank(rule.getEquals()))
1✔
86
      pair(schema, ruleCheckers, dataElement, rule.getEquals(), "equals");
1✔
87

88
    if (StringUtils.isNotBlank(rule.getDisjoint()))
1✔
89
      pair(schema, ruleCheckers, dataElement, rule.getDisjoint(), "disjoint");
1✔
90

91
    if (rule.getIn() != null && !rule.getIn().isEmpty())
1✔
92
      ruleCheckers.add(new EnumerationChecker(dataElement, rule.getIn()));
1✔
93

94
    if (rule.getMinCount() != null)
1✔
95
      ruleCheckers.add(new MinCountChecker(dataElement, rule.getMinCount(), rule.getAllowEmptyInstances()));
1✔
96

97
    if (rule.getMaxCount() != null)
1✔
98
      ruleCheckers.add(new MaxCountChecker(dataElement, rule.getMaxCount(), rule.getAllowEmptyInstances()));
1✔
99

100
    if (rule.getMinLength() != null)
1✔
101
      ruleCheckers.add(new MinLengthChecker(dataElement, rule.getMinLength()));
1✔
102

103
    if (rule.getMaxLength() != null)
1✔
104
      ruleCheckers.add(new MaxLengthChecker(dataElement, rule.getMaxLength()));
1✔
105

106
    if (rule.getMaxWords() != null)
1✔
107
      ruleCheckers.add(new MaxWordsChecker(dataElement, rule.getMaxWords()));
×
108

109
    if (rule.getMinWords() != null)
1✔
110
      ruleCheckers.add(new MinWordsChecker(dataElement, rule.getMinWords()));
×
111

112
    if (StringUtils.isNotBlank(rule.getHasValue()))
1✔
113
      ruleCheckers.add(new HasValueChecker(dataElement, rule.getHasValue()));
1✔
114

115
    if (rule.getHasChildren() != null && !rule.getHasChildren().isEmpty())
1✔
116
      ruleCheckers.add(new HasChildrenChecker(dataElement, rule.getHasChildren()));
1✔
117

118
    if (rule.getMinInclusive() != null)
1✔
119
      ruleCheckers.add(new NumericValueChecker(dataElement, rule.getMinInclusive(), MIN_INCLUSIVE));
×
120

121
    if (rule.getMaxInclusive() != null)
1✔
122
      ruleCheckers.add(new NumericValueChecker(dataElement, rule.getMinInclusive(), MAX_INCLUSIVE));
×
123

124
    if (rule.getMinExclusive() != null)
1✔
125
      ruleCheckers.add(new NumericValueChecker(dataElement, rule.getMinInclusive(), MIN_EXCLUSIVE));
×
126

127
    if (rule.getMaxExclusive() != null)
1✔
128
      ruleCheckers.add(new NumericValueChecker(dataElement, rule.getMinInclusive(), MAX_EXCLUSIVE));
×
129

130
    if (rule.getContentType() != null && !rule.getContentType().isEmpty()) {
1✔
131
      ContentTypeChecker contentTypeChecker = rule.getTimeout() == null
1✔
132
        ? new ContentTypeChecker(dataElement, rule.getContentType())
×
133
        : new ContentTypeChecker(dataElement, dataElement.getLabel(), rule.getContentType(), rule.getTimeout());
1✔
134
      if (StringUtils.isNotBlank(rule.getSkippableUrl()))
1✔
135
        contentTypeChecker.setSkippableUrl(rule.getSkippableUrl());
×
136
      ruleCheckers.add(contentTypeChecker);
1✔
137
    }
138

139
    if (rule.getValidLink() != null) {
1✔
140
      LinkValidityChecker checker = rule.getTimeout() == null
×
141
        ? new LinkValidityChecker(dataElement, rule.getValidLink())
×
142
        : new LinkValidityChecker(dataElement, dataElement.getLabel(), rule.getValidLink(), rule.getTimeout());
×
143
      ruleCheckers.add(checker);
×
144
    }
145

146
    if (rule.getDimension() != null)
1✔
147
      ruleCheckers.add(new ImageDimensionChecker(dataElement, rule.getDimension()));
1✔
148

149
    if (rule.getDependencies() != null && !rule.getDependencies().isEmpty())
1✔
150
      ruleCheckers.add(new DependencyChecker(dataElement, rule.getDependencies()));
1✔
151

152
    if (rule.getUnique() != null && rule.getUnique().equals(Boolean.TRUE))
1✔
153
      ruleCheckers.add(new UniquenessChecker(dataElement));
×
154

155
    if (rule.getMultilingual() != null && rule.getMultilingual().equals(Boolean.TRUE))
1✔
156
      ruleCheckers.add(new MultilingualChecker(dataElement));
×
157

158
    if (rule.getHasLanguageTag() != null)
1✔
159
      ruleCheckers.add(new LanguageTagChecker(dataElement).withScope(rule.getHasLanguageTag()));
×
160

161
    if (rule.getLessThan() != null)
1✔
162
      pair(schema, ruleCheckers, dataElement, rule.getLessThan(), "LessThan");
×
163

164
    if (rule.getLessThanOrEquals() != null)
1✔
165
      pair(schema, ruleCheckers, dataElement, rule.getLessThan(), "lessThanOrEquals");
×
166

167
    if (rule.getLessThanOrEquals() != null)
1✔
168
      ruleCheckers.add(new DependencyChecker(dataElement, rule.getDependencies()));
×
169

170
    if (rule.getAnd() != null) {
1✔
171
      List<RuleChecker> childRuleCheckers = getChildRuleCheckers(schema, dataElement, rule.getAnd(), rule.getId());
1✔
172
      AndChecker checker = new AndChecker(dataElement, childRuleCheckers);
1✔
173
      if (rule.getAlwaysCheckDependencies().equals(Boolean.TRUE))
1✔
174
        checker.setAlwaysCheckDependencies(true);
×
175
      if (rule.getPriorityOnFail() != null && rule.getPriorityOnFail().equals(Boolean.TRUE))
1✔
NEW
176
        checker.setPriorityOnFail(true);
×
177
      ruleCheckers.add(checker);
1✔
178
    }
179

180
    if (rule.getOr() != null) {
1✔
181
      List<RuleChecker> childRuleCheckers = getChildRuleCheckers(schema, dataElement, rule.getOr(), rule.getId());
1✔
182
      OrChecker checker = new OrChecker(dataElement, childRuleCheckers);
1✔
183
      if (rule.getAlwaysCheckDependencies().equals(Boolean.TRUE))
1✔
184
        checker.setAlwaysCheckDependencies(true);
×
185
      ruleCheckers.add(checker);
1✔
186
    }
187

188
    if (rule.getNot() != null) {
1✔
189
      List<RuleChecker> childRuleCheckers = getChildRuleCheckers(schema, dataElement, rule.getNot(), rule.getId());
1✔
190
      ruleCheckers.add(new NotChecker(dataElement, childRuleCheckers));
1✔
191
    }
192

193
    // General properties
194
    // List<String> debuggables = new ArrayList<>();
195
    if (!ruleCheckers.isEmpty()) {
1✔
196
      for (RuleChecker ruleChecker : ruleCheckers) {
1✔
197
        ruleChecker.setFailureScore(rule.getFailureScore());
1✔
198
        ruleChecker.setSuccessScore(rule.getSuccessScore());
1✔
199
        ruleChecker.setNaScore(rule.getNaScore());
1✔
200
        String idValue = StringUtils.isNotBlank(rule.getId()) ? rule.getId() : String.valueOf(++id);
1✔
201
        ruleChecker.setId(idValue);
1✔
202
        ruleChecker.setScope(rule.getScope());
1✔
203
        if (rule.getHidden().equals(Boolean.TRUE))
1✔
204
          ruleChecker.setHidden();
1✔
205
        if (rule.getMandatory().equals(Boolean.TRUE))
1✔
206
          ruleChecker.setMandatory();
×
207
        if (rule.getDebug().equals(Boolean.TRUE)) {
1✔
208
          ruleChecker.setDebug();
1✔
209
          if (ruleChecker instanceof LogicalChecker) {
1✔
210
            for (RuleChecker child : ((LogicalChecker) ruleChecker).getCheckers()) {
1✔
211
              child.setDebug();
1✔
212
            }
1✔
213
          }
214
          // if (ruleChecker instanceof DependencyChecker)
215
          //   debuggables.addAll(((DependencyChecker) ruleChecker).getDependencies());
216
        }
217
        if (StringUtils.isNotBlank(rule.getValuePath()))
1✔
218
          ruleChecker.setValuePath(rule.getValuePath());
1✔
219
      }
1✔
220
    }
221

222
    /*
223
    if (!debuggables.isEmpty()) {
224
      for (RuleChecker ruleChecker : ruleCheckers) {
225
        if (debuggables.contains(ruleChecker.getId()))
226
          ruleChecker.setDebug();
227
      }
228
    }
229
     */
230

231
    return ruleCheckers;
1✔
232
  }
233

234
  private static List<RuleChecker> getChildRuleCheckers(Schema schema, DataElement dataElement, List<Rule> rules, String id) {
235
    List<RuleChecker> childRuleCheckers = new ArrayList<>();
1✔
236
    for (Rule childRule : rules) {
1✔
237
      if (StringUtils.isBlank(childRule.getId()))
1✔
238
        childRule.setId(id);
1✔
239
      List<RuleChecker> localChildRuleCheckers = processRule(schema, dataElement, childRule);
1✔
240
      if (!localChildRuleCheckers.isEmpty())
1✔
241
        childRuleCheckers.addAll(localChildRuleCheckers);
1✔
242
    }
1✔
243
    return childRuleCheckers;
1✔
244
  }
245

246
  private static void pair(Schema schema,
247
                           List<RuleChecker> ruleCheckers,
248
                           DataElement dataElement,
249
                           String fieldReference,
250
                           String type) {
251
    DataElement field2 = schema.getPathByLabel(fieldReference);
1✔
252
    if (field2 != null) {
1✔
253
      RuleChecker ruleChecker = null;
1✔
254
      if ("equals".equals(type)) {
1✔
255
        ruleChecker = new EqualityChecker(dataElement, field2);
1✔
256
      } else if ("disjoint".equals(type)) {
1✔
257
        ruleChecker = new DisjointChecker(dataElement, field2);
1✔
258
      } else if ("lessThan".equals(type)) {
×
259
        ruleChecker = new LessThanPairChecker(dataElement, field2, LessThanPairChecker.TYPE.LESS_THAN);
×
260
      } else if ("lessThanOrEquals".equals(type)) {
×
261
        ruleChecker = new LessThanPairChecker(dataElement, field2, LessThanPairChecker.TYPE.LESS_THAN_OR_EQUALS);
×
262
      }
263

264
      if (ruleChecker != null)
1✔
265
        ruleCheckers.add(ruleChecker);
1✔
266
    } else
1✔
267
      LOGGER.warning(
×
268
        String.format("invalid field reference in %s: %s", type, fieldReference));
×
269
  }
1✔
270

271
  public static void setSchemaForFields(Schema schema) {
272
    for (DataElement dataElement : schema.getPaths())
1✔
273
      dataElement.setSchema(schema);
1✔
274
  }
1✔
275

276
  /**
277
   * Get a rule object by its identifier
278
   * @param schema The schema
279
   * @param id The identifier of the rule
280
   * @return the rule object
281
   */
282
  public static Rule getRuleById(Schema schema, String id) {
283
    for (DataElement dataElement : schema.getPaths()) {
1✔
284
      for (Rule rule : dataElement.getRules()) {
1✔
285
        if (rule.getId().equals(id))
1✔
286
          return rule;
1✔
287
      }
1✔
288
    }
1✔
289
    return null;
×
290
  }
291

292
  /**
293
   * Get the direct dependencies of a rule
294
   * @param rule A rule
295
   * @return List of the rule identifiers on that the current rule depends on
296
   */
297
  public static List<String> getDependencies(Rule rule) {
298
    List<String> dependencies = new ArrayList<>();
1✔
299
    if (rule.getDependencies() != null) {
1✔
300
      dependencies.addAll(rule.getDependencies());
1✔
301
    }
302
    if (rule.getAnd() != null && !rule.getAnd().isEmpty()) {
1✔
303
      for (Rule childRule : rule.getAnd()) {
1✔
304
        dependencies.addAll(getDependencies(childRule));
1✔
305
      }
1✔
306
    }
307
    if (rule.getOr() != null && !rule.getOr().isEmpty()) {
1✔
308
      for (Rule childRule : rule.getOr()) {
1✔
309
        dependencies.addAll(getDependencies(childRule));
1✔
310
      }
1✔
311
    }
312
    if (rule.getNot() != null && !rule.getNot().isEmpty()) {
1✔
313
      for (Rule childRule : rule.getNot()) {
×
314
        dependencies.addAll(getDependencies(childRule));
×
315
      }
×
316
    }
317
    return dependencies;
1✔
318
  }
319

320
  /**
321
   * Returns all dependencies
322
   * @param schema The schema
323
   * @param rule A rule in the schema
324
   * @return List of the rule identifiers on that the current rule directly or independently depends on
325
   */
326
  public static List<String> getAllDependencies(Schema schema, Rule rule) {
327
    Map<String, Boolean> dependenciesMap = new LinkedHashMap<>();
1✔
328
    getDependencies(rule).stream().forEach(e -> dependenciesMap.put(e, false));
1✔
329
    boolean runAgain = !dependenciesMap.isEmpty();
1✔
330
    while (runAgain) {
1✔
331
      runAgain = false;
1✔
332
      for (Map.Entry<String, Boolean> entry : dependenciesMap.entrySet()) {
1✔
333
        String ruleId = entry.getKey();
1✔
334
        boolean processed = entry.getValue();
1✔
335
        if (!processed) {
1✔
336
          Rule depRule = getRuleById(schema, ruleId);
1✔
337
          List<String> additionalOnes = getDependencies(depRule);
1✔
338
          int size = dependenciesMap.size();
1✔
339
          for (String additionalOne : additionalOnes)
1✔
340
            dependenciesMap.putIfAbsent(additionalOne, false);
1✔
341
          if (dependenciesMap.size() > size)
1✔
342
            runAgain = true;
1✔
343
          dependenciesMap.put(ruleId, true);
1✔
344
        }
345
      }
1✔
346
    }
347
    return dependenciesMap.keySet().stream().collect(Collectors.toList());
1✔
348
  }
349
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc