View Javadoc
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 }