439b2960ff56ede323f6b05e247433d2bf11ca25
[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 org.onap.policy.apex.model.basicmodel.concepts.AxValidationResult.ValidationResult;
34 import org.onap.policy.common.utils.validation.Assertions;
35
36 /**
37  * The Class AxKeyInformation holds a map of the key information for the entire Apex model. All Apex models
38  * {@link AxModel} must have an {@link AxKeyInformation} field. The {@link AxKeyInformation} class implements the helper
39  * methods of the {@link AxConceptGetter} interface to allow {@link AxKeyInfo} instances to be retrieved by calling
40  * methods directly on this class without referencing the contained map.
41  *
42  * <p>Validation checks that the key is not null, that the key information map is not empty, that each key and value in
43  * the map is defined, that the key in each map entry matches the key if each entry value, and that no duplicate UUIDs
44  * exist. Each key information entry is then validated individually.
45  */
46 public class AxKeyInformation extends AxConcept implements AxConceptGetter<AxKeyInfo> {
47     private static final long serialVersionUID = -2746380769017043888L;
48
49     private AxArtifactKey key;
50     private Map<AxArtifactKey, AxKeyInfo> keyInfoMap;
51
52     /**
53      * The Default Constructor creates this concept with a null key.
54      */
55     public AxKeyInformation() {
56         this(new AxArtifactKey());
57     }
58
59     /**
60      * Copy constructor.
61      *
62      * @param copyConcept the concept to copy from
63      */
64     public AxKeyInformation(final AxKeyInformation copyConcept) {
65         super(copyConcept);
66     }
67
68     /**
69      * Constructor to create this concept with the specified key.
70      *
71      * @param key the key of the concept
72      */
73     public AxKeyInformation(final AxArtifactKey key) {
74         this(key, new TreeMap<>());
75     }
76
77     /**
78      * Constructor to create this concept and set all its fields.
79      *
80      * @param key the key of the concept
81      * @param keyInfoMap the key info map of the concept
82      */
83     public AxKeyInformation(final AxArtifactKey key, final Map<AxArtifactKey, AxKeyInfo> keyInfoMap) {
84         super();
85         Assertions.argumentNotNull(key, "key may not be null");
86         Assertions.argumentNotNull(keyInfoMap, "keyInfoMap may not be null");
87
88         this.key = key;
89         this.keyInfoMap = new TreeMap<>();
90         this.keyInfoMap.putAll(keyInfoMap);
91     }
92
93     /**
94      * This method generates default key information for all keys found in the concept passed in as a parameter that do
95      * not already have key information.
96      *
97      * @param concept the concept for which to generate key information
98      */
99     public void generateKeyInfo(final AxConcept concept) {
100         for (final AxKey axKey : concept.getKeys()) {
101             if (!(axKey instanceof AxArtifactKey)) {
102                 continue;
103             }
104
105             final AxArtifactKey artifactKey = (AxArtifactKey) axKey;
106
107             keyInfoMap.computeIfAbsent(artifactKey, unusedKey -> {
108                 final var keyInfo = new AxKeyInfo(artifactKey);
109                 // generate a reproducible UUID
110                 keyInfo.setUuid(AxKeyInfo.generateReproducibleUuid(keyInfo.getId() + keyInfo.getDescription()));
111                 return keyInfo;
112             });
113         }
114     }
115
116     /**
117      * {@inheritDoc}.
118      */
119     @Override
120     public AxArtifactKey getKey() {
121         return key;
122     }
123
124     /**
125      * {@inheritDoc}.
126      */
127     @Override
128     public List<AxKey> getKeys() {
129         final List<AxKey> keyList = key.getKeys();
130         keyList.addAll(keyInfoMap.keySet());
131
132         return keyList;
133     }
134
135     /**
136      * {@inheritDoc}.
137      */
138     @Override
139     public void buildReferences() {
140         keyInfoMap.values().stream().forEach(keyInfo -> keyInfo.buildReferences());
141     }
142
143     /**
144      * Sets the key of this concept.
145      *
146      * @param key the key of this concept
147      */
148     public void setKey(final AxArtifactKey key) {
149         Assertions.argumentNotNull(key, "key may not be null");
150         this.key = key;
151     }
152
153     /**
154      * Gets the key info map of this concept.
155      *
156      * @return the key info map of this concept
157      */
158     public Map<AxArtifactKey, AxKeyInfo> getKeyInfoMap() {
159         return keyInfoMap;
160     }
161
162     /**
163      * Sets the key info map of this concept.
164      *
165      * @param keyInfoMap the key info map of this concept
166      */
167     public void setKeyInfoMap(final Map<AxArtifactKey, AxKeyInfo> keyInfoMap) {
168         Assertions.argumentNotNull(keyInfoMap, "keyInfoMap may not be null");
169         this.keyInfoMap = new TreeMap<>();
170         this.keyInfoMap.putAll(keyInfoMap);
171     }
172
173     /**
174      * {@inheritDoc}.
175      */
176     @Override
177     public AxValidationResult validate(final AxValidationResult resultIn) {
178         AxValidationResult result = resultIn;
179
180         if (key.equals(AxArtifactKey.getNullKey())) {
181             result.addValidationMessage(
182                     new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
183         }
184
185         result = key.validate(result);
186
187         if (keyInfoMap.size() == 0) {
188             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
189                     "keyInfoMap may not be empty"));
190         } else {
191             final Set<UUID> uuidSet = new TreeSet<>();
192
193             for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry : keyInfoMap.entrySet()) {
194                 result = validateKeyInfoEntry(keyInfoEntry, uuidSet, result);
195             }
196         }
197
198         return result;
199     }
200
201     /**
202      * Validate a key information entry.
203      *
204      * @param keyInfoEntry the key information entry
205      * @param uuidSet the set of UUIDs encountered in validation so far, the UUID of this entry is added to the set
206      * @param result the validation result to append to
207      * @return The validation result
208      */
209     private AxValidationResult validateKeyInfoEntry(final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry,
210             final Set<UUID> uuidSet, AxValidationResult result) {
211         if (keyInfoEntry.getKey().equals(AxArtifactKey.getNullKey())) {
212             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
213                     "key on keyInfoMap entry " + keyInfoEntry.getKey() + " may not be the null key"));
214         } else if (keyInfoEntry.getValue() == null) {
215             result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
216                     "value on keyInfoMap entry " + keyInfoEntry.getKey() + " may not be null"));
217         } else {
218             if (!keyInfoEntry.getKey().equals(keyInfoEntry.getValue().getKey())) {
219                 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
220                         "key on keyInfoMap entry " + keyInfoEntry.getKey() + " does not equal entry key "
221                                 + keyInfoEntry.getValue().getKey()));
222             }
223
224             result = keyInfoEntry.getValue().validate(result);
225
226             if (uuidSet.contains(keyInfoEntry.getValue().getUuid())) {
227                 result.addValidationMessage(new AxValidationMessage(key, this.getClass(), ValidationResult.INVALID,
228                         "duplicate UUID found on keyInfoMap entry " + keyInfoEntry.getKey() + ":"
229                                 + keyInfoEntry.getValue().getUuid()));
230             } else {
231                 uuidSet.add(keyInfoEntry.getValue().getUuid());
232             }
233         }
234
235         return result;
236     }
237
238     /**
239      * {@inheritDoc}.
240      */
241     @Override
242     public void clean() {
243         key.clean();
244         for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoEntry : keyInfoMap.entrySet()) {
245             keyInfoEntry.getKey().clean();
246             keyInfoEntry.getValue().clean();
247         }
248     }
249
250     /**
251      * {@inheritDoc}.
252      */
253     @Override
254     public String toString() {
255         final var builder = new StringBuilder();
256         builder.append(this.getClass().getSimpleName());
257         builder.append(":(");
258         builder.append("key=");
259         builder.append(key);
260         builder.append(",keyInfoMap=");
261         builder.append(keyInfoMap);
262         builder.append(")");
263         return builder.toString();
264     }
265
266     /**
267      * {@inheritDoc}.
268      */
269     @Override
270     public AxConcept copyTo(final AxConcept target) {
271         Assertions.argumentNotNull(target, "target may not be null");
272
273         final Object copyObject = target;
274         Assertions.instanceOf(copyObject, AxKeyInformation.class);
275
276         final AxKeyInformation copy = ((AxKeyInformation) copyObject);
277         copy.setKey(new AxArtifactKey(key));
278         final Map<AxArtifactKey, AxKeyInfo> newKeyInfoMap = new TreeMap<>();
279         for (final Entry<AxArtifactKey, AxKeyInfo> keyInfoMapEntry : keyInfoMap.entrySet()) {
280             newKeyInfoMap.put(new AxArtifactKey(keyInfoMapEntry.getKey()), new AxKeyInfo(keyInfoMapEntry.getValue()));
281         }
282         copy.setKeyInfoMap(newKeyInfoMap);
283
284         return copy;
285     }
286
287     /**
288      * {@inheritDoc}.
289      */
290     @Override
291     public int hashCode() {
292         final var prime = 31;
293         var result = 1;
294         result = prime * result + key.hashCode();
295         result = prime * result + keyInfoMap.hashCode();
296         return result;
297     }
298
299     /**
300      * {@inheritDoc}.
301      */
302     @Override
303     public boolean equals(final Object obj) {
304         if (obj == null) {
305             return false;
306         }
307         if (this == obj) {
308             return true;
309         }
310
311         if (getClass() != obj.getClass()) {
312             return false;
313         }
314
315         final AxKeyInformation other = (AxKeyInformation) obj;
316         if (!key.equals(other.key)) {
317             return false;
318         }
319         return keyInfoMap.equals(other.keyInfoMap);
320     }
321
322     /**
323      * {@inheritDoc}.
324      */
325     @Override
326     public int compareTo(final AxConcept otherObj) {
327         if (otherObj == null) {
328             return -1;
329         }
330         if (this == otherObj) {
331             return 0;
332         }
333         if (getClass() != otherObj.getClass()) {
334             return this.hashCode() - otherObj.hashCode();
335         }
336
337         final AxKeyInformation other = (AxKeyInformation) otherObj;
338         if (!key.equals(other.key)) {
339             return key.compareTo(other.key);
340         }
341         if (!keyInfoMap.equals(other.keyInfoMap)) {
342             return (keyInfoMap.hashCode() - other.keyInfoMap.hashCode());
343         }
344
345         return 0;
346     }
347
348     /**
349      * {@inheritDoc}.
350      */
351     @Override
352     public AxKeyInfo get(final AxArtifactKey conceptKey) {
353         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKey);
354     }
355
356     /**
357      * {@inheritDoc}.
358      */
359     @Override
360     public AxKeyInfo get(final String conceptKeyName) {
361         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKeyName);
362     }
363
364     /**
365      * {@inheritDoc}.
366      */
367     @Override
368     public AxKeyInfo get(final String conceptKeyName, final String conceptKeyVersion) {
369         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).get(conceptKeyName,
370                 conceptKeyVersion);
371     }
372
373     /**
374      * {@inheritDoc}.
375      */
376     @Override
377     public Set<AxKeyInfo> getAll(final String conceptKeyName) {
378         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).getAll(conceptKeyName);
379     }
380
381     /**
382      * {@inheritDoc}.
383      */
384     @Override
385     public Set<AxKeyInfo> getAll(final String conceptKeyName, final String conceptKeyVersion) {
386         return new AxConceptGetterImpl<>((NavigableMap<AxArtifactKey, AxKeyInfo>) keyInfoMap).getAll(conceptKeyName,
387                 conceptKeyVersion);
388     }
389 }