Policy delete should only return deleted policy
[policy/models.git] / models-tosca / src / main / java / org / onap / policy / models / tosca / simple / provider / SimpleToscaProvider.java
index e7e8160..4dbbc2d 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2019 Nordix Foundation.
+ *  Copyright (C) 2019-2020 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.policy.models.tosca.simple.provider;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
 import javax.ws.rs.core.Response;
 
 import lombok.NonNull;
 
+import org.apache.commons.collections4.CollectionUtils;
+import org.onap.policy.models.base.PfConcept;
+import org.onap.policy.models.base.PfConceptFilter;
 import org.onap.policy.models.base.PfConceptKey;
+import org.onap.policy.models.base.PfKey;
 import org.onap.policy.models.base.PfModelException;
 import org.onap.policy.models.base.PfModelRuntimeException;
+import org.onap.policy.models.base.PfValidationResult;
 import org.onap.policy.models.dao.PfDao;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaEntity;
+import org.onap.policy.models.tosca.simple.concepts.JpaToscaDataType;
+import org.onap.policy.models.tosca.simple.concepts.JpaToscaDataTypes;
+import org.onap.policy.models.tosca.simple.concepts.JpaToscaEntityType;
 import org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicies;
 import org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicy;
 import org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyType;
 import org.onap.policy.models.tosca.simple.concepts.JpaToscaPolicyTypes;
 import org.onap.policy.models.tosca.simple.concepts.JpaToscaServiceTemplate;
 import org.onap.policy.models.tosca.simple.concepts.JpaToscaTopologyTemplate;
+import org.onap.policy.models.tosca.utils.ToscaServiceTemplateUtils;
 import org.onap.policy.models.tosca.utils.ToscaUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,77 +60,336 @@ import org.slf4j.LoggerFactory;
 public class SimpleToscaProvider {
     private static final Logger LOGGER = LoggerFactory.getLogger(SimpleToscaProvider.class);
 
+    // Recurring string constants
+    private static final String DATA_TYPE = "data type ";
+    private static final String POLICY_TYPE = "policy type ";
+    private static final String SERVICE_TEMPLATE_NOT_FOUND_IN_DATABASE = "service template not found in database";
+    private static final String DO_NOT_EXIST = " do not exist";
+    private static final String NOT_FOUND = " not found";
+
     /**
-     * Get policy types.
+     * Get Service Template.
      *
      * @param dao the DAO to use to access the database
-     * @param policyTypeKey the policy type key for the policy types to be retrieved. A null key name returns all policy
-     *        types. A null key version returns all versions of the policy type name specified in the key.
-     * @return the policy types found
-     * @throws PfModelException on errors getting policy types
+     * @return the service template
+     * @throws PfModelException on errors getting the service template
      */
-    public JpaToscaServiceTemplate getPolicyTypes(@NonNull final PfDao dao, @NonNull final PfConceptKey policyTypeKey)
-            throws PfModelException {
+    public JpaToscaServiceTemplate getServiceTemplate(@NonNull final PfDao dao) throws PfModelException {
+        LOGGER.debug("->getServiceTemplate");
 
-        // Create the structure of the TOSCA service template to contain the policy type
-        JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate();
-        serviceTemplate.setPolicyTypes(new JpaToscaPolicyTypes());
+        JpaToscaServiceTemplate serviceTemplate = new SimpleToscaServiceTemplateProvider().read(dao);
+        if (serviceTemplate == null) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND, SERVICE_TEMPLATE_NOT_FOUND_IN_DATABASE);
+        }
+
+        LOGGER.debug("<-getServiceTemplate: serviceTemplate={}", serviceTemplate);
+        return serviceTemplate;
+    }
+
+    /**
+     * Append a service template fragment to the service template in the database.
+     *
+     * @param dao the DAO to use to access the database
+     * @param incomingServiceTemplateFragment the service template containing the definition of the entities to be
+     *        created
+     * @return the TOSCA service template in the database after the operation
+     * @throws PfModelException on errors appending a service template to the template in the database
+     */
+    public JpaToscaServiceTemplate appendToServiceTemplate(@NonNull final PfDao dao,
+        @NonNull final JpaToscaServiceTemplate incomingServiceTemplateFragment) throws PfModelException {
+        LOGGER.debug("->appendServiceTemplateFragment: incomingServiceTemplateFragment={}",
+            incomingServiceTemplateFragment);
 
-        // Add the policy type to the TOSCA service template
-        JpaToscaPolicyType policyType = dao.get(JpaToscaPolicyType.class, policyTypeKey);
-        if (policyType != null) {
-            serviceTemplate.getPolicyTypes().getConceptMap().put(policyTypeKey, policyType);
-            return serviceTemplate;
+        JpaToscaServiceTemplate dbServiceTemplate = new SimpleToscaServiceTemplateProvider().read(dao);
+
+        JpaToscaServiceTemplate serviceTemplateToWrite;
+        if (dbServiceTemplate == null) {
+            serviceTemplateToWrite = incomingServiceTemplateFragment;
         } else {
-            String errorMessage = "policy type not found: " + policyTypeKey.getId();
-            LOGGER.warn(errorMessage);
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, errorMessage);
+            serviceTemplateToWrite =
+                ToscaServiceTemplateUtils.addFragment(dbServiceTemplate, incomingServiceTemplateFragment);
         }
+
+        PfValidationResult result = serviceTemplateToWrite.validate(new PfValidationResult());
+        if (!result.isValid()) {
+            throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, result.toString());
+        }
+
+        new SimpleToscaServiceTemplateProvider().write(dao, serviceTemplateToWrite);
+
+        LOGGER.debug("<-appendServiceTemplateFragment: returnServiceTempalate={}", serviceTemplateToWrite);
+        return serviceTemplateToWrite;
     }
 
     /**
-     * Create policy types.
+     * Get data types.
      *
      * @param dao the DAO to use to access the database
-     * @param serviceTemplate the service template containing the definition of the policy types to be created
-     * @return the TOSCA service template containing the created policy types
-     * @throws PfModelException on errors creating policy types
+     * @param name the name of the data type to get, set to null to get all policy types
+     * @param version the version of the data type to get, set to null to get all versions
+     * @return the data types found
+     * @throws PfModelException on errors getting data types
      */
