1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.core.model.constraint.impl;
7   
8   import java.util.Map;
9   import java.util.Objects;
10  import java.util.Set;
11  
12  import dev.metaschema.core.datatype.markup.MarkupLine;
13  import dev.metaschema.core.datatype.markup.MarkupMultiline;
14  import dev.metaschema.core.metapath.DynamicContext;
15  import dev.metaschema.core.metapath.IMetapathExpression;
16  import dev.metaschema.core.metapath.item.ISequence;
17  import dev.metaschema.core.metapath.item.node.IDefinitionNodeItem;
18  import dev.metaschema.core.model.IAttributable;
19  import dev.metaschema.core.model.ISource;
20  import dev.metaschema.core.model.constraint.IConstraint;
21  import dev.metaschema.core.util.CollectionUtil;
22  import dev.metaschema.core.util.ObjectUtils;
23  import edu.umd.cs.findbugs.annotations.NonNull;
24  import edu.umd.cs.findbugs.annotations.Nullable;
25  
26  /**
27   * The base class for all constraint implementations.
28   */
29  public abstract class AbstractConstraint implements IConstraint { // NOPMD - intentional data class
30    @Nullable
31    private final String id;
32    @Nullable
33    private final String formalName;
34    @Nullable
35    private final MarkupLine description;
36    @NonNull
37    private final ISource source;
38    @NonNull
39    private final Level level;
40    @Nullable
41    private final MarkupMultiline remarks;
42    @NonNull
43    private final Map<IAttributable.Key, Set<String>> properties;
44    @NonNull
45    private final IMetapathExpression target;
46  
47    /**
48     * Construct a new Metaschema constraint.
49     *
50     * @param id
51     *          the optional identifier for the constraint
52     * @param formalName
53     *          the constraint's formal name or {@code null} if not provided
54     * @param description
55     *          the constraint's semantic description or {@code null} if not
56     *          provided
57     * @param source
58     *          information about the constraint source
59     * @param level
60     *          the significance of a violation of this constraint
61     * @param target
62     *          the Metapath expression identifying the nodes the constraint targets
63     * @param properties
64     *          a collection of associated properties
65     * @param remarks
66     *          optional remarks describing the intent of the constraint
67     */
68    protected AbstractConstraint(
69        @Nullable String id,
70        @Nullable String formalName,
71        @Nullable MarkupLine description,
72        @NonNull ISource source,
73        @NonNull Level level,
74        @NonNull IMetapathExpression target,
75        @NonNull Map<IAttributable.Key, Set<String>> properties,
76        @Nullable MarkupMultiline remarks) {
77      Objects.requireNonNull(target);
78      this.id = id;
79      this.formalName = formalName;
80      this.description = description;
81      this.source = source;
82      this.level = ObjectUtils.requireNonNull(level, "level");
83      this.properties = properties;
84      this.remarks = remarks;
85      this.target = target;
86    }
87  
88    @Override
89    public final String getId() {
90      return id;
91    }
92  
93    @Override
94    public MarkupLine getDescription() {
95      return description;
96    }
97  
98    @Override
99    public final String getFormalName() {
100     return formalName;
101   }
102 
103   @Override
104   public ISource getSource() {
105     return source;
106   }
107 
108   @Override
109   @NonNull
110   public Level getLevel() {
111     return level;
112   }
113 
114   @Override
115   public final IMetapathExpression getTarget() {
116     return target;
117   }
118 
119   @Override
120   public Map<IAttributable.Key, Set<String>> getProperties() {
121     return CollectionUtil.unmodifiableMap(properties);
122   }
123 
124   @Override
125   public MarkupMultiline getRemarks() {
126     return remarks;
127   }
128 
129   @Override
130   @NonNull
131   public ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets(
132       @NonNull IDefinitionNodeItem<?, ?> item,
133       @NonNull DynamicContext dynamicContext) {
134     return item.hasValue() ? getTarget().evaluate(item, dynamicContext) : ISequence.empty();
135   }
136 }