1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.core.model.constraint;
7   
8   import gov.nist.secauto.metaschema.core.model.ISource;
9   import gov.nist.secauto.metaschema.core.qname.IEnhancedQName;
10  import gov.nist.secauto.metaschema.core.util.CollectionUtil;
11  
12  import java.util.LinkedHashMap;
13  import java.util.LinkedList;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.concurrent.locks.Lock;
17  import java.util.concurrent.locks.ReadWriteLock;
18  import java.util.concurrent.locks.ReentrantReadWriteLock;
19  
20  import edu.umd.cs.findbugs.annotations.NonNull;
21  
22  /**
23   * A container of rules constraining the effective model of a Metaschema field
24   * or flag data instance.
25   */
26  public class ValueConstraintSet implements IValueConstrained {
27    @NonNull
28    private final ISource source;
29    @SuppressWarnings("PMD.UseConcurrentHashMap") // need ordering
30    @NonNull
31    private final Map<IEnhancedQName, ILet> lets = new LinkedHashMap<>();
32    /**
33     * The collection of constraints in this constraint set.
34     */
35    @NonNull
36    private final List<IConstraint> constraints = new LinkedList<>();
37    @NonNull
38    private final List<IAllowedValuesConstraint> allowedValuesConstraints = new LinkedList<>();
39    @NonNull
40    private final List<IMatchesConstraint> matchesConstraints = new LinkedList<>();
41    @NonNull
42    private final List<IIndexHasKeyConstraint> indexHasKeyConstraints = new LinkedList<>();
43    @NonNull
44    private final List<IExpectConstraint> expectConstraints = new LinkedList<>();
45    /**
46     * The lock used to manage adjustments to the contents of this constraint set.
47     */
48    @NonNull
49    private final ReadWriteLock instanceLock = new ReentrantReadWriteLock();
50  
51    /**
52     * Construct a new constraint set.
53     *
54     * @param source
55     *          information about the resource the constraints were loaded from
56     */
57    public ValueConstraintSet(@NonNull ISource source) {
58      this.source = source;
59    }
60  
61    @Override
62    public ISource getSource() {
63      return source;
64    }
65  
66    /**
67     * Get the read-write lock used to manage access to the underlying constraint
68     * collections.
69     * <p>
70     * This can be used by extending classes to control read/write access to
71     * constraint data, supporting multi-threaded access.
72     *
73     * @return the lock
74     */
75    @NonNull
76    protected ReadWriteLock getLock() {
77      return instanceLock;
78    }
79  
80    /**
81     * Get the underlying constraint collection.
82     * <p>
83     * Access to the returned collection is not thread safe. Callers should use
84     * {@link #getLock()} to get the read/write lock for managing access.
85     *
86     * @return the constraint collection
87     */
88    @NonNull
89    protected List<IConstraint> getConstraintsInternal() {
90      return constraints;
91    }
92  
93    @Override
94    public Map<IEnhancedQName, ILet> getLetExpressions() {
95      return lets;
96    }
97  
98    @Override
99    public ILet addLetExpression(ILet let) {
100     return lets.put(let.getName(), let);
101   }
102 
103   @Override
104   public List<IConstraint> getConstraints() {
105     Lock readLock = instanceLock.readLock();
106     readLock.lock();
107     try {
108       return CollectionUtil.unmodifiableList(constraints);
109     } finally {
110       readLock.unlock();
111     }
112   }
113 
114   @Override
115   public List<IAllowedValuesConstraint> getAllowedValuesConstraints() {
116     Lock readLock = instanceLock.readLock();
117     readLock.lock();
118     try {
119       return CollectionUtil.unmodifiableList(allowedValuesConstraints);
120     } finally {
121       readLock.unlock();
122     }
123   }
124 
125   @Override
126   public List<IMatchesConstraint> getMatchesConstraints() {
127     Lock readLock = instanceLock.readLock();
128     readLock.lock();
129     try {
130       return CollectionUtil.unmodifiableList(matchesConstraints);
131     } finally {
132       readLock.unlock();
133     }
134   }
135 
136   @Override
137   public List<IIndexHasKeyConstraint> getIndexHasKeyConstraints() {
138     Lock readLock = instanceLock.readLock();
139     readLock.lock();
140     try {
141       return CollectionUtil.unmodifiableList(indexHasKeyConstraints);
142     } finally {
143       readLock.unlock();
144     }
145   }
146 
147   @Override
148   public List<IExpectConstraint> getExpectConstraints() {
149     Lock readLock = instanceLock.readLock();
150     readLock.lock();
151     try {
152       return CollectionUtil.unmodifiableList(expectConstraints);
153     } finally {
154       readLock.unlock();
155     }
156   }
157 
158   @Override
159   public final void addConstraint(@NonNull IAllowedValuesConstraint constraint) {
160     Lock writeLock = instanceLock.writeLock();
161     writeLock.lock();
162     try {
163       constraints.add(constraint);
164       allowedValuesConstraints.add(constraint);
165     } finally {
166       writeLock.unlock();
167     }
168   }
169 
170   @Override
171   public final void addConstraint(@NonNull IMatchesConstraint constraint) {
172     Lock writeLock = instanceLock.writeLock();
173     writeLock.lock();
174     try {
175       constraints.add(constraint);
176       matchesConstraints.add(constraint);
177     } finally {
178       writeLock.unlock();
179     }
180   }
181 
182   @Override
183   public final void addConstraint(@NonNull IIndexHasKeyConstraint constraint) {
184     Lock writeLock = instanceLock.writeLock();
185     writeLock.lock();
186     try {
187       constraints.add(constraint);
188       indexHasKeyConstraints.add(constraint);
189     } finally {
190       writeLock.unlock();
191     }
192   }
193 
194   @Override
195   public final void addConstraint(@NonNull IExpectConstraint constraint) {
196     Lock writeLock = instanceLock.writeLock();
197     writeLock.lock();
198     try {
199       constraints.add(constraint);
200       expectConstraints.add(constraint);
201     } finally {
202       writeLock.unlock();
203     }
204   }
205 }