2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2020-2023 Nordix Foundation.
7 * Modifications Copyright (C) 2020, 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
13 * http://www.apache.org/licenses/LICENSE-2.0
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 * ============LICENSE_END=========================================================
23 package org.onap.policy.pap.main.rest;
25 import jakarta.ws.rs.core.Response.Status;
26 import java.util.Collection;
27 import org.onap.policy.common.utils.services.Registry;
28 import org.onap.policy.models.base.PfModelException;
29 import org.onap.policy.models.base.PfModelRuntimeException;
30 import org.onap.policy.models.pap.concepts.PolicyNotification;
31 import org.onap.policy.models.pdp.concepts.Pdp;
32 import org.onap.policy.models.pdp.concepts.PdpGroup;
33 import org.onap.policy.models.pdp.concepts.PdpSubGroup;
34 import org.onap.policy.models.pdp.concepts.PdpUpdate;
35 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
36 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifierOptVersion;
37 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
38 import org.onap.policy.pap.main.PapConstants;
39 import org.onap.policy.pap.main.comm.PdpModifyRequestMap;
40 import org.onap.policy.pap.main.notification.PolicyNotifier;
41 import org.onap.policy.pap.main.service.PdpGroupService;
42 import org.onap.policy.pap.main.service.PolicyAuditService;
43 import org.onap.policy.pap.main.service.PolicyStatusService;
44 import org.onap.policy.pap.main.service.ToscaServiceTemplateService;
45 import org.springframework.beans.factory.annotation.Autowired;
46 import org.springframework.boot.context.event.ApplicationReadyEvent;
47 import org.springframework.context.event.EventListener;
50 * Super class of providers that deploy and undeploy PDP groups. The following items must
51 * be in the {@link Registry}:
53 * <li>PDP Modification Lock</li>
54 * <li>PDP Modify Request Map</li>
55 * <li>PAP DAO Factory</li>
58 public abstract class ProviderBase {
59 public static final String DEFAULT_USER = "PAP";
62 * Lock used when updating PDPs.
64 private Object updateLock;
67 * Used to send UPDATE and STATE-CHANGE requests to the PDPs.
69 private PdpModifyRequestMap requestMap;
72 * Generates policy notifications based on responses from PDPs.
74 private PolicyNotifier notifier;
76 private ToscaServiceTemplateService toscaService;
78 private PdpGroupService pdpGroupService;
80 private PolicyStatusService policyStatusService;
82 private PolicyAuditService policyAuditService;
85 * The setter method for injecting into Spring context.
87 * @param toscaService the toscaService to set
90 public final void setToscaService(ToscaServiceTemplateService toscaService) {
91 this.toscaService = toscaService;
95 * The setter method for injecting into Spring context.
97 * @param pdpGroupService the pdpGroupService to set
100 public final void setPdpGroupService(PdpGroupService pdpGroupService) {
101 this.pdpGroupService = pdpGroupService;
105 * The setter method for injecting into Spring context.
107 * @param policyStatusService the policyStatusService to set
110 public final void setPolicyStatusService(PolicyStatusService policyStatusService) {
111 this.policyStatusService = policyStatusService;
115 * The setter method for injecting into Spring context.
117 * @param policyAuditService the policyAuditService to set
120 public final void setPolicyAuditService(PolicyAuditService policyAuditService) {
121 this.policyAuditService = policyAuditService;
125 * The setter method for injecting into Spring context.
127 * @param policyNotifier the policyNotifier to set
130 public final void setPolicyNotifier(PolicyNotifier policyNotifier) {
131 this.notifier = policyNotifier;
135 * Initializes the parameters..
137 @EventListener(ApplicationReadyEvent.class)
138 public void initialize() {
139 this.updateLock = Registry.get(PapConstants.REG_PDP_MODIFY_LOCK, Object.class);
140 this.requestMap = Registry.get(PapConstants.REG_PDP_MODIFY_MAP, PdpModifyRequestMap.class);
144 * Processes a policy request.
146 * @param user user triggering request
147 * @param request PDP policy request
148 * @param processor function that processes the request
149 * @throws PfModelException if an error occurred
151 protected <T> void process(String user, T request, BiConsumerWithEx<SessionData, T> processor)
152 throws PfModelException {
154 synchronized (updateLock) {
156 var notif = new PolicyNotification();
160 data = new SessionData(user, toscaService, pdpGroupService, policyStatusService, policyAuditService);
161 processor.accept(data, request);
163 // make all of the DB updates
164 data.updateDb(notif);
166 } catch (PfModelRuntimeException e) {
169 } catch (RuntimeException e) {
170 throw new PfModelException(Status.INTERNAL_SERVER_ERROR, "request failed", e);
173 // publish the requests
174 data.getPdpRequests().forEach(pair -> requestMap.addRequest(pair.getLeft(), pair.getRight()));
176 // publish the notifications
177 notifier.publish(notif);
182 * Processes a policy request.
184 * @param request PDP policy request
185 * @param processor function that processes the request
186 * @throws PfModelException if an error occurred
188 protected <T> void process(T request, BiConsumerWithEx<SessionData, T> processor) throws PfModelException {
189 this.process(DEFAULT_USER, request, processor);
193 * Process a single policy from the request.
195 * @param data session data
196 * @param desiredPolicy request policy
197 * @throws PfModelException if an error occurred
199 protected void processPolicy(SessionData data, ToscaConceptIdentifierOptVersion desiredPolicy)
200 throws PfModelException {
202 ToscaPolicy policy = getPolicy(data, desiredPolicy);
204 Collection<PdpGroup> groups = getGroups(data, policy.getTypeIdentifier());
205 if (groups.isEmpty()) {
206 throw new PfModelException(Status.BAD_REQUEST, "policy not supported by any PDP group: "
207 + desiredPolicy.getName() + " " + desiredPolicy.getVersion());
210 var updater = makeUpdater(data, policy, desiredPolicy);
212 for (PdpGroup group : groups) {
213 upgradeGroup(data, group, updater);
218 * Makes a function to update a subgroup. The function is expected to return
219 * {@code true} if the subgroup was updated, {@code false} if no update was
220 * necessary/appropriate.
222 * @param data session data
223 * @param policy policy to be added to or removed from each subgroup
224 * @param desiredPolicy request policy
225 * @return a function to update a subgroup
227 protected abstract Updater makeUpdater(SessionData data, ToscaPolicy policy,
228 ToscaConceptIdentifierOptVersion desiredPolicy);
231 * Finds the active PDP group(s) that supports the given policy type.
233 * @param data session data
234 * @param policyType the policy type of interest
235 * @return the matching PDP group, or {@code null} if no active group supports the
238 private Collection<PdpGroup> getGroups(SessionData data, ToscaConceptIdentifier policyType) {
239 return data.getActivePdpGroupsByPolicyType(policyType);
243 * Updates a group, assigning a new version number, if it actually changes.
245 * @param data session data
246 * @param group the original group, to be updated
247 * @param updater function to update a group
248 * @throws PfModelException if an error occurred
250 private void upgradeGroup(SessionData data, PdpGroup group, Updater updater) throws PfModelException {
254 for (PdpSubGroup subgroup : group.getPdpSubgroups()) {
256 if (!updater.apply(group, subgroup)) {
262 makeUpdates(data, group, subgroup);
272 * Makes UPDATE messages for each PDP in a subgroup.
274 * @param data session data
275 * @param group group containing the subgroup
276 * @param subgroup subgroup whose PDPs should receive messages
278 protected void makeUpdates(SessionData data, PdpGroup group, PdpSubGroup subgroup) {
279 for (Pdp pdp : subgroup.getPdpInstances()) {
280 data.addUpdate(makeUpdate(data, group, subgroup, pdp));
285 * Makes an UPDATE message for a particular PDP.
287 * @param data session data
288 * @param group group to which the PDP should belong
289 * @param subgroup subgroup to which the PDP should belong
290 * @param pdp the PDP of interest
291 * @return a new UPDATE message
293 private PdpUpdate makeUpdate(SessionData data, PdpGroup group, PdpSubGroup subgroup, Pdp pdp) {
295 var update = new PdpUpdate();
297 update.setSource(PapConstants.PAP_NAME);
298 update.setName(pdp.getInstanceId());
299 update.setDescription(group.getDescription());
300 update.setPdpGroup(group.getName());
301 update.setPdpSubgroup(subgroup.getPdpType());
302 update.setPoliciesToBeDeployed(data.getPoliciesToBeDeployed());
303 update.setPoliciesToBeUndeployed(data.getPoliciesToBeUndeployed());
309 * Gets the specified policy.
311 * @param data session data
312 * @param ident policy identifier, with an optional version
313 * @return the policy of interest
314 * @throws PfModelRuntimeException if an error occurred or the policy was not found
316 private ToscaPolicy getPolicy(SessionData data, ToscaConceptIdentifierOptVersion ident) {
318 ToscaPolicy policy = data.getPolicy(ident);
319 if (policy == null) {
320 throw new PfModelRuntimeException(Status.NOT_FOUND,
321 "cannot find policy: " + ident.getName() + " " + ident.getVersion());
326 } catch (PfModelException e) {
327 throw new PfModelRuntimeException(e.getErrorResponse().getResponseCode(),
328 e.getErrorResponse().getErrorMessage(), e);
333 public interface BiConsumerWithEx<F, S> {
335 * Performs this operation on the given arguments.
337 * @param firstArg the first input argument
338 * @param secondArg the second input argument
339 * @throws PfModelException if an error occurred
341 void accept(F firstArg, S secondArg) throws PfModelException;
345 public interface Updater {
346 boolean apply(PdpGroup group, PdpSubGroup subgroup) throws PfModelException;