2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2019 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.comm;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
28 import org.onap.policy.models.base.PfModelException;
29 import org.onap.policy.models.pdp.concepts.Pdp;
30 import org.onap.policy.models.pdp.concepts.PdpGroup;
31 import org.onap.policy.models.pdp.concepts.PdpGroupFilter;
32 import org.onap.policy.models.pdp.concepts.PdpMessage;
33 import org.onap.policy.models.pdp.concepts.PdpStateChange;
34 import org.onap.policy.models.pdp.concepts.PdpSubGroup;
35 import org.onap.policy.models.pdp.concepts.PdpUpdate;
36 import org.onap.policy.models.pdp.enums.PdpState;
37 import org.onap.policy.models.provider.PolicyModelsProvider;
38 import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper;
39 import org.onap.policy.pap.main.comm.msgdata.Request;
40 import org.onap.policy.pap.main.comm.msgdata.RequestListener;
41 import org.onap.policy.pap.main.comm.msgdata.StateChangeReq;
42 import org.onap.policy.pap.main.comm.msgdata.UpdateReq;
43 import org.onap.policy.pap.main.notification.PolicyNotifier;
44 import org.onap.policy.pap.main.parameters.PdpModifyRequestMapParams;
45 import org.onap.policy.pap.main.parameters.RequestParams;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
50 * Maps a PDP name to requests that modify PDPs.
52 public class PdpModifyRequestMap {
53 private static final Logger logger = LoggerFactory.getLogger(PdpModifyRequestMap.class);
55 private static final String UNEXPECTED_BROADCAST = "unexpected broadcast message: ";
58 * Maps a PDP name to its outstanding requests.
60 private final Map<String, PdpRequests> pdp2requests = new HashMap<>();
63 * PDP modification lock.
65 private final Object modifyLock;
68 * The configuration parameters.
70 private final PdpModifyRequestMapParams params;
73 * Factory for PAP DAO.
75 private final PolicyModelsProviderFactoryWrapper daoFactory;
78 * Used to notify when policy updates completes.
80 private final PolicyNotifier policyNotifier;
84 * Constructs the object.
86 * @param params configuration parameters
88 * @throws IllegalArgumentException if a required parameter is not set
90 public PdpModifyRequestMap(PdpModifyRequestMapParams params) {
94 this.modifyLock = params.getModifyLock();
95 this.daoFactory = params.getDaoFactory();
96 this.policyNotifier = params.getPolicyNotifier();
100 * Determines if the map contains any requests.
102 * @return {@code true} if the map is empty, {@code false} otherwise
104 public boolean isEmpty() {
105 return pdp2requests.isEmpty();
109 * Stops publishing requests to the given PDP.
111 * @param pdpName PDP name
113 public void stopPublishing(String pdpName) {
114 synchronized (modifyLock) {
115 PdpRequests requests = pdp2requests.remove(pdpName);
116 if (requests != null) {
117 requests.stopPublishing();
123 * Adds a pair of requests to the map.
125 * @param update the UPDATE request or {@code null}
126 * @param stateChange the STATE-CHANGE request or {@code null}
128 public void addRequest(PdpUpdate update, PdpStateChange stateChange) {
129 if (update == null) {
130 addRequest(stateChange);
132 } else if (stateChange == null) {
135 } else if (stateChange.getState() == PdpState.ACTIVE) {
136 // publish update before activating
137 synchronized (modifyLock) {
139 addRequest(stateChange);
143 // deactivate before publishing update
144 synchronized (modifyLock) {
145 addRequest(stateChange);
152 * Adds an UPDATE request to the map.
154 * @param update the UPDATE request or {@code null}
156 public void addRequest(PdpUpdate update) {
157 if (update == null) {
161 if (isBroadcast(update)) {
162 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + update);
166 RequestParams reqparams = new RequestParams()
167 .setMaxRetryCount(params.getParams().getUpdateParameters().getMaxRetryCount())
168 .setTimers(params.getUpdateTimers())
169 .setModifyLock(params.getModifyLock())
170 .setPdpPublisher(params.getPdpPublisher())
171 .setResponseDispatcher(params.getResponseDispatcher());
174 String name = update.getName() + " " + PdpUpdate.class.getSimpleName();
175 UpdateReq request = new UpdateReq(reqparams, name, update);
177 addSingleton(request);
181 * Adds a STATE-CHANGE request to the map.
183 * @param stateChange the STATE-CHANGE request or {@code null}
185 public void addRequest(PdpStateChange stateChange) {
186 if (stateChange == null) {
190 if (isBroadcast(stateChange)) {
191 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + stateChange);
195 RequestParams reqparams = new RequestParams()
196 .setMaxRetryCount(params.getParams().getStateChangeParameters().getMaxRetryCount())
197 .setTimers(params.getStateChangeTimers())
198 .setModifyLock(params.getModifyLock())
199 .setPdpPublisher(params.getPdpPublisher())
200 .setResponseDispatcher(params.getResponseDispatcher());
203 String name = stateChange.getName() + " " + PdpStateChange.class.getSimpleName();
204 StateChangeReq request = new StateChangeReq(reqparams, name, stateChange);
206 addSingleton(request);
210 * Determines if a message is a broadcast message.
212 * @param message the message to examine
213 * @return {@code true} if the message is a broadcast message, {@code false} if
214 * destined for a single PDP
216 private boolean isBroadcast(PdpMessage message) {
217 return (message.getName() == null);
221 * Configures and adds a request to the map.
223 * @param request the request to be added
225 private void addSingleton(Request request) {
227 synchronized (modifyLock) {
228 PdpRequests requests = pdp2requests.computeIfAbsent(request.getMessage().getName(), this::makePdpRequests);
230 request.setListener(new SingletonListener(requests, request));
231 requests.addSingleton(request);
236 * Removes a PDP from all active groups.
238 * @param pdpName name of the PDP to be removed
239 * @return {@code true} if the PDP was removed from a group, {@code false} if it was
240 * not assigned to a group
241 * @throws PfModelException if an error occurred
243 public boolean removeFromGroups(String pdpName) throws PfModelException {
245 try (PolicyModelsProvider dao = daoFactory.create()) {
247 PdpGroupFilter filter = PdpGroupFilter.builder().groupState(PdpState.ACTIVE).build();
248 List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
249 List<PdpGroup> updates = new ArrayList<>(1);
251 for (PdpGroup group : groups) {
252 if (removeFromGroup(pdpName, group)) {
257 if (updates.isEmpty()) {
261 dao.updatePdpGroups(updates);
268 * Removes a PDP from a group.
270 * @param pdpName name of the PDP to be removed
271 * @param group group from which it should be removed
272 * @return {@code true} if the PDP was removed from the group, {@code false} if it was
273 * not assigned to the group
275 private boolean removeFromGroup(String pdpName, PdpGroup group) {
276 for (PdpSubGroup subgrp : group.getPdpSubgroups()) {
277 if (removeFromSubgroup(pdpName, group, subgrp)) {
286 * Removes a PDP from a subgroup.
288 * @param pdpName name of the PDP to be removed
289 * @param group group from which to attempt to remove the PDP
290 * @param subgrp subgroup from which to attempt to remove the PDP
291 * @return {@code true} if the PDP was removed, {@code false} if the PDP was not in
294 private boolean removeFromSubgroup(String pdpName, PdpGroup group, PdpSubGroup subgrp) {
296 Iterator<Pdp> iter = subgrp.getPdpInstances().iterator();
298 while (iter.hasNext()) {
299 Pdp instance = iter.next();
301 if (pdpName.equals(instance.getInstanceId())) {
302 logger.info("removed {} from group={} subgroup={}", pdpName, group.getName(), subgrp.getPdpType());
304 subgrp.setCurrentInstanceCount(subgrp.getPdpInstances().size());
313 * Creates a new set of requests for a PDP. May be overridden by junit tests.
315 * @param pdpName PDP name
316 * @return a new set of requests
318 protected PdpRequests makePdpRequests(String pdpName) {
319 return new PdpRequests(pdpName, policyNotifier);
323 * Listener for singleton request events.
325 private class SingletonListener implements RequestListener {
326 private final PdpRequests requests;
327 private final Request request;
328 private final String pdpName;
330 public SingletonListener(PdpRequests requests, Request request) {
331 this.requests = requests;
332 this.request = request;
333 this.pdpName = requests.getPdpName();
337 public void failure(String responsePdpName, String reason) {
338 requestCompleted(responsePdpName);
342 public void success(String responsePdpName) {
343 requestCompleted(responsePdpName);
347 * Handles a request completion, starting the next request, if there is one.
349 * @param responsePdpName name of the PDP provided in the response
351 private void requestCompleted(String responsePdpName) {
352 if (pdpName.equals(responsePdpName)) {
353 if (pdp2requests.get(pdpName) == requests) {
354 startNextRequest(request);
357 logger.info("discard old requests for {}", responsePdpName);
358 requests.stopPublishing();
364 public void retryCountExhausted() {
369 * Starts the next request associated with a PDP.
371 * @param request the request that just completed
373 private void startNextRequest(Request request) {
374 if (!requests.startNextRequest(request)) {
375 pdp2requests.remove(pdpName, requests);
380 * Removes a PDP from its subgroup.
382 private void removePdp() {
383 requests.stopPublishing();
385 // remove the requests from the map
386 if (!pdp2requests.remove(pdpName, requests)) {
387 // wasn't in the map - the requests must be old
388 logger.warn("discarding old requests for {}", pdpName);
392 logger.warn("removing {}", pdpName);
394 policyNotifier.removePdp(pdpName);
396 // remove the PDP from all groups
398 removeFromGroups(pdpName);
399 } catch (PfModelException e) {
400 logger.info("unable to remove PDP {} from subgroup", pdpName, e);