d1cc99a224af225c526c46d57ae680ecb9cbc81e
[policy/apex-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019-2022 Nordix Foundation.
5  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.apex.model.basicmodel.concepts;
24
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.NavigableMap;
29 import java.util.Set;
30 import java.util.TreeMap;
31 import java.util.TreeSet;
32 import java.util.UUID;
33 import javax.xml.bind.Unmarshaller;
34 import javax.xml.bind.annotation.XmlAccessType;
35 import javax.xml.bind.annotation.XmlAccessorType;
36 import javax.xml.bind.annotation.XmlElement;
37 import javax.xml.bind.annotation.XmlType;
38 import org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
39 import org.onap.policy.common.utils.validation.Assertions;
40
41 /**
42  * The Class AxKeyInformation holds a map of the key information for the entire Apex model. All Apex models
43  * {@link AxModel} must have an {@link AxKeyInformation} field. The {@link AxKeyInformation} class implements the helper
44  * methods of the {@link AxConceptGetter} interface to allow {@link AxKeyInfo} instances to be retrieved by calling
45  * methods directly on this class without referencing the contained map.
46  *
47  * <p>Validation checks that the key is not null, that the key information map is not empty, that each key and value in
48  * the map is defined, that the key in each map entry matches the key if each entry value, and that no duplicate UUIDs
49  * exist. Each key information entry is then validated individually.
50  */
51 @XmlAccessorType(XmlAccessType.FIELD)
52 @XmlType(name = "AxKeyInformation", namespace = "http://www.onap.org/policy/apex-pdp",
53         propOrder = { "key", "keyInfoMap" })
54
55 public class AxKeyInformation extends AxConcept implements AxConceptGetter<AxKeyInfo> {
56     private static final long serialVersionUID = -2746380769017043888L;
57
58     @XmlElement(name = "key", required = true)
59     private AxArtifactKey key;
60
61     private Map<AxArtifactKey, AxKeyInfo> keyInfoMap;
62
63     /**
64      * The Default Constructor creates this concept with a null key.
65      */
66     public AxKeyInformation() {
67         this(new AxArtifactKey());
68     }
69
70     /**
71      * Copy constructor.
72      *
73      * @param copyConcept the concept to copy from
74      */
75     public AxKeyInformation(final AxKeyInformation copyConcept) {
76         super(copyConcept);
77     }
78
79     /**
80      * Constructor to create this concept with the specified key.
81      *
82      * @param key the key of the concept
83      */
84     public AxKeyInformation(final AxArtifactKey key) {
85         this(key, new TreeMap<>());
86     }
87
88     /**
89      * Constructor to create this concept and set all its fields.
90      *
91      * @param key the key of the concept
92      * @param keyInfoMap the key info map of the concept
93      */
94     public AxKeyInformation(final AxArtifactKey key, final Map<AxArtifactKey, AxKeyInfo> keyInfoMap) {
95         super();
96         Assertions.argumentNotNull(key, "key may not be null");
97         Assertions.argumentNotNull(keyInfoMap, "keyInfoMap may not be null");
98
99         this.key = key;
100         this.keyInfoMap = new TreeMap<>();
101         this.keyInfoMap.putAll(keyInfoMap);
102     }
103
104     /**
105      * When a model is unmarshalled from disk or from the database, the key information map is returned as a raw Hash
106      * Map. This method is called by JAXB after unmarshaling and is used to convert the hash map to a
107      * {@link NavigableMap} so that it will work with the {@link AxConceptGetter} interface.
108      *
109      * @param unmarshaler the unmarshaler that is unmarshaling the model
110      * @param parent the parent object of this object in the unmarshaler
111      */
112     public void afterUnmarshal(final Unmarshaller unmarshaler, final Object parent) {
113         // The map must be navigable to allow name and version searching,
114         // unmarshaling returns a hash map
115         final NavigableMap<AxArtifactKey, AxKeyInfo> navigablekeyInfoMap = new TreeMap<>();
116         navigablekeyInfoMap.putAll(keyInfoMap);
117         keyInfoMap = navigablekeyInfoMap;
118     }
119
120     /**
121      * This method generates default key information for all keys found in the concept passed in as a parameter that do
122      * not already have key information.
123      *
124      * @param concept the concept for which to generate key information
125      */
126     public void generateKeyInfo(final AxConcept concept) {
127         for (final AxKey axKey : concept.getKeys()) {
128             if (!(axKey instanceof AxArtifactKey)) {
129                 continue;
130             }
131
132             final AxArtifactKey artifactKey = (AxArtifactKey) axKey;
133
134             keyInfoMap.computeIfAbsent(artifactKey, unusedKey -> {
135                 final var keyInfo = new AxKeyInfo(artifactKey);
136                 // generate a reproducible UUID
137                 keyInfo.setUuid(AxKeyInfo.generateReproducibleUuid(keyInfo.getId() + keyInfo.getDescription()));
138                 return keyInfo;
139             });
140         }
141     }
142
143     /**
144      * {@inheritDoc}.
145      */
146     @Override
147     public AxArtifactKey getKey() {
148         return key;
149     }
150
151     /**
152      * {@inheritDoc}.
153      */
154     @Override
155     public List<AxKey> getKeys() {
156         final List<AxKey> keyList = key.getKeys();
157         keyList.addAll(keyInfoMap.keySet());
158
159         return keyList;
160     }
161
162     /**
163      * Sets the key of this concept.
164      *
165      * @param key the key of this concept
166      */
167     public void setKey(final AxArtifactKey key) {
168         Assertions.argumentNotNull(key, "key may not be null");
169         this.key = key;
170     }
171
172     /**
173      * Gets the key info map of this concept.
174      *
175      * @return the key info map of this concept
176      */
177     public Map<AxArtifactKey, AxKeyInfo> getKeyInfoMap() {
178         return keyInfoMap;
179     }
180
181     /**
182      * Sets the key info map of this concept.
183      *
184      * @param keyInfoMap the key info map of this concept
185      */
186     public void setKeyInfoMap(final Map<AxArtifactKey, AxKeyInfo> keyInfoMap) {
187         Assertions.argumentNotNull(keyInfoMap, "keyInfoMap may not be null");
188         this.keyInfoMap = new TreeMap<>();
189         this.keyInfoMap.putAll(keyInfoMap);
190     }
191
192     /**
193      * {@inheritDoc}.
194      */
195     @Override
196     public AxValidationResult validate(final AxValidationResult resultIn) {
197         AxValidationResult result = resultIn;
198
199         if (key.equals(AxArtifactKey.getNullKey())) {
200             result.addValidationMessage(
201                     new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
202         }
203
204         result = key.validate(result);
205
206         if (keyInfoMap.size() == 0) {
207             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
208                     "keyInfoMap may not be empty"));
209         } else {
210             final Set<UUID> uuidSet = new TreeSet<>();
211
212             for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry : keyInfoMap.entrySet()) {
213                 result = validateKeyInfoEntry(keyInfoEntry, uuidSet, result);
214             }
215         }
216
217         return result;
218     }
219
220     /**
221      * Validate an key information entry.
222      *
223      * @param keyInfoEntry the key information entry
224      * @param uuidSet the set of UUIDs encountered in validation so far, the UUID of this entry is added to the set
225      * @param result the validation result to append to
226      * @return The validation result
227      */
228     private AxValidationResult validateKeyInfoEntry(final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry,
229             final Set<UUID> uuidSet, AxValidationResult result) {
230         if (keyInfoEntry.getKey().equals(AxArtifactKey.getNullKey())) {
231             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
232                     "key on keyInfoMap entry " + keyInfoEntry.getKey() + " may not be the null key"));
233         } else if (keyInfoEntry.getValue() == null) {
234             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
235                     "value on keyInfoMap entry " + keyInfoEntry.getKey() + " may not be null"));
236         } else {
237             if (!keyInfoEntry.getKey().equals(keyInfoEntry.getValue().getKey())) {
238                 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
239                         "key on keyInfoMap entry " + keyInfoEntry.getKey() + " does not equal entry key "
240                                 + keyInfoEntry.getValue().getKey()));
241             }
242
243             result = keyInfoEntry.getValue().validate(result);
244
245             if (uuidSet.contains(keyInfoEntry.getValue().getUuid())) {
246                 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
247                         "duplicate UUID found on keyInfoMap entry " + keyInfoEntry.getKey() + ":"
248                                 + keyInfoEntry.getValue().getUuid()));
249             } else {
250                 uuidSet.add(keyInfoEntry.getValue().getUuid());
251             }
252         }
253
254         return result;
255     }
256
257     /**
258      * {@inheritDoc}.
259      */
260     @Override
261     public void clean() {
262         key.clean();
263         for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry : keyInfoMap.entrySet()) {
264             keyInfoEntry.getKey().clean();
265             keyInfoEntry.getValue().clean();
266         }
267     }
268
269     /**
270      * {@inheritDoc}.
271      */
272     @Override
273     public String toString() {
274         final var builder = new StringBuilder();
275         builder.append(this.getClass().getSimpleName());
276         builder.append(":(");
277         builder.append("key=");
278         builder.append(key);
279         builder.append(",keyInfoMap=");
280         builder.append(keyInfoMap);
281         builder.append(")");
282         return builder.toString();
283     }
284
285     /**
286      * {@inheritDoc}.
287      */
288     @Override
289     public AxConcept copyTo(final AxConcept target) {
290         Assertions.argumentNotNull(target, "target may not be null");
291
292         final Object copyObject = target;
293         Assertions.instanceOf(copyObject, AxKeyInformation.class);
294
295         final AxKeyInformation copy = ((AxKeyInformation) copyObject);
296         copy.setKey(new AxArtifactKey(key));
297         final Map<AxArtifactKey, AxKeyInfo> newKeyInfoMap = new TreeMap<>();
298         for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoMapEntry : keyInfoMap.entrySet()) {
299             newKeyInfoMap.put(new AxArtifactKey(keyInfoMapEntry.getKey()), new AxKeyInfo(keyInfoMapEntry.getValue()));
300         }
301         copy.setKeyInfoMap(newKeyInfoMap);
302
303         return copy;
304     }
305
306     /**
307      * {@inheritDoc}.
308      */
309     @Override
310     public int hashCode() {
311         final var prime = 31;
312         var result = 1;
313         result = prime * result + key.hashCode();
314         result = prime * result + keyInfoMap.hashCode();
315         return result;
316     }
317
318     /**
319      * {@inheritDoc}.
320      */
321     @Override
322     public boolean equals(final Object obj) {
323         if (obj == null) {
324             return false;
325         }
326         if (this == obj) {
327             return true;
328         }
329
330         if (getClass() != obj.getClass()) {
331             return false;
332         }
333
334         final AxKeyInformation other = (AxKeyInformation) obj;
335         if (!key.equals(other.key)) {
336             return false;
337         }
338         return keyInfoMap.equals(other.keyInfoMap);
339     }
340
341     /**
342      * {@inheritDoc}.
343      */
344     @Override
345     public int compareTo(final AxConcept otherObj) {
346         if (otherObj == null) {
347             return -1;
348         }
349         if (this == otherObj) {
350             return 0;
351         }
352         if (getClass() != otherObj.getClass()) {
353             return this.hashCode() - otherObj.hashCode();
354         }
355
356         final AxKeyInformation other = (AxKeyInformation) otherObj;
357         if (!key.equals(other.key)) {
358             return key.compareTo(other.key);
359         }
360         if (!keyInfoMap.equals(other.keyInfoMap)) {
361             return (keyInfoMap.hashCode() - other.keyInfoMap.hashCode());
362         }
363
364         return 0;
365     }
366
367     /**
368      * {@inheritDoc}.
369      */
370     @Override
371     public AxKeyInfo get(final AxArtifactKey conceptKey) {
372         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKey);
373     }
374
375     /**
376      * {@inheritDoc}.
377      */
378     @Override
379     public AxKeyInfo get(final String conceptKeyName) {
380         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKeyName);
381     }
382
383     /**
384      * {@inheritDoc}.
385      */
386     @Override
387     public AxKeyInfo get(final String conceptKeyName, final String conceptKeyVersion) {
388         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKeyName,
389                 conceptKeyVersion);
390     }
391
392     /**
393      * {@inheritDoc}.
394      */
395     @Override
396     public Set<AxKeyInfo> getAll(final String conceptKeyName) {
397         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).getAll(conceptKeyName);
398     }
399
400     /**
401      * {@inheritDoc}.
402      */
403     @Override
404     public Set<AxKeyInfo> getAll(final String conceptKeyName, final String conceptKeyVersion) {
405         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).getAll(conceptKeyName,
406                 conceptKeyVersion);
407     }
408 }