Changes for Checkstyle 8.32
[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 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.utils.validation.Assertions;
36 import org.onap.policy.models.base.PfValidationResult.ValidationResult;
37
38 /**
39  * This class is the base class for all models in the Policy Framework. All model classes inherit
40  * from this model so all models must have a key and have key information.
41  *
42  * <p>Validation checks that the model key is valid. It goes on to check for null keys and checks
43  * each key for uniqueness in the model. A check is carried out to ensure that an {@link PfKeyInfo}
44  * instance exists for every {@link PfConceptKey} key. For each {@link PfReferenceKey} instance, a
45  * check is made that its parent and local name are nut null and that a {@link PfKeyInfo} entry
46  * exists for its parent. Then a check is made that each used {@link PfConceptKey} and
47  * {@link PfReferenceKey} usage references a key that exists. Finally, a check is made to ensure
48  * that an {@link PfConceptKey} instance exists for every {@link PfKeyInfo} instance.
49  *
50  * @param <C> the type of concept on which the interface is applied.
51  */
52
53 @Entity
54 @Table(name = "PfModel")
55 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
56 @Data
57 @EqualsAndHashCode(callSuper = false)
58 public abstract class PfModel extends PfConcept {
59     private static final String IS_A_NULL_KEY = " is a null key";
60
61     private static final long serialVersionUID = -771659065637205430L;
62
63     @EmbeddedId
64     private PfConceptKey key;
65
66     /**
67      * The Default Constructor creates this concept with a NULL artifact key.
68      */
69     public PfModel() {
70         this(new PfConceptKey());
71     }
72
73     /**
74      * Constructor to create this concept with the specified key.
75      *
76      * @param key the key of this concept
77      */
78     public PfModel(@NonNull final PfConceptKey key) {
79         super();
80         Assertions.argumentNotNull(key, "key may not be null");
81
82         this.key = key;
83     }
84
85     /**
86      * Copy constructor.
87      *
88      * @param copyConcept the concept to copy from
89      */
90     public PfModel(@NonNull final PfModel copyConcept) {
91         super(copyConcept);
92         this.key = new PfConceptKey(copyConcept.key);
93     }
94
95     /**
96      * Registers this model with the {@link PfModelService}. All models are registered with the
97      * model service so that models can be references from anywhere in the Policy Framework system
98      * without being passed as references through deep call chains.
99      */
100     public abstract void register();
101
102     @Override
103     public List<PfKey> getKeys() {
104         return key.getKeys();
105     }
106
107     @Override
108     public void clean() {
109         key.clean();
110     }
111
112     @Override
113     public PfValidationResult validate(@NonNull final PfValidationResult resultIn) {
114         PfValidationResult result = resultIn;
115
116         if (key.isNullKey()) {
117             result.addValidationMessage(
118                     new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
119         }
120
121         result = key.validate(result);
122
123         // Key consistency check
124         final Set<PfConceptKey> artifactKeySet = new TreeSet<>();
125         final Set<PfReferenceKey> referenceKeySet = new TreeSet<>();
126         final Set<PfKeyUse> usedKeySet = new TreeSet<>();
127
128         for (final PfKey pfKey : this.getKeys()) {
129             // Check for the two type of keys we have
130             if (pfKey instanceof PfConceptKey) {
131                 result = validateArtifactKeyInModel((PfConceptKey) pfKey, artifactKeySet, result);
132             } else if (pfKey instanceof PfReferenceKey) {
133                 result = validateReferenceKeyInModel((PfReferenceKey) pfKey, referenceKeySet, result);
134             } else {
135                 // It must be a PfKeyUse, nothing else is legal
136                 usedKeySet.add((PfKeyUse) pfKey);
137             }
138         }
139
140         // Check all reference keys have correct parent keys
141         for (final PfReferenceKey referenceKey : referenceKeySet) {
142             if (!artifactKeySet.contains(referenceKey.getParentConceptKey())) {
143                 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
144                         "parent artifact key not found for reference key " + referenceKey));
145             }
146         }
147
148         result = validateKeyUses(usedKeySet, artifactKeySet, referenceKeySet, result);
149
150         return result;
151     }
152
153     /**
154      * Check for consistent usage of an artifact key in the model.
155      *
156      * @param artifactKey The artifact key to check
157      * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to
158      *        the set
159      * @param result The validation result to append to
160      * @return the result of the validation
161      */
162     private PfValidationResult validateArtifactKeyInModel(final PfConceptKey artifactKey,
163             final Set<PfConceptKey> artifactKeySet, final PfValidationResult result) {
164         // Null key check
165         if (artifactKey.isNullKey()) {
166             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
167                     "key " + artifactKey + IS_A_NULL_KEY));
168         }
169
170         // Null key name start check
171         if (artifactKey.getName().toUpperCase().startsWith(PfKey.NULL_KEY_NAME)) {
172             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
173                     "key " + artifactKey + " name starts with keyword " + PfKey.NULL_KEY_NAME));
174         }
175
176         // Unique key check
177         if (artifactKeySet.contains(artifactKey)) {
178             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
179                     "duplicate key " + artifactKey + " found"));
180         } else {
181             artifactKeySet.add(artifactKey);
182         }
183
184         return result;
185     }
186
187     /**
188      * Check for consistent usage of a reference key in the model.
189      *
190      * @param artifactKey The reference key to check
191      * @param referenceKeySet The set of reference keys encountered so far, this key is appended to
192      *        the set
193      * @param result The validation result to append to
194      * @return the result of the validation
195      */
196     private PfValidationResult validateReferenceKeyInModel(final PfReferenceKey referenceKey,
197             final Set<PfReferenceKey> referenceKeySet, final PfValidationResult result) {
198         // Null key check
199         if (referenceKey.isNullKey()) {
200             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
201                     "key " + referenceKey + IS_A_NULL_KEY));
202         }
203
204         // Null parent key check
205         if (referenceKey.getParentConceptKey().isNullKey()) {
206             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
207                     "parent artifact key of key " + referenceKey + IS_A_NULL_KEY));
208         }
209
210         // Null local name check
211         if (referenceKey.getLocalName().equals(PfKey.NULL_KEY_NAME)) {
212             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
213                     "key " + referenceKey + " has a null local name"));
214         }
215
216         // Null key name start check
217         if (referenceKey.getParentConceptKey().getName().toUpperCase().startsWith(PfKey.NULL_KEY_NAME)) {
218             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
219                     "key " + referenceKey + " parent name starts with keyword " + PfKey.NULL_KEY_NAME));
220         }
221
222         // Unique key check
223         if (referenceKeySet.contains(referenceKey)) {
224             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
225                     "duplicate key " + referenceKey + " found"));
226         } else {
227             referenceKeySet.add(referenceKey);
228         }
229
230         return result;
231     }
232
233     /**
234      * Check for consistent usage of cross-key references in the model.
235      *
236      * @param usedKeySet The set of all keys used in the model
237      * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to
238      *        the set
239      * @param referenceKeySet The set of reference keys encountered so far, this key is appended to
240      *        the set
241      * @param result The validation result to append to
242      * @return the result of the validation
243      */
244     private PfValidationResult validateKeyUses(final Set<PfKeyUse> usedKeySet, final Set<PfConceptKey> artifactKeySet,
245             final Set<PfReferenceKey> referenceKeySet, final PfValidationResult result) {
246         // Check all key uses
247         for (final PfKeyUse usedKey : usedKeySet) {
248             if (usedKey.getKey() instanceof PfConceptKey) {
249                 // PfConceptKey usage, check the key exists
250                 if (!artifactKeySet.contains(usedKey.getKey())) {
251                     result.addValidationMessage(new PfValidationMessage(usedKey.getKey(), this.getClass(),
252                             ValidationResult.INVALID, "an artifact key used in the model is not defined"));
253                 }
254             } else {
255                 // PfReferenceKey usage, check the key exists
256                 if (!referenceKeySet.contains(usedKey.getKey())) {
257                     result.addValidationMessage(new PfValidationMessage(usedKey.getKey(), this.getClass(),
258                             ValidationResult.INVALID, "a reference key used in the model is not defined"));
259                 }
260             }
261         }
262
263         return result;
264     }
265
266     @Override
267     public int compareTo(final PfConcept otherObj) {
268         if (otherObj == null) {
269             return -1;
270         }
271         if (this == otherObj) {
272             return 0;
273         }
274         if (getClass() != otherObj.getClass()) {
275             return getClass().getName().compareTo(otherObj.getClass().getName());
276         }
277
278         final PfModel other = (PfModel) otherObj;
279
280         return key.compareTo(other.key);
281     }
282 }