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 }