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    @SuppressWarnings("PMD.AvoidUsingVolatile") // Required for thread-safe lazy init
31    @Nullable
32    private volatile String cachedIdentifier;
33    @Nullable
34    private final String id;
35    @Nullable
36    private final String formalName;
37    @Nullable
38    private final MarkupLine description;
39    @NonNull
40    private final ISource source;
41    @NonNull
42    private final Level level;
43    @Nullable
44    private final MarkupMultiline remarks;
45    @NonNull
46    private final Map<IAttributable.Key, Set<String>> properties;
47    @NonNull
48    private final IMetapathExpression target;
49  
50    /**
51     * Construct a new Metaschema constraint.
52     *
53     * @param id
54     *          the optional identifier for the constraint
55     * @param formalName
56     *          the constraint's formal name or {@code null} if not provided
57     * @param description
58     *          the constraint's semantic description or {@code null} if not
59     *          provided
60     * @param source
61     *          information about the constraint source
62     * @param level
63     *          the significance of a violation of this constraint
64     * @param target
65     *          the Metapath expression identifying the nodes the constraint targets
66     * @param properties
67     *          a collection of associated properties
68     * @param remarks
69     *          optional remarks describing the intent of the constraint
70     */
71    protected AbstractConstraint(
72        @Nullable String id,
73        @Nullable String formalName,
74        @Nullable MarkupLine description,
75        @NonNull ISource source,
76        @NonNull Level level,
77        @NonNull IMetapathExpression target,
78        @NonNull Map<IAttributable.Key, Set<String>> properties,
79        @Nullable MarkupMultiline remarks) {
80      Objects.requireNonNull(target);
81      this.id = id;
82      this.formalName = formalName;
83      this.description = description;
84      this.source = source;
85      this.level = ObjectUtils.requireNonNull(level, "level");
86      this.properties = properties;
87      this.remarks = remarks;
88      this.target = target;
89    }
90  
91    @Override
92    public final String getId() {
93      return id;
94    }
95  
96    @Override
97    public String getInternalIdentifier() {
98      String result = cachedIdentifier;
99      if (result == null) {
100       result = IConstraint.super.getInternalIdentifier();
101       cachedIdentifier = result;
102     }
103     return result;
104   }
105 
106   @Override
107   public MarkupLine getDescription() {
108     return description;
109   }
110 
111   @Override
112   public final String getFormalName() {
113     return formalName;
114   }
115 
116   @Override
117   public ISource getSource() {
118     return source;
119   }
120 
121   @Override
122   @NonNull
123   public Level getLevel() {
124     return level;
125   }
126 
127   @Override
128   public final IMetapathExpression getTarget() {
129     return target;
130   }
131 
132   @Override
133   public Map<IAttributable.Key, Set<String>> getProperties() {
134     return CollectionUtil.unmodifiableMap(properties);
135   }
136 
137   @Override
138   public MarkupMultiline getRemarks() {
139     return remarks;
140   }
141 
142   @Override
143   @NonNull
144   public ISequence<? extends IDefinitionNodeItem<?, ?>> matchTargets(
145       @NonNull IDefinitionNodeItem<?, ?> item,
146       @NonNull DynamicContext dynamicContext) {
147     return item.hasValue() ? getTarget().evaluate(item, dynamicContext) : ISequence.empty();
148   }
149 }