Add DAO Enabled Tosca Model
[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  * ================================================================================
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.onap.policy.models.base;
22
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Map.Entry;
26 import java.util.NavigableMap;
27 import java.util.Set;
28 import java.util.TreeMap;
29
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;
36
37 import lombok.Data;
38 import lombok.EqualsAndHashCode;
39 import lombok.NonNull;
40
41 import org.onap.policy.common.utils.validation.Assertions;
42 import org.onap.policy.models.base.PfValidationResult.ValidationResult;
43
44 /**
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.
49  *
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
53  * individually.
54  *
55  * @param C the concept being contained
56  */
57 @Entity
58 @Table(name = "PfConceptContainer")
59 @Data
60 @EqualsAndHashCode(callSuper = false)
61
62 public class PfConceptContainer<C extends PfConcept> extends PfConcept implements PfConceptGetter<C> {
63     private static final long serialVersionUID = -324211738823208318L;
64
65     @EmbeddedId
66     private PfConceptKey key;
67
68     @ManyToMany(cascade = CascadeType.ALL)
69     private Map<PfConceptKey, C> conceptMap;
70
71     /**
72      * The Default Constructor creates a {@link PfConceptContainer} object with a null artifact key
73      * and creates an empty concept map.
74      */
75     public PfConceptContainer() {
76         this(new PfConceptKey());
77     }
78
79     /**
80      * The Key Constructor creates a {@link PfConceptContainer} object with the given artifact key
81      * and creates an empty concept map.
82      *
83      * @param key the concept key
84      */
85     public PfConceptContainer(@NonNull final PfConceptKey key) {
86         this(key, new TreeMap<PfConceptKey, C>());
87     }
88
89     /**
90      * This Constructor creates an concept container with all of its fields defined.
91      *
92      * @param key the concept container key
93      * @param conceptMap the concepts to be stored in the concept container
94      */
95     public PfConceptContainer(@NonNull final PfConceptKey key, @NonNull final Map<PfConceptKey, C> conceptMap) {
96         super();
97
98         this.key = key;
99         this.conceptMap = new TreeMap<>(conceptMap);
100     }
101
102     /**
103      * Copy constructor.
104      *
105      * @param copyConcept the concept to copy from
106      */
107     public PfConceptContainer(@NonNull final PfConceptContainer<C> copyConcept) {
108         super(copyConcept);
109     }
110
111     @Override
112     public List<PfKey> getKeys() {
113         final List<PfKey> keyList = key.getKeys();
114
115         for (final C concept : conceptMap.values()) {
116             keyList.addAll(concept.getKeys());
117         }
118
119         return keyList;
120     }
121
122     @Override
123     public void clean() {
124         key.clean();
125         for (final Entry<PfConceptKey, C> conceptEntry : conceptMap.entrySet()) {
126             conceptEntry.getKey().clean();
127             conceptEntry.getValue().clean();
128         }
129     }
130
131     @Override
132     public PfValidationResult validate(@NonNull final PfValidationResult resultIn) {
133         PfValidationResult result = resultIn;
134
135         if (key.equals(PfConceptKey.getNullKey())) {
136             result.addValidationMessage(
137                     new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID, "key is a null key"));
138         }
139
140         result = key.validate(result);
141
142         if (conceptMap.isEmpty()) {
143             result.addValidationMessage(new PfValidationMessage(key, this.getClass(), ValidationResult.INVALID,
144                     "conceptMap may not be empty"));
145         } else {
146             result = validateConceptMap(result);
147         }
148
149         return result;
150     }
151
152     /**
153      * Validate the concept map of the container.
154      *
155      * @param resultIn the incoming validation results so far
156      * @return the validation results with the results of this validation added
157      */
158     private PfValidationResult validateConceptMap(final PfValidationResult resultIn) {
159         PfValidationResult result = resultIn;
160
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);
173             } else {
174                 result = conceptEntry.getValue().validate(result);
175             }
176         }
177         return result;
178     }
179
180     @Override
181     public int compareTo(final PfConcept otherConcept) {
182         if (otherConcept == null) {
183             return -1;
184         }
185         if (this == otherConcept) {
186             return 0;
187         }
188         if (getClass() != otherConcept.getClass()) {
189             return this.hashCode() - otherConcept.hashCode();
190         }
191
192         @SuppressWarnings("unchecked")
193         final PfConceptContainer<C> other = (PfConceptContainer<C>) otherConcept;
194         int retVal = key.compareTo(other.key);
195         if (retVal != 0) {
196             return retVal;
197         }
198
199         if (!conceptMap.equals(other.conceptMap)) {
200             return (conceptMap.hashCode() - other.conceptMap.hashCode());
201         }
202
203         return 0;
204     }
205
206     @Override
207     public PfConcept copyTo(@NonNull final PfConcept target) {
208         Assertions.instanceOf(target, PfConceptContainer.class);
209
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()));
217         }
218         copy.setConceptMap(newConceptMap);
219
220         return copy;
221     }
222
223     @Override
224     public C get(final PfConceptKey conceptKey) {
225         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKey);
226     }
227
228     @Override
229     public C get(final String conceptKeyName) {
230         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKeyName);
231     }
232
233     @Override
234     public C get(final String conceptKeyName, final String conceptKeyVersion) {
235         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).get(conceptKeyName,
236                 conceptKeyVersion);
237     }
238
239     @Override
240     public Set<C> getAll(final String conceptKeyName) {
241         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).getAll(conceptKeyName);
242     }
243
244     @Override
245     public Set<C> getAll(final String conceptKeyName, final String conceptKeyVersion) {
246         return new PfConceptGetterImpl<>((NavigableMap<PfConceptKey, C>) conceptMap).getAll(conceptKeyName,
247                 conceptKeyVersion);
248     }
249
250     /**
251      * Private inner class that returns a clone of a concept by calling the copy constructor on the
252      * original class.
253      */
254     private class ConceptCloner {
255         @SuppressWarnings("unchecked")
256         public C cloneConcept(final C originalConcept) {
257             try {
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() + "\"",
264                         ex);
265             }
266         }
267     }
268 }