Remove deprecated methods from models
[policy/models.git] / models-base / src / main / java / org / onap / policy / models / base / PfConceptContainer.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation.
4  *  Modifications Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
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.models.base;
23
24 import java.lang.reflect.ParameterizedType;
25 import java.util.ArrayList;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30 import java.util.NavigableMap;
31 import java.util.Set;
32 import java.util.TreeMap;
33 import javax.persistence.CascadeType;
34 import javax.persistence.EmbeddedId;
35 import javax.persistence.Entity;
36 import javax.persistence.FetchType;
37 import javax.persistence.ManyToMany;
38 import javax.persistence.Table;
39 import javax.ws.rs.core.Response;
40 import lombok.Data;
41 import lombok.EqualsAndHashCode;
42 import lombok.NonNull;
43 import org.onap.policy.models.base.PfValidationResult.ValidationResult;
44
45 // @formatter:off
46 /**
47  * This class is a concept container and holds a map of concepts. The {@link PfConceptContainer} class implements the
48  * helper methods of the {@link PfConceptGetter} interface to allow {@link PfConceptContainer} instances to be retrieved
49  * by calling methods directly on this class without referencing the contained map.
50  *
51  * <p>Validation checks that a container key is not null. An error is issued if no concepts are defined in a container.
52  * Each concept entry is checked to ensure that its key and value are not null and that the key matches the key in the
53  * map value. Each concept entry is then validated individually.
54  *
55  * @param C the concept being contained
56  */
57 //@formatter:on
58 @Entity
59 @Table(name = "PfConceptContainer")
60 @Data
61 @EqualsAndHashCode(callSuper = false)
62
63 public class PfConceptContainer<C extends PfConcept, A extends PfNameVersion> extends PfConcept
64         implements PfConceptGetter<C>, PfAuthorative<List<Map<String, A>>> {
65     private static final long serialVersionUID = -324211738823208318L;
66
67     @EmbeddedId
68     private PfConceptKey key;
69
70     @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
71     private Map<PfConceptKey, C> conceptMap;
72
73     /**
74      * The Default Constructor creates a {@link PfConceptContainer} object with a null artifact key and creates an empty
75      * concept map.
76      */
77     public PfConceptContainer() {
78         this(new PfConceptKey());
79     }
80
81     /**
82      * The Key Constructor creates a {@link PfConceptContainer} object with the given artifact key and creates an empty
83      * concept map.
84      *
85      * @param key the concept key
86      */
87     public PfConceptContainer(@NonNull final PfConceptKey key) {
88         this(key, new TreeMap<PfConceptKey, C>());
89     }
90
91     /**
92      * This Constructor creates an concept container with all of its fields defined.
93      *
94      * @param key the concept container key
95      * @param conceptMap the concepts to be stored in the concept container
96      */
97     public PfConceptContainer(@NonNull final PfConceptKey key, @NonNull final Map<PfConceptKey, C> conceptMap) {
98         super();
99
100         this.key = key;
101         this.conceptMap = new TreeMap<>(conceptMap);
102     }
103
104     /**
105      * Copy constructor.
106      *
107      * @param copyConcept the concept to copy from
108      */
109     public PfConceptContainer(@NonNull final PfConceptContainer<C, A> copyConcept) {
110         super(copyConcept);
111         this.key = new PfConceptKey(copyConcept.key);
112
113         this.conceptMap = new TreeMap<>();
114         for (final Entry<PfConceptKey, C> conceptMapEntry : copyConcept.conceptMap.entrySet()) {
115             PfConceptKey newK = new PfConceptKey(conceptMapEntry.getKey());
116             C newC = PfUtils.makeCopy(conceptMapEntry.getValue());
117             this.conceptMap.put(newK, newC);
118         }
119     }
120
121     @Override
122     public List<PfKey> getKeys() {
123         final List<PfKey> keyList = key.getKeys();
124
125         for (final C concept : conceptMap.values()) {
126             keyList.addAll(concept.getKeys());
127         }
128
129         return keyList;
130     }
131
132     @Override
133     public List<Map<String, A>> toAuthorative() {
134         // The returned list is a list of map singletons with one map for each map
135         // entry in the concept container
136         List<Map<String, A>> toscaPolicyMapList = new ArrayList<>();
137
138         for (Entry<PfConceptKey, C> conceptEntry : getConceptMap().entrySet()) {
139             // Create a map to hold this entry
140             Map<String, A> toscaPolicyMap = new LinkedHashMap<>(1);
141
142             // Add the concept container entry to the singleton map
143             @SuppressWarnings("unchecked")
144             PfAuthorative<A> authoritiveImpl = (PfAuthorative<A>) conceptEntry.getValue();
145             toscaPolicyMap.put(conceptEntry.getKey().getName(), authoritiveImpl.toAuthorative());
146
147             // Add the map to the returned list
148             toscaPolicyMapList.add(toscaPolicyMap);
149         }
150
151         return toscaPolicyMapList;
152     }
153
154     @Override
155     public void fromAuthorative(List<Map<String, A>> authorativeList) {
156         // Clear any existing map entries
157         conceptMap.clear();
158
159         // Concepts are in lists of maps
160         for (Map<String, A> incomingConceptMap : authorativeList) {
161             // Add the map entries one by one
162             for (Entry<String, A> incomingConceptEntry : incomingConceptMap.entrySet()) {
163                 C jpaConcept = getConceptNewInstance();
164
165                 // This cast allows us to call the fromAuthorative method
166                 @SuppressWarnings("unchecked")
167                 PfAuthorative<A> authoritiveImpl = (PfAuthorative<A>) jpaConcept;
168
169                 if (incomingConceptEntry.getValue().getName() == null) {
170                     incomingConceptEntry.getValue().setName(incomingConceptEntry.getKey());
171                 }
172
173                 // Set the key name and the rest of the values on the concept
174                 authoritiveImpl.fromAuthorative(incomingConceptEntry.getValue());
175
176                 // This cast gets the key of the concept
177                 PfConceptKey conceptKey = (PfConceptKey) jpaConcept.getKey();
178
179                 // Set the concept key of the concept
180                 conceptKey.setName(incomingConceptEntry.getValue().getName());
181
182                 if (incomingConceptEntry.getValue().getVersion() != null) {
183                     conceptKey.setVersion(incomingConceptEntry.getValue().getVersion());
184                 }
185                 else {
186                     conceptKey.setVersion(PfKey.NULL_KEY_VERSION);
187                 }
188
189                 // After all that, save the map entry
190                 conceptMap.put(conceptKey, jpaConcept);
191             }
192         }
193
194         if (conceptMap.isEmpty()) {
195             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
196                     "An incoming list of concepts must have at least one entry");
197         }
198     }
199
200     @Override
201     public void clean() {
202         key.clean();
203         for (final Entry<PfConceptKey, C> conceptEntry : conceptMap.entrySet()) {
204             conceptEntry.getKey().clean();
205             conceptEntry.getValue().clean();
206         }
207     }
208
209     @Override
210     public PfValidationResult validate(@NonNull final PfValidationResult resultIn) {
211         PfValidationResult result = resultIn;
212
213         if (key.equals(PfConceptKey.getNullKey())) {
214             result.addValidationMessage(
215                     new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
216         }
217
218         result = key.validate(result);
219
220         if (conceptMap.isEmpty()) {
221             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
222                     "conceptMap may not be empty"));
223         } else {
224             result = validateConceptMap(result);
225         }
226
227         return result;
228     }
229
230     /**
231      * Validate the concept map of the container.
232      *
233      * @param resultIn the incoming validation results so far
234      * @return the validation results with the results of this validation added
235      */
236     private PfValidationResult validateConceptMap(final PfValidationResult resultIn) {
237         PfValidationResult result = resultIn;
238
239         for (final Entry<PfConceptKey, C> conceptEntry : conceptMap.entrySet()) {
240             if (conceptEntry.getKey().equals(PfConceptKey.getNullKey())) {
241                 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
242                         "key on concept entry " + conceptEntry.getKey() + " may not be the null key"));
243             } else
244                 if (conceptEntry.getValue() == null) {
245                     result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
246                             "value on concept entry " + conceptEntry.getKey() + " may not be null"));
247                 } else
248                     if (!conceptEntry.getKey().equals(conceptEntry.getValue().getKey())) {
249                         result.addValidationMessage(new PfValidationMessage(key, this.getClass(),
250                                 ValidationResult.INVALID, "key on concept entry key " + conceptEntry.getKey()
251                                         + " does not equal concept value key " + conceptEntry.getValue().getKey()));
252                         result = conceptEntry.getValue().validate(result);
253                     } else {
254                         result = conceptEntry.getValue().validate(result);
255                     }
256         }
257         return result;
258     }
259
260     @Override
261     public int compareTo(final PfConcept otherConcept) {
262         if (otherConcept == null) {
263             return -1;
264         }
265         if (this == otherConcept) {
266             return 0;
267         }
268         if (getClass() != otherConcept.getClass()) {
269             return getClass().getName().compareTo(otherConcept.getClass().getName());
270         }
271
272         @SuppressWarnings("unchecked")
273         final PfConceptContainer<C, A> other = (PfConceptContainer<C, A>) otherConcept;
274         int retVal = key.compareTo(other.key);
275         if (retVal != 0) {
276             return retVal;
277         }
278
279         if (!conceptMap.equals(other.conceptMap)) {
280             return (conceptMap.hashCode() - other.conceptMap.hashCode());
281         }
282
283         return 0;
284     }
285
286     @Override
287     public C get(final PfConceptKey conceptKey) {
288         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKey);
289     }
290
291     @Override
292     public C get(final String conceptKeyName) {
293         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKeyName);
294     }
295
296     @Override
297     public C get(final String conceptKeyName, final String conceptKeyVersion) {
298         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKeyName,
299                 conceptKeyVersion);
300     }
301
302     @Override
303     public Set<C> getAll(final String conceptKeyName) {
304         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).getAll(conceptKeyName);
305     }
306
307     @Override
308     public Set<C> getAll(final String conceptKeyName, final String conceptKeyVersion) {
309         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).getAll(conceptKeyName,
310                 conceptKeyVersion);
311     }
312
313     /**
314      * Get a new empty instance of a concept for this concept map.
315      *
316      * @return the new instance
317      */
318     @SuppressWarnings("unchecked")
319     private C getConceptNewInstance() {
320         try {
321             String conceptClassName =
322                     ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
323             return (C) Class.forName(conceptClassName).getDeclaredConstructor().newInstance();
324         } catch (Exception ex) {
325             throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR,
326                     "failed to instantiate instance of container concept class", ex);
327         }
328     }
329 }