Added the new versioning validation for policy and policy type
[policy/api.git] / main / src / main / java / org / onap / policy / api / main / rest / provider / LegacyOperationalPolicyProvider.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP Policy API
4  * ================================================================================
5  * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  * SPDX-License-Identifier: Apache-2.0
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.api.main.rest.provider;
24
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Map;
28 import javax.ws.rs.core.Response;
29
30 import org.apache.commons.lang3.tuple.Pair;
31 import org.onap.policy.models.base.PfConceptKey;
32 import org.onap.policy.models.base.PfModelException;
33 import org.onap.policy.models.base.PfModelRuntimeException;
34 import org.onap.policy.models.pdp.concepts.PdpGroup;
35 import org.onap.policy.models.pdp.concepts.PdpGroupFilter;
36 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier;
37 import org.onap.policy.models.tosca.legacy.concepts.LegacyOperationalPolicy;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 /**
42  * Class to provide all kinds of legacy operational policy operations.
43  *
44  * @author Chenfei Gao (cgao@research.att.com)
45  */
46 public class LegacyOperationalPolicyProvider extends CommonModelProvider {
47
48     private static final Logger LOGGER = LoggerFactory.getLogger(LegacyOperationalPolicyProvider.class);
49
50     private static final String INVALID_POLICY_VERSION = "legacy policy version is not an integer";
51     private static final String LEGACY_MINOR_PATCH_SUFFIX = ".0.0";
52     private static final PfConceptKey LEGACY_OPERATIONAL_TYPE =
53             new PfConceptKey("onap.policies.controlloop.Operational", "1.0.0");
54
55     /**
56      * Default constructor.
57      */
58     public LegacyOperationalPolicyProvider() throws PfModelException {
59         super();
60     }
61
62     /**
63      * Retrieves a list of operational policies matching specified ID and version.
64      *
65      * @param policyId the ID of policy
66      * @param policyVersion the version of policy
67      *
68      * @return the LegacyOperationalPolicy object
69      */
70     public LegacyOperationalPolicy fetchOperationalPolicy(String policyId, String policyVersion)
71             throws PfModelException {
72
73         if (policyVersion != null) {
74             validNumber(policyVersion, INVALID_POLICY_VERSION);
75         }
76         return modelsProvider.getOperationalPolicy(policyId, policyVersion);
77     }
78
79     /**
80      * Retrieves a list of deployed operational policies in each pdp group.
81      *
82      * @param policyId the ID of the policy
83      *
84      * @return a list of deployed policies in each pdp group
85      *
86      * @throws PfModelException the PfModel parsing exception
87      */
88     public Map<Pair<String, String>, List<LegacyOperationalPolicy>> fetchDeployedOperationalPolicies(String policyId)
89             throws PfModelException {
90
91         return collectDeployedPolicies(
92                 policyId, LEGACY_OPERATIONAL_TYPE, modelsProvider::getOperationalPolicy, List::add, new ArrayList<>(5));
93     }
94
95     /**
96      * Creates a new operational policy.
97      *
98      * @param body the entity body of policy
99      *
100      * @return the LegacyOperationalPolicy object
101      */
102     public LegacyOperationalPolicy createOperationalPolicy(LegacyOperationalPolicy body) throws PfModelException {
103
104         validateOperationalPolicyVersion(body);
105         return modelsProvider.createOperationalPolicy(body);
106     }
107
108     /**
109      * Deletes the operational policies matching specified ID and version.
110      *
111      * @param policyId the ID of policy
112      * @param policyVersion the version of policy
113      *
114      * @return the LegacyOperationalPolicy object
115      */
116     public LegacyOperationalPolicy deleteOperationalPolicy(String policyId, String policyVersion)
117             throws PfModelException {
118
119         validNumber(policyVersion, INVALID_POLICY_VERSION);
120         validateDeleteEligibility(policyId, policyVersion);
121
122         return modelsProvider.deleteOperationalPolicy(policyId, policyVersion);
123     }
124
125     /**
126      * Validates whether specified policy can be deleted based on the rule that deployed policy cannot be deleted.
127      *
128      * @param policyId the ID of policy
129      * @param policyVersion the version of policy
130      *
131      * @throws PfModelException the PfModel parsing exception
132      */
133     private void validateDeleteEligibility(String policyId, String policyVersion) throws PfModelException {
134
135         List<ToscaPolicyIdentifier> policies = new ArrayList<>(5);
136         policies.add(new ToscaPolicyIdentifier(policyId, policyVersion + LEGACY_MINOR_PATCH_SUFFIX));
137         PdpGroupFilter pdpGroupFilter = PdpGroupFilter.builder().policyList(policies).build();
138
139         List<PdpGroup> pdpGroups = modelsProvider.getFilteredPdpGroups(pdpGroupFilter);
140
141         if (!pdpGroups.isEmpty()) {
142             throw new PfModelException(Response.Status.CONFLICT,
143                     constructDeletePolicyViolationMessage(policyId, policyVersion, pdpGroups));
144         }
145     }
146
147     /**
148      * Validates the specified version of the operational policy provided in the payload.
149      *
150      * @param body the operational policy payload
151      *
152      * @throws PfModelException on errors parsing PfModel
153      */
154     private void validateOperationalPolicyVersion(LegacyOperationalPolicy body) throws PfModelException {
155
156         validateOperationalPolicyVersionExist(body);
157         validateNoDuplicateVersionInDb(body);
158     }
159
160     /**
161      * Validates whether the version of the operational policy is specified in the payload.
162      *
163      * @param body the operational policy payload
164      *
165      * @throws PfModelException on errors parsing PfModel
166      */
167     private void validateOperationalPolicyVersionExist(LegacyOperationalPolicy body) throws PfModelException {
168
169         if (body.getPolicyVersion() == null) {
170             String errMsg = "mandatory field 'policy-version' is missing in the policy: " + body.getPolicyId();
171             throw new PfModelException(Response.Status.NOT_ACCEPTABLE, errMsg);
172         }
173     }
174
175     /**
176      * Validates that there is no duplicate version of the operational policy which is already stored in the database.
177      *
178      * @param body the operational policy payload
179      *
180      * @throws PfModelException on errors parsing PfModel
181      */
182     private void validateNoDuplicateVersionInDb(LegacyOperationalPolicy body) throws PfModelException {
183
184         try {
185             modelsProvider.getOperationalPolicy(body.getPolicyId(), body.getPolicyVersion());
186         } catch (PfModelRuntimeException exc) {
187             if (!hasSameOperationalPolicyFound(body, exc)) {
188                 return;
189             }
190             throw new PfModelException(exc.getErrorResponse().getResponseCode(), "unexpected runtime error", exc);
191         }
192
193         // There is one duplicate version stored in the DB.
194         // Try to get the latest version
195         LegacyOperationalPolicy latest = modelsProvider.getOperationalPolicy(body.getPolicyId(), null);
196         final String[] versionArray = latest.getPolicyVersion().split("\\.");
197         String errMsg = "operational policy " + body.getPolicyId() + ":" + body.getPolicyVersion()
198             + " already exists; its latest version is " + versionArray[0];
199         throw new PfModelException(Response.Status.NOT_ACCEPTABLE, errMsg);
200     }
201
202     /**
203      * Checks if the same operational policy found in the database.
204      *
205      * @param body the legacy operational policy payload
206      * @param exc the runtime exception thrown by policy model provider
207      *
208      * @return a boolean flag indicating the check result
209      */
210     private boolean hasSameOperationalPolicyFound(LegacyOperationalPolicy body, PfModelRuntimeException exc) {
211
212         if (exc.getErrorResponse().getResponseCode() == Response.Status.BAD_REQUEST
213                 && exc.getErrorResponse().getErrorMessage().contains("no policy found")) {
214             LOGGER.debug("no duplicate policy {}:{} found in the DB", body.getPolicyId(), body.getPolicyVersion());
215             return false;
216         }
217         return true;
218     }
219 }