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.util.List;
25 import java.util.Map.Entry;
26 import java.util.NavigableMap;
28 import java.util.TreeMap;
30 import javax.persistence.CascadeType;
31 import javax.persistence.EmbeddedId;
32 import javax.persistence.Entity;
33 import javax.persistence.ManyToMany;
34 import javax.persistence.Table;
35 import javax.ws.rs.core.Response;
38 import lombok.EqualsAndHashCode;
39 import lombok.NonNull;
41 import org.onap.policy.common.utils.validation.Assertions;
42 import org.onap.policy.models.base.PfValidationResult.ValidationResult;
45 * This class is a concept container and holds a map of concepts. The {@link PfConceptContainer}
46 * class implements the helper methods of the {@link PfConceptGetter} interface to allow
47 * {@link PfConceptContainer} instances to be retrieved by calling methods directly on this class
48 * without referencing the contained map.
50 * <p>Validation checks that the container key is not null. An error is issued if no concepts are
51 * defined in the container. Each concept entry is checked to ensure that its key and value are not
52 * null and that the key matches the key in the map value. Each concept entry is then validated
55 * @param C the concept being contained
58 @Table(name = "PfConceptContainer")
60 @EqualsAndHashCode(callSuper = false)
62 public class PfConceptContainer<C extends PfConcept> extends PfConcept implements PfConceptGetter<C> {
63 private static final long serialVersionUID = -324211738823208318L;
66 private PfConceptKey key;
68 @ManyToMany(cascade = CascadeType.ALL)
69 private Map<PfConceptKey, C> conceptMap;
72 * The Default Constructor creates a {@link PfConceptContainer} object with a null artifact key
73 * and creates an empty concept map.
75 public PfConceptContainer() {
76 this(new PfConceptKey());
80 * The Key Constructor creates a {@link PfConceptContainer} object with the given artifact key
81 * and creates an empty concept map.
83 * @param key the concept key
85 public PfConceptContainer(@NonNull final PfConceptKey key) {
86 this(key, new TreeMap<PfConceptKey, C>());
90 * This Constructor creates an concept container with all of its fields defined.
92 * @param key the concept container key
93 * @param conceptMap the concepts to be stored in the concept container
95 public PfConceptContainer(@NonNull final PfConceptKey key, @NonNull final Map<PfConceptKey, C> conceptMap) {
99 this.conceptMap = new TreeMap<>(conceptMap);
105 * @param copyConcept the concept to copy from
107 public PfConceptContainer(@NonNull final PfConceptContainer<C> copyConcept) {
112 public List<PfKey> getKeys() {
113 final List<PfKey> keyList = key.getKeys();
115 for (final C concept : conceptMap.values()) {
116 keyList.addAll(concept.getKeys());
123 public void clean() {
125 for (final Entry<PfConceptKey, C> conceptEntry : conceptMap.entrySet()) {
126 conceptEntry.getKey().clean();
127 conceptEntry.getValue().clean();
132 public PfValidationResult validate(@NonNull final PfValidationResult resultIn) {
133 PfValidationResult result = resultIn;
135 if (key.equals(PfConceptKey.getNullKey())) {
136 result.addValidationMessage(
137 new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
140 result = key.validate(result);
142 if (conceptMap.isEmpty()) {
143 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
144 "conceptMap may not be empty"));
146 result = validateConceptMap(result);
153 * Validate the concept map of the container.
155 * @param resultIn the incoming validation results so far
156 * @return the validation results with the results of this validation added
158 private PfValidationResult validateConceptMap(final PfValidationResult resultIn) {
159 PfValidationResult result = resultIn;
161 for (final Entry<PfConceptKey, C> conceptEntry : conceptMap.entrySet()) {
162 if (conceptEntry.getKey().equals(PfConceptKey.getNullKey())) {
163 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
164 "key on concept entry " + conceptEntry.getKey() + " may not be the null key"));
165 } else if (conceptEntry.getValue() == null) {
166 result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
167 "value on concept entry " + conceptEntry.getKey() + " may not be null"));
168 } else if (!conceptEntry.getKey().equals(conceptEntry.getValue().getKey())) {
169 result.addValidationMessage(new PfValidationMessage(key, this.getClass(),
170 ValidationResult.INVALID, "key on concept entry key " + conceptEntry.getKey()
171 + " does not equal concept value key " + conceptEntry.getValue().getKey()));
172 result = conceptEntry.getValue().validate(result);
174 result = conceptEntry.getValue().validate(result);
181 public int compareTo(final PfConcept otherConcept) {
182 if (otherConcept == null) {
185 if (this == otherConcept) {
188 if (getClass() != otherConcept.getClass()) {
189 return this.hashCode() - otherConcept.hashCode();
192 @SuppressWarnings("unchecked")
193 final PfConceptContainer<C> other = (PfConceptContainer<C>) otherConcept;
194 int retVal = key.compareTo(other.key);
199 if (!conceptMap.equals(other.conceptMap)) {
200 return (conceptMap.hashCode() - other.conceptMap.hashCode());
207 public PfConcept copyTo(@NonNull final PfConcept target) {
208 Assertions.instanceOf(target, PfConceptContainer.class);
210 @SuppressWarnings("unchecked")
211 final PfConceptContainer<C> copy = (PfConceptContainer<C>) target;
212 copy.setKey(new PfConceptKey(key));
213 final Map<PfConceptKey, C> newConceptMap = new TreeMap<>();
214 for (final Entry<PfConceptKey, C> conceptMapEntry : conceptMap.entrySet()) {
215 newConceptMap.put(new PfConceptKey(conceptMapEntry.getKey()),
216 new ConceptCloner().cloneConcept(conceptMapEntry.getValue()));
218 copy.setConceptMap(newConceptMap);
224 public C get(final PfConceptKey conceptKey) {
225 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKey);
229 public C get(final String conceptKeyName) {
230 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKeyName);
234 public C get(final String conceptKeyName, final String conceptKeyVersion) {
235 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKeyName,
240 public Set<C> getAll(final String conceptKeyName) {
241 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).getAll(conceptKeyName);
245 public Set<C> getAll(final String conceptKeyName, final String conceptKeyVersion) {
246 return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).getAll(conceptKeyName,
251 * Private inner class that returns a clone of a concept by calling the copy constructor on the
254 private class ConceptCloner {
255 @SuppressWarnings("unchecked")
256 public C cloneConcept(final C originalConcept) {
258 C clonedConcept = (C) originalConcept.getClass().newInstance();
259 originalConcept.copyTo(clonedConcept);
260 return clonedConcept;
261 } catch (Exception ex) {
262 throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR,
263 "Failed to create a clone of class \"" + originalConcept.getClass().getCanonicalName() + "\"",