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;
28 import javax.persistence.CascadeType;
29 import javax.persistence.EmbeddedId;
30 import javax.persistence.Entity;
31 import javax.persistence.Inheritance;
32 import javax.persistence.InheritanceType;
33 import javax.persistence.JoinColumn;
34 import javax.persistence.JoinColumns;
35 import javax.persistence.OneToOne;
36 import javax.persistence.Table;
37 import javax.xml.bind.annotation.XmlAccessType;
38 import javax.xml.bind.annotation.XmlAccessorType;
39 import javax.xml.bind.annotation.XmlElement;
40 import javax.xml.bind.annotation.XmlRootElement;
41 import javax.xml.bind.annotation.XmlType;
42 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
44 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
45 import org.onap.policy.apex.model.basicmodel.handling.KeyInfoMarshalFilter;
46 import org.onap.policy.apex.model.basicmodel.service.ModelService;
47 import org.onap.policy.common.utils.validation.Assertions;
50 * This class is the base class for all models in Apex. All model classes inherit from this model so all models must
51 * have a key and have key information.
53 * <p>Validation checks that the model key is valid. It goes on to check for null keys and checks each key for
54 * uniqueness in the model. A check is carried out to ensure that an {@link AxKeyInfo} instance exists for every
55 * {@link AxArtifactKey} key. For each {@link AxReferenceKey} instance, a check is made that its parent and local name
56 * are nut null and that a {@link AxKeyInfo} entry exists for its parent. Then a check is made that each used
57 * {@link AxArtifactKey} and {@link AxReferenceKey} usage references a key that exists. Finally, a check is made to
58 * ensure that an {@link AxArtifactKey} instance exists for every {@link AxKeyInfo} instance.
62 @Table(name = "AxModel")
63 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
65 @XmlRootElement(name = "apexModel", namespace = "http://www.onap.org/policy/apex-pdp")
66 @XmlAccessorType(XmlAccessType.FIELD)
67 @XmlType(name = "AxModel", namespace = "http://www.onap.org/policy/apex-pdp", propOrder =
68 { "key", "keyInformation" })
70 public class AxModel extends AxConcept {
71 private static final String IS_A_NULL_KEY = " is a null key";
73 private static final long serialVersionUID = -771659065637205430L;
76 @XmlElement(name = "key", required = true)
77 private AxArtifactKey key;
80 @OneToOne(cascade = CascadeType.ALL)
81 @JoinColumns({ @JoinColumn(name = "keyInformationName", referencedColumnName = "name"),
82 @JoinColumn(name = "keyInformationVersion", referencedColumnName = "version") })
83 @XmlElement(name = "keyInformation", required = true)
84 @XmlJavaTypeAdapter(KeyInfoMarshalFilter.class)
85 private AxKeyInformation keyInformation;
89 * The Default Constructor creates this concept with a NULL artifact key.
92 this(new AxArtifactKey());
98 * @param copyConcept the concept to copy from
100 public AxModel(final AxModel copyConcept) {
105 * Constructor to create this concept with the specified key.
107 * @param key the key of this concept
109 public AxModel(final AxArtifactKey key) {
110 this(key, new AxKeyInformation(new AxArtifactKey(key.getName() + "_KeyInfo", key.getVersion())));
114 * Constructor to create this concept and set all its fields.
116 * @param key the key of this concept
117 * @param keyInformation the key information of this concept
119 public AxModel(final AxArtifactKey key, final AxKeyInformation keyInformation) {
121 Assertions.argumentNotNull(key, "key may not be null");
122 Assertions.argumentNotNull(keyInformation, "keyInformation may not be null");
125 this.keyInformation = keyInformation;
129 * Registers this model with the {@link ModelService}. All models are registered with the model service so that
130 * models can be references from anywhere in the Apex system without being passed as references through deep call
133 public void register() {
134 ModelService.registerModel(AxKeyInformation.class, getKeyInformation());
141 public AxArtifactKey getKey() {
149 public List<AxKey> getKeys() {
150 final List<AxKey> keyList = key.getKeys();
152 // We just add the key for the KeyInformation itself. We don't add the
153 // keys from key information because
154 // that is a list of key information for existing keys
155 keyList.add(keyInformation.getKey());
161 * Sets the key of this concept.
163 * @param key the key of this concept
165 public void setKey(final AxArtifactKey key) {
166 Assertions.argumentNotNull(key, "key may not be null");
171 * Gets the key information of this concept.
173 * @return the key information of this concept
175 public AxKeyInformation getKeyInformation() {
176 return keyInformation;
180 * Sets the key information of this concept.
182 * @param keyInformation the key information of this concept
184 public void setKeyInformation(final AxKeyInformation keyInformation) {
185 Assertions.argumentNotNull(keyInformation, "keyInformation may not be null");
186 this.keyInformation = keyInformation;
193 public AxValidationResult validate(final AxValidationResult resultIn) {
194 AxValidationResult result = resultIn;
196 if (key.equals(AxArtifactKey.getNullKey())) {
197 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
198 "key is a null key"));
201 result = key.validate(result);
202 result = keyInformation.validate(result);
204 // Key consistency check
205 final Set<AxArtifactKey> artifactKeySet = new TreeSet<>();
206 final Set<AxReferenceKey> referenceKeySet = new TreeSet<>();
207 final Set<AxKeyUse> usedKeySet = new TreeSet<>();
209 for (final AxKey axKey : this.getKeys()) {
210 // Check for the two type of keys we have
211 if (axKey instanceof AxArtifactKey) {
212 result = validateArtifactKeyInModel((AxArtifactKey) axKey, artifactKeySet, result);
213 } else if (axKey instanceof AxReferenceKey) {
214 result = validateReferenceKeyInModel((AxReferenceKey) axKey, referenceKeySet, result);
216 // It must be an AxKeyUse, nothing else is legal
218 usedKeySet.add((AxKeyUse) axKey);
222 // Check all reference keys have correct parent keys
223 for (final AxReferenceKey referenceKey : referenceKeySet) {
224 if (!artifactKeySet.contains(referenceKey.getParentArtifactKey())) {
225 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
226 "parent artifact key not found for reference key " + referenceKey));
230 result = validateKeyUses(usedKeySet, artifactKeySet, referenceKeySet, result);
232 // Check key information for unused key information
233 for (final AxArtifactKey keyInfoKey : keyInformation.getKeyInfoMap().keySet()) {
234 if (!artifactKeySet.contains(keyInfoKey)) {
235 result.addValidationMessage(new AxValidationMessage(keyInfoKey, this.getClass(),
236 ValidationResult.WARNING, "key not found for key information entry"));
244 * Check for consistent usage of an artifact key in the model.
246 * @param artifactKey The artifact key to check
247 * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to the set
248 * @param result The validation result to append to
249 * @return the result of the validation
251 private AxValidationResult validateArtifactKeyInModel(final AxArtifactKey artifactKey,
252 final Set<AxArtifactKey> artifactKeySet, final AxValidationResult result) {
254 if (artifactKey.equals(AxArtifactKey.getNullKey())) {
255 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
256 "key " + artifactKey + IS_A_NULL_KEY));
259 // Null key name start check
260 if (artifactKey.getName().toUpperCase().startsWith(AxKey.NULL_KEY_NAME)) {
261 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
262 "key " + artifactKey + " name starts with keyword " + AxKey.NULL_KEY_NAME));
266 if (artifactKeySet.contains(artifactKey)) {
267 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
268 "duplicate key " + artifactKey + " found"));
270 artifactKeySet.add(artifactKey);
273 // Key information check
274 if (!keyInformation.getKeyInfoMap().containsKey(artifactKey)) {
275 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
276 "key information not found for key " + artifactKey));
283 * Check for consistent usage of a reference key in the model.
285 * @param artifactKey The reference key to check
286 * @param referenceKeySet The set of reference keys encountered so far, this key is appended to the set
287 * @param result The validation result to append to
288 * @return the result of the validation
290 private AxValidationResult validateReferenceKeyInModel(final AxReferenceKey referenceKey,
291 final Set<AxReferenceKey> referenceKeySet, final AxValidationResult result) {
293 if (referenceKey.equals(AxReferenceKey.getNullKey())) {
294 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
295 "key " + referenceKey + IS_A_NULL_KEY));
298 // Null parent key check
299 if (referenceKey.getParentArtifactKey().equals(AxArtifactKey.getNullKey())) {
300 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
301 "parent artifact key of key " + referenceKey + IS_A_NULL_KEY));
304 // Null local name check
305 if (referenceKey.getLocalName().equals(AxKey.NULL_KEY_NAME)) {
306 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
307 "key " + referenceKey + " has a null local name"));
310 // Null key name start check
311 if (referenceKey.getParentArtifactKey().getName().toUpperCase().startsWith(AxKey.NULL_KEY_NAME)) {
312 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
313 "key " + referenceKey + " parent name starts with keyword " + AxKey.NULL_KEY_NAME));
317 if (referenceKeySet.contains(referenceKey)) {
318 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
319 "duplicate key " + referenceKey + " found"));
321 referenceKeySet.add(referenceKey);
324 // Key information check
325 if (!keyInformation.getKeyInfoMap().containsKey(referenceKey.getParentArtifactKey())) {
326 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
327 "key information not found for parent key of key " + referenceKey));
334 * Check for consistent usage of cross-key references in the model.
336 * @param usedKeySet The set of all keys used in the model
337 * @param artifactKeySet The set of artifact keys encountered so far, this key is appended to the set
338 * @param referenceKeySet The set of reference keys encountered so far, this key is appended to the set
339 * @param result The validation result to append to
340 * @return the result of the validation
342 private AxValidationResult validateKeyUses(final Set<AxKeyUse> usedKeySet, final Set<AxArtifactKey> artifactKeySet,
343 final Set<AxReferenceKey> referenceKeySet, final AxValidationResult result) {
344 // Check all key uses
345 for (final AxKeyUse usedKey : usedKeySet) {
346 if (usedKey.getKey() instanceof AxArtifactKey) {
347 // AxArtifact key usage, check the key exists
348 if (!artifactKeySet.contains(usedKey.getKey())) {
349 result.addValidationMessage(new AxValidationMessage(usedKey.getKey(), this.getClass(),
350 ValidationResult.INVALID, "an artifact key used in the model is not defined"));
353 // AxReference key usage, check the key exists
354 if (!referenceKeySet.contains(usedKey.getKey())) {
355 result.addValidationMessage(new AxValidationMessage(usedKey.getKey(), this.getClass(),
356 ValidationResult.INVALID, "a reference key used in the model is not defined"));
368 public void clean() {
370 keyInformation.clean();
377 public String toString() {
378 final StringBuilder builder = new StringBuilder();
379 builder.append(this.getClass().getSimpleName());
380 builder.append(":(");
381 builder.append("key=");
383 builder.append(",keyInformation=");
384 builder.append(keyInformation);
386 return builder.toString();
393 public AxConcept copyTo(final AxConcept target) {
394 Assertions.argumentNotNull(target, "target may not be null");
396 final Object copyObject = target;
397 Assertions.instanceOf(copyObject, AxModel.class);
399 final AxModel copy = ((AxModel) copyObject);
400 copy.setKey(new AxArtifactKey(key));
401 copy.setKeyInformation(new AxKeyInformation(keyInformation));
410 public int hashCode() {
411 final int prime = 31;
413 result = prime * result + key.hashCode();
414 result = prime * result + keyInformation.hashCode();
422 public boolean equals(final Object obj) {
429 if (getClass() != obj.getClass()) {
433 final AxModel other = (AxModel) obj;
434 if (!key.equals(other.key)) {
437 return keyInformation.equals(other.keyInformation);
444 public int compareTo(final AxConcept otherObj) {
445 if (otherObj == null) {
448 if (this == otherObj) {
451 if (getClass() != otherObj.getClass()) {
452 return this.hashCode() - otherObj.hashCode();
455 final AxModel other = (AxModel) otherObj;
456 if (!key.equals(other.key)) {
457 return key.compareTo(other.key);
459 return keyInformation.compareTo(other.keyInformation);