-    public JpaToscaServiceTemplate createPolicyTypes(@NonNull final PfDao dao,
-            @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
+    public JpaToscaServiceTemplate getDataTypes(@NonNull final PfDao dao, final String name, final String version)
+        throws PfModelException {
+        LOGGER.debug("->getDataTypes: name={}, version={}", name, version);
 
-        ToscaUtils.assertPolicyTypesExist(serviceTemplate);
+        final JpaToscaServiceTemplate dbServiceTemplate = getServiceTemplate(dao);
 
-        for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getAll(null)) {
-            dao.create(policyType);
+        if (!ToscaUtils.doDataTypesExist(dbServiceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
+                "data types for " + name + ":" + version + DO_NOT_EXIST);
         }
 
-        // Return the created policy types
-        JpaToscaPolicyTypes returnPolicyTypes = new JpaToscaPolicyTypes();
+        JpaToscaServiceTemplate serviceTemplate = getCascadedDataTypes(dbServiceTemplate, name, version);
 
-        for (PfConceptKey policyTypeKey : serviceTemplate.getPolicyTypes().getConceptMap().keySet()) {
-            returnPolicyTypes.getConceptMap().put(policyTypeKey, dao.get(JpaToscaPolicyType.class, policyTypeKey));
+        LOGGER.debug("<-getDataTypes: name={}, version={}, serviceTemplate={}", name, version, serviceTemplate);
+        return serviceTemplate;
+    }
+
+    /**
+     * Get the cascaded data types for a data type name and version.
+     *
+     * @param dbServiceTemplate the service template to search for the cascaded data types
+     * @param name the data type name we are searching for
+     * @param version the data type version we are searching for
+     * @return a service template containing the cascaded data types
+     * @throws PfModelException on errors getting the data types
+     */
+    public JpaToscaServiceTemplate getCascadedDataTypes(@NonNull final JpaToscaServiceTemplate dbServiceTemplate,
+        final String name, final String version) throws PfModelException {
+
+        JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate(dbServiceTemplate);
+        serviceTemplate.setPolicyTypes(null);
+        serviceTemplate.setTopologyTemplate(null);
+
+        ToscaUtils.getEntityTree(serviceTemplate.getDataTypes(), name, version);
+
+        if (!ToscaUtils.doDataTypesExist(serviceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
+                "data types for " + name + ":" + version + DO_NOT_EXIST);
+        }
+
+        for (JpaToscaDataType dataType : serviceTemplate.getDataTypes().getConceptMap().values()) {
+            Collection<PfConceptKey> referencedDataTypeKeys = dataType.getReferencedDataTypes();
+
+            for (PfConceptKey referencedDataTypeKey : referencedDataTypeKeys) {
+                JpaToscaServiceTemplate dataTypeEntityTreeServiceTemplate = getCascadedDataTypes(dbServiceTemplate,
+                    referencedDataTypeKey.getName(), referencedDataTypeKey.getVersion());
+
+                serviceTemplate =
+                    ToscaServiceTemplateUtils.addFragment(serviceTemplate, dataTypeEntityTreeServiceTemplate);
+            }
+        }
+        return serviceTemplate;
+    }
+
+    /**
+     * Create data types.
+     *
+     * @param dao the DAO to use to access the database
+     * @param incomingServiceTemplate the service template containing the definition of the data types to be created
+     * @return the TOSCA service template containing the created data types
+     * @throws PfModelException on errors creating data types
+     */
+    public JpaToscaServiceTemplate createDataTypes(@NonNull final PfDao dao,
+        @NonNull final JpaToscaServiceTemplate incomingServiceTemplate) throws PfModelException {
+        LOGGER.debug("->createDataTypes: incomingServiceTemplate={}", incomingServiceTemplate);
+
+        ToscaUtils.assertDataTypesExist(incomingServiceTemplate);
+
+        JpaToscaServiceTemplate writtenServiceTemplate = appendToServiceTemplate(dao, incomingServiceTemplate);
+
+        LOGGER.debug("<-createDataTypes: writtenServiceTemplate={}", writtenServiceTemplate);
+        return incomingServiceTemplate;
+    }
+
+    /**
+     * Update Data types.
+     *
+     * @param dao the DAO to use to access the database
+     * @param serviceTemplate the service template containing the definition of the data types to be modified
+     * @return the TOSCA service template containing the modified data types
+     * @throws PfModelException on errors updating Data types
+     */
+    public JpaToscaServiceTemplate updateDataTypes(@NonNull final PfDao dao,
+        @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
+        LOGGER.debug("->updateDataTypes: serviceTempalate={}", serviceTemplate);
+
+        ToscaUtils.assertDataTypesExist(serviceTemplate);
+
+        for (JpaToscaDataType dataType : serviceTemplate.getDataTypes().getAll(null)) {
+            dao.update(dataType);
+        }
+
+        // Return the created data types
+        JpaToscaDataTypes returnDataTypes = new JpaToscaDataTypes();
+
+        for (PfConceptKey dataTypeKey : serviceTemplate.getDataTypes().getConceptMap().keySet()) {
+            returnDataTypes.getConceptMap().put(dataTypeKey, dao.get(JpaToscaDataType.class, dataTypeKey));
         }
 
         JpaToscaServiceTemplate returnServiceTemplate = new JpaToscaServiceTemplate();
-        returnServiceTemplate.setPolicyTypes(returnPolicyTypes);
+        returnServiceTemplate.setDataTypes(returnDataTypes);
 
+        LOGGER.debug("<-updateDataTypes: returnServiceTempalate={}", returnServiceTemplate);
         return returnServiceTemplate;
     }
 
+    /**
+     * Delete Data types.
+     *
+     * @param dao the DAO to use to access the database
+     * @param dataTypeKey the data type key for the Data types to be deleted, if the version of the key is null, all
+     *        versions of the data type are deleted.
+     * @return the TOSCA service template containing the data types that were deleted
+     * @throws PfModelException on errors deleting data types
+     */
+    public JpaToscaServiceTemplate deleteDataType(@NonNull final PfDao dao, @NonNull final PfConceptKey dataTypeKey)
+        throws PfModelException {
+        LOGGER.debug("->deleteDataType: key={}", dataTypeKey);
+
+        JpaToscaServiceTemplate serviceTemplate = getServiceTemplate(dao);
+
+        if (!ToscaUtils.doDataTypesExist(serviceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND, "no data types found");
+        }
+
+        JpaToscaDataType dataType4Deletion = serviceTemplate.getDataTypes().get(dataTypeKey);
+        if (dataType4Deletion == null) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND, DATA_TYPE + dataTypeKey.getId() + NOT_FOUND);
+        }
+
+        for (JpaToscaDataType dataType : serviceTemplate.getDataTypes().getAll(null)) {
+            if (dataType.getReferencedDataTypes().contains(dataTypeKey)) {
+                throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE,
+                    DATA_TYPE + dataTypeKey.getId() + " is in use, it is referenced in data type " + dataType.getId());
+            }
+        }
+
+        if (ToscaUtils.doPolicyTypesExist(serviceTemplate)) {
+            for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getAll(null)) {
+                if (policyType.getReferencedDataTypes().contains(dataTypeKey)) {
+                    throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, DATA_TYPE + dataTypeKey.getId()
+                        + " is in use, it is referenced in policy type " + policyType.getId());
+                }
+            }
+        }
+
+        dao.delete(JpaToscaDataType.class, dataTypeKey);
+
+        LOGGER.debug("<-deleteDataType: key={}, serviceTempalate={}", dataTypeKey, serviceTemplate);
+        return serviceTemplate;
+    }
+
+    /**
+     * Get policy types.
+     *
+     * @param dao the DAO to use to access the database
+     * @param name the name of the policy type to get, set to null to get all policy types
+     * @param version the version of the policy type to get, set to null to get all versions
+     * @return the policy types found
+     * @throws PfModelException on errors getting policy types
+     */
+    public JpaToscaServiceTemplate getPolicyTypes(@NonNull final PfDao dao, final String name, final String version)
+        throws PfModelException {
+        LOGGER.debug("->getPolicyTypes: name={}, version={}", name, version);
+
+        final JpaToscaServiceTemplate dbServiceTemplate = getServiceTemplate(dao);
+
+        if (!ToscaUtils.doPolicyTypesExist(dbServiceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
+                "policy types for " + name + ":" + version + DO_NOT_EXIST);
+        }
+
+        JpaToscaServiceTemplate serviceTemplate = getCascadedPolicyTypes(dbServiceTemplate, name, version);
+
+        LOGGER.debug("<-getPolicyTypes: name={}, version={}, serviceTemplate={}", name, version, serviceTemplate);
+        return serviceTemplate;
+    }
+
+    /**
+     * Get the cascaded policy types for a policy type name and version.
+     *
+     * @param dbServiceTemplate the service template to search for the cascaded policy types
+     * @param name the policy type name we are searching for
+     * @param version the policy type version we are searching for
+     * @return a service template containing the cascaded policy types
+     * @throws PfModelException on errors getting the policy types
+     */
+    public JpaToscaServiceTemplate getCascadedPolicyTypes(final JpaToscaServiceTemplate dbServiceTemplate,
+        final String name, final String version) throws PfModelException {
+
+        JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate(dbServiceTemplate);
+
+        serviceTemplate.setDataTypes(null);
+        serviceTemplate.setTopologyTemplate(null);
+
+        ToscaUtils.getEntityTree(serviceTemplate.getPolicyTypes(), name, version);
+
+        if (!ToscaUtils.doPolicyTypesExist(serviceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
+                "policy types for " + name + ":" + version + DO_NOT_EXIST);
+        }
+
+        JpaToscaServiceTemplate dataTypeServiceTemplate = new JpaToscaServiceTemplate(serviceTemplate);
+        dataTypeServiceTemplate.setPolicyTypes(null);
+
+        for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getConceptMap().values()) {
+            Collection<PfConceptKey> referencedDataTypeKeys = policyType.getReferencedDataTypes();
+
+            for (PfConceptKey referencedDataTypeKey : referencedDataTypeKeys) {
+                JpaToscaServiceTemplate dataTypeEntityTreeServiceTemplate = getCascadedDataTypes(dbServiceTemplate,
+                    referencedDataTypeKey.getName(), referencedDataTypeKey.getVersion());
+
+                dataTypeServiceTemplate =
+                    ToscaServiceTemplateUtils.addFragment(dataTypeServiceTemplate, dataTypeEntityTreeServiceTemplate);
+            }
+        }
+
+        serviceTemplate = ToscaServiceTemplateUtils.addFragment(serviceTemplate, dataTypeServiceTemplate);
+        return serviceTemplate;
+    }
+
     /**
      * Create policy types.
      *
      * @param dao the DAO to use to access the database
+     * @param incomingServiceTemplate the service template containing the definition of the policy types to be created
+     * @return the TOSCA service template containing the created policy types
+     * @throws PfModelException on errors creating policy types
+     */
+    public JpaToscaServiceTemplate createPolicyTypes(@NonNull final PfDao dao,
+        @NonNull final JpaToscaServiceTemplate incomingServiceTemplate) throws PfModelException {
+        LOGGER.debug("->createPolicyTypes: serviceTempalate={}", incomingServiceTemplate);
+
+        ToscaUtils.assertPolicyTypesExist(incomingServiceTemplate);
+
+        JpaToscaServiceTemplate writtenServiceTemplate = appendToServiceTemplate(dao, incomingServiceTemplate);
+
+        LOGGER.debug("<-createPolicyTypes: writtenServiceTemplate={}", writtenServiceTemplate);
+        return incomingServiceTemplate;
+    }
+
+    /**
+     * Update policy types.
+     *
+     * @param dao the DAO to use to access the database
      * @param serviceTemplate the service template containing the definition of the policy types to be modified
      * @return the TOSCA service template containing the modified policy types
      * @throws PfModelException on errors updating policy types
      */
     public JpaToscaServiceTemplate updatePolicyTypes(@NonNull final PfDao dao,
-            @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
+        @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
+        LOGGER.debug("->updatePolicyTypes: serviceTempalate={}", serviceTemplate);
 
         ToscaUtils.assertPolicyTypesExist(serviceTemplate);
 
+        // Update the data types on the policy type
+        if (ToscaUtils.doDataTypesExist(serviceTemplate)) {
+            updateDataTypes(dao, serviceTemplate);
+        }
+
         for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getAll(null)) {
             dao.update(policyType);
         }
