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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
22 package org.onap.policy.models.base;
24 import java.util.List;
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;
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;
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.
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.
54 * @param <C> the type of concept on which the interface is applied.
58 @Table(name = "PfModel")
59 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
61 @EqualsAndHashCode(callSuper = false)
62 public abstract class PfModel extends PfConcept {
63 private static final String KEYS_TOKEN = "keys";
65 private static final long serialVersionUID = -771659065637205430L;
70 private PfConceptKey key;
73 * The Default Constructor creates this concept with a NULL artifact key.
76 this(new PfConceptKey());
80 * Constructor to create this concept with the specified key.
82 * @param key the key of this concept
84 protected PfModel(@NonNull final PfConceptKey key) {
86 Assertions.argumentNotNull(key, "key may not be null");
94 * @param copyConcept the concept to copy from
96 protected PfModel(@NonNull final PfModel copyConcept) {
98 this.key = new PfConceptKey(copyConcept.key);
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.
106 public abstract void register();
109 public List<PfKey> getKeys() {
110 return key.getKeys();
114 public void clean() {
119 public BeanValidationResult validate(@NonNull String fieldName) {
120 BeanValidationResult result = new PfValidator().validateTop(fieldName, this);
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<>();
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);
134 // It must be a PfKeyUse, nothing else is legal
135 usedKeySet.add((PfKeyUse) pfKey);
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");
146 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 where to add the results
159 private void validateArtifactKeyInModel(final PfConceptKey artifactKey,
160 final Set<PfConceptKey> artifactKeySet, final BeanValidationResult result) {
162 validateKeyNotNull(result, KEYS_TOKEN, artifactKey);
164 BeanValidationResult result2 = new BeanValidationResult(KEYS_TOKEN, artifactKey);
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);
173 if (artifactKeySet.contains(artifactKey)) {
174 addResult(result, KEYS_TOKEN, artifactKey, "duplicate key");
176 artifactKeySet.add(artifactKey);
181 * Check for consistent usage of a reference key in the model.
183 * @param referenceKey The reference key to check
184 * @param referenceKeySet The set of reference keys encountered so far, this key is appended to
186 * @param result where to add the results
188 private void validateReferenceKeyInModel(final PfReferenceKey referenceKey,
189 final Set<PfReferenceKey> referenceKeySet, final BeanValidationResult result) {
191 if (referenceKey.isNullKey()) {
192 addResult(result, KEYS_TOKEN, referenceKey, IS_A_NULL_KEY);
195 BeanValidationResult result2 = new BeanValidationResult(KEYS_TOKEN, referenceKey);
197 // Null parent key check
198 if (referenceKey.getParentConceptKey().isNullKey()) {
199 addResult(result2, "parent key of " + referenceKey.getId(), referenceKey.getParentConceptKey().getId(),
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);
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);
215 if (referenceKeySet.contains(referenceKey)) {
216 addResult(result, KEYS_TOKEN, referenceKey, "duplicate key");
218 referenceKeySet.add(referenceKey);
223 * Check for consistent usage of cross-key references in the model.
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
228 * @param referenceKeySet The set of reference keys encountered so far, this key is appended to
230 * @param result where to add the results
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));
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));
253 public int compareTo(final PfConcept otherObj) {
254 if (otherObj == null) {
257 if (this == otherObj) {
260 if (getClass() != otherObj.getClass()) {
261 return getClass().getName().compareTo(otherObj.getClass().getName());
264 final PfModel other = (PfModel) otherObj;
266 return key.compareTo(other.key);