2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2019 Nordix Foundation.
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.models.base;
23 import java.lang.reflect.ParameterizedType;
24 import java.util.ArrayList;
25 import java.util.LinkedHashMap;
26 import java.util.List;
28 import java.util.Map.Entry;
29 import java.util.NavigableMap;
31 import java.util.TreeMap;
33 import javax.persistence.CascadeType;
34 import javax.persistence.EmbeddedId;
35 import javax.persistence.Entity;
36 import javax.persistence.ManyToMany;
37 import javax.persistence.Table;
38 import javax.ws.rs.core.Response;
41 import lombok.EqualsAndHashCode;
42 import lombok.NonNull;
44 import org.onap.policy.common.utils.validation.Assertions;
45 import org.onap.policy.models.base.PfValidationResult.ValidationResult;
49 * This class is a concept container and holds a map of concepts. The {@link PfConceptContainer} class implements the
50 * helper methods of the {@link PfConceptGetter} interface to allow {@link PfConceptContainer} instances to be retrieved
51 * by calling methods directly on this class without referencing the contained map.
53 * <p>Validation checks that a container key is not null. An error is issued if no concepts are defined in a container.
54 * Each concept entry is checked to ensure that its key and value are not null and that the key matches the key in the
55 * map value. Each concept entry is then validated individually.
57 * @param C the concept being contained
61 @Table(name = "PfConceptContainer")
63 @EqualsAndHashCode(callSuper = false)
65 public class PfConceptContainer<C extends PfConcept, A extends PfNameVersion> extends PfConcept
66 implements PfConceptGetter<C>, PfAuthorative<List<Map<String, A>>> {
67 private static final long serialVersionUID = -324211738823208318L;
70 private PfConceptKey key;
72 @ManyToMany(cascade = CascadeType.ALL)
73 private Map<PfConceptKey, C> conceptMap;
76 * The Default Constructor creates a {@link PfConceptContainer} object with a null artifact key and creates an empty
79 public PfConceptContainer() {
80 this(new PfConceptKey());
84 * The Key Constructor creates a {@link PfConceptContainer} object with the given artifact key and creates an empty
87 * @param key the concept key
89 public PfConceptContainer(@NonNull final PfConceptKey key) {
90 this(key, new TreeMap<PfConceptKey, C>());
94 * This Constructor creates an concept container with all of its fields defined.
96 * @param key the concept container key
97 * @param conceptMap the concepts to be stored in the concept container
99 public PfConceptContainer(@NonNull final PfConceptKey key, @NonNull final Map<PfConceptKey, C> conceptMap) {
103 this.conceptMap = new TreeMap<>(conceptMap);
109 * @param copyConcept the concept to copy from
111 public PfConceptContainer(@NonNull final PfConceptContainer<C, A> copyConcept) {
116 public List<PfKey> getKeys() {
117 final List<PfKey> keyList = key.getKeys();
119 for (final C concept : conceptMap.values()) {
120 keyList.addAll(concept.getKeys());
127 public List<Map<String, A>> toAuthorative() {
128 Map<String, A> toscaPolicyMap = new LinkedHashMap<>();
130 for (Entry<PfConceptKey, C> conceptEntry : getConceptMap().entrySet()) {
131 @SuppressWarnings("unchecked")
132 PfAuthorative<A> authoritiveImpl = (PfAuthorative<A>) conceptEntry.getValue();
133 toscaPolicyMap.put(conceptEntry.getKey().getName(), authoritiveImpl.toAuthorative());
136 List<Map<String, A>> toscaPolicyMapList = new ArrayList<>();
137 toscaPolicyMapList.add(toscaPolicyMap);
139 return toscaPolicyMapList;
143 public void fromAuthorative(List<Map<String, A>> authorativeList) {
144 // Clear any existing map entries
147 // Concepts are in lists of maps
148 for (Map<String, A> incomingConceptMap : authorativeList) {
149 // Add the map entries one by one
150 for (Entry<String, A> incomingConceptEntry : incomingConceptMap.entrySet()) {
151 C jpaConcept = getConceptNewInstance();
153 // This cast allows us to call the fromAuthorative method
154 @SuppressWarnings("unchecked")
155 PfAuthorative<A> authoritiveImpl = (PfAuthorative<A>) jpaConcept;
157 if (incomingConceptEntry.getValue().getName() == null) {
158 incomingConceptEntry.getValue().setName(incomingConceptEntry.getKey());
161 // Set the key name and the rest of the values on the concept
162 authoritiveImpl.fromAuthorative(incomingConceptEntry.getValue());
164 // This cast gets the key of the concept
165 PfConceptKey conceptKey = (PfConceptKey) jpaConcept.getKey();
167 // Set the concept key of the concept
168 conceptKey.setName(incomingConceptEntry.getValue().getName());
170 if (incomingConceptEntry.getValue().getVersion() != null) {
171 conceptKey.setVersion(incomingConceptEntry.getValue().getVersion());
174 conceptKey.setVersion(PfKey.NULL_KEY_VERSION);
177 // After all that, save the map entry
178 conceptMap.put(conceptKey, jpaConcept);
182 if (conceptMap.isEmpty()) {
183 throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
184 "An incoming list of concepts must have at least one entry");
189 public void clean() {
191 for (final Entry<PfConceptKey, C> conceptEntry : conceptMap.entrySet()) {
192 conceptEntry.getKey().clean();
193 conceptEntry.getValue().clean();
198 public PfValidationResult validate(@NonNull final PfValidationResult resultIn) {
199 PfValidationResult result = resultIn;
201 if (key.equals(PfConceptKey.getNullKey())) {
202 result.addValidationMessage(
203 new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
206 result = key.validate(result);
208 if (conceptMap.isEmpty()) {
209 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
210 "conceptMap may not be empty"));
212 result = validateConceptMap(result);
219 * Validate the concept map of the container.
221 * @param resultIn the incoming validation results so far
222 * @return the validation results with the results of this validation added
224 private PfValidationResult validateConceptMap(final PfValidationResult resultIn) {
225 PfValidationResult result = resultIn;
227 for (final Entry<PfConceptKey, C> conceptEntry : conceptMap.entrySet()) {
228 if (conceptEntry.getKey().equals(PfConceptKey.getNullKey())) {
229 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
230 "key on concept entry " + conceptEntry.getKey() + " may not be the null key"));
232 if (conceptEntry.getValue() == null) {
233 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
234 "value on concept entry " + conceptEntry.getKey() + " may not be null"));
236 if (!conceptEntry.getKey().equals(conceptEntry.getValue().getKey())) {
237 result.addValidationMessage(new PfValidationMessage(key, this.getClass(),
238 ValidationResult.INVALID, "key on concept entry key " + conceptEntry.getKey()
239 + " does not equal concept value key " + conceptEntry.getValue().getKey()));
240 result = conceptEntry.getValue().validate(result);
242 result = conceptEntry.getValue().validate(result);
249 public int compareTo(final PfConcept otherConcept) {
250 if (otherConcept == null) {
253 if (this == otherConcept) {
256 if (getClass() != otherConcept.getClass()) {
257 return this.hashCode() - otherConcept.hashCode();
260 @SuppressWarnings("unchecked")
261 final PfConceptContainer<C, A> other = (PfConceptContainer<C, A>) otherConcept;
262 int retVal = key.compareTo(other.key);
267 if (!conceptMap.equals(other.conceptMap)) {
268 return (conceptMap.hashCode() - other.conceptMap.hashCode());
275 public PfConcept copyTo(@NonNull final PfConcept target) {
276 Assertions.instanceOf(target, PfConceptContainer.class);
278 @SuppressWarnings("unchecked")
279 final PfConceptContainer<C, A> copy = (PfConceptContainer<C, A>) target;
280 copy.setKey(new PfConceptKey(key));
281 final Map<PfConceptKey, C> newConceptMap = new TreeMap<>();
282 for (final Entry<PfConceptKey, C> conceptMapEntry : conceptMap.entrySet()) {
283 C newC = getConceptNewInstance();
284 conceptMapEntry.getValue().copyTo(newC);
285 newConceptMap.put(new PfConceptKey(conceptMapEntry.getKey()), newC);
287 copy.setConceptMap(newConceptMap);
293 public C get(final PfConceptKey conceptKey) {
294 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKey);
298 public C get(final String conceptKeyName) {
299 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKeyName);
303 public C get(final String conceptKeyName, final String conceptKeyVersion) {
304 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKeyName,
309 public Set<C> getAll(final String conceptKeyName) {
310 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).getAll(conceptKeyName);
314 public Set<C> getAll(final String conceptKeyName, final String conceptKeyVersion) {
315 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).getAll(conceptKeyName,
320 * Get a new empty instance of a concept for this concept map.
322 * @return the new instance
324 @SuppressWarnings("unchecked")
325 private C getConceptNewInstance() {
327 String conceptClassName =
328 ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0].getTypeName();
329 return (C) Class.forName(conceptClassName).newInstance();
330 } catch (Exception ex) {
331 throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR,
332 "failed to instantiate instance of container concept class", ex);