IConstraint.java

  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. package gov.nist.secauto.metaschema.core.model.constraint;

  27. import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
  28. import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
  29. import gov.nist.secauto.metaschema.core.metapath.DynamicContext;
  30. import gov.nist.secauto.metaschema.core.metapath.ISequence;
  31. import gov.nist.secauto.metaschema.core.metapath.MetapathExpression;
  32. import gov.nist.secauto.metaschema.core.metapath.item.node.IDefinitionNodeItem;

  33. import java.net.URI;
  34. import java.util.HashMap;
  35. import java.util.Map;
  36. import java.util.Set;

  37. import javax.xml.namespace.QName;

  38. import edu.umd.cs.findbugs.annotations.NonNull;
  39. import edu.umd.cs.findbugs.annotations.Nullable;

  40. /**
  41.  * Represents a rule constraining the model of a Metaschema assembly, field or
  42.  * flag. Provides a common interface for all constraint definitions.
  43.  */
  44. public interface IConstraint {
  45.   /**
  46.    * The degree to which a constraint violation is significant.
  47.    * <p>
  48.    * These values are ordered from least significant to most significant.
  49.    */
  50.   enum Level {
  51.     /**
  52.      * A violation of the constraint represents a point of interest.
  53.      */
  54.     INFORMATIONAL,
  55.     /**
  56.      * A violation of the constraint represents a potential issue with the content.
  57.      */
  58.     WARNING,
  59.     /**
  60.      * A violation of the constraint represents a fault in the content. This may
  61.      * include issues around compatibility, integrity, consistency, etc.
  62.      */
  63.     ERROR,
  64.     /**
  65.      * A violation of the constraint represents a serious fault in the content that
  66.      * will prevent typical use of the content.
  67.      */
  68.     CRITICAL;
  69.   }

  70.   /**
  71.    * The default level to use if no level is provided.
  72.    */
  73.   @NonNull
  74.   Level DEFAULT_LEVEL = Level.ERROR;
  75.   /**
  76.    * The default target Metapath expression to use if no target is provided.
  77.    */
  78.   @NonNull
  79.   MetapathExpression DEFAULT_TARGET = MetapathExpression.CONTEXT_NODE;
  80.   /**
  81.    * The default target Metapath expression to use if no target is provided.
  82.    */
  83.   @NonNull
  84.   String DEFAULT_TARGET_METAPATH = ".";

  85.   /**
  86.    * Retrieve the unique identifier for the constraint.
  87.    *
  88.    * @return the identifier or {@code null} if no identifier is defined
  89.    */
  90.   @Nullable
  91.   String getId();

  92.   @Nullable
  93.   MarkupLine getDescription();

  94.   @Nullable
  95.   String getFormalName();

  96.   /**
  97.    * Get information about the source of the constraint.
  98.    *
  99.    * @return the source information
  100.    */
  101.   @NonNull
  102.   ISource getSource();

  103.   /**
  104.    * The significance of a violation of this constraint.
  105.    *
  106.    * @return the level
  107.    */
  108.   @NonNull
  109.   Level getLevel();

  110.   @NonNull
  111.   Map<QName, Set<String>> getProperties();

  112.   /**
  113.    * Retrieve the Metapath expression to use to query the targets of the
  114.    * constraint.
  115.    *
  116.    * @return a Metapath expression
  117.    */
  118.   @NonNull
  119.   MetapathExpression getTarget();

  120.   /**
  121.    * Based on the provided {@code contextNodeItem}, find all nodes matching the
  122.    * target expression.
  123.    *
  124.    * @param contextNodeItem
  125.    *          the node item to evaluate the target expression against
  126.    * @return the matching nodes as a sequence
  127.    * @see #getTarget()
  128.    */
  129.   @NonNull
  130.   default ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets(
  131.       @NonNull IDefinitionNodeItem<?, ?> contextNodeItem) {
  132.     return getTarget().evaluate(contextNodeItem);
  133.   }

  134.   /**
  135.    * Based on the provided {@code contextNodeItem}, find all nodes matching the
  136.    * target expression.
  137.    *
  138.    * @param item
  139.    *          the node item to evaluate the target expression against
  140.    * @param dynamicContext
  141.    *          the Metapath evaluation context to use
  142.    * @return the matching nodes as a sequence
  143.    * @see #getTarget()
  144.    */
  145.   @NonNull
  146.   default ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets(@NonNull IDefinitionNodeItem<?, ?> item,
  147.       @NonNull DynamicContext dynamicContext) {
  148.     return item.hasValue() ? getTarget().evaluate(item, dynamicContext) : ISequence.empty();
  149.   }

  150.   /**
  151.    * Retrieve the remarks associated with the constraint.
  152.    *
  153.    * @return the remarks or {@code null} if no remarks are defined
  154.    */
  155.   MarkupMultiline getRemarks();

  156.   <T, R> R accept(@NonNull IConstraintVisitor<T, R> visitor, T state);

  157.   interface ISource {
  158.     enum SourceType {
  159.       /**
  160.        * A constraint embedded in a model.
  161.        */
  162.       MODEL,
  163.       /**
  164.        * A constraint defined externally from a model.
  165.        */
  166.       EXTERNAL;
  167.     }

  168.     @NonNull
  169.     SourceType getSourceType();

  170.     @Nullable
  171.     URI getSource();
  172.   }

  173.   final class InternalModelSource implements ISource {
  174.     @NonNull
  175.     private static final ISource SINGLETON = new InternalModelSource();

  176.     @NonNull
  177.     public static ISource instance() {
  178.       return SINGLETON;
  179.     }

  180.     private InternalModelSource() {
  181.       // reduce visibility
  182.     }

  183.     @Override
  184.     public SourceType getSourceType() {
  185.       return SourceType.MODEL;
  186.     }

  187.     @Override
  188.     public URI getSource() {
  189.       // always null
  190.       return null;
  191.     }
  192.   }

  193.   final class ExternalModelSource implements IConstraint.ISource {
  194.     @NonNull
  195.     private static final Map<URI, ExternalModelSource> sources = new HashMap<>(); // NOPMD - intentional
  196.     @NonNull
  197.     private final URI modelUri;

  198.     @NonNull
  199.     public static ISource instance(@NonNull URI location) {
  200.       ISource retval;
  201.       synchronized (sources) {
  202.         retval = sources.get(location);
  203.         if (retval == null) {
  204.           retval = new ExternalModelSource(location);
  205.         }
  206.       }
  207.       return retval;
  208.     }

  209.     private ExternalModelSource(@NonNull URI modelSource) {
  210.       this.modelUri = modelSource;
  211.     }

  212.     @Override
  213.     public SourceType getSourceType() {
  214.       return SourceType.MODEL;
  215.     }

  216.     @NonNull
  217.     @Override
  218.     public URI getSource() {
  219.       return modelUri;
  220.     }
  221.   }

  222.   final class ExternalSource implements IConstraint.ISource {
  223.     @NonNull
  224.     private static final Map<URI, ExternalSource> sources = new HashMap<>(); // NOPMD - intentional

  225.     @NonNull
  226.     private final URI modelUri;

  227.     @NonNull
  228.     public static ISource instance(@NonNull URI location) {
  229.       ISource retval;
  230.       synchronized (sources) {
  231.         retval = sources.get(location);
  232.         if (retval == null) {
  233.           retval = new ExternalModelSource(location);
  234.         }
  235.       }
  236.       return retval;
  237.     }

  238.     private ExternalSource(@NonNull URI modelSource) {
  239.       this.modelUri = modelSource;
  240.     }

  241.     @Override
  242.     public SourceType getSourceType() {
  243.       return SourceType.EXTERNAL;
  244.     }

  245.     @NonNull
  246.     @Override
  247.     public URI getSource() {
  248.       return modelUri;
  249.     }
  250.   }
  251. }