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