1 /*
2 * Portions of this software was developed by employees of the National Institute
3 * of Standards and Technology (NIST), an agency of the Federal Government and is
4 * being made available as a public service. Pursuant to title 17 United States
5 * Code Section 105, works of NIST employees are not subject to copyright
6 * protection in the United States. This software may be subject to foreign
7 * copyright. Permission in the United States and in foreign countries, to the
8 * extent that NIST may hold copyright, to use, copy, modify, create derivative
9 * works, and distribute this software and its documentation without fee is hereby
10 * granted on a non-exclusive basis, provided that this notice and disclaimer
11 * of warranty appears in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER
14 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY
15 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM
17 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE
18 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT
19 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT,
20 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM,
21 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY,
22 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR
23 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT
24 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER.
25 */
26
27 package gov.nist.secauto.metaschema.core.model.constraint;
28
29 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
30 import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
31 import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
32 import gov.nist.secauto.metaschema.core.metapath.ISequence;
33 import gov.nist.secauto.metaschema.core.metapath.MetapathExpression;
34 import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem;
35
36 import java.net.URI;
37 import java.util.HashMap;
38 import java.util.Map;
39 import java.util.Set;
40
41 import javax.xml.namespace.QName;
42
43 import edu.umd.cs.findbugs.annotations.NonNull;
44 import edu.umd.cs.findbugs.annotations.Nullable;
45
46 /**
47 * Represents a rule constraining the model of a Metaschema assembly, field or
48 * flag. Provides a common interface for all constraint definitions.
49 */
50 public interface IConstraint {
51 /**
52 * The degree to which a constraint violation is significant.
53 * <p>
54 * These values are ordered from least significant to most significant.
55 */
56 enum Level {
57 /**
58 * A violation of the constraint represents a point of interest.
59 */
60 INFORMATIONAL,
61 /**
62 * A violation of the constraint represents a potential issue with the content.
63 */
64 WARNING,
65 /**
66 * A violation of the constraint represents a fault in the content. This may
67 * include issues around compatibility, integrity, consistency, etc.
68 */
69 ERROR,
70 /**
71 * A violation of the constraint represents a serious fault in the content that
72 * will prevent typical use of the content.
73 */
74 CRITICAL;
75 }
76
77 /**
78 * The default level to use if no level is provided.
79 */
80 @NonNull
81 Level DEFAULT_LEVEL = Level.ERROR;
82 /**
83 * The default target Metapath expression to use if no target is provided.
84 */
85 @NonNull
86 MetapathExpression DEFAULT_TARGET = MetapathExpression.CONTEXT_NODE;
87 /**
88 * The default target Metapath expression to use if no target is provided.
89 */
90 @NonNull
91 String DEFAULT_TARGET_METAPATH = ".";
92
93 /**
94 * Retrieve the unique identifier for the constraint.
95 *
96 * @return the identifier or {@code null} if no identifier is defined
97 */
98 @Nullable
99 String getId();
100
101 @Nullable
102 MarkupLine getDescription();
103
104 @Nullable
105 String getFormalName();
106
107 /**
108 * Get information about the source of the constraint.
109 *
110 * @return the source information
111 */
112 @NonNull
113 ISource getSource();
114
115 /**
116 * The significance of a violation of this constraint.
117 *
118 * @return the level
119 */
120 @NonNull
121 Level getLevel();
122
123 @NonNull
124 Map<QName, Set<String>> getProperties();
125
126 /**
127 * Retrieve the Metapath expression to use to query the targets of the
128 * constraint.
129 *
130 * @return a Metapath expression
131 */
132 @NonNull
133 MetapathExpression getTarget();
134
135 /**
136 * Based on the provided {@code contextNodeItem}, find all nodes matching the
137 * target expression.
138 *
139 * @param contextNodeItem
140 * the node item to evaluate the target expression against
141 * @return the matching nodes as a sequence
142 * @see #getTarget()
143 */
144 @NonNull
145 default ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets(
146 @NonNull IDefinitionNodeItem<?, ?> contextNodeItem) {
147 return getTarget().evaluate(contextNodeItem);
148 }
149
150 /**
151 * Based on the provided {@code contextNodeItem}, find all nodes matching the
152 * target expression.
153 *
154 * @param item
155 * the node item to evaluate the target expression against
156 * @param dynamicContext
157 * the Metapath evaluation context to use
158 * @return the matching nodes as a sequence
159 * @see #getTarget()
160 */
161 @NonNull
162 default ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets(@NonNull IDefinitionNodeItem<?, ?> item,
163 @NonNull DynamicContext dynamicContext) {
164 return item.hasValue() ? getTarget().evaluate(item, dynamicContext) : ISequence.empty();
165 }
166
167 /**
168 * Retrieve the remarks associated with the constraint.
169 *
170 * @return the remarks or {@code null} if no remarks are defined
171 */
172 MarkupMultiline getRemarks();
173
174 <T, R> R accept(@NonNull IConstraintVisitor<T, R> visitor, T state);
175
176 interface ISource {
177 enum SourceType {
178 /**
179 * A constraint embedded in a model.
180 */
181 MODEL,
182 /**
183 * A constraint defined externally from a model.
184 */
185 EXTERNAL;
186 }
187
188 @NonNull
189 SourceType getSourceType();
190
191 @Nullable
192 URI getSource();
193 }
194
195 final class InternalModelSource implements ISource {
196 @NonNull
197 private static final ISource SINGLETON = new InternalModelSource();
198
199 @NonNull
200 public static ISource instance() {
201 return SINGLETON;
202 }
203
204 private InternalModelSource() {
205 // reduce visibility
206 }
207
208 @Override
209 public SourceType getSourceType() {
210 return SourceType.MODEL;
211 }
212
213 @Override
214 public URI getSource() {
215 // always null
216 return null;
217 }
218 }
219
220 final class ExternalModelSource implements IConstraint.ISource {
221 @NonNull
222 private static final Map<URI, ExternalModelSource> sources = new HashMap<>(); // NOPMD - intentional
223 @NonNull
224 private final URI modelUri;
225
226 @NonNull
227 public static ISource instance(@NonNull URI location) {
228 ISource retval;
229 synchronized (sources) {
230 retval = sources.get(location);
231 if (retval == null) {
232 retval = new ExternalModelSource(location);
233 }
234 }
235 return retval;
236 }
237
238 private ExternalModelSource(@NonNull URI modelSource) {
239 this.modelUri = modelSource;
240 }
241
242 @Override
243 public SourceType getSourceType() {
244 return SourceType.MODEL;
245 }
246
247 @NonNull
248 @Override
249 public URI getSource() {
250 return modelUri;
251 }
252 }
253
254 final class ExternalSource implements IConstraint.ISource {
255 @NonNull
256 private static final Map<URI, ExternalSource> sources = new HashMap<>(); // NOPMD - intentional
257
258 @NonNull
259 private final URI modelUri;
260
261 @NonNull
262 public static ISource instance(@NonNull URI location) {
263 ISource retval;
264 synchronized (sources) {
265 retval = sources.get(location);
266 if (retval == null) {
267 retval = new ExternalModelSource(location);
268 }
269 }
270 return retval;
271 }
272
273 private ExternalSource(@NonNull URI modelSource) {
274 this.modelUri = modelSource;
275 }
276
277 @Override
278 public SourceType getSourceType() {
279 return SourceType.EXTERNAL;
280 }
281
282 @NonNull
283 @Override
284 public URI getSource() {
285 return modelUri;
286 }
287 }
288 }