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.Collections;
25 import java.util.HashMap;
26 import java.util.Iterator;
27 import java.util.List;
29 import org.onap.policy.models.base.PfModelException;
30 import org.onap.policy.models.pdp.concepts.Pdp;
31 import org.onap.policy.models.pdp.concepts.PdpGroup;
32 import org.onap.policy.models.pdp.concepts.PdpGroupFilter;
33 import org.onap.policy.models.pdp.concepts.PdpMessage;
34 import org.onap.policy.models.pdp.concepts.PdpStateChange;
35 import org.onap.policy.models.pdp.concepts.PdpSubGroup;
36 import org.onap.policy.models.pdp.concepts.PdpUpdate;
37 import org.onap.policy.models.pdp.enums.PdpState;
38 import org.onap.policy.models.provider.PolicyModelsProvider;
39 import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper;
40 import org.onap.policy.pap.main.comm.msgdata.Request;
41 import org.onap.policy.pap.main.comm.msgdata.RequestListener;
42 import org.onap.policy.pap.main.comm.msgdata.StateChangeReq;
43 import org.onap.policy.pap.main.comm.msgdata.UpdateReq;
44 import org.onap.policy.pap.main.notification.PolicyNotifier;
45 import org.onap.policy.pap.main.parameters.PdpModifyRequestMapParams;
46 import org.onap.policy.pap.main.parameters.RequestParams;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
51 * Maps a PDP name to requests that modify PDPs.
53 public class PdpModifyRequestMap {
54 private static final Logger logger = LoggerFactory.getLogger(PdpModifyRequestMap.class);
56 private static final String UNEXPECTED_BROADCAST = "unexpected broadcast message: ";
59 * Maps a PDP name to its outstanding requests.
61 private final Map<String, PdpRequests> pdp2requests = new HashMap<>();
64 * PDP modification lock.
66 private final Object modifyLock;
69 * The configuration parameters.
71 private final PdpModifyRequestMapParams params;
74 * Factory for PAP DAO.
76 private final PolicyModelsProviderFactoryWrapper daoFactory;
79 * Used to notify when policy updates completes.
81 private final PolicyNotifier policyNotifier;
85 * Constructs the object.
87 * @param params configuration parameters
89 * @throws IllegalArgumentException if a required parameter is not set
91 public PdpModifyRequestMap(PdpModifyRequestMapParams params) {
95 this.modifyLock = params.getModifyLock();
96 this.daoFactory = params.getDaoFactory();
97 this.policyNotifier = params.getPolicyNotifier();
101 * Determines if the map contains any requests.
103 * @return {@code true} if the map is empty, {@code false} otherwise
105 public boolean isEmpty() {
106 return pdp2requests.isEmpty();
110 * Stops publishing requests to the given PDP.
112 * @param pdpName PDP name
114 public void stopPublishing(String pdpName) {
115 synchronized (modifyLock) {
116 PdpRequests requests = pdp2requests.remove(pdpName);
117 if (requests != null) {
118 requests.stopPublishing();
124 * Adds a pair of requests to the map.
126 * @param update the UPDATE request or {@code null}
127 * @param stateChange the STATE-CHANGE request or {@code null}
129 public void addRequest(PdpUpdate update, PdpStateChange stateChange) {
130 if (update == null) {
131 addRequest(stateChange);
134 synchronized (modifyLock) {
136 addRequest(stateChange);
142 * Adds an UPDATE request to the map.
144 * @param update the UPDATE request or {@code null}
146 public void addRequest(PdpUpdate update) {
147 if (update == null) {
151 if (isBroadcast(update)) {
152 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + update);
156 RequestParams reqparams = new RequestParams()
157 .setMaxRetryCount(params.getParams().getUpdateParameters().getMaxRetryCount())
158 .setTimers(params.getUpdateTimers())
159 .setModifyLock(params.getModifyLock())
160 .setPdpPublisher(params.getPdpPublisher())
161 .setResponseDispatcher(params.getResponseDispatcher());
164 String name = update.getName() + " " + PdpUpdate.class.getSimpleName();
165 UpdateReq request = new UpdateReq(reqparams, name, update);
167 addSingleton(request);
171 * Adds a STATE-CHANGE request to the map.
173 * @param stateChange the STATE-CHANGE request or {@code null}
175 public void addRequest(PdpStateChange stateChange) {
176 if (stateChange == null) {
180 if (isBroadcast(stateChange)) {
181 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + stateChange);
185 RequestParams reqparams = new RequestParams()
186 .setMaxRetryCount(params.getParams().getStateChangeParameters().getMaxRetryCount())
187 .setTimers(params.getStateChangeTimers())
188 .setModifyLock(params.getModifyLock())
189 .setPdpPublisher(params.getPdpPublisher())
190 .setResponseDispatcher(params.getResponseDispatcher());
193 String name = stateChange.getName() + " " + PdpStateChange.class.getSimpleName();
194 StateChangeReq request = new StateChangeReq(reqparams, name, stateChange);
196 addSingleton(request);
200 * Determines if a message is a broadcast message.
202 * @param message the message to examine
203 * @return {@code true} if the message is a broadcast message, {@code false} if
204 * destined for a single PDP
206 private boolean isBroadcast(PdpMessage message) {
207 return (message.getName() == null);
211 * Configures and adds a request to the map.
213 * @param request the request to be added
215 private void addSingleton(Request request) {
217 synchronized (modifyLock) {
218 PdpRequests requests = pdp2requests.computeIfAbsent(request.getMessage().getName(), this::makePdpRequests);
220 request.setListener(new SingletonListener(requests, request));
221 requests.addSingleton(request);
226 * Removes a PDP from all active groups.
228 * @param pdpName name of the PDP to be removed
229 * @return {@code true} if the PDP was removed from a group, {@code false} if it was
230 * not assigned to a group
231 * @throws PfModelException if an error occurred
233 public boolean removeFromGroups(String pdpName) throws PfModelException {
235 try (PolicyModelsProvider dao = daoFactory.create()) {
237 PdpGroupFilter filter = PdpGroupFilter.builder().groupState(PdpState.ACTIVE).build();
238 List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
239 List<PdpGroup> updates = new ArrayList<>(1);
241 for (PdpGroup group : groups) {
242 if (removeFromGroup(pdpName, group)) {
247 if (updates.isEmpty()) {
251 dao.updatePdpGroups(updates);
258 * Removes a PDP from a group.
260 * @param pdpName name of the PDP to be removed
261 * @param group group from which it should be removed
262 * @return {@code true} if the PDP was removed from the group, {@code false} if it was
263 * not assigned to the group
265 private boolean removeFromGroup(String pdpName, PdpGroup group) {
266 for (PdpSubGroup subgrp : group.getPdpSubgroups()) {
267 if (removeFromSubgroup(pdpName, group, subgrp)) {
276 * Removes a PDP from a subgroup.
278 * @param pdpName name of the PDP to be removed
279 * @param group group from which to attempt to remove the PDP
280 * @param subgrp subgroup from which to attempt to remove the PDP
281 * @return {@code true} if the PDP was removed, {@code false} if the PDP was not in
284 private boolean removeFromSubgroup(String pdpName, PdpGroup group, PdpSubGroup subgrp) {
286 Iterator<Pdp> iter = subgrp.getPdpInstances().iterator();
288 while (iter.hasNext()) {
289 Pdp instance = iter.next();
291 if (pdpName.equals(instance.getInstanceId())) {
292 logger.info("removed {} from group={} subgroup={}", pdpName, group.getName(), subgrp.getPdpType());
294 subgrp.setCurrentInstanceCount(subgrp.getPdpInstances().size());
303 * Creates a new set of requests for a PDP. May be overridden by junit tests.
305 * @param pdpName PDP name
306 * @return a new set of requests
308 protected PdpRequests makePdpRequests(String pdpName) {
309 return new PdpRequests(pdpName, policyNotifier);
313 * Listener for singleton request events.
315 private class SingletonListener implements RequestListener {
316 private final PdpRequests requests;
317 private final Request request;
319 public SingletonListener(PdpRequests requests, Request request) {
320 this.requests = requests;
321 this.request = request;
325 public void failure(String pdpName, String reason) {
326 if (requests.getPdpName().equals(pdpName)) {
327 disablePdp(requests);
332 public void success(String pdpName) {
333 if (requests.getPdpName().equals(pdpName)) {
334 if (pdp2requests.get(requests.getPdpName()) == requests) {
335 startNextRequest(requests, request);
338 logger.info("discard old requests for {}", pdpName);
339 requests.stopPublishing();
345 public void retryCountExhausted() {
346 disablePdp(requests);
350 * Starts the next request associated with a PDP.
352 * @param requests current set of requests
353 * @param request the request that just completed
355 private void startNextRequest(PdpRequests requests, Request request) {
356 if (!requests.startNextRequest(request)) {
357 pdp2requests.remove(requests.getPdpName(), requests);
362 * Disables a PDP by removing it from its subgroup and then sending it a PASSIVE
365 * @param requests the requests associated with the PDP to be disabled
367 private void disablePdp(PdpRequests requests) {
369 policyNotifier.removePdp(requests.getPdpName());
371 // remove the requests from the map
372 if (!pdp2requests.remove(requests.getPdpName(), requests)) {
373 // don't have the info we need to disable it
374 logger.warn("no requests with which to disable {}", requests.getPdpName());
378 logger.warn("disabling {}", requests.getPdpName());
380 requests.stopPublishing();
382 // remove the PDP from all groups
383 boolean removed = false;
385 removed = removeFromGroups(requests.getPdpName());
386 } catch (PfModelException e) {
387 logger.info("unable to remove PDP {} from subgroup", requests.getPdpName(), e);
390 // send the state change
391 PdpStateChange change = new PdpStateChange();
392 change.setName(requests.getPdpName());
393 change.setState(PdpState.PASSIVE);
396 // send an update, too
397 PdpUpdate update = new PdpUpdate();
398 update.setName(requests.getPdpName());
399 update.setPolicies(Collections.emptyList());
401 addRequest(update, change);