2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2021 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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * ============LICENSE_END=========================================================
21 package org.onap.policy.pap.main.notification;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
27 import java.util.Map.Entry;
28 import org.onap.policy.models.pap.concepts.PolicyNotification;
29 import org.onap.policy.models.pap.concepts.PolicyStatus;
30 import org.onap.policy.models.pdp.concepts.PdpPolicyStatus;
31 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
34 * Tracks policy status so that notifications can be generated.
36 public class DeploymentTracker {
37 public final Map<ToscaConceptIdentifier, PolicyStatus> deployMap = new HashMap<>();
38 public final Map<ToscaConceptIdentifier, PolicyStatus> undeployMap = new HashMap<>();
42 * Gets the status of all deployments.
44 * @return the status of all deployments
46 public Collection<PolicyStatus> getDeploymentStatus() {
47 return deployMap.values();
51 * Gets the status of all undeployments.
53 * @return the status of all undeployments
55 public Collection<PolicyStatus> getUndeploymentStatus() {
56 return undeployMap.values();
60 * Compares this tracking data with new tracking data, adding new policy status to a
61 * notification based on the differences.
63 * @param notif notification to which to add policy status
64 * @param newTracker new tracking data
66 public void addNotifications(PolicyNotification notif, DeploymentTracker newTracker) {
67 merge(notif.getAdded(), deployMap, newTracker.deployMap);
68 merge(notif.getDeleted(), undeployMap, newTracker.undeployMap);
70 // include those that no longer exist
71 addMissing(notif, newTracker);
75 * Merges original tracking data with new tracking data, adding new policy status to
78 * @param list list to which to add policy status
79 * @param originalMap original tracking data
80 * @param newMap new tracking data
82 private void merge(List<PolicyStatus> list, Map<ToscaConceptIdentifier, PolicyStatus> originalMap,
83 Map<ToscaConceptIdentifier, PolicyStatus> newMap) {
85 for (Entry<ToscaConceptIdentifier, PolicyStatus> entry : newMap.entrySet()) {
86 ToscaConceptIdentifier policy = entry.getKey();
87 PolicyStatus newStat = entry.getValue();
88 PolicyStatus oldStat = originalMap.get(policy);
90 if (needNotification(oldStat, newStat)) {
97 * Determines if a notification is needed.
99 * @param oldStat original status, or {@code null}
100 * @param newStat new status
101 * @return {@code true} if a notification is needed for the policy, {@code false}
104 protected boolean needNotification(PolicyStatus oldStat, PolicyStatus newStat) {
105 if (oldStat == null) {
106 // new policy - need notification if it's complete now
107 return (newStat.getIncompleteCount() == 0);
110 if (newStat.getIncompleteCount() == 0) {
111 // don't care if the success count changes (i.e., new PDPs can be added
112 // without requiring a notification)
113 return (oldStat.getIncompleteCount() > 0 || newStat.getFailureCount() != oldStat.getFailureCount());
116 // something is incomplete - only notify if it was previously complete
117 return (oldStat.getIncompleteCount() == 0);
121 * Adds notifications for previously deployed policies that are missing from the new
124 * @param notif notification to which to add policy status
125 * @param newTracker new tracking data
127 private void addMissing(PolicyNotification notif, DeploymentTracker newTracker) {
128 Map<ToscaConceptIdentifier, PolicyStatus> newDeployMap = newTracker.deployMap;
130 for (Entry<ToscaConceptIdentifier, PolicyStatus> entry : deployMap.entrySet()) {
131 if (entry.getValue().getIncompleteCount() != 0 || newDeployMap.containsKey(entry.getKey())) {
133 * This policy deployment was previously incomplete, or it still exists in
134 * the new tracker. Either way, it needs no notification.
139 // no longer deployed
140 PolicyStatus status = entry.getValue();
142 // create a status with counts that are all zero
143 var newStatus = new PolicyStatus();
144 newStatus.setPolicyId(status.getPolicyId());
145 newStatus.setPolicyVersion(status.getPolicyVersion());
146 newStatus.setPolicyTypeId(status.getPolicyTypeId());
147 newStatus.setPolicyTypeVersion(status.getPolicyTypeVersion());
150 * Adding the status to the "added" set may be a bit unexpected, but when all
151 * status records are deleted from the group, we don't actually undeploy the
152 * policy from the subgroup. Instead, we leave it in the subgroup so that as
153 * soon as a PDP registers, we immediately deploy the policy to the PDP and
154 * continue on; the client can always undeploy the policy when it receives the
155 * notification, if so desired.
157 notif.getAdded().add(newStatus);
162 * Adds status to the tracking data. Assumes the associated PDP/policy pair has not be
165 * @param status status to be added
167 public void add(StatusAction status) {
168 if (status.getAction() == StatusAction.Action.DELETED) {
172 add(status.getStatus());
176 * Adds status to the tracking data. Assumes the associated PDP/policy pair has not be
179 * @param status status to be added
181 public void add(PdpPolicyStatus status) {
183 ToscaConceptIdentifier policy = status.getPolicy();
185 // get the entry from the relevant map, creating an entry if necessary
186 Map<ToscaConceptIdentifier, PolicyStatus> map = (status.isDeploy() ? deployMap : undeployMap);
188 PolicyStatus newStat = map.computeIfAbsent(policy, key -> {
189 var value = new PolicyStatus();
190 value.setPolicyId(policy.getName());
191 value.setPolicyVersion(policy.getVersion());
192 value.setPolicyTypeId(status.getPolicyType().getName());
193 value.setPolicyTypeVersion(status.getPolicyType().getVersion());
197 // bump the relevant count
198 switch (status.getState()) {
200 newStat.setSuccessCount(newStat.getSuccessCount() + 1);
203 newStat.setFailureCount(newStat.getFailureCount() + 1);
206 newStat.setIncompleteCount(newStat.getIncompleteCount() + 1);