Policy DB contents removed on DB deadlock
[policy/models.git] / models-tosca / src / main / java / org / onap / policy / models / tosca / simple / provider / SimpleToscaProvider.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019-2020 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.tosca.simple.provider;
22
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.List;
26
27 import javax.ws.rs.core.Response;
28
29 import lombok.NonNull;
30
31 import org.apache.commons.collections4.CollectionUtils;
32 import org.onap.policy.models.base.PfConcept;
33 import org.onap.policy.models.base.PfConceptFilter;
34 import org.onap.policy.models.base.PfConceptKey;
35 import org.onap.policy.models.base.PfKey;
36 import org.onap.policy.models.base.PfModelException;
37 import org.onap.policy.models.base.PfModelRuntimeException;
38 import org.onap.policy.models.base.PfValidationResult;
39 import org.onap.policy.models.dao.PfDao;
40 import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity;
41 import org.onap.policy.models.tosca.simple.concepts.JpaToscaDataType;
42 import org.onap.policy.models.tosca.simple.concepts.JpaToscaDataTypes;
43 import org.onap.policy.models.tosca.simple.concepts.JpaToscaEntityType;
44 import org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicies;
45 import org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicy;
46 import org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyType;
47 import org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyTypes;
48 import org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate;
49 import org.onap.policy.models.tosca.simple.concepts.JpaToscaTopologyTemplate;
50 import org.onap.policy.models.tosca.utils.ToscaServiceTemplateUtils;
51 import org.onap.policy.models.tosca.utils.ToscaUtils;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 /**
56  * This class provides the provision of information on TOSCA concepts in the database to callers.
57  *
58  * @author Liam Fallon (liam.fallon@est.tech)
59  */
60 public class SimpleToscaProvider {
61     private static final Logger LOGGER = LoggerFactory.getLogger(SimpleToscaProvider.class);
62
63     // Recurring string constants
64     private static final String DATA_TYPE = "data type ";
65     private static final String POLICY_TYPE = "policy type ";
66     private static final String SERVICE_TEMPLATE_NOT_FOUND_IN_DATABASE = "service template not found in database";
67     private static final String DO_NOT_EXIST = " do not exist";
68     private static final String NOT_FOUND = " not found";
69
70     /**
71      * Get Service Template.
72      *
73      * @param dao the DAO to use to access the database
74      * @return the service template
75      * @throws PfModelException on errors getting the service template
76      */
77     public JpaToscaServiceTemplate getServiceTemplate(@NonNull final PfDao dao) throws PfModelException {
78         LOGGER.debug("->getServiceTemplate");
79
80         JpaToscaServiceTemplate serviceTemplate = new SimpleToscaServiceTemplateProvider().read(dao);
81         if (serviceTemplate == null) {
82             throw new PfModelRuntimeException(Response.Status.NOT_FOUND, SERVICE_TEMPLATE_NOT_FOUND_IN_DATABASE);
83         }
84
85         LOGGER.debug("<-getServiceTemplate: serviceTemplate={}", serviceTemplate);
86         return serviceTemplate;
87     }
88
89     /**
90      * Append a service template fragment to the service template in the database.
91      *
92      * @param dao the DAO to use to access the database
93      * @param incomingServiceTemplateFragment the service template containing the definition of the entities to be
94      *        created
95      * @return the TOSCA service template in the database after the operation
96      * @throws PfModelException on errors appending a service template to the template in the database
97      */
98     public JpaToscaServiceTemplate appendToServiceTemplate(@NonNull final PfDao dao,
99         @NonNull final JpaToscaServiceTemplate incomingServiceTemplateFragment) throws PfModelException {
100         LOGGER.debug("->appendServiceTemplateFragment: incomingServiceTemplateFragment={}",
101             incomingServiceTemplateFragment);
102
103         JpaToscaServiceTemplate dbServiceTemplate = new SimpleToscaServiceTemplateProvider().read(dao);
104
105         JpaToscaServiceTemplate serviceTemplateToWrite;
106         if (dbServiceTemplate == null) {
107             serviceTemplateToWrite = incomingServiceTemplateFragment;
108         } else {
109             serviceTemplateToWrite =
110                 ToscaServiceTemplateUtils.addFragment(dbServiceTemplate, incomingServiceTemplateFragment);
111         }
112
113         PfValidationResult result = serviceTemplateToWrite.validate(new PfValidationResult());
114         if (!result.isValid()) {
115             throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, result.toString());
116         }
117
118         new SimpleToscaServiceTemplateProvider().write(dao, serviceTemplateToWrite);
119
120         LOGGER.debug("<-appendServiceTemplateFragment: returnServiceTempalate={}", serviceTemplateToWrite);
121         return serviceTemplateToWrite;
122     }
123
124     /**
125      * Get data types.
126      *
127      * @param dao the DAO to use to access the database
128      * @param name the name of the data type to get, set to null to get all policy types
129      * @param version the version of the data type to get, set to null to get all versions
130      * @return the data types found
131      * @throws PfModelException on errors getting data types
132      */
133     public JpaToscaServiceTemplate getDataTypes(@NonNull final PfDao dao, final String name, final String version)
134         throws PfModelException {
135         LOGGER.debug("->getDataTypes: name={}, version={}", name, version);
136
137         final JpaToscaServiceTemplate dbServiceTemplate = getServiceTemplate(dao);
138
139         if (!ToscaUtils.doDataTypesExist(dbServiceTemplate)) {
140             throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
141                 "data types for " + name + ":" + version + DO_NOT_EXIST);
142         }
143
144         JpaToscaServiceTemplate serviceTemplate = getCascadedDataTypes(dbServiceTemplate, name, version);
145
146         LOGGER.debug("<-getDataTypes: name={}, version={}, serviceTemplate={}", name, version, serviceTemplate);
147         return serviceTemplate;
148     }
149
150     /**
151      * Get the cascaded data types for a data type name and version.
152      *
153      * @param dbServiceTemplate the service template to search for the cascaded data types
154      * @param name the data type name we are searching for
155      * @param version the data type version we are searching for
156      * @return a service template containing the cascaded data types
157      * @throws PfModelException on errors getting the data types
158      */
159     public JpaToscaServiceTemplate getCascadedDataTypes(@NonNull final JpaToscaServiceTemplate dbServiceTemplate,
160         final String name, final String version) throws PfModelException {
161
162         JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate(dbServiceTemplate);
163         serviceTemplate.setPolicyTypes(null);
164         serviceTemplate.setTopologyTemplate(null);
165
166         ToscaUtils.getEntityTree(serviceTemplate.getDataTypes(), name, version);
167
168         if (!ToscaUtils.doDataTypesExist(serviceTemplate)) {
169             throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
170                 "data types for " + name + ":" + version + DO_NOT_EXIST);
171         }
172
173         for (JpaToscaDataType dataType : serviceTemplate.getDataTypes().getConceptMap().values()) {
174             Collection<PfConceptKey> referencedDataTypeKeys = dataType.getReferencedDataTypes();
175
176             for (PfConceptKey referencedDataTypeKey : referencedDataTypeKeys) {
177                 JpaToscaServiceTemplate dataTypeEntityTreeServiceTemplate = getCascadedDataTypes(dbServiceTemplate,
178                     referencedDataTypeKey.getName(), referencedDataTypeKey.getVersion());
179
180                 serviceTemplate =
181                     ToscaServiceTemplateUtils.addFragment(serviceTemplate, dataTypeEntityTreeServiceTemplate);
182             }
183         }
184         return serviceTemplate;
185     }
186
187     /**
188      * Create data types.
189      *
190      * @param dao the DAO to use to access the database
191      * @param incomingServiceTemplate the service template containing the definition of the data types to be created
192      * @return the TOSCA service template containing the created data types
193      * @throws PfModelException on errors creating data types
194      */
195     public JpaToscaServiceTemplate createDataTypes(@NonNull final PfDao dao,
196         @NonNull final JpaToscaServiceTemplate incomingServiceTemplate) throws PfModelException {
197         LOGGER.debug("->createDataTypes: incomingServiceTemplate={}", incomingServiceTemplate);
198
199         ToscaUtils.assertDataTypesExist(incomingServiceTemplate);
200
201         JpaToscaServiceTemplate writtenServiceTemplate = appendToServiceTemplate(dao, incomingServiceTemplate);
202
203         LOGGER.debug("<-createDataTypes: writtenServiceTemplate={}", writtenServiceTemplate);
204         return incomingServiceTemplate;
205     }
206
207     /**
208      * Update Data types.
209      *
210      * @param dao the DAO to use to access the database
211      * @param serviceTemplate the service template containing the definition of the data types to be modified
212      * @return the TOSCA service template containing the modified data types
213      * @throws PfModelException on errors updating Data types
214      */
215     public JpaToscaServiceTemplate updateDataTypes(@NonNull final PfDao dao,
216         @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
217         LOGGER.debug("->updateDataTypes: serviceTempalate={}", serviceTemplate);
218
219         ToscaUtils.assertDataTypesExist(serviceTemplate);
220
221         for (JpaToscaDataType dataType : serviceTemplate.getDataTypes().getAll(null)) {
222             dao.update(dataType);
223         }
224
225         // Return the created data types
226         JpaToscaDataTypes returnDataTypes = new JpaToscaDataTypes();
227
228         for (PfConceptKey dataTypeKey : serviceTemplate.getDataTypes().getConceptMap().keySet()) {
229             returnDataTypes.getConceptMap().put(dataTypeKey, dao.get(JpaToscaDataType.class, dataTypeKey));
230         }
231
232         JpaToscaServiceTemplate returnServiceTemplate = new JpaToscaServiceTemplate();
233         returnServiceTemplate.setDataTypes(returnDataTypes);
234
235         LOGGER.debug("<-updateDataTypes: returnServiceTempalate={}", returnServiceTemplate);
236         return returnServiceTemplate;
237     }
238
239     /**
240      * Delete Data types.
241      *
242      * @param dao the DAO to use to access the database
243      * @param dataTypeKey the data type key for the Data types to be deleted, if the version of the key is null, all
244      *        versions of the data type are deleted.
245      * @return the TOSCA service template containing the data types that were deleted
246      * @throws PfModelException on errors deleting data types
247      */
248     public JpaToscaServiceTemplate deleteDataType(@NonNull final PfDao dao, @NonNull final PfConceptKey dataTypeKey)
249         throws PfModelException {
250         LOGGER.debug("->deleteDataType: key={}", dataTypeKey);
251
252         JpaToscaServiceTemplate serviceTemplate = getServiceTemplate(dao);
253
254         if (!ToscaUtils.doDataTypesExist(serviceTemplate)) {
255             throw new PfModelRuntimeException(Response.Status.NOT_FOUND, "no data types found");
256         }
257
258         JpaToscaDataType dataType4Deletion = serviceTemplate.getDataTypes().get(dataTypeKey);
259         if (dataType4Deletion == null) {
260             throw new PfModelRuntimeException(Response.Status.NOT_FOUND, DATA_TYPE + dataTypeKey.getId() + NOT_FOUND);
261         }
262
263         for (JpaToscaDataType dataType : serviceTemplate.getDataTypes().getAll(null)) {
264             if (dataType.getReferencedDataTypes().contains(dataTypeKey)) {
265                 throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE,
266                     DATA_TYPE + dataTypeKey.getId() + " is in use, it is referenced in data type " + dataType.getId());
267             }
268         }
269
270         if (ToscaUtils.doPolicyTypesExist(serviceTemplate)) {
271             for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getAll(null)) {
272                 if (policyType.getReferencedDataTypes().contains(dataTypeKey)) {
273                     throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, DATA_TYPE + dataTypeKey.getId()
274                         + " is in use, it is referenced in policy type " + policyType.getId());
275                 }
276             }
277         }
278
279         serviceTemplate.getDataTypes().getConceptMap().remove(dataTypeKey);
280         new SimpleToscaServiceTemplateProvider().write(dao, serviceTemplate);
281         dao.delete(dataType4Deletion);
282
283         JpaToscaServiceTemplate deletedServiceTemplate = new JpaToscaServiceTemplate();
284         deletedServiceTemplate.setDataTypes(new JpaToscaDataTypes());
285         deletedServiceTemplate.getDataTypes().getConceptMap().put(dataTypeKey, dataType4Deletion);
286
287         LOGGER.debug("<-deleteDataType: key={}, serviceTempalate={}", dataTypeKey, deletedServiceTemplate);
288         return deletedServiceTemplate;
289     }
290
291     /**
292      * Get policy types.
293      *
294      * @param dao the DAO to use to access the database
295      * @param name the name of the policy type to get, set to null to get all policy types
296      * @param version the version of the policy type to get, set to null to get all versions
297      * @return the policy types found
298      * @throws PfModelException on errors getting policy types
299      */
300     public JpaToscaServiceTemplate getPolicyTypes(@NonNull final PfDao dao, final String name, final String version)
301         throws PfModelException {
302         LOGGER.debug("->getPolicyTypes: name={}, version={}", name, version);
303
304         final JpaToscaServiceTemplate dbServiceTemplate = getServiceTemplate(dao);
305
306         if (!ToscaUtils.doPolicyTypesExist(dbServiceTemplate)) {
307             throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
308                 "policy types for " + name + ":" + version + DO_NOT_EXIST);
309         }
310
311         JpaToscaServiceTemplate serviceTemplate = getCascadedPolicyTypes(dbServiceTemplate, name, version);
312
313         LOGGER.debug("<-getPolicyTypes: name={}, version={}, serviceTemplate={}", name, version, serviceTemplate);
314         return serviceTemplate;
315     }
316
317     /**
318      * Get the cascaded policy types for a policy type name and version.
319      *
320      * @param dbServiceTemplate the service template to search for the cascaded policy types
321      * @param name the policy type name we are searching for
322      * @param version the policy type version we are searching for
323      * @return a service template containing the cascaded policy types
324      * @throws PfModelException on errors getting the policy types
325      */
326     public JpaToscaServiceTemplate getCascadedPolicyTypes(final JpaToscaServiceTemplate dbServiceTemplate,
327         final String name, final String version) throws PfModelException {
328
329         JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate(dbServiceTemplate);
330
331         serviceTemplate.setDataTypes(null);
332         serviceTemplate.setTopologyTemplate(null);
333
334         ToscaUtils.getEntityTree(serviceTemplate.getPolicyTypes(), name, version);
335
336         if (!ToscaUtils.doPolicyTypesExist(serviceTemplate)) {
337             throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
338                 "policy types for " + name + ":" + version + DO_NOT_EXIST);
339         }
340
341         JpaToscaServiceTemplate dataTypeServiceTemplate = new JpaToscaServiceTemplate(serviceTemplate);
342         dataTypeServiceTemplate.setPolicyTypes(null);
343
344         for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getConceptMap().values()) {
345             Collection<PfConceptKey> referencedDataTypeKeys = policyType.getReferencedDataTypes();
346
347             for (PfConceptKey referencedDataTypeKey : referencedDataTypeKeys) {
348                 JpaToscaServiceTemplate dataTypeEntityTreeServiceTemplate = getCascadedDataTypes(dbServiceTemplate,
349                     referencedDataTypeKey.getName(), referencedDataTypeKey.getVersion());
350
351                 dataTypeServiceTemplate =
352                     ToscaServiceTemplateUtils.addFragment(dataTypeServiceTemplate, dataTypeEntityTreeServiceTemplate);
353             }
354         }
355
356         serviceTemplate = ToscaServiceTemplateUtils.addFragment(serviceTemplate, dataTypeServiceTemplate);
357         return serviceTemplate;
358     }
359
360     /**
361      * Create policy types.
362      *
363      * @param dao the DAO to use to access the database
364      * @param incomingServiceTemplate the service template containing the definition of the policy types to be created
365      * @return the TOSCA service template containing the created policy types
366      * @throws PfModelException on errors creating policy types
367      */
368     public JpaToscaServiceTemplate createPolicyTypes(@NonNull final PfDao dao,
369         @NonNull final JpaToscaServiceTemplate incomingServiceTemplate) throws PfModelException {
370         LOGGER.debug("->createPolicyTypes: serviceTempalate={}", incomingServiceTemplate);
371
372         ToscaUtils.assertPolicyTypesExist(incomingServiceTemplate);
373
374         JpaToscaServiceTemplate writtenServiceTemplate = appendToServiceTemplate(dao, incomingServiceTemplate);
375
376         LOGGER.debug("<-createPolicyTypes: writtenServiceTemplate={}", writtenServiceTemplate);
377         return incomingServiceTemplate;
378     }
379
380     /**
381      * Update policy types.
382      *
383      * @param dao the DAO to use to access the database
384      * @param serviceTemplate the service template containing the definition of the policy types to be modified
385      * @return the TOSCA service template containing the modified policy types
386      * @throws PfModelException on errors updating policy types
387      */
388     public JpaToscaServiceTemplate updatePolicyTypes(@NonNull final PfDao dao,
389         @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
390         LOGGER.debug("->updatePolicyTypes: serviceTempalate={}", serviceTemplate);
391
392         ToscaUtils.assertPolicyTypesExist(serviceTemplate);
393
394         // Update the data types on the policy type
395         if (ToscaUtils.doDataTypesExist(serviceTemplate)) {
396             updateDataTypes(dao, serviceTemplate);
397         }
398
399         for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getAll(null)) {
400             dao.update(policyType);
401         }
402
403         // Return the created policy types
404         JpaToscaPolicyTypes returnPolicyTypes = new JpaToscaPolicyTypes();
405
406         for (PfConceptKey policyTypeKey : serviceTemplate.getPolicyTypes().getConceptMap().keySet()) {
407             returnPolicyTypes.getConceptMap().put(policyTypeKey, dao.get(JpaToscaPolicyType.class, policyTypeKey));
408         }
409
410         JpaToscaServiceTemplate returnServiceTemplate = new JpaToscaServiceTemplate();
411         returnServiceTemplate.setPolicyTypes(returnPolicyTypes);
412
413         LOGGER.debug("<-updatePolicyTypes: returnServiceTempalate={}", returnServiceTemplate);
414         return returnServiceTemplate;
415     }
416
417     /**
418      * Delete policy types.
419      *
420      * @param dao the DAO to use to access the database
421      * @param policyTypeKey the policy type key for the policy types to be deleted, if the version of the key is null,
422      *        all versions of the policy type are deleted.
423      * @return the TOSCA service template containing the policy types that were deleted
424      * @throws PfModelException on errors deleting policy types
425      */
426     public JpaToscaServiceTemplate deletePolicyType(@NonNull final PfDao dao, @NonNull final PfConceptKey policyTypeKey)
427         throws PfModelException {
428         LOGGER.debug("->deletePolicyType: key={}", policyTypeKey);
429
430         JpaToscaServiceTemplate serviceTemplate = getServiceTemplate(dao);
431
432         if (!ToscaUtils.doPolicyTypesExist(serviceTemplate)) {
433             throw new PfModelRuntimeException(Response.Status.NOT_FOUND, "no policy types found");
434         }
435
436         JpaToscaPolicyType policyType4Deletion = serviceTemplate.getPolicyTypes().get(policyTypeKey);
437         if (policyType4Deletion == null) {
438             throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
439                 POLICY_TYPE + policyTypeKey.getId() + NOT_FOUND);
440         }
441
442         for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getAll(null)) {
443             Collection<JpaToscaEntityType<ToscaEntity>> ancestorList = ToscaUtils
444                 .getEntityTypeAncestors(serviceTemplate.getPolicyTypes(), policyType, new PfValidationResult());
445
446             if (ancestorList.contains(policyType4Deletion)) {
447                 throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, POLICY_TYPE + policyTypeKey.getId()
448                     + " is in use, it is referenced in policy type " + policyType.getId());
449             }
450         }
451
452         if (ToscaUtils.doPoliciesExist(serviceTemplate)) {
453             for (JpaToscaPolicy policy : serviceTemplate.getTopologyTemplate().getPolicies().getAll(null)) {
454                 if (policyTypeKey.equals(policy.getType())) {
455                     throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, POLICY_TYPE
456                         + policyTypeKey.getId() + " is in use, it is referenced in policy " + policy.getId());
457                 }
458             }
459         }
460
461         serviceTemplate.getPolicyTypes().getConceptMap().remove(policyTypeKey);
462         new SimpleToscaServiceTemplateProvider().write(dao, serviceTemplate);
463         dao.delete(policyType4Deletion);
464
465         JpaToscaServiceTemplate deletedServiceTemplate = new JpaToscaServiceTemplate();
466         deletedServiceTemplate.setPolicyTypes(new JpaToscaPolicyTypes());
467         deletedServiceTemplate.getPolicyTypes().getConceptMap().put(policyTypeKey, policyType4Deletion);
468
469         LOGGER.debug("<-deletePolicyType: key={}, serviceTempalate={}", policyTypeKey, deletedServiceTemplate);
470         return deletedServiceTemplate;
471     }
472
473     /**
474      * Get policies.
475      *
476      * @param dao the DAO to use to access the database
477      * @param name the name of the policy to get, set to null to get all policy types
478      * @param version the version of the policy to get, set to null to get all versions
479      * @return the policies found
480      * @throws PfModelException on errors getting policies
481      */
482     public JpaToscaServiceTemplate getPolicies(@NonNull final PfDao dao, final String name, final String version)
483         throws PfModelException {
484         LOGGER.debug("->getPolicies: name={}, version={}", name, version);
485
486         JpaToscaServiceTemplate dbServiceTemplate = getServiceTemplate(dao);
487
488         if (!ToscaUtils.doPoliciesExist(dbServiceTemplate)) {
489             throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
490                 "policies for " + name + ":" + version + DO_NOT_EXIST);
491         }
492
493         JpaToscaServiceTemplate returnServiceTemplate = getCascadedPolicies(dbServiceTemplate, name, version);
494
495         LOGGER.debug("<-getPolicies: name={}, version={}, serviceTemplate={}", name, version, returnServiceTemplate);
496         return returnServiceTemplate;
497     }
498
499     /**
500      * Get the cascaded policies for a policy name and version.
501      *
502      * @param dbServiceTemplate the service template to search for the cascaded policy
503      * @param name the policy name we are searching for
504      * @param version the policy version we are searching for
505      * @return a service template containing the cascaded policy
506      * @throws PfModelException on errors getting the policy
507      */
508     public JpaToscaServiceTemplate getCascadedPolicies(final JpaToscaServiceTemplate dbServiceTemplate,
509         final String name, final String version) throws PfModelException {
510
511         JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate(dbServiceTemplate);
512         serviceTemplate.setDataTypes(new JpaToscaDataTypes());
513         serviceTemplate.setPolicyTypes(new JpaToscaPolicyTypes());
514
515         ToscaUtils.getEntityTree(serviceTemplate.getTopologyTemplate().getPolicies(), name, version);
516
517         if (!ToscaUtils.doPoliciesExist(serviceTemplate)) {
518             throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
519                 "policies for " + name + ":" + version + DO_NOT_EXIST);
520         }
521
522         JpaToscaServiceTemplate returnServiceTemplate = new JpaToscaServiceTemplate(serviceTemplate);
523         returnServiceTemplate.getTopologyTemplate().setPolicies(new JpaToscaPolicies());
524
525         for (JpaToscaPolicy policy : serviceTemplate.getTopologyTemplate().getPolicies().getConceptMap().values()) {
526             JpaToscaServiceTemplate referencedEntitiesServiceTemplate =
527                 getCascadedPolicyTypes(dbServiceTemplate, policy.getType().getName(), policy.getType().getVersion());
528
529             returnServiceTemplate.getTopologyTemplate().getPolicies().getConceptMap().put(policy.getKey(), policy);
530             returnServiceTemplate =
531                 ToscaServiceTemplateUtils.addFragment(returnServiceTemplate, referencedEntitiesServiceTemplate);
532         }
533
534         return returnServiceTemplate;
535     }
536
537     /**
538      * Create policies.
539      *
540      * @param dao the DAO to use to access the database
541      * @param incomingServiceTemplate the service template containing the definitions of the new policies to be created.
542      * @return the TOSCA service template containing the policy types that were created
543      * @throws PfModelException on errors creating policies
544      */
545     public JpaToscaServiceTemplate createPolicies(@NonNull final PfDao dao,
546         @NonNull final JpaToscaServiceTemplate incomingServiceTemplate) throws PfModelException {
547         LOGGER.debug("->createPolicies: incomingServiceTemplate={}", incomingServiceTemplate);
548
549         ToscaUtils.assertPoliciesExist(incomingServiceTemplate);
550
551         JpaToscaServiceTemplate writtenServiceTemplate = appendToServiceTemplate(dao, incomingServiceTemplate);
552
553         LOGGER.debug("<-createPolicies: writtenServiceTemplate={}", writtenServiceTemplate);
554         return incomingServiceTemplate;
555     }
556
557     /**
558      * Update policies.
559      *
560      * @param dao the DAO to use to access the database
561      * @param serviceTemplate the service template containing the definitions of the policies to be updated.
562      * @return the TOSCA service template containing the policies that were updated
563      * @throws PfModelException on errors updating policies
564      */
565     public JpaToscaServiceTemplate updatePolicies(@NonNull final PfDao dao,
566         @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
567         LOGGER.debug("->updatePolicies: serviceTempalate={}", serviceTemplate);
568
569         ToscaUtils.assertPoliciesExist(serviceTemplate);
570
571         for (JpaToscaPolicy policy : serviceTemplate.getTopologyTemplate().getPolicies().getAll(null)) {
572             verifyPolicyTypeForPolicy(dao, policy);
573             dao.update(policy);
574         }
575
576         // Return the created policy types
577         JpaToscaPolicies returnPolicies = new JpaToscaPolicies();
578         returnPolicies.setKey(serviceTemplate.getTopologyTemplate().getPolicies().getKey());
579
580         for (PfConceptKey policyKey : serviceTemplate.getTopologyTemplate().getPolicies().getConceptMap().keySet()) {
581             returnPolicies.getConceptMap().put(policyKey, dao.get(JpaToscaPolicy.class, policyKey));
582         }
583
584         serviceTemplate.getTopologyTemplate().setPolicies(returnPolicies);
585
586         LOGGER.debug("<-updatePolicies: serviceTemplate={}", serviceTemplate);
587         return serviceTemplate;
588     }
589
590     /**
591      * Delete policies.
592      *
593      * @param dao the DAO to use to access the database
594      * @param policyKey the policy key
595      * @return the TOSCA service template containing the policies that were deleted
596      * @throws PfModelException on errors deleting policies
597      */
598     public JpaToscaServiceTemplate deletePolicy(@NonNull final PfDao dao, @NonNull final PfConceptKey policyKey)
599         throws PfModelException {
600         LOGGER.debug("->deletePolicy: key={}", policyKey);
601
602         JpaToscaServiceTemplate serviceTemplate = getServiceTemplate(dao);
603
604         if (!ToscaUtils.doPoliciesExist(serviceTemplate)) {
605             throw new PfModelRuntimeException(Response.Status.NOT_FOUND, "no policies found");
606         }
607
608         JpaToscaPolicy policy4Deletion = serviceTemplate.getTopologyTemplate().getPolicies().get(policyKey);
609         if (policy4Deletion == null) {
610             throw new PfModelRuntimeException(Response.Status.NOT_FOUND, "policy " + policyKey.getId() + NOT_FOUND);
611         }
612
613         serviceTemplate.getTopologyTemplate().getPolicies().getConceptMap().remove(policyKey);
614         new SimpleToscaServiceTemplateProvider().write(dao, serviceTemplate);
615         dao.delete(policy4Deletion);
616
617         JpaToscaServiceTemplate deletedServiceTemplate = new JpaToscaServiceTemplate();
618         deletedServiceTemplate.setTopologyTemplate(new JpaToscaTopologyTemplate());
619         deletedServiceTemplate.getTopologyTemplate().setPolicies(new JpaToscaPolicies());
620         deletedServiceTemplate.getTopologyTemplate().getPolicies().getConceptMap().put(policyKey, policy4Deletion);
621
622         LOGGER.debug("<-deletePolicy: key={}, serviceTempalate={}", policyKey, deletedServiceTemplate);
623         return deletedServiceTemplate;
624     }
625
626     /**
627      * Verify the policy type for a policy exists.
628      *
629      * @param dao the DAO to use to access policy types in the database
630      * @param policy the policy to check the policy type for
631      */
632     private void verifyPolicyTypeForPolicy(final PfDao dao, final JpaToscaPolicy policy) {
633         PfConceptKey policyTypeKey = policy.getType();
634
635         JpaToscaPolicyType policyType = null;
636
637         if (PfKey.NULL_KEY_VERSION.equals(policyTypeKey.getVersion())) {
638             policyType = getLatestPolicyTypeVersion(dao, policyTypeKey.getName());
639
640             if (policyType != null) {
641                 policy.getType().setVersion(policyType.getKey().getVersion());
642             }
643         } else {
644             policyType = dao.get(JpaToscaPolicyType.class, policyTypeKey);
645         }
646
647         if (policyType == null) {
648             String errorMessage =
649                 POLICY_TYPE + policyTypeKey.getId() + " for policy " + policy.getId() + " does not exist";
650             throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, errorMessage);
651         }
652     }
653
654     /**
655      * Get the latest version of the policy type for the given policy type name.
656      *
657      * @param dao the DAO to use to access policy types in the database
658      * @param policyTypeName the name of the policy type
659      * @return the latest policy type
660      */
661     private JpaToscaPolicyType getLatestPolicyTypeVersion(final PfDao dao, final String policyTypeName) {
662         // Policy type version is not specified, get the latest version from the database
663         List<JpaToscaPolicyType> jpaPolicyTypeList = dao.getFiltered(JpaToscaPolicyType.class, policyTypeName, null);
664
665         if (CollectionUtils.isEmpty(jpaPolicyTypeList)) {
666             return null;
667         }
668
669         // Create a filter to get the latest version of the policy type
670         PfConceptFilter pfConceptFilter = PfConceptFilter.builder().version(PfConceptFilter.LATEST_VERSION).build();
671
672         // FIlter the returned policy type list
673         List<PfConcept> policyTypeKeyList = new ArrayList<>(jpaPolicyTypeList);
674         List<PfConcept> filterdPolicyTypeList = pfConceptFilter.filter(policyTypeKeyList);
675
676         // We should have one and only one returned entry
677         if (filterdPolicyTypeList.size() != 1) {
678             String errorMessage = "search for latest policy type " + policyTypeName + " returned more than one entry";
679             throw new PfModelRuntimeException(Response.Status.CONFLICT, errorMessage);
680         }
681
682         return (JpaToscaPolicyType) filterdPolicyTypeList.get(0);
683     }
684 }