@@ -131,6 +404,7 @@ public class SimpleToscaProvider {
         JpaToscaServiceTemplate returnServiceTemplate = new JpaToscaServiceTemplate();
         returnServiceTemplate.setPolicyTypes(returnPolicyTypes);
 
+        LOGGER.debug("<-updatePolicyTypes: returnServiceTempalate={}", returnServiceTemplate);
         return returnServiceTemplate;
     }
 
@@ -143,74 +417,135 @@ public class SimpleToscaProvider {
      * @return the TOSCA service template containing the policy types that were deleted
      * @throws PfModelException on errors deleting policy types
      */
-    public JpaToscaServiceTemplate deletePolicyType(@NonNull final PfDao dao,
-            @NonNull final PfConceptKey policyTypeKey)
-            throws PfModelException {
+    public JpaToscaServiceTemplate deletePolicyType(@NonNull final PfDao dao, @NonNull final PfConceptKey policyTypeKey)
+        throws PfModelException {
+        LOGGER.debug("->deletePolicyType: key={}", policyTypeKey);
 
-        JpaToscaServiceTemplate serviceTemplate = getPolicyTypes(dao, policyTypeKey);
+        JpaToscaServiceTemplate serviceTemplate = getServiceTemplate(dao);
+
+        if (!ToscaUtils.doPolicyTypesExist(serviceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND, "no policy types found");
+        }
+
+        JpaToscaEntityType<? extends ToscaEntity> policyType4Deletion =
+            serviceTemplate.getPolicyTypes().get(policyTypeKey);
+        if (policyType4Deletion == null) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
+                POLICY_TYPE + policyTypeKey.getId() + NOT_FOUND);
+        }
+
+        for (JpaToscaPolicyType policyType : serviceTemplate.getPolicyTypes().getAll(null)) {
+            Collection<JpaToscaEntityType<ToscaEntity>> ancestorList = ToscaUtils
+                .getEntityTypeAncestors(serviceTemplate.getPolicyTypes(), policyType, new PfValidationResult());
+
+            if (ancestorList.contains(policyType4Deletion)) {
+                throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, POLICY_TYPE + policyTypeKey.getId()
+                    + " is in use, it is referenced in policy type " + policyType.getId());
+            }
+        }
+
+        if (ToscaUtils.doPoliciesExist(serviceTemplate)) {
+            for (JpaToscaPolicy policy : serviceTemplate.getTopologyTemplate().getPolicies().getAll(null)) {
+                if (policyTypeKey.equals(policy.getType())) {
+                    throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, POLICY_TYPE
+                        + policyTypeKey.getId() + " is in use, it is referenced in policy " + policy.getId());
+                }
+            }
+        }
 
         dao.delete(JpaToscaPolicyType.class, policyTypeKey);
 
