2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2019 Nordix Foundation.
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.models.base;
23 import java.util.List;
25 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;
34 import lombok.EqualsAndHashCode;
35 import lombok.NonNull;
37 import org.onap.policy.common.utils.validation.Assertions;
38 import org.onap.policy.models.base.PfValidationResult.ValidationResult;
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.
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 PfKeyInfo}
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 nut null and that a {@link PfKeyInfo} 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 PfKeyInfo} instance.
52 * @param <C> the type of concept on which the interface is applied.
56 @Table(name = "PfModel")
57 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
59 @EqualsAndHashCode(callSuper = false)
60 public abstract class PfModel extends PfConcept {
61 private static final String IS_A_NULL_KEY = " is a null key";
63 private static final long serialVersionUID = -771659065637205430L;
67 private PfConceptKey key = PfConceptKey.getNullKey();
70 * The Default Constructor creates this concept with a NULL artifact key.
73 this(new PfConceptKey());
79 * @param copyConcept the concept to copy from
81 public PfModel(final PfModel copyConcept) {
86 * Constructor to create this concept with the specified key.
88 * @param key the key of this concept
90 public PfModel(final PfConceptKey key) {
92 Assertions.argumentNotNull(key, "key may not be null");
98 * Registers this model with the {@link PfModelService}. All models are registered with the
99 * model service so that models can be references from anywhere in the Policy Framework system
100 * without being passed as references through deep call chains.
102 public abstract void register();
105 public List<PfKey> getKeys() {
106 return key.getKeys();
110 public PfValidationResult validate(final PfValidationResult resultIn) {
111 PfValidationResult result = resultIn;
113 if (key.equals(PfConceptKey.getNullKey())) {
114 result.addValidationMessage(
115 new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
118 result = key.validate(result);
120 // Key consistency check
121 final Set<PfConceptKey> artifactKeySet = new TreeSet<>();
122 final Set<PfReferenceKey> referenceKeySet = new TreeSet<>();
123 final Set<PfKeyUse> usedKeySet = new TreeSet<>();
125 for (final PfKey pfKey : this.getKeys()) {
126 // Check for the two type of keys we have
127 if (pfKey instanceof PfConceptKey) {
128 result = validateArtifactKeyInModel((PfConceptKey) pfKey, artifactKeySet, result);
129 } else if (pfKey instanceof PfReferenceKey) {
130 result = validateReferenceKeyInModel((PfReferenceKey) pfKey, referenceKeySet, result);
132 // It must be an PfKeyUse, nothing else is legal
134 usedKeySet.add((PfKeyUse) pfKey);
138 // Check all reference keys have correct parent keys
139 for (final PfReferenceKey referenceKey : referenceKeySet) {
140 if (!artifactKeySet.contains(referenceKey.getParentConceptKey())) {
141 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
142 "parent artifact key not found for reference key " + referenceKey));
146 result = validateKeyUses(usedKeySet, artifactKeySet, referenceKeySet, result);
152 * Check for consistent usage of an artifact key in the model.
154 * @param artifactKey The artifact key to check
155 * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to
157 * @param result The validation result to append to
158 * @return the result of the validation
160 private PfValidationResult validateArtifactKeyInModel(final PfConceptKey artifactKey,
161 final Set<PfConceptKey> artifactKeySet, final PfValidationResult result) {
163 if (artifactKey.equals(PfConceptKey.getNullKey())) {
164 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
165 "key " + artifactKey + IS_A_NULL_KEY));
168 // Null key name start check
169 if (artifactKey.getName().toUpperCase().startsWith(PfKey.NULL_KEY_NAME)) {
170 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
171 "key " + artifactKey + " name starts with keyword " + PfKey.NULL_KEY_NAME));
175 if (artifactKeySet.contains(artifactKey)) {
176 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
177 "duplicate key " + artifactKey + " found"));
179 artifactKeySet.add(artifactKey);
186 * Check for consistent usage of a reference key in the model.
188 * @param artifactKey The reference key to check
189 * @param referenceKeySet The set of reference keys encountered so far, this key is appended to
191 * @param result The validation result to append to
192 * @return the result of the validation
194 private PfValidationResult validateReferenceKeyInModel(final PfReferenceKey referenceKey,
195 final Set<PfReferenceKey> referenceKeySet, final PfValidationResult result) {
197 if (referenceKey.equals(PfReferenceKey.getNullKey())) {
198 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
199 "key " + referenceKey + IS_A_NULL_KEY));
202 // Null parent key check
203 if (referenceKey.getParentConceptKey().equals(PfConceptKey.getNullKey())) {
204 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
205 "parent artifact key of key " + referenceKey + IS_A_NULL_KEY));
208 // Null local name check
209 if (referenceKey.getLocalName().equals(PfKey.NULL_KEY_NAME)) {
210 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
211 "key " + referenceKey + " has a null local name"));
214 // Null key name start check
215 if (referenceKey.getParentConceptKey().getName().toUpperCase().startsWith(PfKey.NULL_KEY_NAME)) {
216 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
217 "key " + referenceKey + " parent name starts with keyword " + PfKey.NULL_KEY_NAME));
221 if (referenceKeySet.contains(referenceKey)) {
222 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
223 "duplicate key " + referenceKey + " found"));
225 referenceKeySet.add(referenceKey);
232 * Check for consistent usage of cross-key references in the model.
234 * @param usedKeySet The set of all keys used in the model
235 * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to
237 * @param referenceKeySet The set of reference keys encountered so far, this key is appended to
239 * @param result The validation result to append to
240 * @return the result of the validation
242 private PfValidationResult validateKeyUses(final Set<PfKeyUse> usedKeySet, final Set<PfConceptKey> artifactKeySet,
243 final Set<PfReferenceKey> referenceKeySet, final PfValidationResult result) {
244 // Check all key uses
245 for (final PfKeyUse usedKey : usedKeySet) {
246 if (usedKey.getKey() instanceof PfConceptKey) {
247 // PfConceptKey usage, check the key exists
248 if (!artifactKeySet.contains(usedKey.getKey())) {
249 result.addValidationMessage(new PfValidationMessage(usedKey.getKey(), this.getClass(),
250 ValidationResult.INVALID, "an artifact key used in the model is not defined"));
253 // PfReferenceKey usage, check the key exists
254 if (!referenceKeySet.contains(usedKey.getKey())) {
255 result.addValidationMessage(new PfValidationMessage(usedKey.getKey(), this.getClass(),
256 ValidationResult.INVALID, "a reference key used in the model is not defined"));
265 public void clean() {
270 public PfConcept copyTo(final PfConcept target) {
271 Assertions.argumentNotNull(target, "target may not be null");
273 final Object copyObject = target;
274 Assertions.instanceOf(copyObject, PfModel.class);
276 final PfModel copy = ((PfModel) copyObject);
277 copy.setKey(new PfConceptKey(key));
285 * @see java.lang.Comparable#compareTo(java.lang.Object)
288 public int compareTo(final PfConcept otherObj) {
289 if (otherObj == null) {
292 if (this == otherObj) {
295 if (getClass() != otherObj.getClass()) {
296 return this.hashCode() - otherObj.hashCode();
299 final PfModel other = (PfModel) otherObj;
301 return key.compareTo(other.key);