1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.model.constraint;
7   
8   import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
9   import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem;
10  import gov.nist.secauto.metaschema.core.model.constraint.impl.DefaultExpectConstraint;
11  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
12  
13  import edu.umd.cs.findbugs.annotations.NonNull;
14  
15  /**
16   * Represents a rule requiring a Metaschema assembly, field, or flag data
17   * instance to pass a Metapath-based test.
18   * <p>
19   * A custom message can be used to indicate what a test failure signifies.
20   */
21  public interface IExpectConstraint extends IConstraint {
22    /**
23     * Get the test to use to validate selected nodes.
24     *
25     * @return the test metapath expression to use
26     */
27    @NonNull
28    String getTest();
29  
30    /**
31     * A message to emit when the constraint is violated. Allows embedded Metapath
32     * expressions using the syntax {@code \{ metapath \}}.
33     *
34     * @return the message if defined or {@code null} otherwise
35     */
36    String getMessage();
37  
38    /**
39     * Generate a violation message using the provide item and dynamic context for
40     * inline Metapath value insertion.
41     *
42     * @param item
43     *          the target Metapath item to use as the focus for Metapath evaluation
44     * @param context
45     *          the dynamic context for Metapath evaluation
46     * @return the message
47     */
48    String generateMessage(@NonNull INodeItem item, @NonNull DynamicContext context);
49  
50    @Override
51    default <T, R> R accept(IConstraintVisitor<T, R> visitor, T state) {
52      return visitor.visitExpectConstraint(this, state);
53    }
54  
55    /**
56     * Create a new constraint builder.
57     *
58     * @return the builder
59     */
60    @NonNull
61    static Builder builder() {
62      return new Builder();
63    }
64  
65    final class Builder
66        extends AbstractConstraintBuilder<Builder, IExpectConstraint> {
67      private String test;
68      private String message;
69  
70      private Builder() {
71        // disable construction
72      }
73  
74      /**
75       * Use the provided test to validate selected nodes.
76       *
77       * @param test
78       *          the test metapath expression to use
79       * @return this builder
80       */
81      @NonNull
82      public Builder test(@NonNull String test) {
83        this.test = test;
84        return this;
85      }
86  
87      /**
88       * A message to emit when the constraint is violated. Allows embedded Metapath
89       * expressions using the syntax {@code \{ metapath \}}.
90       *
91       * @param message
92       *          the message if defined or {@code null} otherwise
93       * @return this builder
94       */
95      @NonNull
96      public Builder message(@NonNull String message) {
97        this.message = message;
98        return this;
99      }
100 
101     @Override
102     protected Builder getThis() {
103       return this;
104     }
105 
106     @Override
107     protected void validate() {
108       super.validate();
109 
110       ObjectUtils.requireNonNull(getTest());
111     }
112 
113     private String getTest() {
114       return test;
115     }
116 
117     private String getMessage() {
118       return message;
119     }
120 
121     @Override
122     protected IExpectConstraint newInstance() {
123       return new DefaultExpectConstraint(
124           getId(),
125           getFormalName(),
126           getDescription(),
127           ObjectUtils.notNull(getSource()),
128           getLevel(),
129           getTarget(),
130           getProperties(),
131           ObjectUtils.requireNonNull(getTest()),
132           getMessage(),
133           getRemarks());
134     }
135   }
136 }