2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2016-2018 Ericsson. All rights reserved.
4 * Modifications Copyright (C) 2019 Nordix Foundation.
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.apex.model.basicmodel.concepts;
24 import java.util.List;
26 import java.util.TreeSet;
27 import javax.persistence.CascadeType;
28 import javax.persistence.EmbeddedId;
29 import javax.persistence.Entity;
30 import javax.persistence.Inheritance;
31 import javax.persistence.InheritanceType;
32 import javax.persistence.JoinColumn;
33 import javax.persistence.JoinColumns;
34 import javax.persistence.OneToOne;
35 import javax.persistence.Table;
36 import javax.xml.bind.annotation.XmlAccessType;
37 import javax.xml.bind.annotation.XmlAccessorType;
38 import javax.xml.bind.annotation.XmlElement;
39 import javax.xml.bind.annotation.XmlRootElement;
40 import javax.xml.bind.annotation.XmlType;
41 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
42 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
43 import org.onap.policy.apex.model.basicmodel.handling.KeyInfoMarshalFilter;
44 import org.onap.policy.apex.model.basicmodel.service.ModelService;
45 import org.onap.policy.common.utils.validation.Assertions;
48 * This class is the base class for all models in Apex. All model classes inherit from this model so all models must
49 * have a key and have key information.
51 * <p>Validation checks that the model key is valid. It goes on to check for null keys and checks each key for
52 * uniqueness in the model. A check is carried out to ensure that an {@link AxKeyInfo} instance exists for every
53 * {@link AxArtifactKey} key. For each {@link AxReferenceKey} instance, a check is made that its parent and local name
54 * are nut null and that a {@link AxKeyInfo} entry exists for its parent. Then a check is made that each used
55 * {@link AxArtifactKey} and {@link AxReferenceKey} usage references a key that exists. Finally, a check is made to
56 * ensure that an {@link AxArtifactKey} instance exists for every {@link AxKeyInfo} instance.
60 @Table(name = "AxModel")
61 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
63 @XmlRootElement(name = "apexModel", namespace = "http://www.onap.org/policy/apex-pdp")
64 @XmlAccessorType(XmlAccessType.FIELD)
65 @XmlType(name = "AxModel", namespace = "http://www.onap.org/policy/apex-pdp", propOrder =
66 { "key", "keyInformation" })
68 public class AxModel extends AxConcept {
69 private static final String IS_A_NULL_KEY = " is a null key";
71 private static final long serialVersionUID = -771659065637205430L;
74 @XmlElement(name = "key", required = true)
75 private AxArtifactKey key;
78 @OneToOne(cascade = CascadeType.ALL)
79 @JoinColumns({ @JoinColumn(name = "keyInformationName", referencedColumnName = "name"),
80 @JoinColumn(name = "keyInformationVersion", referencedColumnName = "version") })
81 @XmlElement(name = "keyInformation", required = true)
82 @XmlJavaTypeAdapter(KeyInfoMarshalFilter.class)
83 private AxKeyInformation keyInformation;
87 * The Default Constructor creates this concept with a NULL artifact key.
90 this(new AxArtifactKey());
96 * @param copyConcept the concept to copy from
98 public AxModel(final AxModel copyConcept) {
103 * Constructor to create this concept with the specified key.
105 * @param key the key of this concept
107 public AxModel(final AxArtifactKey key) {
108 this(key, new AxKeyInformation(new AxArtifactKey(key.getName() + "_KeyInfo", key.getVersion())));
112 * Constructor to create this concept and set all its fields.
114 * @param key the key of this concept
115 * @param keyInformation the key information of this concept
117 public AxModel(final AxArtifactKey key, final AxKeyInformation keyInformation) {
119 Assertions.argumentNotNull(key, "key may not be null");
120 Assertions.argumentNotNull(keyInformation, "keyInformation may not be null");
123 this.keyInformation = keyInformation;
127 * Registers this model with the {@link ModelService}. All models are registered with the model service so that
128 * models can be references from anywhere in the Apex system without being passed as references through deep call
131 public void register() {
132 ModelService.registerModel(AxKeyInformation.class, getKeyInformation());
139 public AxArtifactKey getKey() {
147 public List<AxKey> getKeys() {
148 final List<AxKey> keyList = key.getKeys();
150 // We just add the key for the KeyInformation itself. We don't add the
151 // keys from key information because
152 // that is a list of key information for existing keys
153 keyList.add(keyInformation.getKey());
159 * Sets the key of this concept.
161 * @param key the key of this concept
163 public void setKey(final AxArtifactKey key) {
164 Assertions.argumentNotNull(key, "key may not be null");
169 * Gets the key information of this concept.
171 * @return the key information of this concept
173 public AxKeyInformation getKeyInformation() {
174 return keyInformation;
178 * Sets the key information of this concept.
180 * @param keyInformation the key information of this concept
182 public void setKeyInformation(final AxKeyInformation keyInformation) {
183 Assertions.argumentNotNull(keyInformation, "keyInformation may not be null");
184 this.keyInformation = keyInformation;
191 public AxValidationResult validate(final AxValidationResult resultIn) {
192 AxValidationResult result = resultIn;
194 if (key.equals(AxArtifactKey.getNullKey())) {
195 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
196 "key is a null key"));
199 result = key.validate(result);
200 result = keyInformation.validate(result);
202 // Key consistency check
203 final Set<AxArtifactKey> artifactKeySet = new TreeSet<>();
204 final Set<AxReferenceKey> referenceKeySet = new TreeSet<>();
205 final Set<AxKeyUse> usedKeySet = new TreeSet<>();
207 for (final AxKey axKey : this.getKeys()) {
208 // Check for the two type of keys we have
209 if (axKey instanceof AxArtifactKey) {
210 result = validateArtifactKeyInModel((AxArtifactKey) axKey, artifactKeySet, result);
211 } else if (axKey instanceof AxReferenceKey) {
212 result = validateReferenceKeyInModel((AxReferenceKey) axKey, referenceKeySet, result);
214 // It must be an AxKeyUse, nothing else is legal
215 usedKeySet.add((AxKeyUse) axKey);
219 // Check all reference keys have correct parent keys
220 for (final AxReferenceKey referenceKey : referenceKeySet) {
221 if (!artifactKeySet.contains(referenceKey.getParentArtifactKey())) {
222 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
223 "parent artifact key not found for reference key " + referenceKey));
227 result = validateKeyUses(usedKeySet, artifactKeySet, referenceKeySet, result);
229 // Check key information for unused key information
230 for (final AxArtifactKey keyInfoKey : keyInformation.getKeyInfoMap().keySet()) {
231 if (!artifactKeySet.contains(keyInfoKey)) {
232 result.addValidationMessage(new AxValidationMessage(keyInfoKey, this.getClass(),
233 ValidationResult.WARNING, "key not found for key information entry"));
241 * Check for consistent usage of an artifact key in the model.
243 * @param artifactKey The artifact key to check
244 * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to the set
245 * @param result The validation result to append to
246 * @return the result of the validation
248 private AxValidationResult validateArtifactKeyInModel(final AxArtifactKey artifactKey,
249 final Set<AxArtifactKey> artifactKeySet, final AxValidationResult result) {
251 if (artifactKey.equals(AxArtifactKey.getNullKey())) {
252 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
253 "key " + artifactKey + IS_A_NULL_KEY));
256 // Null key name start check
257 if (artifactKey.getName().toUpperCase().startsWith(AxKey.NULL_KEY_NAME)) {
258 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
259 "key " + artifactKey + " name starts with keyword " + AxKey.NULL_KEY_NAME));
263 if (artifactKeySet.contains(artifactKey)) {
264 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
265 "duplicate key " + artifactKey + " found"));
267 artifactKeySet.add(artifactKey);
270 // Key information check
271 if (!keyInformation.getKeyInfoMap().containsKey(artifactKey)) {
272 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
273 "key information not found for key " + artifactKey));
280 * Check for consistent usage of a reference key in the model.
282 * @param artifactKey The reference key to check
283 * @param referenceKeySet The set of reference keys encountered so far, this key is appended to the set
284 * @param result The validation result to append to
285 * @return the result of the validation
287 private AxValidationResult validateReferenceKeyInModel(final AxReferenceKey referenceKey,
288 final Set<AxReferenceKey> referenceKeySet, final AxValidationResult result) {
290 if (referenceKey.equals(AxReferenceKey.getNullKey())) {
291 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
292 "key " + referenceKey + IS_A_NULL_KEY));
295 // Null parent key check
296 if (referenceKey.getParentArtifactKey().equals(AxArtifactKey.getNullKey())) {
297 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
298 "parent artifact key of key " + referenceKey + IS_A_NULL_KEY));
301 // Null local name check
302 if (referenceKey.getLocalName().equals(AxKey.NULL_KEY_NAME)) {
303 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
304 "key " + referenceKey + " has a null local name"));
307 // Null key name start check
308 if (referenceKey.getParentArtifactKey().getName().toUpperCase().startsWith(AxKey.NULL_KEY_NAME)) {
309 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
310 "key " + referenceKey + " parent name starts with keyword " + AxKey.NULL_KEY_NAME));
314 if (referenceKeySet.contains(referenceKey)) {
315 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
316 "duplicate key " + referenceKey + " found"));
318 referenceKeySet.add(referenceKey);
321 // Key information check
322 if (!keyInformation.getKeyInfoMap().containsKey(referenceKey.getParentArtifactKey())) {
323 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
324 "key information not found for parent key of key " + referenceKey));
331 * Check for consistent usage of cross-key references in the model.
333 * @param usedKeySet The set of all keys used in the model
334 * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to the set
335 * @param referenceKeySet The set of reference keys encountered so far, this key is appended to the set
336 * @param result The validation result to append to
337 * @return the result of the validation
339 private AxValidationResult validateKeyUses(final Set<AxKeyUse> usedKeySet, final Set<AxArtifactKey> artifactKeySet,
340 final Set<AxReferenceKey> referenceKeySet, final AxValidationResult result) {
341 // Check all key uses
342 for (final AxKeyUse usedKey : usedKeySet) {
343 if (usedKey.getKey() instanceof AxArtifactKey) {
344 // AxArtifact key usage, check the key exists
345 if (!artifactKeySet.contains(usedKey.getKey())) {
346 result.addValidationMessage(new AxValidationMessage(usedKey.getKey(), this.getClass(),
347 ValidationResult.INVALID, "an artifact key used in the model is not defined"));
350 // AxReference key usage, check the key exists
351 if (!referenceKeySet.contains(usedKey.getKey())) {
352 result.addValidationMessage(new AxValidationMessage(usedKey.getKey(), this.getClass(),
353 ValidationResult.INVALID, "a reference key used in the model is not defined"));
365 public void clean() {
367 keyInformation.clean();
374 public String toString() {
375 final StringBuilder builder = new StringBuilder();
376 builder.append(this.getClass().getSimpleName());
377 builder.append(":(");
378 builder.append("key=");
380 builder.append(",keyInformation=");
381 builder.append(keyInformation);
383 return builder.toString();
390 public AxConcept copyTo(final AxConcept target) {
391 Assertions.argumentNotNull(target, "target may not be null");
393 final Object copyObject = target;
394 Assertions.instanceOf(copyObject, AxModel.class);
396 final AxModel copy = ((AxModel) copyObject);
397 copy.setKey(new AxArtifactKey(key));
398 copy.setKeyInformation(new AxKeyInformation(keyInformation));
407 public int hashCode() {
408 final int prime = 31;
410 result = prime * result + key.hashCode();
411 result = prime * result + keyInformation.hashCode();
419 public boolean equals(final Object obj) {
426 if (getClass() != obj.getClass()) {
430 final AxModel other = (AxModel) obj;
431 if (!key.equals(other.key)) {
434 return keyInformation.equals(other.keyInformation);
441 public int compareTo(final AxConcept otherObj) {
442 if (otherObj == null) {
445 if (this == otherObj) {
448 if (getClass() != otherObj.getClass()) {
449 return this.hashCode() - otherObj.hashCode();
452 final AxModel other = (AxModel) otherObj;
453 if (!key.equals(other.key)) {
454 return key.compareTo(other.key);
456 return keyInformation.compareTo(other.keyInformation);