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