Changed identifiers to concept identifiers
[policy/pap.git] / main / src / main / java / org / onap / policy / pap / main / notification / PolicyCommonTracker.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP PAP
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
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
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=========================================================
21  */
22
23 package org.onap.policy.pap.main.notification;
24
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;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.Optional;
33 import java.util.Set;
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;
38
39 /**
40  * Common super class for deploy and undeploy trackers.
41  */
42 public abstract class PolicyCommonTracker {
43
44     /**
45      * Maps a policy id to its deployment data. The subclass determines when an entry is
46      * removed.
47      *
48      * <p/>
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.
51      */
52     private final Map<ToscaConceptIdentifier, PolicyTrackerData> policy2data = new LinkedHashMap<>();
53
54
55     /**
56      * Constructs the object.
57      */
58     protected PolicyCommonTracker() {
59         super();
60     }
61
62     /**
63      * Gets the status of all policies being tracked.
64      *
65      * @return the status of all policies
66      */
67     public List<PolicyStatus> getStatus() {
68         return policy2data.entrySet().stream().map(this::makeStatus).collect(Collectors.toList());
69     }
70
71     /**
72      * Gets the status of all versions of a policy.
73      *
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
76      */
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());
81     }
82
83     /**
84      * Gets the status of a particular policy.
85      *
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
88      */
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));
93     }
94
95     /**
96      * Adds data to the tracker.
97      *
98      * @param data data to be added to the tracker
99      */
100     public void addData(PolicyPdpNotificationData data) {
101         policy2data.computeIfAbsent(data.getPolicyId(), policyId -> new PolicyTrackerData(data.getPolicyType()))
102                         .addPdps(data.getPdps());
103     }
104
105     /**
106      * Removes a set of PDPs from all policies within the tracker.
107      *
108      * @param notifyData data identifying the policy and the PDPs to be removed from it
109      */
110     public void removeData(PolicyPdpNotificationData notifyData) {
111
112         policy2data.computeIfPresent(notifyData.getPolicyId(), (policyId, data) -> {
113
114             if (!data.removePdps(notifyData.getPdps())) {
115                 // not complete yet
116                 return data;
117             }
118
119             // this policy is complete
120             return (shouldRemove(data) ? null : data);
121         });
122     }
123
124     /**
125      * Removes a PDP from all policies within the tracker.
126      *
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
130      */
131     public void removePdp(String pdp, List<PolicyStatus> statusList) {
132         updateMap(statusList, (policyId, data) -> data.removePdp(pdp));
133     }
134
135     /**
136      * Processes a response from a PDP.
137      *
138      * @param pdp PDP of interest
139      * @param activePolicies policies that are still active on the PDP, as specified in
140      *        the response
141      * @param statusList status messages are added here if policies become complete as a
142      *        result of this operation
143      */
144     public void processResponse(String pdp, Collection<ToscaConceptIdentifier> activePolicies,
145                     List<PolicyStatus> statusList) {
146         processResponse(pdp, new HashSet<>(activePolicies), statusList);
147     }
148
149     /**
150      * Processes a response from a PDP.
151      *
152      * @param pdp PDP of interest
153      * @param activePolicies policies that are still active on the PDP, as specified in
154      *        the response
155      * @param statusList status messages are added here if policies become complete as a
156      *        result of this operation
157      */
158     public void processResponse(String pdp, Set<ToscaConceptIdentifier> activePolicies, List<PolicyStatus> statusList) {
159         updateMap(statusList, (policyId, data) -> updateData(pdp, data, activePolicies.contains(policyId)));
160     }
161
162     /**
163      * Updates the map.
164      *
165      * <p/>
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.
170      *
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)
175      */
176     private void updateMap(List<PolicyStatus> statusList,
177                     BiPredicate<ToscaConceptIdentifier, PolicyTrackerData> updater) {
178
179         Iterator<Entry<ToscaConceptIdentifier, PolicyTrackerData>> iter = policy2data.entrySet().iterator();
180         while (iter.hasNext()) {
181             Entry<ToscaConceptIdentifier, PolicyTrackerData> ent = iter.next();
182
183             ToscaConceptIdentifier policyId = ent.getKey();
184             PolicyTrackerData data = ent.getValue();
185
186             if (!updater.test(policyId, data)) {
187                 // not complete yet
188                 continue;
189             }
190
191             // this policy is complete - notify
192             statusList.add(makeStatus(ent));
193
194             if (shouldRemove(data)) {
195                 iter.remove();
196             }
197         }
198     }
199
200     /**
201      * Updates the policy data, based on a response from a PDP.
202      *
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
209      */
210     protected abstract boolean updateData(String pdp, PolicyTrackerData data, boolean stillActive);
211
212     /**
213      * Determines if a policy should be removed from the tracker, based on the state of
214      * its data.
215      *
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
219      */
220     protected abstract boolean shouldRemove(PolicyTrackerData data);
221
222     /**
223      * Makes a status notification for the given policy entry.
224      *
225      * @param entry policy entry
226      * @return a new status notification
227      */
228     private PolicyStatus makeStatus(Map.Entry<ToscaConceptIdentifier, PolicyTrackerData> entry) {
229         return makeStatus(entry.getKey(), entry.getValue());
230     }
231
232     /**
233      * Makes a status notification for the given policy.
234      *
235      * @param policyId policy ID
236      * @param data data to be used to set the status fields
237      * @return a new status notification
238      */
239     private PolicyStatus makeStatus(ToscaConceptIdentifier policyId, PolicyTrackerData data) {
240
241         PolicyStatus status = new PolicyStatus(data.getPolicyType(), policyId);
242         data.putValuesInto(status);
243         return status;
244     }
245 }