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