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.parameters.PdpModifyRequestMapParams;
44 import org.onap.policy.pap.main.parameters.RequestParams;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
49 * Maps a PDP name to requests that modify PDPs.
51 public class PdpModifyRequestMap {
52 private static final Logger logger = LoggerFactory.getLogger(PdpModifyRequestMap.class);
54 private static final String UNEXPECTED_BROADCAST = "unexpected broadcast message: ";
57 * Maps a PDP name to its outstanding requests.
59 private final Map<String, PdpRequests> pdp2requests = new HashMap<>();
62 * PDP modification lock.
64 private final Object modifyLock;
67 * The configuration parameters.
69 private final PdpModifyRequestMapParams params;
72 * Factory for PAP DAO.
74 private final PolicyModelsProviderFactoryWrapper daoFactory;
78 * Constructs the object.
80 * @param params configuration parameters
82 * @throws IllegalArgumentException if a required parameter is not set
84 public PdpModifyRequestMap(PdpModifyRequestMapParams params) {
88 this.modifyLock = params.getModifyLock();
89 this.daoFactory = params.getDaoFactory();
93 * Determines if the map contains any requests.
95 * @return {@code true} if the map is empty, {@code false} otherwise
97 public boolean isEmpty() {
98 return pdp2requests.isEmpty();
102 * Stops publishing requests to the given PDP.
104 * @param pdpName PDP name
106 public void stopPublishing(String pdpName) {
107 synchronized (modifyLock) {
108 PdpRequests requests = pdp2requests.remove(pdpName);
109 if (requests != null) {
110 requests.stopPublishing();
116 * Adds a pair of requests to the map.
118 * @param update the UPDATE request or {@code null}
119 * @param stateChange the STATE-CHANGE request or {@code null}
121 public void addRequest(PdpUpdate update, PdpStateChange stateChange) {
122 if (update == null) {
123 addRequest(stateChange);
126 synchronized (modifyLock) {
128 addRequest(stateChange);
134 * Adds an UPDATE request to the map.
136 * @param update the UPDATE request or {@code null}
138 public void addRequest(PdpUpdate update) {
139 if (update == null) {
143 if (isBroadcast(update)) {
144 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + update);
148 RequestParams reqparams = new RequestParams()
149 .setMaxRetryCount(params.getParams().getUpdateParameters().getMaxRetryCount())
150 .setTimers(params.getUpdateTimers())
151 .setModifyLock(params.getModifyLock())
152 .setPublisher(params.getPublisher())
153 .setResponseDispatcher(params.getResponseDispatcher());
156 String name = update.getName() + " " + PdpUpdate.class.getSimpleName();
157 UpdateReq request = new UpdateReq(reqparams, name, update);
159 addSingleton(request);
163 * Adds a STATE-CHANGE request to the map.
165 * @param stateChange the STATE-CHANGE request or {@code null}
167 public void addRequest(PdpStateChange stateChange) {
168 if (stateChange == null) {
172 if (isBroadcast(stateChange)) {
173 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + stateChange);
177 RequestParams reqparams = new RequestParams()
178 .setMaxRetryCount(params.getParams().getStateChangeParameters().getMaxRetryCount())
179 .setTimers(params.getStateChangeTimers())
180 .setModifyLock(params.getModifyLock())
181 .setPublisher(params.getPublisher())
182 .setResponseDispatcher(params.getResponseDispatcher());
185 String name = stateChange.getName() + " " + PdpStateChange.class.getSimpleName();
186 StateChangeReq request = new StateChangeReq(reqparams, name, stateChange);
188 addSingleton(request);
192 * Determines if a message is a broadcast message.
194 * @param message the message to examine
195 * @return {@code true} if the message is a broadcast message, {@code false} if
196 * destined for a single PDP
198 private boolean isBroadcast(PdpMessage message) {
199 return (message.getName() == null);
203 * Configures and adds a request to the map.
205 * @param request the request to be added
207 private void addSingleton(Request request) {
209 synchronized (modifyLock) {
210 PdpRequests requests = pdp2requests.computeIfAbsent(request.getMessage().getName(), this::makePdpRequests);
212 request.setListener(new SingletonListener(requests, request));
213 requests.addSingleton(request);
218 * Removes a PDP from all active groups.
220 * @param pdpName name of the PDP to be removed
221 * @return {@code true} if the PDP was removed from a group, {@code false} if it was
222 * not assigned to a group
223 * @throws PfModelException if an error occurs
225 public boolean removeFromGroups(String pdpName) throws PfModelException {
227 try (PolicyModelsProvider dao = daoFactory.create()) {
229 PdpGroupFilter filter = PdpGroupFilter.builder().groupState(PdpState.ACTIVE).build();
230 List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
231 List<PdpGroup> updates = new ArrayList<>(1);
233 for (PdpGroup group : groups) {
234 if (removeFromGroup(pdpName, group)) {
239 if (updates.isEmpty()) {
243 dao.updatePdpGroups(updates);
250 * Removes a PDP from a group.
252 * @param pdpName name of the PDP to be removed
253 * @param group group from which it should be removed
254 * @return {@code true} if the PDP was removed from the group, {@code false} if it was
255 * not assigned to the group
257 private boolean removeFromGroup(String pdpName, PdpGroup group) {
258 for (PdpSubGroup subgrp : group.getPdpSubgroups()) {
259 if (removeFromSubgroup(pdpName, group, subgrp)) {
268 * Removes a PDP from a subgroup.
270 * @param pdpName name of the PDP to be removed
271 * @param group group from which to attempt to remove the PDP
272 * @param subgrp subgroup from which to attempt to remove the PDP
273 * @return {@code true} if the PDP was removed, {@code false} if the PDP was not in
276 private boolean removeFromSubgroup(String pdpName, PdpGroup group, PdpSubGroup subgrp) {
278 Iterator<Pdp> iter = subgrp.getPdpInstances().iterator();
280 while (iter.hasNext()) {
281 Pdp instance = iter.next();
283 if (pdpName.equals(instance.getInstanceId())) {
284 logger.info("removed {} from group={} subgroup={}", pdpName, group.getName(), subgrp.getPdpType());
286 subgrp.setCurrentInstanceCount(subgrp.getPdpInstances().size());
295 * Creates a new set of requests for a PDP. May be overridden by junit tests.
297 * @param pdpName PDP name
298 * @return a new set of requests
300 protected PdpRequests makePdpRequests(String pdpName) {
301 return new PdpRequests(pdpName);
305 * Listener for singleton request events.
307 private class SingletonListener implements RequestListener {
308 private final PdpRequests requests;
309 private final Request request;
311 public SingletonListener(PdpRequests requests, Request request) {
312 this.requests = requests;
313 this.request = request;
317 public void failure(String pdpName, String reason) {
318 if (requests.getPdpName().equals(pdpName)) {
319 disablePdp(requests);
324 public void success(String pdpName) {
325 if (requests.getPdpName().equals(pdpName)) {
326 if (pdp2requests.get(requests.getPdpName()) == requests) {
327 startNextRequest(requests, request);
330 logger.info("discard old requests for {}", pdpName);
331 requests.stopPublishing();
337 public void retryCountExhausted() {
338 disablePdp(requests);
342 * Starts the next request associated with a PDP.
344 * @param requests current set of requests
345 * @param request the request that just completed
347 private void startNextRequest(PdpRequests requests, Request request) {
348 if (!requests.startNextRequest(request)) {
349 pdp2requests.remove(requests.getPdpName(), requests);
354 * Disables a PDP by removing it from its subgroup and then sending it a PASSIVE
357 * @param requests the requests associated with the PDP to be disabled
359 private void disablePdp(PdpRequests requests) {
361 // remove the requests from the map
362 if (!pdp2requests.remove(requests.getPdpName(), requests)) {
363 // don't have the info we need to disable it
364 logger.warn("no requests with which to disable {}", requests.getPdpName());
368 logger.warn("disabling {}", requests.getPdpName());
370 requests.stopPublishing();
372 // remove the PDP from all groups
373 boolean removed = false;
375 removed = removeFromGroups(requests.getPdpName());
376 } catch (PfModelException e) {
377 logger.info("unable to remove PDP {} from subgroup", requests.getPdpName(), e);
380 // send the state change
381 PdpStateChange change = new PdpStateChange();
382 change.setName(requests.getPdpName());
383 change.setState(PdpState.PASSIVE);
386 // send an update, too
387 PdpUpdate update = new PdpUpdate();
388 update.setName(requests.getPdpName());
390 addRequest(update, change);