8060ee7c49906ad7536bac63a81c8f783918ff72
[policy/api.git] / main / src / main / java / org / onap / policy / api / main / rest / provider / PolicyProvider.java
1 /*-\r
2  * ============LICENSE_START=======================================================\r
3  * ONAP Policy API\r
4  * ================================================================================\r
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.\r
6  * ================================================================================\r
7  * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * you may not use this file except in compliance with the License.\r
9  * You may obtain a copy of the License at\r
10  *\r
11  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  *\r
13  * Unless required by applicable law or agreed to in writing, software\r
14  * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * See the License for the specific language governing permissions and\r
17  * limitations under the License.\r
18  *\r
19  * SPDX-License-Identifier: Apache-2.0\r
20  * ============LICENSE_END=========================================================\r
21  */\r
22 \r
23 package org.onap.policy.api.main.rest.provider;\r
24 \r
25 import java.util.ArrayList;\r
26 import java.util.HashMap;\r
27 import java.util.List;\r
28 import java.util.Map;\r
29 import javax.ws.rs.core.Response;\r
30 import org.apache.commons.lang3.tuple.Pair;\r
31 import org.onap.policy.api.main.parameters.ApiParameterGroup;\r
32 import org.onap.policy.common.parameters.ParameterService;\r
33 import org.onap.policy.models.base.PfModelException;\r
34 import org.onap.policy.models.pdp.concepts.PdpGroup;\r
35 import org.onap.policy.models.pdp.concepts.PdpGroupFilter;\r
36 import org.onap.policy.models.pdp.concepts.PdpSubGroup;\r
37 import org.onap.policy.models.provider.PolicyModelsProvider;\r
38 import org.onap.policy.models.provider.PolicyModelsProviderFactory;\r
39 import org.onap.policy.models.provider.PolicyModelsProviderParameters;\r
40 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;\r
41 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyFilter;\r
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;\r
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;\r
44 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;\r
45 \r
46 /**\r
47  * Class to provide all kinds of policy operations.\r
48  *\r
49  * @author Chenfei Gao (cgao@research.att.com)\r
50  */\r
51 public class PolicyProvider implements AutoCloseable {\r
52 \r
53     private PolicyModelsProvider modelsProvider;\r
54 \r
55     /**\r
56      * Default constructor.\r
57      */\r
58     public PolicyProvider() throws PfModelException {\r
59 \r
60         ApiParameterGroup parameterGroup = ParameterService.get("ApiGroup");\r
61         PolicyModelsProviderParameters providerParameters = parameterGroup.getDatabaseProviderParameters();\r
62         modelsProvider = new PolicyModelsProviderFactory().createPolicyModelsProvider(providerParameters);\r
63     }\r
64 \r
65     /**\r
66      * Retrieves a list of policies matching specified ID and version of both policy type and policy.\r
67      *\r
68      * @param policyTypeId the ID of policy type\r
69      * @param policyTypeVersion the version of policy type\r
70      * @param policyId the ID of policy\r
71      * @param policyVersion the version of policy\r
72      *\r
73      * @return the ToscaServiceTemplate object\r
74      *\r
75      * @throws PfModelException the PfModel parsing exception\r
76      */\r
77     public ToscaServiceTemplate fetchPolicies(String policyTypeId, String policyTypeVersion,\r
78             String policyId, String policyVersion) throws PfModelException {\r
79 \r
80         ToscaPolicyFilter policyFilter = ToscaPolicyFilter.builder()\r
81                 .name(policyId).version(policyVersion)\r
82                 .type(policyTypeId).typeVersion(policyTypeVersion).build();\r
83         ToscaServiceTemplate serviceTemplate = modelsProvider.getFilteredPolicies(policyFilter);\r
84 \r
85         if (!hasPolicy(serviceTemplate)) {\r
86             throw new PfModelException(Response.Status.NOT_FOUND,\r
87                     constructResourceNotFoundMessage(policyTypeId, policyTypeVersion, policyId, policyVersion));\r
88         }\r
89 \r
90         return serviceTemplate;\r
91     }\r
92 \r
93     /**\r
94      * Retrieves a list of policies with the latest versions that match specified policy type id and version.\r
95      *\r
96      * @param policyTypeId the ID of policy type\r
97      * @param policyTypeVersion the version of policy type\r
98      * @param policyId the ID of the policy\r
99      *\r
100      * @return the ToscaServiceTemplate object\r
101      *\r
102      * @throws PfModelException the PfModel parsing exception\r
103      */\r
104     public ToscaServiceTemplate fetchLatestPolicies(String policyTypeId, String policyTypeVersion,\r
105             String policyId) throws PfModelException {\r
106 \r
107         ToscaPolicyFilter policyFilter = ToscaPolicyFilter.builder()\r
108                 .name(policyId).version(ToscaPolicyFilter.LATEST_VERSION)\r
109                 .type(policyTypeId).typeVersion(policyTypeVersion).build();\r
110         ToscaServiceTemplate serviceTemplate = modelsProvider.getFilteredPolicies(policyFilter);\r
111 \r
112         if (!hasPolicy(serviceTemplate)) {\r
113             throw new PfModelException(Response.Status.NOT_FOUND,\r
114                     constructResourceNotFoundMessage(policyTypeId, policyTypeVersion, policyId, null));\r
115         }\r
116 \r
117         return serviceTemplate;\r
118     }\r
119 \r
120     /**\r
121      * Retrieves a list of deployed policies in each pdp group.\r
122      *\r
123      * @param policyTypeId the ID of policy type\r
124      * @param policyTypeVersion the version of policy type\r
125      * @param policyId the ID of the policy\r
126      *\r
127      * @return a list of deployed policies in each pdp group\r
128      *\r
129      * @throws PfModelException the PfModel parsing exception\r
130      */\r
131     public Map<Pair<String, String>, List<ToscaPolicy>> fetchDeployedPolicies(\r
132             String policyTypeId, String policyTypeVersion, String policyId) throws PfModelException {\r
133 \r
134         List<ToscaPolicyTypeIdentifier> policyTypes = new ArrayList<>();\r
135         policyTypes.add(new ToscaPolicyTypeIdentifier(policyTypeId, policyTypeVersion));\r
136         PdpGroupFilter pdpGroupFilter = PdpGroupFilter.builder().policyTypeList(policyTypes).build();\r
137         List<PdpGroup> pdpGroups = modelsProvider.getFilteredPdpGroups(pdpGroupFilter);\r
138 \r
139         if (pdpGroups.isEmpty()) {\r
140             throw new PfModelException(Response.Status.NOT_FOUND,\r
141                     constructDeploymentNotFoundMessage(policyTypeId, policyTypeVersion, policyId));\r
142         }\r
143 \r
144         Map<Pair<String, String>, List<ToscaPolicy>> deployedPolicyMap =\r
145                 constructDeployedPolicyMap(pdpGroups, policyId);\r
146         if (deployedPolicyMap.isEmpty()) {\r
147             throw new PfModelException(Response.Status.NOT_FOUND,\r
148                     constructDeploymentNotFoundMessage(policyTypeId, policyTypeVersion, policyId));\r
149         }\r
150 \r
151         return deployedPolicyMap;\r
152     }\r
153 \r
154     /**\r
155      * Creates a new policy for a policy type ID and version.\r
156      *\r
157      * @param policyTypeId the ID of policy type\r
158      * @param policyTypeVersion the version of policy type\r
159      * @param body the entity body of policy\r
160      *\r
161      * @return the ToscaServiceTemplate object\r
162      *\r
163      * @throws PfModelException the PfModel parsing exception\r
164      */\r
165     public ToscaServiceTemplate createPolicy(String policyTypeId, String policyTypeVersion,\r
166                                              ToscaServiceTemplate body) throws PfModelException {\r
167 \r
168         validatePolicyTypeExist(policyTypeId, policyTypeVersion);\r
169         validatePolicyTypeMatch(policyTypeId, policyTypeVersion, body);\r
170 \r
171         return modelsProvider.createPolicies(body);\r
172     }\r
173 \r
174     /**\r
175      * Deletes the policy matching specified ID and version of both policy type and policy.\r
176      *\r
177      * @param policyTypeId the ID of policy type\r
178      * @param policyTypeVersion the version of policy type\r
179      * @param policyId the ID of policy\r
180      * @param policyVersion the version of policy\r
181      *\r
182      * @return the ToscaServiceTemplate object\r
183      *\r
184      * @throws PfModelException the PfModel parsing exception\r
185      */\r
186     public ToscaServiceTemplate deletePolicy(String policyTypeId, String policyTypeVersion,\r
187                                  String policyId, String policyVersion) throws PfModelException {\r
188 \r
189         validateDeleteEligibility(policyTypeId, policyTypeVersion, policyId, policyVersion);\r
190 \r
191         ToscaServiceTemplate serviceTemplate = modelsProvider.deletePolicy(policyId, policyVersion);\r
192 \r
193         if (!hasPolicy(serviceTemplate)) {\r
194             throw new PfModelException(Response.Status.NOT_FOUND,\r
195                     constructResourceNotFoundMessage(policyTypeId, policyTypeVersion, policyId, policyVersion));\r
196         }\r
197 \r
198         return serviceTemplate;\r
199     }\r
200 \r
201     /**\r
202      * Validates whether policy type exists.\r
203      *\r
204      * @param policyTypeId the ID of policy type\r
205      * @param policyTypeVersion the version of policy type\r
206      *\r
207      * @throws PfModelException the PfModel parsing exception\r
208      */\r
209     private void validatePolicyTypeExist(String policyTypeId, String policyTypeVersion) throws PfModelException {\r
210 \r
211         ToscaServiceTemplate serviceTemplate = modelsProvider.getPolicyTypes(policyTypeId, policyTypeVersion);\r
212         if (!hasPolicyType(serviceTemplate)) {\r
213             throw new PfModelException(Response.Status.NOT_FOUND,\r
214                     "policy type with ID " + policyTypeId + ":" + policyTypeVersion + " does not exist");\r
215         }\r
216     }\r
217 \r
218     /**\r
219      * Validates the match between policy type specified in path and the one specified in type of policy.\r
220      *\r
221      * @param policyTypeId the ID of policy type\r
222      * @param policyTypeVersion the version of policy type\r
223      * @param serviceTemplate the ToscaServiceTemplate to validate\r
224      *\r
225      * @throws PfModelException the PfModel parsing exception\r
226      */\r
227     private void validatePolicyTypeMatch(String policyTypeId, String policyTypeVersion,\r
228             ToscaServiceTemplate serviceTemplate) throws PfModelException {\r
229 \r
230         List<Map<String, ToscaPolicy>> policies = serviceTemplate.getToscaTopologyTemplate().getPolicies();\r
231         for (Map<String, ToscaPolicy> policy : policies) {\r
232             if (policy.size() > 1) {\r
233                 throw new PfModelException(Response.Status.BAD_REQUEST,\r
234                         "one policy block contains more than one policies");\r
235             }\r
236             ToscaPolicy policyContent = policy.values().iterator().next();\r
237             if (!policyTypeId.equalsIgnoreCase(policyContent.getType())) {\r
238                 throw new PfModelException(Response.Status.BAD_REQUEST, "policy type id does not match");\r
239             }\r
240             if (policyContent.getTypeVersion() != null\r
241                     && !policyTypeVersion.equalsIgnoreCase(policyContent.getTypeVersion())) {\r
242                 throw new PfModelException(Response.Status.BAD_REQUEST, "policy type version does not match");\r
243             }\r
244         }\r
245     }\r
246 \r
247     /**\r
248      * Validates whether specified policy can be deleted based on the rule that deployed policy cannot be deleted.\r
249      *\r
250      * @param policyTypeId the ID of policy type\r
251      * @param policyTypeVersion the version of policy type\r
252      * @param policyId the ID of policy\r
253      * @param policyVersion the version of policy\r
254      *\r
255      * @throws PfModelException the PfModel parsing exception\r
256      */\r
257     private void validateDeleteEligibility(String policyTypeId, String policyTypeVersion,\r
258             String policyId, String policyVersion) throws PfModelException {\r
259 \r
260         List<ToscaPolicyTypeIdentifier> policyTypes = new ArrayList<>();\r
261         policyTypes.add(new ToscaPolicyTypeIdentifier(policyTypeId, policyTypeVersion));\r
262         List<ToscaPolicyIdentifier> policies = new ArrayList<>();\r
263         policies.add(new ToscaPolicyIdentifier(policyId, policyVersion));\r
264         PdpGroupFilter pdpGroupFilter = PdpGroupFilter.builder()\r
265                 .policyTypeList(policyTypes).policyList(policies).build();\r
266 \r
267         List<PdpGroup> pdpGroups = modelsProvider.getFilteredPdpGroups(pdpGroupFilter);\r
268 \r
269         if (!pdpGroups.isEmpty()) {\r
270             throw new PfModelException(Response.Status.CONFLICT,\r
271                     constructDeleteRuleViolationMessage(policyId, policyVersion, pdpGroups));\r
272         }\r
273     }\r
274 \r
275     /**\r
276      * Constructs returned message for policy delete rule violation.\r
277      *\r
278      * @param policyId the ID of policy\r
279      * @param policyVersion the version of policy\r
280      * @param pdpGroups the list of pdp groups\r
281      *\r
282      * @return the constructed message\r
283      */\r
284     private String constructDeleteRuleViolationMessage(\r
285             String policyId, String policyVersion, List<PdpGroup> pdpGroups) {\r
286 \r
287         List<String> pdpGroupNameVersionList = new ArrayList<>();\r
288         for (PdpGroup pdpGroup : pdpGroups) {\r
289             pdpGroupNameVersionList.add(pdpGroup.getName() + ":" + pdpGroup.getVersion());\r
290         }\r
291         String deployedPdpGroups = String.join(",", pdpGroupNameVersionList);\r
292         return "policy with ID " + policyId + ":" + policyVersion\r
293                 + " cannot be deleted as it is deployed in pdp groups " + deployedPdpGroups;\r
294     }\r
295 \r
296     /**\r
297      * Constructs the map of deployed pdp groups and deployed policies.\r
298      *\r
299      * @param pdpGroups the list of pdp groups that contain the specified policy\r
300      * @param policyId the ID of policy\r
301      *\r
302      * @return the constructed map of pdp groups and deployed policies\r
303      *\r
304      * @throws PfModelException the PfModel parsing exception\r
305      */\r
306     private Map<Pair<String, String>, List<ToscaPolicy>> constructDeployedPolicyMap(\r
307             List<PdpGroup> pdpGroups, String policyId) throws PfModelException {\r
308 \r
309         Map<Pair<String, String>, List<ToscaPolicy>> deployedPolicyMap = new HashMap<>();\r
310         for (PdpGroup pdpGroup : pdpGroups) {\r
311             List<ToscaPolicyIdentifier> policyIdentifiers = new ArrayList<>();\r
312             for (PdpSubGroup pdpSubGroup : pdpGroup.getPdpSubgroups()) {\r
313                 for (ToscaPolicyIdentifier policyIdentifier : pdpSubGroup.getPolicies()) {\r
314                     if (policyId.equalsIgnoreCase(policyIdentifier.getName())) {\r
315                         policyIdentifiers.add(policyIdentifier);\r
316                     }\r
317                 }\r
318             }\r
319             List<ToscaPolicy> deployedPolicies = new ArrayList<>();\r
320             if (!policyIdentifiers.isEmpty()) {\r
321                 for (ToscaPolicyIdentifier policyIdentifier : policyIdentifiers) {\r
322                     deployedPolicies.addAll(\r
323                             modelsProvider.getPolicyList(policyIdentifier.getName(), policyIdentifier.getVersion()));\r
324                 }\r
325             }\r
326             if (!deployedPolicies.isEmpty()) {\r
327                 deployedPolicyMap.put(Pair.of(pdpGroup.getName(), pdpGroup.getVersion()), deployedPolicies);\r
328             }\r
329         }\r
330         return deployedPolicyMap;\r
331     }\r
332 \r
333     /**\r
334      * Constructs returned message for not found resource.\r
335      *\r
336      * @param policyTypeId the ID of policy type\r
337      * @param policyTypeVersion the version of policy type\r
338      * @param policyId the ID of policy\r
339      * @param policyVersion the version of policy\r
340      *\r
341      * @return constructed message\r
342      */\r
343     private String constructResourceNotFoundMessage(String policyTypeId, String policyTypeVersion,\r
344             String policyId, String policyVersion) {\r
345 \r
346         return "policy with ID " + policyId + ":" + policyVersion\r
347                 + " and type " + policyTypeId + ":" + policyTypeVersion + " does not exist";\r
348     }\r
349 \r
350     /**\r
351      * Constructs returned message for not found policy deployment.\r
352      *\r
353      * @param policyTypeId the ID of policy type\r
354      * @param policyTypeVersion the version of policy type\r
355      * @param policyId the ID of policy\r
356      * @param policyVersion the version of policy\r
357      *\r
358      * @return constructed message\r
359      */\r
360     private String constructDeploymentNotFoundMessage(String policyTypeId, String policyTypeVersion,\r
361             String policyId) {\r
362 \r
363         return "could not find policy with ID " + policyId + " and type "\r
364                 + policyTypeId + ":" + policyTypeVersion + " deployed in any pdp group";\r
365     }\r
366 \r
367     /**\r
368      * Checks if service template contains any policy.\r
369      *\r
370      * @param serviceTemplate the service template to check against\r
371      *\r
372      * @return boolean whether service template contains any policy\r
373      */\r
374     private boolean hasPolicy(ToscaServiceTemplate serviceTemplate) {\r
375 \r
376         if (serviceTemplate.getToscaTopologyTemplate().getPolicies() == null) {\r
377             return false;\r
378         } else if (serviceTemplate.getToscaTopologyTemplate().getPolicies().isEmpty()) {\r
379             return false;\r
380         } else if (serviceTemplate.getToscaTopologyTemplate().getPolicies().get(0).isEmpty()) {\r
381             return false;\r
382         } else {\r
383             return true;\r
384         }\r
385     }\r
386 \r
387     /**\r
388      * Checks if service template contains any policy type.\r
389      *\r
390      * @param serviceTemplate the service template to check against\r
391      *\r
392      * @return boolean whether service template contains any policy type\r
393      */\r
394     private boolean hasPolicyType(ToscaServiceTemplate serviceTemplate) {\r
395 \r
396         if (serviceTemplate.getPolicyTypes() == null) {\r
397             return false;\r
398         } else if (serviceTemplate.getPolicyTypes().isEmpty()) {\r
399             return false;\r
400         } else if (serviceTemplate.getPolicyTypes().get(0).isEmpty()) {\r
401             return false;\r
402         } else {\r
403             return true;\r
404         }\r
405     }\r
406 \r
407     /**\r
408      * Closes the connection to database.\r
409      *\r
410      * @throws PfModelException the PfModel parsing exception\r
411      */\r
412     @Override\r
413     public void close() throws PfModelException {\r
414 \r
415         modelsProvider.close();\r
416     }\r
417 }\r