87a53896b165704ef6b9ac95c9d59f9c76762ed4
[policy/api.git] / main / src / main / java / org / onap / policy / api / main / startstop / ApiDatabaseInitializer.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP Policy API
4  * ================================================================================
5  * Copyright (C) 2019-2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019-2021 Nordix Foundation.
7  * Modifications Copyright (C) 2022 Bell Canada. All rights reserved.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * SPDX-License-Identifier: Apache-2.0
22  * ============LICENSE_END=========================================================
23  */
24
25 package org.onap.policy.api.main.startstop;
26
27 import java.util.LinkedHashMap;
28 import java.util.LinkedList;
29 import java.util.List;
30 import javax.annotation.PostConstruct;
31 import lombok.RequiredArgsConstructor;
32 import org.onap.policy.api.main.config.PolicyPreloadConfig;
33 import org.onap.policy.api.main.exception.PolicyApiException;
34 import org.onap.policy.api.main.service.ToscaServiceTemplateService;
35 import org.onap.policy.common.utils.coder.CoderException;
36 import org.onap.policy.common.utils.coder.StandardYamlCoder;
37 import org.onap.policy.common.utils.resources.ResourceUtils;
38 import org.onap.policy.models.base.PfModelException;
39 import org.onap.policy.models.base.PfModelRuntimeException;
40 import org.onap.policy.models.tosca.authorative.concepts.ToscaEntityFilter;
41 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyType;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaTopologyTemplate;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
47 import org.springframework.stereotype.Component;
48
49 /**
50  * This class creates initial policy types in the database.
51  *
52  * @author Chenfei Gao (cgao@research.att.com)
53  */
54 @Component
55 @ConditionalOnProperty(value = "database.initialize", havingValue = "true", matchIfMissing = true)
56 @RequiredArgsConstructor
57 public class ApiDatabaseInitializer {
58
59     private static final Logger LOGGER = LoggerFactory.getLogger(ApiDatabaseInitializer.class);
60     private static final StandardYamlCoder coder = new StandardYamlCoder();
61
62     private final ToscaServiceTemplateService toscaServiceTemplateService;
63     private final PolicyPreloadConfig policyPreloadConfig;
64
65     @PostConstruct
66     public void loadData() throws PolicyApiException {
67         initializeApiDatabase(policyPreloadConfig.getPolicyTypes(), policyPreloadConfig.getPolicies());
68     }
69
70     /**
71      * Initializes database by preloading policy types and policies.
72      *
73      * @param policyTypes List of policy types to preload.
74      * @param policies List of policies to preload.
75      * @throws PolicyApiException in case of errors.
76      */
77     public void initializeApiDatabase(final List<String> policyTypes, final List<String> policies)
78         throws PolicyApiException {
79         try {
80             if (alreadyExists()) {
81                 LOGGER.warn("DB already contains policy data - skipping preload");
82                 return;
83             }
84
85             var serviceTemplate = new ToscaServiceTemplate();
86             serviceTemplate.setDataTypes(new LinkedHashMap<>());
87             serviceTemplate.setPolicyTypes(new LinkedHashMap<>());
88             serviceTemplate.setToscaDefinitionsVersion("tosca_simple_yaml_1_1_0");
89
90             ToscaServiceTemplate createdPolicyTypes =
91                 preloadServiceTemplate(serviceTemplate, policyTypes, toscaServiceTemplateService::createPolicyType);
92             preloadServiceTemplate(createdPolicyTypes, policies, toscaServiceTemplateService::createPolicies);
93         } catch (final PolicyApiException | PfModelException | CoderException exp) {
94             throw new PolicyApiException(exp);
95         }
96     }
97
98     private boolean alreadyExists() throws PfModelException {
99         try {
100             ToscaServiceTemplate serviceTemplate = toscaServiceTemplateService
101                 .getFilteredPolicyTypes(ToscaEntityFilter.<ToscaPolicyType>builder().build());
102             if (!serviceTemplate.getPolicyTypes().isEmpty()) {
103                 return true;
104             }
105         } catch (PfModelRuntimeException e) {
106             LOGGER.trace("DB does not yet contain policy types", e);
107         }
108         return false;
109     }
110
111     private ToscaServiceTemplate preloadServiceTemplate(ToscaServiceTemplate serviceTemplate, List<String> entities,
112             FunctionWithEx<ToscaServiceTemplate, ToscaServiceTemplate> getter)
113             throws PolicyApiException, CoderException, PfModelException {
114
115         for (String entity : entities) {
116             var entityAsStringYaml = ResourceUtils.getResourceAsString(entity);
117             if (entityAsStringYaml == null) {
118                 LOGGER.warn("Preloading entity cannot be found: {}", entity);
119                 continue;
120             }
121
122             ToscaServiceTemplate singleEntity = coder.decode(entityAsStringYaml, ToscaServiceTemplate.class);
123             if (singleEntity == null) {
124                 throw new PolicyApiException("Error deserializing entity from file: " + entity);
125             }
126
127             // Consolidate data types and policy types
128             if (singleEntity.getDataTypes() != null) {
129                 serviceTemplate.getDataTypes().putAll(singleEntity.getDataTypes());
130             }
131             if (singleEntity.getPolicyTypes() != null) {
132                 serviceTemplate.getPolicyTypes().putAll(singleEntity.getPolicyTypes());
133             }
134
135             // Consolidate policies
136             var topologyTemplate = singleEntity.getToscaTopologyTemplate();
137             if (topologyTemplate != null && topologyTemplate.getPolicies() != null) {
138                 serviceTemplate.setToscaTopologyTemplate(new ToscaTopologyTemplate());
139                 serviceTemplate.getToscaTopologyTemplate().setPolicies(new LinkedList<>());
140                 serviceTemplate.getToscaTopologyTemplate().getPolicies()
141                         .addAll(singleEntity.getToscaTopologyTemplate().getPolicies());
142             }
143         }
144         // Preload the specified entities
145         ToscaServiceTemplate createdServiceTemplate = getter.apply(serviceTemplate);
146         LOGGER.debug("Created initial tosca service template in DB - {}", createdServiceTemplate);
147         return createdServiceTemplate;
148     }
149
150     @FunctionalInterface
151     protected interface FunctionWithEx<T, R> {
152         public R apply(T value) throws PfModelException;
153     }
154 }