Changes for checkstyle 8.32
[policy/apex-pdp.git] / model / basic-model / src / main / java / org / onap / policy / apex / model / basicmodel / concepts / AxModel.java
1 /*-
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
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.apex.model.basicmodel.concepts;
23
24 import java.util.List;
25 import java.util.Set;
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;
46
47 /**
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.
50  *
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.
57  */
58
59 @Entity
60 @Table(name = "AxModel")
61 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
62
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" })
67
68 public class AxModel extends AxConcept {
69     private static final String IS_A_NULL_KEY = " is a null key";
70
71     private static final long serialVersionUID = -771659065637205430L;
72
73     @EmbeddedId
74     @XmlElement(name = "key", required = true)
75     private AxArtifactKey key;
76
77     // @formatter:off
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;
84     // @formatter:on
85
86     /**
87      * The Default Constructor creates this concept with a NULL artifact key.
88      */
89     public AxModel() {
90         this(new AxArtifactKey());
91     }
92
93     /**
94      * Copy constructor.
95      *
96      * @param copyConcept the concept to copy from
97      */
98     public AxModel(final AxModel copyConcept) {
99         super(copyConcept);
100     }
101
102     /**
103      * Constructor to create this concept with the specified key.
104      *
105      * @param key the key of this concept
106      */
107     public AxModel(final AxArtifactKey key) {
108         this(key, new AxKeyInformation(new AxArtifactKey(key.getName() + "_KeyInfo", key.getVersion())));
109     }
110
111     /**
112      * Constructor to create this concept and set all its fields.
113      *
114      * @param key the key of this concept
115      * @param keyInformation the key information of this concept
116      */
117     public AxModel(final AxArtifactKey key, final AxKeyInformation keyInformation) {
118         super();
119         Assertions.argumentNotNull(key, "key may not be null");
120         Assertions.argumentNotNull(keyInformation, "keyInformation may not be null");
121
122         this.key = key;
123         this.keyInformation = keyInformation;
124     }
125
126     /**
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
129      * chains.
130      */
131     public void register() {
132         ModelService.registerModel(AxKeyInformation.class, getKeyInformation());
133     }
134
135     /**
136      * {@inheritDoc}.
137      */
138     @Override
139     public AxArtifactKey getKey() {
140         return key;
141     }
142
143     /**
144      * {@inheritDoc}.
145      */
146     @Override
147     public List<AxKey> getKeys() {
148         final List<AxKey> keyList = key.getKeys();
149
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());
154
155         return keyList;
156     }
157
158     /**
159      * Sets the key of this concept.
160      *
161      * @param key the key of this concept
162      */
163     public void setKey(final AxArtifactKey key) {
164         Assertions.argumentNotNull(key, "key may not be null");
165         this.key = key;
166     }
167
168     /**
169      * Gets the key information of this concept.
170      *
171      * @return the key information of this concept
172      */
173     public AxKeyInformation getKeyInformation() {
174         return keyInformation;
175     }
176
177     /**
178      * Sets the key information of this concept.
179      *
180      * @param keyInformation the key information of this concept
181      */
182     public void setKeyInformation(final AxKeyInformation keyInformation) {
183         Assertions.argumentNotNull(keyInformation, "keyInformation may not be null");
184         this.keyInformation = keyInformation;
185     }
186
187     /**
188      * {@inheritDoc}.
189      */
190     @Override
191     public AxValidationResult validate(final AxValidationResult resultIn) {
192         AxValidationResult result = resultIn;
193
194         if (key.equals(AxArtifactKey.getNullKey())) {
195             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
196                             "key is a null key"));
197         }
198
199         result = key.validate(result);
200         result = keyInformation.validate(result);
201
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<>();
206
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);
213             } else {
214                 // It must be an AxKeyUse, nothing else is legal
215                 usedKeySet.add((AxKeyUse) axKey);
216             }
217         }
218
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));
224             }
225         }
226
227         result = validateKeyUses(usedKeySet, artifactKeySet, referenceKeySet, result);
228
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"));
234             }
235         }
236
237         return result;
238     }
239
240     /**
241      * Check for consistent usage of an artifact key in the model.
242      *
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
247      */
248     private AxValidationResult validateArtifactKeyInModel(final AxArtifactKey artifactKey,
249                     final Set<AxArtifactKey> artifactKeySet, final AxValidationResult result) {
250         // Null key check
251         if (artifactKey.equals(AxArtifactKey.getNullKey())) {
252             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
253                             "key " + artifactKey + IS_A_NULL_KEY));
254         }
255
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));
260         }
261
262         // Unique key check
263         if (artifactKeySet.contains(artifactKey)) {
264             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
265                             "duplicate key " + artifactKey + " found"));
266         } else {
267             artifactKeySet.add(artifactKey);
268         }
269
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));
274         }
275
276         return result;
277     }
278
279     /**
280      * Check for consistent usage of a reference key in the model.
281      *
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
286      */
287     private AxValidationResult validateReferenceKeyInModel(final AxReferenceKey referenceKey,
288                     final Set<AxReferenceKey> referenceKeySet, final AxValidationResult result) {
289         // Null key check
290         if (referenceKey.equals(AxReferenceKey.getNullKey())) {
291             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
292                             "key " + referenceKey + IS_A_NULL_KEY));
293         }
294
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));
299         }
300
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"));
305         }
306
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));
311         }
312
313         // Unique key check
314         if (referenceKeySet.contains(referenceKey)) {
315             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
316                             "duplicate key " + referenceKey + " found"));
317         } else {
318             referenceKeySet.add(referenceKey);
319         }
320
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));
325         }
326
327         return result;
328     }
329
330     /**
331      * Check for consistent usage of cross-key references in the model.
332      *
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
338      */
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"));
348                 }
349             } else {
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"));
354                 }
355             }
356         }
357
358         return result;
359     }
360
361     /**
362      * {@inheritDoc}.
363      */
364     @Override
365     public void clean() {
366         key.clean();
367         keyInformation.clean();
368     }
369
370     /**
371      * {@inheritDoc}.
372      */
373     @Override
374     public String toString() {
375         final StringBuilder builder = new StringBuilder();
376         builder.append(this.getClass().getSimpleName());
377         builder.append(":(");
378         builder.append("key=");
379         builder.append(key);
380         builder.append(",keyInformation=");
381         builder.append(keyInformation);
382         builder.append(")");
383         return builder.toString();
384     }
385
386     /**
387      * {@inheritDoc}.
388      */
389     @Override
390     public AxConcept copyTo(final AxConcept target) {
391         Assertions.argumentNotNull(target, "target may not be null");
392
393         final Object copyObject = target;
394         Assertions.instanceOf(copyObject, AxModel.class);
395
396         final AxModel copy = ((AxModel) copyObject);
397         copy.setKey(new AxArtifactKey(key));
398         copy.setKeyInformation(new AxKeyInformation(keyInformation));
399
400         return copy;
401     }
402
403     /**
404      * {@inheritDoc}.
405      */
406     @Override
407     public int hashCode() {
408         final int prime = 31;
409         int result = 1;
410         result = prime * result + key.hashCode();
411         result = prime * result + keyInformation.hashCode();
412         return result;
413     }
414
415     /**
416      * {@inheritDoc}.
417      */
418     @Override
419     public boolean equals(final Object obj) {
420         if (obj == null) {
421             return false;
422         }
423         if (this == obj) {
424             return true;
425         }
426         if (getClass() != obj.getClass()) {
427             return false;
428         }
429
430         final AxModel other = (AxModel) obj;
431         if (!key.equals(other.key)) {
432             return false;
433         }
434         return keyInformation.equals(other.keyInformation);
435     }
436
437     /**
438      * {@inheritDoc}.
439      */
440     @Override
441     public int compareTo(final AxConcept otherObj) {
442         if (otherObj == null) {
443             return -1;
444         }
445         if (this == otherObj) {
446             return 0;
447         }
448         if (getClass() != otherObj.getClass()) {
449             return this.hashCode() - otherObj.hashCode();
450         }
451
452         final AxModel other = (AxModel) otherObj;
453         if (!key.equals(other.key)) {
454             return key.compareTo(other.key);
455         }
456         return keyInformation.compareTo(other.keyInformation);
457     }
458 }