2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
6 * Modifications Copyright (C) 2020 Bell Canada. All rights reserved.
7 * Modifications Copyright (C) 2021 Nordix Foundation.
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.notification;
25 import java.util.Collection;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.LinkedHashMap;
29 import java.util.List;
31 import java.util.Map.Entry;
32 import java.util.Optional;
34 import java.util.function.BiPredicate;
35 import java.util.stream.Collectors;
36 import org.onap.policy.models.pap.concepts.PolicyStatus;
37 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier;
40 * Common super class for deploy and undeploy trackers.
42 public abstract class PolicyCommonTracker {
45 * Maps a policy id to its deployment data. The subclass determines when an entry is
49 * Use a LinkedHashMap, because we'll be doing lots of iteration over the map, and
50 * iteration over a LinkedHashMap is faster than over a plain HashMap.
52 private final Map<ToscaConceptIdentifier, PolicyTrackerData> policy2data = new LinkedHashMap<>();
56 * Constructs the object.
58 protected PolicyCommonTracker() {
63 * Gets the status of all policies being tracked.
65 * @return the status of all policies
67 public List<PolicyStatus> getStatus() {
68 return policy2data.entrySet().stream().map(this::makeStatus).collect(Collectors.toList());
72 * Gets the status of all versions of a policy.
74 * @param policyId ID of the policy of interest, without the version
75 * @return the status of all versions of the policy having the given ID
77 public List<PolicyStatus> getStatus(String policyId) {
78 // version is not specified - have to scan the whole list
79 return policy2data.entrySet().stream().filter(ent -> ent.getKey().getName().equals(policyId))
80 .map(this::makeStatus).collect(Collectors.toList());
84 * Gets the status of a particular policy.
86 * @param ident identifier of the policy of interest
87 * @return the status of the given policy, or empty if the policy is not found
89 public Optional<PolicyStatus> getStatus(ToscaConceptIdentifier ident) {
90 ToscaConceptIdentifier ident2 = new ToscaConceptIdentifier(ident.getName(), ident.getVersion());
91 PolicyTrackerData data = policy2data.get(ident2);
92 return Optional.ofNullable(data == null ? null : makeStatus(ident2, data));
96 * Adds data to the tracker.
98 * @param data data to be added to the tracker
100 public void addData(PolicyPdpNotificationData data) {
101 policy2data.computeIfAbsent(data.getPolicyId(), policyId -> new PolicyTrackerData(data.getPolicyType()))
102 .addPdps(data.getPdps());
106 * Removes a set of PDPs from all policies within the tracker.
108 * @param notifyData data identifying the policy and the PDPs to be removed from it
110 public void removeData(PolicyPdpNotificationData notifyData) {
112 policy2data.computeIfPresent(notifyData.getPolicyId(), (policyId, data) -> {
114 if (!data.removePdps(notifyData.getPdps())) {
119 // this policy is complete
120 return (shouldRemove(data) ? null : data);
125 * Removes a PDP from all policies within the tracker.
127 * @param pdp PDP to be removed
128 * @param statusList status messages are added here if policies become complete as a
129 * result of this operation
131 public void removePdp(String pdp, List<PolicyStatus> statusList) {
132 updateMap(statusList, (policyId, data) -> data.removePdp(pdp));
136 * Processes a response from a PDP.
138 * @param pdp PDP of interest
139 * @param activePolicies policies that are still active on the PDP, as specified in
141 * @param statusList status messages are added here if policies become complete as a
142 * result of this operation
144 public void processResponse(String pdp, Collection<ToscaConceptIdentifier> activePolicies,
145 List<PolicyStatus> statusList) {
146 processResponse(pdp, new HashSet<>(activePolicies), statusList);
150 * Processes a response from a PDP.
152 * @param pdp PDP of interest
153 * @param activePolicies policies that are still active on the PDP, as specified in
155 * @param statusList status messages are added here if policies become complete as a
156 * result of this operation
158 public void processResponse(String pdp, Set<ToscaConceptIdentifier> activePolicies, List<PolicyStatus> statusList) {
159 updateMap(statusList, (policyId, data) -> updateData(pdp, data, activePolicies.contains(policyId)));
166 * Note: this iterates through the whole map. While it may be more efficient to
167 * iterate through just the policies relevant to the PDP, that would complicate the
168 * code and complicate the testing. In addition, this should still perform well
169 * enough, but if not, it can always be enhanced.
171 * @param statusList status messages are added here if policies become complete as a
172 * result of this operation
173 * @param updater function to update a policy's data. Returns {@code true} if the
174 * policy is complete (i.e., no longer awaiting any responses)
176 private void updateMap(List<PolicyStatus> statusList,
177 BiPredicate<ToscaConceptIdentifier, PolicyTrackerData> updater) {
179 Iterator<Entry<ToscaConceptIdentifier, PolicyTrackerData>> iter = policy2data.entrySet().iterator();
180 while (iter.hasNext()) {
181 Entry<ToscaConceptIdentifier, PolicyTrackerData> ent = iter.next();
183 ToscaConceptIdentifier policyId = ent.getKey();
184 PolicyTrackerData data = ent.getValue();
186 if (!updater.test(policyId, data)) {
191 // this policy is complete - notify
192 statusList.add(makeStatus(ent));
194 if (shouldRemove(data)) {
201 * Updates the policy data, based on a response from a PDP.
203 * @param pdp PDP whose response was just received
204 * @param data data associated with the policy of interest
205 * @param stillActive {@code true} if the policy is still active for the PDP,
206 * {@code false} otherwise
207 * @return {@code true} if the policy is complete (i.e., no longer awaiting any
208 * responses), {@code false} otherwise
210 protected abstract boolean updateData(String pdp, PolicyTrackerData data, boolean stillActive);
213 * Determines if a policy should be removed from the tracker, based on the state of
216 * @param data data associated with the policy of interest
217 * @return {@code true} if the policy should be removed from the tracker,
218 * {@code false} otherwise
220 protected abstract boolean shouldRemove(PolicyTrackerData data);
223 * Makes a status notification for the given policy entry.
225 * @param entry policy entry
226 * @return a new status notification
228 private PolicyStatus makeStatus(Map.Entry<ToscaConceptIdentifier, PolicyTrackerData> entry) {
229 return makeStatus(entry.getKey(), entry.getValue());
233 * Makes a status notification for the given policy.
235 * @param policyId policy ID
236 * @param data data to be used to set the status fields
237 * @return a new status notification
239 private PolicyStatus makeStatus(ToscaConceptIdentifier policyId, PolicyTrackerData data) {
241 PolicyStatus status = new PolicyStatus(data.getPolicyType(), policyId);
242 data.putValuesInto(status);