001/*
002 * Portions of this software was developed by employees of the National Institute
003 * of Standards and Technology (NIST), an agency of the Federal Government and is
004 * being made available as a public service. Pursuant to title 17 United States
005 * Code Section 105, works of NIST employees are not subject to copyright
006 * protection in the United States. This software may be subject to foreign
007 * copyright. Permission in the United States and in foreign countries, to the
008 * extent that NIST may hold copyright, to use, copy, modify, create derivative
009 * works, and distribute this software and its documentation without fee is hereby
010 * granted on a non-exclusive basis, provided that this notice and disclaimer
011 * of warranty appears in all copies.
012 *
013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE.  IN NO EVENT
019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
025 */
026
027package gov.nist.secauto.metaschema.core.model.constraint;
028
029import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
030import gov.nist.secauto.metaschema.core.metapath.ISequence;
031import gov.nist.secauto.metaschema.core.metapath.MetapathException;
032import gov.nist.secauto.metaschema.core.metapath.format.IPathFormatter;
033import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
034import gov.nist.secauto.metaschema.core.model.constraint.IConstraint.Level;
035import gov.nist.secauto.metaschema.core.model.validation.IValidationResult;
036import gov.nist.secauto.metaschema.core.util.CollectionUtil;
037
038import java.util.LinkedList;
039import java.util.List;
040import java.util.Objects;
041
042import edu.umd.cs.findbugs.annotations.NonNull;
043
044public class FindingCollectingConstraintValidationHandler
045    extends AbstractConstraintValidationHandler
046    implements IValidationResult {
047  @NonNull
048  private final List<ConstraintValidationFinding> findings = new LinkedList<>();
049  @NonNull
050  private IPathFormatter pathFormatter = IPathFormatter.METAPATH_PATH_FORMATER;
051  @NonNull
052  private Level highestLevel = IConstraint.Level.INFORMATIONAL;
053
054  @Override
055  @NonNull
056  public IPathFormatter getPathFormatter() {
057    return pathFormatter;
058  }
059
060  public void setPathFormatter(@NonNull IPathFormatter pathFormatter) {
061    this.pathFormatter = Objects.requireNonNull(pathFormatter, "pathFormatter");
062  }
063
064  @Override
065  @NonNull
066  public List<ConstraintValidationFinding> getFindings() {
067    return CollectionUtil.unmodifiableList(findings);
068  }
069
070  @Override
071  @NonNull
072  public Level getHighestSeverity() {
073    return highestLevel;
074  }
075
076  protected void addFinding(@NonNull ConstraintValidationFinding finding) {
077    findings.add(finding);
078
079    Level severity = finding.getSeverity();
080    if (severity.ordinal() > highestLevel.ordinal()) {
081      highestLevel = severity;
082    }
083  }
084
085  @Override
086  public void handleCardinalityMinimumViolation(
087      @NonNull ICardinalityConstraint constraint,
088      @NonNull INodeItem node,
089      @NonNull ISequence<? extends INodeItem> targets) {
090    addFinding(ConstraintValidationFinding.builder(constraint, node)
091        .targets(targets.asList())
092        .message(newCardinalityMinimumViolationMessage(constraint, node, targets))
093        .build());
094  }
095
096  @Override
097  public void handleCardinalityMaximumViolation(
098      @NonNull ICardinalityConstraint constraint,
099      @NonNull INodeItem node,
100      @NonNull ISequence<? extends INodeItem> targets) {
101    addFinding(ConstraintValidationFinding.builder(constraint, node)
102        .targets(targets.asList())
103        .message(newCardinalityMaximumViolationMessage(constraint, node, targets))
104        .build());
105  }
106
107  @Override
108  public void handleIndexDuplicateKeyViolation(
109      @NonNull IIndexConstraint constraint,
110      @NonNull INodeItem node,
111      @NonNull INodeItem oldItem,
112      @NonNull INodeItem target) {
113    addFinding(ConstraintValidationFinding.builder(constraint, node)
114        .target(target)
115        .message(newIndexDuplicateKeyViolationMessage(constraint, node, oldItem, target))
116        .build());
117  }
118
119  @Override
120  public void handleUniqueKeyViolation(
121      @NonNull IUniqueConstraint constraint,
122      @NonNull INodeItem node,
123      @NonNull INodeItem oldItem,
124      @NonNull INodeItem target) {
125    addFinding(ConstraintValidationFinding.builder(constraint, node)
126        .target(target)
127        .message(newUniqueKeyViolationMessage(constraint, node, oldItem, target))
128        .build());
129  }
130
131  @SuppressWarnings("null")
132  @Override
133  public void handleKeyMatchError(
134      @NonNull IKeyConstraint constraint,
135      @NonNull INodeItem node,
136      @NonNull INodeItem target,
137      @NonNull MetapathException cause) {
138    addFinding(ConstraintValidationFinding.builder(constraint, node)
139        .target(target)
140        .message(cause.getLocalizedMessage())
141        .cause(cause)
142        .build());
143  }
144
145  @Override
146  public void handleMatchPatternViolation(
147      @NonNull IMatchesConstraint constraint,
148      @NonNull INodeItem node,
149      @NonNull INodeItem target,
150      @NonNull String value) {
151    addFinding(ConstraintValidationFinding.builder(constraint, node)
152        .target(target)
153        .message(newMatchPatternViolationMessage(constraint, node, target, value))
154        .build());
155  }
156
157  @Override
158  public void handleMatchDatatypeViolation(
159      @NonNull IMatchesConstraint constraint,
160      @NonNull INodeItem node,
161      @NonNull INodeItem target,
162      @NonNull String value,
163      @NonNull IllegalArgumentException cause) {
164    addFinding(ConstraintValidationFinding.builder(constraint, node)
165        .target(target)
166        .message(newMatchDatatypeViolationMessage(constraint, node, target, value))
167        .cause(cause)
168        .build());
169  }
170
171  @Override
172  public void handleExpectViolation(
173      @NonNull IExpectConstraint constraint,
174      @NonNull INodeItem node,
175      @NonNull INodeItem target,
176      @NonNull DynamicContext dynamicContext) {
177    addFinding(ConstraintValidationFinding.builder(constraint, node)
178        .target(target)
179        .message(newExpectViolationMessage(constraint, node, target, dynamicContext))
180        .build());
181  }
182
183  @Override
184  public void handleAllowedValuesViolation(@NonNull List<IAllowedValuesConstraint> failedConstraints,
185      @NonNull INodeItem target) {
186    addFinding(ConstraintValidationFinding.builder(failedConstraints, target)
187        .target(target)
188        .message(newAllowedValuesViolationMessage(failedConstraints, target))
189        .build());
190  }
191
192  @Override
193  public void handleIndexDuplicateViolation(IIndexConstraint constraint, INodeItem node) {
194    addFinding(ConstraintValidationFinding.builder(constraint, node)
195        .message(newIndexDuplicateViolationMessage(constraint, node))
196        .severity(Level.CRITICAL)
197        .build());
198  }
199
200  @Override
201  public void handleIndexMiss(IIndexHasKeyConstraint constraint, INodeItem node, INodeItem target, List<String> key) {
202    addFinding(ConstraintValidationFinding.builder(constraint, node)
203        .message(newIndexMissMessage(constraint, node, target, key))
204        .build());
205  }
206
207}