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);
133 } else if (stateChange == null) {
136 } else if (stateChange.getState() == PdpState.ACTIVE) {
137 // publish update before activating
138 synchronized (modifyLock) {
140 addRequest(stateChange);
144 // deactivate before publishing update
145 synchronized (modifyLock) {
146 addRequest(stateChange);
153 * Adds an UPDATE request to the map.
155 * @param update the UPDATE request or {@code null}
157 public void addRequest(PdpUpdate update) {
158 if (update == null) {
162 if (isBroadcast(update)) {
163 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + update);
167 RequestParams reqparams = new RequestParams()
168 .setMaxRetryCount(params.getParams().getUpdateParameters().getMaxRetryCount())
169 .setTimers(params.getUpdateTimers())
170 .setModifyLock(params.getModifyLock())
171 .setPdpPublisher(params.getPdpPublisher())
172 .setResponseDispatcher(params.getResponseDispatcher());
175 String name = update.getName() + " " + PdpUpdate.class.getSimpleName();
176 UpdateReq request = new UpdateReq(reqparams, name, update);
178 addSingleton(request);
182 * Adds a STATE-CHANGE request to the map.
184 * @param stateChange the STATE-CHANGE request or {@code null}
186 public void addRequest(PdpStateChange stateChange) {
187 if (stateChange == null) {
191 if (isBroadcast(stateChange)) {
192 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + stateChange);
196 RequestParams reqparams = new RequestParams()
197 .setMaxRetryCount(params.getParams().getStateChangeParameters().getMaxRetryCount())
198 .setTimers(params.getStateChangeTimers())
199 .setModifyLock(params.getModifyLock())
200 .setPdpPublisher(params.getPdpPublisher())
201 .setResponseDispatcher(params.getResponseDispatcher());
204 String name = stateChange.getName() + " " + PdpStateChange.class.getSimpleName();
205 StateChangeReq request = new StateChangeReq(reqparams, name, stateChange);
207 addSingleton(request);
211 * Determines if a message is a broadcast message.
213 * @param message the message to examine
214 * @return {@code true} if the message is a broadcast message, {@code false} if
215 * destined for a single PDP
217 private boolean isBroadcast(PdpMessage message) {
218 return (message.getName() == null);
222 * Configures and adds a request to the map.
224 * @param request the request to be added
226 private void addSingleton(Request request) {
228 synchronized (modifyLock) {
229 PdpRequests requests = pdp2requests.computeIfAbsent(request.getMessage().getName(), this::makePdpRequests);
231 request.setListener(new SingletonListener(requests, request));
232 requests.addSingleton(request);
237 * Removes a PDP from all active groups.
239 * @param pdpName name of the PDP to be removed
240 * @return {@code true} if the PDP was removed from a group, {@code false} if it was
241 * not assigned to a group
242 * @throws PfModelException if an error occurred
244 public boolean removeFromGroups(String pdpName) throws PfModelException {
246 try (PolicyModelsProvider dao = daoFactory.create()) {
248 PdpGroupFilter filter = PdpGroupFilter.builder().groupState(PdpState.ACTIVE).build();
249 List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
250 List<PdpGroup> updates = new ArrayList<>(1);
252 for (PdpGroup group : groups) {
253 if (removeFromGroup(pdpName, group)) {
258 if (updates.isEmpty()) {
262 dao.updatePdpGroups(updates);
269 * Removes a PDP from a group.
271 * @param pdpName name of the PDP to be removed
272 * @param group group from which it should be removed
273 * @return {@code true} if the PDP was removed from the group, {@code false} if it was
274 * not assigned to the group
276 private boolean removeFromGroup(String pdpName, PdpGroup group) {
277 for (PdpSubGroup subgrp : group.getPdpSubgroups()) {
278 if (removeFromSubgroup(pdpName, group, subgrp)) {
287 * Removes a PDP from a subgroup.
289 * @param pdpName name of the PDP to be removed
290 * @param group group from which to attempt to remove the PDP
291 * @param subgrp subgroup from which to attempt to remove the PDP
292 * @return {@code true} if the PDP was removed, {@code false} if the PDP was not in
295 private boolean removeFromSubgroup(String pdpName, PdpGroup group, PdpSubGroup subgrp) {
297 Iterator<Pdp> iter = subgrp.getPdpInstances().iterator();
299 while (iter.hasNext()) {
300 Pdp instance = iter.next();
302 if (pdpName.equals(instance.getInstanceId())) {
303 logger.info("removed {} from group={} subgroup={}", pdpName, group.getName(), subgrp.getPdpType());
305 subgrp.setCurrentInstanceCount(subgrp.getPdpInstances().size());
314 * Creates a new set of requests for a PDP. May be overridden by junit tests.
316 * @param pdpName PDP name
317 * @return a new set of requests
319 protected PdpRequests makePdpRequests(String pdpName) {
320 return new PdpRequests(pdpName, policyNotifier);
324 * Listener for singleton request events.
326 private class SingletonListener implements RequestListener {
327 private final PdpRequests requests;
328 private final Request request;
330 public SingletonListener(PdpRequests requests, Request request) {
331 this.requests = requests;
332 this.request = request;
336 public void failure(String pdpName, String reason) {
337 if (requests.getPdpName().equals(pdpName)) {
338 disablePdp(requests);
343 public void success(String pdpName) {
344 if (requests.getPdpName().equals(pdpName)) {
345 if (pdp2requests.get(requests.getPdpName()) == requests) {
346 startNextRequest(requests, request);
349 logger.info("discard old requests for {}", pdpName);
350 requests.stopPublishing();
356 public void retryCountExhausted() {
357 disablePdp(requests);
361 * Starts the next request associated with a PDP.
363 * @param requests current set of requests
364 * @param request the request that just completed
366 private void startNextRequest(PdpRequests requests, Request request) {
367 if (!requests.startNextRequest(request)) {
368 pdp2requests.remove(requests.getPdpName(), requests);
373 * Disables a PDP by removing it from its subgroup and then sending it a PASSIVE
376 * @param requests the requests associated with the PDP to be disabled
378 private void disablePdp(PdpRequests requests) {
380 policyNotifier.removePdp(requests.getPdpName());
382 // remove the requests from the map
383 if (!pdp2requests.remove(requests.getPdpName(), requests)) {
384 // don't have the info we need to disable it
385 logger.warn("no requests with which to disable {}", requests.getPdpName());
389 logger.warn("disabling {}", requests.getPdpName());
391 requests.stopPublishing();
393 // remove the PDP from all groups
394 boolean removed = false;
396 removed = removeFromGroups(requests.getPdpName());
397 } catch (PfModelException e) {
398 logger.info("unable to remove PDP {} from subgroup", requests.getPdpName(), e);
401 // send the state change
402 PdpStateChange change = new PdpStateChange();
403 change.setName(requests.getPdpName());
404 change.setState(PdpState.PASSIVE);
407 // send an update, too
408 PdpUpdate update = new PdpUpdate();
409 update.setName(requests.getPdpName());
410 update.setPolicies(Collections.emptyList());
412 addRequest(update, change);