JPA concepts for TOSCA
[policy/models.git] / models-tosca / src / main / java / org / onap / policy / models / tosca / simple / concepts / JpaToscaPolicy.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP Policy Model
4  * ================================================================================
5  * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019-2020 Nordix Foundation.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  * SPDX-License-Identifier: Apache-2.0
21  * ============LICENSE_END=========================================================
22  */
23
24 package org.onap.policy.models.tosca.simple.concepts;
25
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30 import javax.persistence.AttributeOverride;
31 import javax.persistence.AttributeOverrides;
32 import javax.persistence.Column;
33 import javax.persistence.ElementCollection;
34 import javax.persistence.Entity;
35 import javax.persistence.Inheritance;
36 import javax.persistence.InheritanceType;
37 import javax.persistence.Lob;
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.common.utils.coder.CoderException;
44 import org.onap.policy.common.utils.coder.StandardCoder;
45 import org.onap.policy.common.utils.validation.ParameterValidationUtils;
46 import org.onap.policy.models.base.PfAuthorative;
47 import org.onap.policy.models.base.PfConcept;
48 import org.onap.policy.models.base.PfConceptKey;
49 import org.onap.policy.models.base.PfKey;
50 import org.onap.policy.models.base.PfModelRuntimeException;
51 import org.onap.policy.models.base.PfUtils;
52 import org.onap.policy.models.base.PfValidationMessage;
53 import org.onap.policy.models.base.PfValidationResult;
54 import org.onap.policy.models.base.PfValidationResult.ValidationResult;
55 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
56
57 /**
58  * Class to represent the policy in TOSCA definition.
59  *
60  * @author Chenfei Gao (cgao@research.att.com)
61  * @author Liam Fallon (liam.fallon@est.tech)
62  */
63 @Entity
64 @Table(name = "ToscaPolicy")
65 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
66 @Data
67 @EqualsAndHashCode(callSuper = true)
68 public class JpaToscaPolicy extends JpaToscaEntityType<ToscaPolicy> implements PfAuthorative<ToscaPolicy> {
69     private static final long serialVersionUID = 3265174757061982805L;
70
71     // Tags for metadata
72     private static final String METADATA_POLICY_ID_TAG = "policy-id";
73     private static final String METADATA_POLICY_VERSION_TAG = "policy-version";
74
75     private static final StandardCoder STANDARD_CODER = new StandardCoder();
76
77     // @formatter:off
78     @Column
79     @AttributeOverrides({
80         @AttributeOverride(name = "name",
81                            column = @Column(name = "type_name")),
82         @AttributeOverride(name = "version",
83                            column = @Column(name = "type_version"))
84         })
85     private PfConceptKey type;
86
87     @ElementCollection
88     @Lob
89     private Map<String, String> properties;
90
91     @ElementCollection
92     private List<PfConceptKey> targets;
93     // @formatter:on
94
95     /**
96      * The Default Constructor creates a {@link JpaToscaPolicy} object with a null key.
97      */
98     public JpaToscaPolicy() {
99         this(new PfConceptKey());
100     }
101
102     /**
103      * The Key Constructor creates a {@link JpaToscaPolicy} object with the given concept key.
104      *
105      * @param key the key
106      */
107     public JpaToscaPolicy(@NonNull final PfConceptKey key) {
108         this(key, new PfConceptKey());
109     }
110
111     /**
112      * The full Constructor creates a {@link JpaToscaPolicy} object with all mandatory fields.
113      *
114      * @param key the key
115      * @param type the type of the policy
116      */
117     public JpaToscaPolicy(@NonNull final PfConceptKey key, @NonNull final PfConceptKey type) {
118         super(key);
119         this.type = type;
120     }
121
122     /**
123      * Copy constructor.
124      *
125      * @param copyConcept the concept to copy from
126      */
127     public JpaToscaPolicy(@NonNull final JpaToscaPolicy copyConcept) {
128         super(copyConcept);
129         this.type = new PfConceptKey(copyConcept.type);
130         this.properties = (copyConcept.properties != null ? new LinkedHashMap<>(copyConcept.properties) : null);
131         this.targets = PfUtils.mapList(copyConcept.targets, PfConceptKey::new);
132     }
133
134     /**
135      * Authorative constructor.
136      *
137      * @param authorativeConcept the authorative concept to copy from
138      */
139     public JpaToscaPolicy(final ToscaPolicy authorativeConcept) {
140         super(new PfConceptKey());
141         type = new PfConceptKey();
142         this.fromAuthorative(authorativeConcept);
143     }
144
145     @Override
146     public ToscaPolicy toAuthorative() {
147         ToscaPolicy toscaPolicy = new ToscaPolicy();
148         super.setToscaEntity(toscaPolicy);
149         super.toAuthorative();
150
151         toscaPolicy.setType(type.getName());
152
153         if (!PfKey.NULL_KEY_VERSION.equals(type.getVersion())) {
154             toscaPolicy.setTypeVersion(type.getVersion());
155         } else {
156             toscaPolicy.setTypeVersion(null);
157         }
158
159         toscaPolicy.setProperties(PfUtils.mapMap(properties, property -> {
160             try {
161                 return STANDARD_CODER.decode(property, Object.class);
162             } catch (CoderException ce) {
163                 String errorMessage = "error decoding property JSON value read from database: " + property;
164                 throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, errorMessage, ce);
165             }
166         }));
167
168         return toscaPolicy;
169     }
170
171     @Override
172     public void fromAuthorative(@NonNull final ToscaPolicy toscaPolicy) {
173         super.fromAuthorative(toscaPolicy);
174
175         if (toscaPolicy.getType() != null) {
176             type.setName(toscaPolicy.getType());
177         } else {
178             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
179                     "PolicyType type not specified, the type of the PolicyType for this policy must be specified in "
180                             + "the type field");
181         }
182
183         if (toscaPolicy.getTypeVersion() != null) {
184             type.setVersion(toscaPolicy.getTypeVersion());
185         } else {
186             throw new PfModelRuntimeException(Response.Status.BAD_REQUEST,
187                     "PolicyType version not specified, the version of the PolicyType for this policy must be specified"
188                             + " in the type_version field");
189         }
190
191         properties = PfUtils.mapMap(toscaPolicy.getProperties(), property -> {
192             try {
193                 return STANDARD_CODER.encode(property);
194             } catch (CoderException ce) {
195                 String errorMessage = "error encoding property JSON value for database: " + property;
196                 throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, errorMessage, ce);
197             }
198         });
199
200         // Add the property metadata if it doesn't exist already
201         if (toscaPolicy.getMetadata() == null) {
202             setMetadata(new LinkedHashMap<>());
203         }
204
205         // Add the policy name and version fields to the metadata
206         getMetadata().put(METADATA_POLICY_ID_TAG, getKey().getName());
207         getMetadata().put(METADATA_POLICY_VERSION_TAG, getKey().getVersion());
208     }
209
210     @Override
211     public List<PfKey> getKeys() {
212         final List<PfKey> keyList = super.getKeys();
213
214         keyList.addAll(type.getKeys());
215
216         if (targets != null) {
217             keyList.addAll(targets);
218         }
219
220         return keyList;
221     }
222
223     @Override
224     public void clean() {
225         super.clean();
226
227         type.clean();
228
229         if (targets != null) {
230             for (PfConceptKey target : targets) {
231                 target.clean();
232             }
233         }
234     }
235
236     @Override
237     public PfValidationResult validate(@NonNull final PfValidationResult resultIn) {
238         PfValidationResult result = super.validate(resultIn);
239
240         if (PfKey.NULL_KEY_VERSION.equals(getKey().getVersion())) {
241             result.addValidationMessage(new PfValidationMessage(getKey(), this.getClass(), ValidationResult.INVALID,
242                     "key version is a null version"));
243         }
244
245         if (type == null || type.isNullKey()) {
246             result.addValidationMessage(new PfValidationMessage(getKey(), this.getClass(), ValidationResult.INVALID,
247                     "type is null or a null key"));
248         } else {
249             result = type.validate(result);
250         }
251
252         if (properties != null) {
253             validateProperties(result);
254         }
255
256         if (targets != null) {
257             result = validateTargets(result);
258         }
259
260         return result;
261     }
262
263     /**
264      * Validate the policy properties.
265      *
266      * @param result where to put the validation results
267      */
268     private void validateProperties(final PfValidationResult result) {
269
270         for (Entry<String, String> propertyEntry : properties.entrySet()) {
271             if (!ParameterValidationUtils.validateStringParameter(propertyEntry.getKey())) {
272                 result.addValidationMessage(new PfValidationMessage(getKey(), this.getClass(), ValidationResult.INVALID,
273                         "policy property key may not be null "));
274             } else if (propertyEntry.getValue() == null) {
275                 result.addValidationMessage(new PfValidationMessage(getKey(), this.getClass(), ValidationResult.INVALID,
276                         "policy property value may not be null "));
277             }
278         }
279     }
280
281     /**
282      * Validate the policy targets.
283      *
284      * @param resultIn The result of validations up to now
285      * @return the validation result
286      */
287     private PfValidationResult validateTargets(final PfValidationResult resultIn) {
288         PfValidationResult result = resultIn;
289
290         for (PfConceptKey target : targets) {
291             if (target == null) {
292                 result.addValidationMessage(new PfValidationMessage(getKey(), this.getClass(), ValidationResult.INVALID,
293                         "policy target may not be null "));
294             } else {
295                 result = target.validate(result);
296             }
297         }
298         return result;
299     }
300
301     @Override
302     public int compareTo(final PfConcept otherConcept) {
303         if (otherConcept == null) {
304             return -1;
305         }
306
307         if (this == otherConcept) {
308             return 0;
309         }
310
311         if (getClass() != otherConcept.getClass()) {
312             return getClass().getName().compareTo(otherConcept.getClass().getName());
313         }
314
315         final JpaToscaPolicy other = (JpaToscaPolicy) otherConcept;
316         int result = super.compareTo(other);
317         if (result != 0) {
318             return result;
319         }
320
321         result = type.compareTo(other.type);
322         if (result != 0) {
323             return result;
324         }
325
326         result = PfUtils.compareMaps(properties, other.properties);
327         if (result != 0) {
328             return result;
329         }
330
331         return PfUtils.compareCollections(targets, other.targets);
332     }
333 }