-        return serviceTemplate;
+        JpaToscaServiceTemplate deletedServiceTemplate = new JpaToscaServiceTemplate();
+        deletedServiceTemplate.setPolicyTypes(new JpaToscaPolicyTypes());
+        deletedServiceTemplate.getPolicyTypes().getConceptMap().put(policyTypeKey,
+            serviceTemplate.getPolicyTypes().getConceptMap().get(policyTypeKey));
+
+        LOGGER.debug("<-deletePolicyType: key={}, serviceTempalate={}", policyTypeKey, deletedServiceTemplate);
+        return deletedServiceTemplate;
     }
 
     /**
      * Get policies.
      *
      * @param dao the DAO to use to access the database
-     * @param policyKey the policy key for the policies to be retrieved. The parent name and version must be specified.
-     *        A null local name returns all policies for a parent policy type.
+     * @param name the name of the policy to get, set to null to get all policy types
+     * @param version the version of the policy to get, set to null to get all versions
      * @return the policies found
      * @throws PfModelException on errors getting policies
      */
-    public JpaToscaServiceTemplate getPolicies(@NonNull final PfDao dao, @NonNull final PfConceptKey policyKey)
-            throws PfModelException {
-
-        // Create the structure of the TOSCA service template to contain the policy type
-        JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate();
-        serviceTemplate.setTopologyTemplate(new JpaToscaTopologyTemplate());
-        serviceTemplate.getTopologyTemplate().setPolicies(new JpaToscaPolicies());
-
-        // Add the policy to the TOSCA service template
-        JpaToscaPolicy policy = dao.get(JpaToscaPolicy.class, policyKey);
-        if (policy != null) {
-            serviceTemplate.getTopologyTemplate().getPolicies().getConceptMap().put(policyKey, policy);
-            return serviceTemplate;
-        } else {
-            String errorMessage = "policy not found: " + policyKey.getId();
-            LOGGER.warn(errorMessage);
-            throw new PfModelRuntimeException(Response.Status.BAD_REQUEST, errorMessage);
+    public JpaToscaServiceTemplate getPolicies(@NonNull final PfDao dao, final String name, final String version)
+        throws PfModelException {
+        LOGGER.debug("->getPolicies: name={}, version={}", name, version);
+
+        JpaToscaServiceTemplate dbServiceTemplate = getServiceTemplate(dao);
+
+        if (!ToscaUtils.doPoliciesExist(dbServiceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
+                "policies for " + name + ":" + version + DO_NOT_EXIST);
         }
+
+        JpaToscaServiceTemplate returnServiceTemplate = getCascadedPolicies(dbServiceTemplate, name, version);
+
+        LOGGER.debug("<-getPolicies: name={}, version={}, serviceTemplate={}", name, version, returnServiceTemplate);
+        return returnServiceTemplate;
     }
 
     /**
-     * Create policies.
+     * Get the cascaded policies for a policy name and version.
      *
-     * @param dao the DAO to use to access the database
-     * @param serviceTemplate the service template containing the definitions of the new policies to be created.
-     * @return the TOSCA service template containing the policy types that were created
-     * @throws PfModelException on errors creating policies
+     * @param dbServiceTemplate the service template to search for the cascaded policy
+     * @param name the policy name we are searching for
+     * @param version the policy version we are searching for
+     * @return a service template containing the cascaded policy
+     * @throws PfModelException on errors getting the policy
      */
-    public JpaToscaServiceTemplate createPolicies(@NonNull final PfDao dao,
-            @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
+    public JpaToscaServiceTemplate getCascadedPolicies(final JpaToscaServiceTemplate dbServiceTemplate,
+        final String name, final String version) throws PfModelException {
 
-        ToscaUtils.assertPoliciesExist(serviceTemplate);
+        JpaToscaServiceTemplate serviceTemplate = new JpaToscaServiceTemplate(dbServiceTemplate);
+        serviceTemplate.setDataTypes(new JpaToscaDataTypes());
+        serviceTemplate.setPolicyTypes(new JpaToscaPolicyTypes());
 
-        for (JpaToscaPolicy policy : serviceTemplate.getTopologyTemplate().getPolicies().getAll(null)) {
-            dao.create(policy);
+        ToscaUtils.getEntityTree(serviceTemplate.getTopologyTemplate().getPolicies(), name, version);
+
+        if (!ToscaUtils.doPoliciesExist(serviceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND,
+                "policies for " + name + ":" + version + DO_NOT_EXIST);
         }
 
-        // Return the created policy types
-        JpaToscaPolicies returnPolicies = new JpaToscaPolicies();
-        returnPolicies.setKey(serviceTemplate.getTopologyTemplate().getPolicies().getKey());
+        JpaToscaServiceTemplate returnServiceTemplate = new JpaToscaServiceTemplate(serviceTemplate);
+        returnServiceTemplate.getTopologyTemplate().setPolicies(new JpaToscaPolicies());
 
-        for (PfConceptKey policyKey : serviceTemplate.getTopologyTemplate().getPolicies().getConceptMap().keySet()) {
-            returnPolicies.getConceptMap().put(policyKey, dao.get(JpaToscaPolicy.class, policyKey));
+        for (JpaToscaPolicy policy : serviceTemplate.getTopologyTemplate().getPolicies().getConceptMap().values()) {
+            JpaToscaServiceTemplate referencedEntitiesServiceTemplate =
+                getCascadedPolicyTypes(dbServiceTemplate, policy.getType().getName(), policy.getType().getVersion());
+
+            returnServiceTemplate.getTopologyTemplate().getPolicies().getConceptMap().put(policy.getKey(), policy);
+            returnServiceTemplate =
+                ToscaServiceTemplateUtils.addFragment(returnServiceTemplate, referencedEntitiesServiceTemplate);
         }
 
-        serviceTemplate.getTopologyTemplate().setPolicies(returnPolicies);
+        return returnServiceTemplate;
+    }
 
-        return serviceTemplate;
+    /**
+     * Create policies.
+     *
+     * @param dao the DAO to use to access the database
+     * @param incomingServiceTemplate the service template containing the definitions of the new policies to be created.
+     * @return the TOSCA service template containing the policy types that were created
+     * @throws PfModelException on errors creating policies
+     */
+    public JpaToscaServiceTemplate createPolicies(@NonNull final PfDao dao,
+        @NonNull final JpaToscaServiceTemplate incomingServiceTemplate) throws PfModelException {
+        LOGGER.debug("->createPolicies: incomingServiceTemplate={}", incomingServiceTemplate);
+
+        ToscaUtils.assertPoliciesExist(incomingServiceTemplate);
+
+        JpaToscaServiceTemplate writtenServiceTemplate = appendToServiceTemplate(dao, incomingServiceTemplate);
+
+        LOGGER.debug("<-createPolicies: writtenServiceTemplate={}", writtenServiceTemplate);
+        return incomingServiceTemplate;
     }
 
     /**
@@ -222,11 +557,13 @@ public class SimpleToscaProvider {
      * @throws PfModelException on errors updating policies
      */
     public JpaToscaServiceTemplate updatePolicies(@NonNull final PfDao dao,
-            @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
+        @NonNull final JpaToscaServiceTemplate serviceTemplate) throws PfModelException {
+        LOGGER.debug("->updatePolicies: serviceTempalate={}", serviceTemplate);
 
         ToscaUtils.assertPoliciesExist(serviceTemplate);
 
         for (JpaToscaPolicy policy : serviceTemplate.getTopologyTemplate().getPolicies().getAll(null)) {
+            verifyPolicyTypeForPolicy(dao, policy);
             dao.update(policy);
         }
 
@@ -240,6 +577,7 @@ public class SimpleToscaProvider {
 
         serviceTemplate.getTopologyTemplate().setPolicies(returnPolicies);
 
+        LOGGER.debug("<-updatePolicies: serviceTemplate={}", serviceTemplate);
         return serviceTemplate;
     }
 
@@ -252,12 +590,88 @@ public class SimpleToscaProvider {
      * @throws PfModelException on errors deleting policies
      */
     public JpaToscaServiceTemplate deletePolicy(@NonNull final PfDao dao, @NonNull final PfConceptKey policyKey)
-            throws PfModelException {
+        throws PfModelException {
+        LOGGER.debug("->deletePolicy: key={}", policyKey);
+
+        JpaToscaServiceTemplate serviceTemplate = getServiceTemplate(dao);
 
-        JpaToscaServiceTemplate serviceTemplate = getPolicies(dao, policyKey);
+        if (!ToscaUtils.doPoliciesExist(serviceTemplate)) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND, "no policies found");
+        }
+
+        JpaToscaPolicy policy4Deletion = serviceTemplate.getTopologyTemplate().getPolicies().get(policyKey);
+        if (policy4Deletion == null) {
+            throw new PfModelRuntimeException(Response.Status.NOT_FOUND, "policy " + policyKey.getId() + NOT_FOUND);
+        }
 
         dao.delete(JpaToscaPolicy.class, policyKey);
 
-        return serviceTemplate;
+        JpaToscaServiceTemplate deletedServiceTemplate = new JpaToscaServiceTemplate();
+        deletedServiceTemplate.setTopologyTemplate(new JpaToscaTopologyTemplate());
+        deletedServiceTemplate.getTopologyTemplate().setPolicies(new JpaToscaPolicies());
+        deletedServiceTemplate.getTopologyTemplate().getPolicies().getConceptMap().put(policyKey,
+            serviceTemplate.getTopologyTemplate().getPolicies().getConceptMap().get(policyKey));
+
+        LOGGER.debug("<-deletePolicy: key={}, serviceTempalate={}", policyKey, deletedServiceTemplate);
+        return deletedServiceTemplate;
+    }
+
+    /**
+     * Verify the policy type for a policy exists.
+     *
+     * @param dao the DAO to use to access policy types in the database
+     * @param policy the policy to check the policy type for
+     */
+    private void verifyPolicyTypeForPolicy(final PfDao dao, final JpaToscaPolicy policy) {
+        PfConceptKey policyTypeKey = policy.getType();
+
+        JpaToscaPolicyType policyType = null;
+
+        if (PfKey.NULL_KEY_VERSION.equals(policyTypeKey.getVersion())) {
+            policyType = getLatestPolicyTypeVersion(dao, policyTypeKey.getName());
+
+            if (policyType != null) {
+                policy.getType().setVersion(policyType.getKey().getVersion());
+            }
+        } else {
+            policyType = dao.get(JpaToscaPolicyType.class, policyTypeKey);
+        }
+
+        if (policyType == null) {
+            String errorMessage =
+                POLICY_TYPE + policyTypeKey.getId() + " for policy " + policy.getId() + " does not exist";
+            throw new PfModelRuntimeException(Response.Status.NOT_ACCEPTABLE, errorMessage);
+        }
+    }
+
+    /**
+     * Get the latest version of the policy type for the given policy type name.
+     *
+     * @param dao the DAO to use to access policy types in the database
+     * @param policyTypeName the name of the policy type
+     * @return the latest policy type
+     */
+    private JpaToscaPolicyType getLatestPolicyTypeVersion(final PfDao dao, final String policyTypeName) {
+        // Policy type version is not specified, get the latest version from the database
+        List<JpaToscaPolicyType> jpaPolicyTypeList = dao.getFiltered(JpaToscaPolicyType.class, policyTypeName, null);
+
+        if (CollectionUtils.isEmpty(jpaPolicyTypeList)) {
+            return null;
+        }
+
+        // Create a filter to get the latest version of the policy type
+        PfConceptFilter pfConceptFilter = PfConceptFilter.builder().version(PfConceptFilter.LATEST_VERSION).build();
+
+        // FIlter the returned policy type list
+        List<PfConcept> policyTypeKeyList = new ArrayList<>(jpaPolicyTypeList);
+        List<PfConcept> filterdPolicyTypeList = pfConceptFilter.filter(policyTypeKeyList);
+
+        // We should have one and only one returned entry
+        if (filterdPolicyTypeList.size() != 1) {
+            String errorMessage = "search for latest policy type " + policyTypeName + " returned more than one entry";
+            throw new PfModelRuntimeException(Response.Status.CONFLICT, errorMessage);
+        }
+
+        return (JpaToscaPolicyType) filterdPolicyTypeList.get(0);
     }
 }