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.datatype.markup.MarkupMultiline;
9   import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
10  import gov.nist.secauto.metaschema.core.metapath.IMetapathExpression;
11  import gov.nist.secauto.metaschema.core.metapath.MetapathException;
12  import gov.nist.secauto.metaschema.core.metapath.item.ISequence;
13  import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem;
14  import gov.nist.secauto.metaschema.core.model.IAttributable;
15  import gov.nist.secauto.metaschema.core.model.IDescribable;
16  import gov.nist.secauto.metaschema.core.model.ISource;
17  import gov.nist.secauto.metaschema.core.util.ObjectUtils;
18  
19  import edu.umd.cs.findbugs.annotations.NonNull;
20  import edu.umd.cs.findbugs.annotations.Nullable;
21  
22  /**
23   * Represents a rule constraining the model of a Metaschema assembly, field or
24   * flag. Provides a common interface for all constraint definitions.
25   */
26  public interface IConstraint extends IAttributable, IDescribable {
27    /**
28     * The type of constraint.
29     */
30    enum Type {
31      /** Constraint restricting the set of allowed values. */
32      ALLOWED_VALUES("allowed-values"),
33      /** Constraint specifying occurrence requirements. */
34      CARDINALITY("cardinality"),
35      /** Constraint expressing an expected condition. */
36      EXPECT("expect"),
37      /** Constraint creating an index over items. */
38      INDEX("index"),
39      /** Constraint requiring uniqueness across items. */
40      UNIQUE("unique"),
41      /** Constraint verifying index key references. */
42      INDEX_HAS_KEY("index-has-key"),
43      /** Constraint validating pattern matching. */
44      MATCHES("matches");
45  
46      @NonNull
47      private final String name;
48  
49      Type(@NonNull String name) {
50        this.name = name;
51      }
52  
53      /**
54       * Get the name identifier for this constraint type.
55       *
56       * @return the name
57       */
58      @NonNull
59      public String getName() {
60        return name;
61      }
62    }
63  
64    /**
65     * The degree to which a constraint violation is significant.
66     * <p>
67     * These values are ordered from least significant to most significant.
68     */
69    enum Level {
70      /**
71       * No violation.
72       */
73      NONE,
74      /**
75       * A violation of the constraint represents a point of interest.
76       */
77      INFORMATIONAL,
78      /**
79       * A violation of the constraint represents a fault in the content that may
80       * warrant review by a developer when performing model or tool development.
81       */
82      DEBUG,
83      /**
84       * A violation of the constraint represents a potential issue with the content.
85       */
86      WARNING,
87      /**
88       * A violation of the constraint represents a fault in the content. This may
89       * include issues around compatibility, integrity, consistency, etc.
90       */
91      ERROR,
92      /**
93       * A violation of the constraint represents a serious fault in the content that
94       * will prevent typical use of the content.
95       */
96      CRITICAL;
97    }
98  
99    /**
100    * Get the default level to use if no level is provided.
101    *
102    * @return the default level
103    */
104   @NonNull
105   static Level defaultLevel() {
106     return Level.ERROR;
107   }
108 
109   /**
110    * Get the Metapath to use if no target is provided.
111    *
112    * @return the expression
113    */
114   @NonNull
115   static IMetapathExpression defaultTarget() {
116     return IMetapathExpression.contextNode();
117   }
118 
119   /**
120    * Get a string that identifies the provided constraint using the most specific
121    * information available.
122    *
123    * @param constraint
124    *          the constraint to identify
125    * @return the constraint identification statement
126    */
127   @NonNull
128   static String getConstraintIdentity(@NonNull IConstraint constraint) {
129     String identity;
130     if (constraint.getId() != null) {
131       identity = String.format("with id '%s'", constraint.getId());
132     } else if (constraint.getFormalName() != null) {
133       identity = String.format("with the formal name '%s'", constraint.getFormalName());
134     } else {
135       identity = String.format("targeting '%s'", constraint.getTarget().getPath());
136     }
137     return ObjectUtils.notNull(identity);
138   }
139 
140   /**
141    * Get the constraint type.
142    *
143    * @return the constraint type
144    */
145   @NonNull
146   Type getType();
147 
148   /**
149    * Retrieve the unique identifier for the constraint.
150    *
151    * @return the identifier or {@code null} if no identifier is defined
152    */
153   @Nullable
154   String getId();
155 
156   /**
157    * Get information about the source of the constraint.
158    *
159    * @return the source information
160    */
161   @NonNull
162   ISource getSource();
163 
164   /**
165    * The significance of a violation of this constraint.
166    *
167    * @return the level
168    */
169   @NonNull
170   Level getLevel();
171 
172   /**
173    * Retrieve the Metapath expression to use to query the targets of the
174    * constraint.
175    *
176    * @return a Metapath expression
177    */
178   @NonNull
179   IMetapathExpression getTarget();
180 
181   /**
182    * Based on the provided {@code contextNodeItem}, find all nodes matching the
183    * target expression.
184    *
185    * @param item
186    *          the node item to evaluate the target expression against
187    * @param dynamicContext
188    *          the Metapath evaluation context to use
189    * @return the matching nodes as a sequence
190    * @throws MetapathException
191    *           if an error occurred during evaluation
192    * @see #getTarget()
193    */
194   @NonNull
195   ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets(
196       @NonNull IDefinitionNodeItem<?, ?> item,
197       @NonNull DynamicContext dynamicContext);
198 
199   /**
200    * Retrieve the remarks associated with the constraint.
201    *
202    * @return the remarks or {@code null} if no remarks are defined
203    */
204   MarkupMultiline getRemarks();
205 
206   /**
207    * Used for double dispatch supporting the visitor pattern provided by
208    * implementations of {@link IConstraintVisitor}.
209    *
210    * @param <T>
211    *          the Java type of a state object passed to the visitor
212    * @param <R>
213    *          the Java type of the result returned by the visitor methods
214    * @param visitor
215    *          the visitor implementation
216    * @param state
217    *          the state object passed to the visitor
218    * @return the visitation result
219    * @see IConstraintVisitor
220    */
221   <T, R> R accept(@NonNull IConstraintVisitor<T, R> visitor, T state);
222 }