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.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;
79 * Constructs the object.
81 * @param params configuration parameters
83 * @throws IllegalArgumentException if a required parameter is not set
85 public PdpModifyRequestMap(PdpModifyRequestMapParams params) {
89 this.modifyLock = params.getModifyLock();
90 this.daoFactory = params.getDaoFactory();
94 * Determines if the map contains any requests.
96 * @return {@code true} if the map is empty, {@code false} otherwise
98 public boolean isEmpty() {
99 return pdp2requests.isEmpty();
103 * Stops publishing requests to the given PDP.
105 * @param pdpName PDP name
107 public void stopPublishing(String pdpName) {
108 synchronized (modifyLock) {
109 PdpRequests requests = pdp2requests.remove(pdpName);
110 if (requests != null) {
111 requests.stopPublishing();
117 * Adds a pair of requests to the map.
119 * @param update the UPDATE request or {@code null}
120 * @param stateChange the STATE-CHANGE request or {@code null}
122 public void addRequest(PdpUpdate update, PdpStateChange stateChange) {
123 if (update == null) {
124 addRequest(stateChange);
127 synchronized (modifyLock) {
129 addRequest(stateChange);
135 * Adds an UPDATE request to the map.
137 * @param update the UPDATE request or {@code null}
139 public void addRequest(PdpUpdate update) {
140 if (update == null) {
144 if (isBroadcast(update)) {
145 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + update);
149 RequestParams reqparams = new RequestParams()
150 .setMaxRetryCount(params.getParams().getUpdateParameters().getMaxRetryCount())
151 .setTimers(params.getUpdateTimers())
152 .setModifyLock(params.getModifyLock())
153 .setPublisher(params.getPublisher())
154 .setResponseDispatcher(params.getResponseDispatcher());
157 String name = update.getName() + " " + PdpUpdate.class.getSimpleName();
158 UpdateReq request = new UpdateReq(reqparams, name, update);
160 addSingleton(request);
164 * Adds a STATE-CHANGE request to the map.
166 * @param stateChange the STATE-CHANGE request or {@code null}
168 public void addRequest(PdpStateChange stateChange) {
169 if (stateChange == null) {
173 if (isBroadcast(stateChange)) {
174 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + stateChange);
178 RequestParams reqparams = new RequestParams()
179 .setMaxRetryCount(params.getParams().getStateChangeParameters().getMaxRetryCount())
180 .setTimers(params.getStateChangeTimers())
181 .setModifyLock(params.getModifyLock())
182 .setPublisher(params.getPublisher())
183 .setResponseDispatcher(params.getResponseDispatcher());
186 String name = stateChange.getName() + " " + PdpStateChange.class.getSimpleName();
187 StateChangeReq request = new StateChangeReq(reqparams, name, stateChange);
189 addSingleton(request);
193 * Determines if a message is a broadcast message.
195 * @param message the message to examine
196 * @return {@code true} if the message is a broadcast message, {@code false} if
197 * destined for a single PDP
199 private boolean isBroadcast(PdpMessage message) {
200 return (message.getName() == null);
204 * Configures and adds a request to the map.
206 * @param request the request to be added
208 private void addSingleton(Request request) {
210 synchronized (modifyLock) {
211 PdpRequests requests = pdp2requests.computeIfAbsent(request.getMessage().getName(), this::makePdpRequests);
213 request.setListener(new SingletonListener(requests, request));
214 requests.addSingleton(request);
219 * Removes a PDP from all active groups.
221 * @param pdpName name of the PDP to be removed
222 * @return {@code true} if the PDP was removed from a group, {@code false} if it was
223 * not assigned to a group
224 * @throws PfModelException if an error occurred
226 public boolean removeFromGroups(String pdpName) throws PfModelException {
228 try (PolicyModelsProvider dao = daoFactory.create()) {
230 PdpGroupFilter filter = PdpGroupFilter.builder().groupState(PdpState.ACTIVE).build();
231 List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
232 List<PdpGroup> updates = new ArrayList<>(1);
234 for (PdpGroup group : groups) {
235 if (removeFromGroup(pdpName, group)) {
240 if (updates.isEmpty()) {
244 dao.updatePdpGroups(updates);
251 * Removes a PDP from a group.
253 * @param pdpName name of the PDP to be removed
254 * @param group group from which it should be removed
255 * @return {@code true} if the PDP was removed from the group, {@code false} if it was
256 * not assigned to the group
258 private boolean removeFromGroup(String pdpName, PdpGroup group) {
259 for (PdpSubGroup subgrp : group.getPdpSubgroups()) {
260 if (removeFromSubgroup(pdpName, group, subgrp)) {
269 * Removes a PDP from a subgroup.
271 * @param pdpName name of the PDP to be removed
272 * @param group group from which to attempt to remove the PDP
273 * @param subgrp subgroup from which to attempt to remove the PDP
274 * @return {@code true} if the PDP was removed, {@code false} if the PDP was not in
277 private boolean removeFromSubgroup(String pdpName, PdpGroup group, PdpSubGroup subgrp) {
279 Iterator<Pdp> iter = subgrp.getPdpInstances().iterator();
281 while (iter.hasNext()) {
282 Pdp instance = iter.next();
284 if (pdpName.equals(instance.getInstanceId())) {
285 logger.info("removed {} from group={} subgroup={}", pdpName, group.getName(), subgrp.getPdpType());
287 subgrp.setCurrentInstanceCount(subgrp.getPdpInstances().size());
296 * Creates a new set of requests for a PDP. May be overridden by junit tests.
298 * @param pdpName PDP name
299 * @return a new set of requests
301 protected PdpRequests makePdpRequests(String pdpName) {
302 return new PdpRequests(pdpName);
306 * Listener for singleton request events.
308 private class SingletonListener implements RequestListener {
309 private final PdpRequests requests;
310 private final Request request;
312 public SingletonListener(PdpRequests requests, Request request) {
313 this.requests = requests;
314 this.request = request;
318 public void failure(String pdpName, String reason) {
319 if (requests.getPdpName().equals(pdpName)) {
320 disablePdp(requests);
325 public void success(String pdpName) {
326 if (requests.getPdpName().equals(pdpName)) {
327 if (pdp2requests.get(requests.getPdpName()) == requests) {
328 startNextRequest(requests, request);
331 logger.info("discard old requests for {}", pdpName);
332 requests.stopPublishing();
338 public void retryCountExhausted() {
339 disablePdp(requests);
343 * Starts the next request associated with a PDP.
345 * @param requests current set of requests
346 * @param request the request that just completed
348 private void startNextRequest(PdpRequests requests, Request request) {
349 if (!requests.startNextRequest(request)) {
350 pdp2requests.remove(requests.getPdpName(), requests);
355 * Disables a PDP by removing it from its subgroup and then sending it a PASSIVE
358 * @param requests the requests associated with the PDP to be disabled
360 private void disablePdp(PdpRequests requests) {
362 // remove the requests from the map
363 if (!pdp2requests.remove(requests.getPdpName(), requests)) {
364 // don't have the info we need to disable it
365 logger.warn("no requests with which to disable {}", requests.getPdpName());
369 logger.warn("disabling {}", requests.getPdpName());
371 requests.stopPublishing();
373 // remove the PDP from all groups
374 boolean removed = false;
376 removed = removeFromGroups(requests.getPdpName());
377 } catch (PfModelException e) {
378 logger.info("unable to remove PDP {} from subgroup", requests.getPdpName(), e);
381 // send the state change
382 PdpStateChange change = new PdpStateChange();
383 change.setName(requests.getPdpName());
384 change.setState(PdpState.PASSIVE);
387 // send an update, too
388 PdpUpdate update = new PdpUpdate();
389 update.setName(requests.getPdpName());
390 update.setPolicies(Collections.emptyList());
392 addRequest(update, change);