Java 17 Upgrade
[policy/models.git] / models-base / src / main / java / org / onap / policy / models / base / PfModel.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019, 2023 Nordix Foundation.
4  *  Modifications Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
5  *  Modifications Copyright (C) 2022 Bell Canada. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.models.base;
24
25 import jakarta.persistence.EmbeddedId;
26 import jakarta.persistence.MappedSuperclass;
27 import java.io.Serial;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.TreeSet;
31 import lombok.Data;
32 import lombok.EqualsAndHashCode;
33 import lombok.NonNull;
34 import org.onap.policy.common.parameters.BeanValidationResult;
35 import org.onap.policy.common.parameters.ValidationStatus;
36 import org.onap.policy.common.parameters.annotations.NotNull;
37 import org.onap.policy.common.utils.validation.Assertions;
38 import org.onap.policy.models.base.validation.annotations.VerifyKey;
39
40 /**
41  * This class is the base class for all models in the Policy Framework. All model classes inherit
42  * from this model so all models must have a key and have key information.
43  *
44  * <p>Validation checks that the model key is valid. It goes on to check for null keys and checks
45  * each key for uniqueness in the model. A check is carried out to ensure that an {@link PfKey}
46  * instance exists for every {@link PfConceptKey} key. For each {@link PfReferenceKey} instance, a
47  * check is made that its parent and local name are not null and that a {@link PfKey} entry
48  * exists for its parent. Then a check is made that each used {@link PfConceptKey} and
49  * {@link PfReferenceKey} usage references a key that exists. Finally, a check is made to ensure
50  * that an {@link PfConceptKey} instance exists for every {@link PfKey} instance.
51  *
52  * @param <C> the type of concept on which the interface is applied.
53  */
54
55 @MappedSuperclass
56 @Data
57 @EqualsAndHashCode(callSuper = false)
58 public abstract class PfModel extends PfConcept {
59     private static final String KEYS_TOKEN = "keys";
60
61     @Serial
62     private static final long serialVersionUID = -771659065637205430L;
63
64     @EmbeddedId
65     @VerifyKey
66     @NotNull
67     private PfConceptKey key;
68
69     /**
70      * The Default Constructor creates this concept with a NULL artifact key.
71      */
72     protected PfModel() {
73         this(new PfConceptKey());
74     }
75
76     /**
77      * Constructor to create this concept with the specified key.
78      *
79      * @param key the key of this concept
80      */
81     protected PfModel(@NonNull final PfConceptKey key) {
82         super();
83         Assertions.argumentNotNull(key, "key may not be null");
84
85         this.key = key;
86     }
87
88     /**
89      * Copy constructor.
90      *
91      * @param copyConcept the concept to copy from
92      */
93     protected PfModel(@NonNull final PfModel copyConcept) {
94         super(copyConcept);
95         this.key = new PfConceptKey(copyConcept.key);
96     }
97
98     /**
99      * Registers this model with the {@link PfModelService}. All models are registered with the
100      * model service so that models can be references from anywhere in the Policy Framework system
101      * without being passed as references through deep call chains.
102      */
103     public abstract void register();
104
105     @Override
106     public List<PfKey> getKeys() {
107         return key.getKeys();
108     }
109
110     @Override
111     public void clean() {
112         key.clean();
113     }
114
115     @Override
116     public BeanValidationResult validate(@NonNull String fieldName) {
117         BeanValidationResult result = new PfValidator().validateTop(fieldName, this);
118
119         // Key consistency check
120         final Set<PfConceptKey> artifactKeySet = new TreeSet<>();
121         final Set<PfReferenceKey> referenceKeySet = new TreeSet<>();
122         final Set<PfKeyUse> usedKeySet = new TreeSet<>();
123
124         for (final PfKey pfKey : this.getKeys()) {
125             // Check for the two type of keys we have
126             if (pfKey instanceof PfConceptKey) {
127                 validateArtifactKeyInModel((PfConceptKey) pfKey, artifactKeySet, result);
128             } else if (pfKey instanceof PfReferenceKey) {
129                 validateReferenceKeyInModel((PfReferenceKey) pfKey, referenceKeySet, result);
130             } else {
131                 // It must be a PfKeyUse, nothing else is legal
132                 usedKeySet.add((PfKeyUse) pfKey);
133             }
134         }
135
136         // Check all reference keys have correct parent keys
137         for (final PfReferenceKey referenceKey : referenceKeySet) {
138             if (!artifactKeySet.contains(referenceKey.getParentConceptKey())) {
139                 addResult(result, "reference key", referenceKey, "parent artifact key not found");
140             }
141         }
142
143         validateKeyUses(usedKeySet, artifactKeySet, referenceKeySet, result);
144
145         return result;
146     }
147
148     /**
149      * Check for consistent usage of an artifact key in the model.
150      *
151      * @param artifactKey    The artifact key to check
152      * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to
153      *                       the set
154      * @param result         where to add the results
155      */
156     private void validateArtifactKeyInModel(final PfConceptKey artifactKey,
157                                             final Set<PfConceptKey> artifactKeySet, final BeanValidationResult result) {
158
159         validateKeyNotNull(result, KEYS_TOKEN, artifactKey);
160
161         var result2 = new BeanValidationResult(KEYS_TOKEN, artifactKey);
162
163         // Null key name start check
164         if (artifactKey.getName().toUpperCase().startsWith(PfKey.NULL_KEY_NAME)) {
165             addResult(result2, "name of " + artifactKey.getId(), artifactKey.getName(),
166                 "starts with keyword " + PfKey.NULL_KEY_NAME);
167         }
168
169         // Unique key check
170         if (artifactKeySet.contains(artifactKey)) {
171             addResult(result, KEYS_TOKEN, artifactKey, "duplicate key");
172         } else {
173             artifactKeySet.add(artifactKey);
174         }
175     }
176
177     /**
178      * Check for consistent usage of a reference key in the model.
179      *
180      * @param referenceKey    The reference key to check
181      * @param referenceKeySet The set of reference keys encountered so far, this key is appended to
182      *                        the set
183      * @param result          where to add the results
184      */
185     private void validateReferenceKeyInModel(final PfReferenceKey referenceKey,
186                                              final Set<PfReferenceKey> referenceKeySet,
187                                              final BeanValidationResult result) {
188         // Null key check
189         if (referenceKey.isNullKey()) {
190             addResult(result, KEYS_TOKEN, referenceKey, IS_A_NULL_KEY);
191         }
192
193         var result2 = new BeanValidationResult(KEYS_TOKEN, referenceKey);
194
195         // Null parent key check
196         if (referenceKey.getParentConceptKey().isNullKey()) {
197             addResult(result2, "parent key of " + referenceKey.getId(), referenceKey.getParentConceptKey().getId(),
198                 IS_A_NULL_KEY);
199         }
200
201         // Null local name check
202         if (referenceKey.getLocalName().equals(PfKey.NULL_KEY_NAME)) {
203             addResult(result2, "local name of " + referenceKey.getId(), referenceKey.getLocalName(), IS_NULL);
204         }
205
206         // Null key name start check
207         if (referenceKey.getParentConceptKey().getName().toUpperCase().startsWith(PfKey.NULL_KEY_NAME)) {
208             addResult(result2, "parent name of " + referenceKey.getId(), referenceKey.getParentConceptKey().getName(),
209                 "starts with keyword " + PfKey.NULL_KEY_NAME);
210         }
211
212         // Unique key check
213         if (referenceKeySet.contains(referenceKey)) {
214             addResult(result, KEYS_TOKEN, referenceKey, "duplicate key");
215         } else {
216             referenceKeySet.add(referenceKey);
217         }
218     }
219
220     /**
221      * Check for consistent usage of cross-key references in the model.
222      *
223      * @param usedKeySet      The set of all keys used in the model
224      * @param artifactKeySet  The set of artifact keys encountered so far, this key is appended to
225      *                        the set
226      * @param referenceKeySet The set of reference keys encountered so far, this key is appended to
227      *                        the set
228      * @param result          where to add the results
229      */
230     private void validateKeyUses(final Set<PfKeyUse> usedKeySet, final Set<PfConceptKey> artifactKeySet,
231                                  final Set<PfReferenceKey> referenceKeySet, final BeanValidationResult result) {
232         // Check all key uses
233         for (final PfKeyUse usedKey : usedKeySet) {
234             if (usedKey.getKey() instanceof PfConceptKey) {
235                 // PfConceptKey usage, check the key exists
236                 if (!artifactKeySet.contains(usedKey.getKey())) {
237                     result.addResult("artifact key", usedKey.getId(), ValidationStatus.INVALID, NOT_DEFINED);
238                 }
239             } else {
240                 // PfReferenceKey usage, check the key exists
241                 if (!referenceKeySet.contains(usedKey.getKey())) {
242                     result.addResult("reference key", usedKey.getId(), ValidationStatus.INVALID, NOT_DEFINED);
243                 }
244             }
245         }
246     }
247
248     @Override
249     public int compareTo(final PfConcept otherObj) {
250         if (otherObj == null) {
251             return -1;
252         }
253         if (this == otherObj) {
254             return 0;
255         }
256         if (getClass() != otherObj.getClass()) {
257             return getClass().getName().compareTo(otherObj.getClass().getName());
258         }
259
260         final PfModel other = (PfModel) otherObj;
261
262         return key.compareTo(other.key);
263     }
264 }