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