Modify policy provider to support GET/CREATE
[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 {\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         close();\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         close();\r
119         return serviceTemplate;\r
120     }\r
121 \r
122     /**\r
123      * Retrieves a list of deployed policies in each pdp group.\r
124      *\r
125      * @param policyTypeId the ID of policy type\r
126      * @param policyTypeVersion the version of policy type\r
127      * @param policyId the ID of the policy\r
128      *\r
129      * @return a list of deployed policies in each pdp group\r
130      *\r
131      * @throws PfModelException the PfModel parsing exception\r
132      */\r
133     public Map<Pair<String, String>, List<ToscaPolicy>> fetchDeployedPolicies(\r
134             String policyTypeId, String policyTypeVersion, String policyId) throws PfModelException {\r
135 \r
136         List<ToscaPolicyTypeIdentifier> policyTypes = new ArrayList<>();\r
137         policyTypes.add(new ToscaPolicyTypeIdentifier(policyTypeId, policyTypeVersion));\r
138         PdpGroupFilter pdpGroupFilter = PdpGroupFilter.builder().policyTypeList(policyTypes).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 = constructDeployedPolicyMap(\r
147                 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         close();\r
154         return deployedPolicyMap;\r
155     }\r
156 \r
157     /**\r
158      * Creates a new policy for a policy type ID and version.\r
159      *\r
160      * @param policyTypeId the ID of policy type\r
161      * @param policyTypeVersion the version of policy type\r
162      * @param body the entity body of policy\r
163      *\r
164      * @return the ToscaServiceTemplate object\r
165      *\r
166      * @throws PfModelException the PfModel parsing exception\r
167      */\r
168     public ToscaServiceTemplate createPolicy(String policyTypeId, String policyTypeVersion,\r
169                                              ToscaServiceTemplate body) throws PfModelException {\r
170 \r
171         validatePolicyTypeExist(policyTypeId, policyTypeVersion);\r
172         validatePolicyTypeMatch(policyTypeId, policyTypeVersion, body);\r
173 \r
174         ToscaServiceTemplate serviceTemplate = modelsProvider.createPolicies(body);\r
175 \r
176         close();\r
177         return serviceTemplate;\r
178     }\r
179 \r
180     /**\r
181      * Deletes the policy matching specified ID and version of both policy type and policy.\r
182      *\r
183      * @param policyTypeId the ID of policy type\r
184      * @param policyTypeVersion the version of policy type\r
185      * @param policyId the ID of policy\r
186      * @param policyVersion the version of policy\r
187      *\r
188      * @return the ToscaServiceTemplate object\r
189      *\r
190      * @throws PfModelException the PfModel parsing exception\r
191      */\r
192     public ToscaServiceTemplate deletePolicy(String policyTypeId, String policyTypeVersion,\r
193                                  String policyId, String policyVersion) throws PfModelException {\r
194 \r
195         validateDeleteEligibility(policyTypeId, policyTypeVersion, policyId, policyVersion);\r
196 \r
197         ToscaServiceTemplate serviceTemplate = modelsProvider.deletePolicy(policyId, policyVersion);\r
198 \r
199         if (!hasPolicy(serviceTemplate)) {\r
200             throw new PfModelException(Response.Status.NOT_FOUND,\r
201                     constructResourceNotFoundMessage(policyTypeId, policyTypeVersion, policyId, policyVersion));\r
202         }\r
203 \r
204         close();\r
205         return serviceTemplate;\r
206     }\r
207 \r
208     /**\r
209      * Validates whether policy type exists.\r
210      *\r
211      * @param policyTypeId the ID of policy type\r
212      * @param policyTypeVersion the version of policy type\r
213      *\r
214      * @throws PfModelException the PfModel parsing exception\r
215      */\r
216     private void validatePolicyTypeExist(String policyTypeId, String policyTypeVersion) throws PfModelException {\r
217 \r
218         try {\r
219             modelsProvider.getPolicyTypes(policyTypeId, policyTypeVersion);\r
220         } catch (Exception e) {\r
221             throw new PfModelException(Response.Status.NOT_FOUND, "specified policy type does not exist", e);\r
222         }\r
223     }\r
224 \r
225     /**\r
226      * Validates the match between policy type specified in path and the one specified in type of policy.\r
227      *\r
228      * @param policyTypeId the ID of policy type\r
229      * @param policyTypeVersion the version of policy type\r
230      * @param serviceTemplate the ToscaServiceTemplate to validate\r
231      *\r
232      * @throws PfModelException the PfModel parsing exception\r
233      */\r
234     private void validatePolicyTypeMatch(String policyTypeId, String policyTypeVersion,\r
235             ToscaServiceTemplate serviceTemplate) throws PfModelException {\r
236 \r
237         List<Map<String, ToscaPolicy>> policies = serviceTemplate.getToscaTopologyTemplate().getPolicies();\r
238         for (Map<String, ToscaPolicy> policy : policies) {\r
239             if (policy.size() > 1) {\r
240                 throw new PfModelException(Response.Status.BAD_REQUEST,\r
241                         "one policy block contains more than one policies");\r
242             }\r
243             ToscaPolicy policyContent = policy.values().iterator().next();\r
244             if (!policyTypeId.equalsIgnoreCase(policyContent.getType())) {\r
245                 throw new PfModelException(Response.Status.BAD_REQUEST, "policy type id does not match");\r
246             }\r
247             if (policyContent.getTypeVersion() != null\r
248                     && !policyTypeVersion.equalsIgnoreCase(policyContent.getTypeVersion())) {\r
249                 throw new PfModelException(Response.Status.BAD_REQUEST, "policy type version does not match");\r
250             }\r
251         }\r
252     }\r
253 \r
254     /**\r
255      * Validates whether specified policy can be deleted based on the rule that deployed policy cannot be deleted.\r
256      *\r
257      * @param policyTypeId the ID of policy type\r
258      * @param policyTypeVersion the version of policy type\r
259      * @param policyId the ID of policy\r
260      * @param policyVersion the version of policy\r
261      *\r
262      * @throws PfModelException the PfModel parsing exception\r
263      */\r
264     private void validateDeleteEligibility(String policyTypeId, String policyTypeVersion,\r
265             String policyId, String policyVersion) throws PfModelException {\r
266 \r
267         List<ToscaPolicyTypeIdentifier> policyTypes = new ArrayList<>();\r
268         policyTypes.add(new ToscaPolicyTypeIdentifier(policyTypeId, policyTypeVersion));\r
269         List<ToscaPolicyIdentifier> policies = new ArrayList<>();\r
270         policies.add(new ToscaPolicyIdentifier(policyId, policyVersion));\r
271         PdpGroupFilter pdpGroupFilter = PdpGroupFilter.builder()\r
272                 .policyTypeList(policyTypes).policyList(policies).build();\r
273 \r
274         List<PdpGroup> pdpGroups = modelsProvider.getFilteredPdpGroups(pdpGroupFilter);\r
275 \r
276         if (!pdpGroups.isEmpty()) {\r
277             throw new PfModelException(Response.Status.CONFLICT, "the policy has been deployed in pdp group");\r
278         }\r
279     }\r
280 \r
281     private Map<Pair<String, String>, List<ToscaPolicy>> constructDeployedPolicyMap(\r
282             List<PdpGroup> pdpGroups, String policyId) throws PfModelException {\r
283 \r
284         Map<Pair<String, String>, List<ToscaPolicy>> deployedPolicyMap = new HashMap<>();\r
285         for (PdpGroup pdpGroup : pdpGroups) {\r
286             List<ToscaPolicyIdentifier> policyIdentifiers = new ArrayList<>();\r
287             for (PdpSubGroup pdpSubGroup : pdpGroup.getPdpSubgroups()) {\r
288                 for (ToscaPolicyIdentifier policyIdentifier : pdpSubGroup.getPolicies()) {\r
289                     if (policyId.equalsIgnoreCase(policyIdentifier.getName())) {\r
290                         policyIdentifiers.add(policyIdentifier);\r
291                     }\r
292                 }\r
293             }\r
294             List<ToscaPolicy> deployedPolicies = new ArrayList<>();\r
295             if (!policyIdentifiers.isEmpty()) {\r
296                 for (ToscaPolicyIdentifier policyIdentifier : policyIdentifiers) {\r
297                     deployedPolicies.addAll(\r
298                             modelsProvider.getPolicyList(policyIdentifier.getName(), policyIdentifier.getVersion()));\r
299                 }\r
300             }\r
301             if (!deployedPolicies.isEmpty()) {\r
302                 deployedPolicyMap.put(Pair.of(pdpGroup.getName(), pdpGroup.getVersion()), deployedPolicies);\r
303             }\r
304         }\r
305         return deployedPolicyMap;\r
306     }\r
307 \r
308     /**\r
309      * Constructs returned message for not found resource.\r
310      *\r
311      * @param policyTypeId the ID of policy type\r
312      * @param policyTypeVersion the version of policy type\r
313      * @param policyId the ID of policy\r
314      * @param policyVersion the version of policy\r
315      *\r
316      * @return constructed message\r
317      */\r
318     private String constructResourceNotFoundMessage(String policyTypeId, String policyTypeVersion,\r
319             String policyId, String policyVersion) {\r
320 \r
321         return "policy with ID " + policyId + ":" + policyVersion\r
322                 + " and type " + policyTypeId + ":" + policyTypeVersion + " does not exist";\r
323     }\r
324 \r
325     /**\r
326      * Constructs returned message for not found policy deployment.\r
327      *\r
328      * @param policyTypeId the ID of policy type\r
329      * @param policyTypeVersion the version of policy type\r
330      * @param policyId the ID of policy\r
331      * @param policyVersion the version of policy\r
332      *\r
333      * @return constructed message\r
334      */\r
335     private String constructDeploymentNotFoundMessage(String policyTypeId, String policyTypeVersion,\r
336             String policyId) {\r
337 \r
338         return "could not find policy with ID " + policyId + " and type "\r
339                 + policyTypeId + ":" + policyTypeVersion + " deployed in any pdp group";\r
340     }\r
341 \r
342     /**\r
343      * Checks if service template contains any policy.\r
344      *\r
345      * @param serviceTemplate the service template to check against\r
346      *\r
347      * @return boolean whether service template contains any policy\r
348      */\r
349     private boolean hasPolicy(ToscaServiceTemplate serviceTemplate) {\r
350 \r
351         if (serviceTemplate.getToscaTopologyTemplate().getPolicies() == null) {\r
352             return false;\r
353         } else if (serviceTemplate.getToscaTopologyTemplate().getPolicies().isEmpty()) {\r
354             return false;\r
355         } else if (serviceTemplate.getToscaTopologyTemplate().getPolicies().get(0).isEmpty()) {\r
356             return false;\r
357         } else {\r
358             return true;\r
359         }\r
360     }\r
361 \r
362     /**\r
363      * Closes the connection to database.\r
364      *\r
365      * @throws PfModelException the PfModel parsing exception\r
366      */\r
367     private void close() throws PfModelException {\r
368         try {\r
369             modelsProvider.close();\r
370         } catch (Exception e) {\r
371             throw new PfModelException(\r
372                     Response.Status.INTERNAL_SERVER_ERROR, "error closing connection to database", e);\r
373         }\r
374     }\r
375 }\r