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 * Stops publishing requests to the given PDP.
95 * @param pdpName PDP name
97 public void stopPublishing(String pdpName) {
98 synchronized (modifyLock) {
99 PdpRequests requests = pdp2requests.remove(pdpName);
100 if (requests != null) {
101 requests.stopPublishing();
107 * Adds a pair of requests to the map.
109 * @param update the UPDATE request or {@code null}
110 * @param stateChange the STATE-CHANGE request or {@code null}
112 public void addRequest(PdpUpdate update, PdpStateChange stateChange) {
113 if (update == null) {
114 addRequest(stateChange);
117 synchronized (modifyLock) {
119 addRequest(stateChange);
125 * Adds an UPDATE request to the map.
127 * @param update the UPDATE request or {@code null}
129 public void addRequest(PdpUpdate update) {
130 if (update == null) {
134 if (isBroadcast(update)) {
135 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + update);
139 RequestParams reqparams = new RequestParams()
140 .setMaxRetryCount(params.getParams().getUpdateParameters().getMaxRetryCount())
141 .setTimers(params.getUpdateTimers())
142 .setModifyLock(params.getModifyLock())
143 .setPublisher(params.getPublisher())
144 .setResponseDispatcher(params.getResponseDispatcher());
147 String name = update.getName() + " " + PdpUpdate.class.getSimpleName();
148 UpdateReq request = new UpdateReq(reqparams, name, update);
150 addSingleton(request);
154 * Adds a STATE-CHANGE request to the map.
156 * @param stateChange the STATE-CHANGE request or {@code null}
158 public void addRequest(PdpStateChange stateChange) {
159 if (stateChange == null) {
163 if (isBroadcast(stateChange)) {
164 throw new IllegalArgumentException(UNEXPECTED_BROADCAST + stateChange);
168 RequestParams reqparams = new RequestParams()
169 .setMaxRetryCount(params.getParams().getStateChangeParameters().getMaxRetryCount())
170 .setTimers(params.getStateChangeTimers())
171 .setModifyLock(params.getModifyLock())
172 .setPublisher(params.getPublisher())
173 .setResponseDispatcher(params.getResponseDispatcher());
176 String name = stateChange.getName() + " " + PdpStateChange.class.getSimpleName();
177 StateChangeReq request = new StateChangeReq(reqparams, name, stateChange);
179 addSingleton(request);
183 * Determines if a message is a broadcast message.
185 * @param message the message to examine
186 * @return {@code true} if the message is a broadcast message, {@code false} if
187 * destined for a single PDP
189 private boolean isBroadcast(PdpMessage message) {
190 return (message.getName() == null);
194 * Configures and adds a request to the map.
196 * @param request the request to be added
198 private void addSingleton(Request request) {
200 synchronized (modifyLock) {
201 PdpRequests requests = pdp2requests.computeIfAbsent(request.getMessage().getName(), this::makePdpRequests);
203 request.setListener(new SingletonListener(requests, request));
204 requests.addSingleton(request);
209 * Starts the next request associated with a PDP.
211 * @param requests current set of requests
212 * @param request the request that just completed
214 private void startNextRequest(PdpRequests requests, Request request) {
215 if (!requests.startNextRequest(request)) {
216 pdp2requests.remove(requests.getPdpName(), requests);
221 * Disables a PDP by removing it from its subgroup and then sending it a PASSIVE
224 * @param requests the requests associated with the PDP to be disabled
226 private void disablePdp(PdpRequests requests) {
228 // remove the requests from the map
229 if (!pdp2requests.remove(requests.getPdpName(), requests)) {
230 // don't have the info we need to disable it
231 logger.warn("no requests with which to disable {}", requests.getPdpName());
235 logger.warn("disabling {}", requests.getPdpName());
237 requests.stopPublishing();
239 // remove the PDP from all groups
241 removeFromGroups(requests.getPdpName());
242 } catch (PfModelException e) {
243 logger.info("unable to remove PDP {} from subgroup", requests.getPdpName(), e);
246 // send the state change
247 PdpStateChange change = new PdpStateChange();
248 change.setName(requests.getPdpName());
249 change.setState(PdpState.PASSIVE);
254 * Removes a PDP from all active groups.
256 * @param pdpName name of the PDP to be removed
257 * @throws PfModelException if an error occurs
259 public void removeFromGroups(String pdpName) throws PfModelException {
261 try (PolicyModelsProvider dao = daoFactory.create()) {
263 PdpGroupFilter filter = PdpGroupFilter.builder().groupState(PdpState.ACTIVE).build();
264 List<PdpGroup> groups = dao.getFilteredPdpGroups(filter);
265 List<PdpGroup> updates = new ArrayList<>(1);
267 for (PdpGroup group : groups) {
268 if (removeFromGroup(pdpName, group)) {
273 if (!updates.isEmpty()) {
274 dao.updatePdpGroups(updates);
280 * Removes a PDP from a group.
282 * @param pdpName name of the PDP to be removed
283 * @param group group from which it should be removed
284 * @return {@code true} if the PDP was removed from the, {@code false} if it was not
285 * assigned to the group
287 private boolean removeFromGroup(String pdpName, PdpGroup group) {
288 for (PdpSubGroup subgrp : group.getPdpSubgroups()) {
289 if (removeFromSubgroup(pdpName, group, subgrp)) {
298 * Removes a PDP from a subgroup.
300 * @param pdpName name of the PDP to be removed
301 * @param group group from which to attempt to remove the PDP
302 * @param subgrp subgroup from which to attempt to remove the PDP
303 * @return {@code true} if the PDP was removed, {@code false} if the PDP was not in
306 private boolean removeFromSubgroup(String pdpName, PdpGroup group, PdpSubGroup subgrp) {
308 Iterator<Pdp> iter = subgrp.getPdpInstances().iterator();
310 while (iter.hasNext()) {
311 Pdp instance = iter.next();
313 if (pdpName.equals(instance.getInstanceId())) {
314 logger.info("removed {} from group={} version={} subgroup={}", pdpName, group.getName(),
315 group.getVersion(), subgrp.getPdpType());
317 subgrp.setCurrentInstanceCount(subgrp.getPdpInstances().size());
326 * Creates a new set of requests for a PDP. May be overridden by junit tests.
328 * @param pdpName PDP name
329 * @return a new set of requests
331 protected PdpRequests makePdpRequests(String pdpName) {
332 return new PdpRequests(pdpName);
336 * Listener for singleton request events.
338 private class SingletonListener implements RequestListener {
339 private final PdpRequests requests;
340 private final Request request;
342 public SingletonListener(PdpRequests requests, Request request) {
343 this.requests = requests;
344 this.request = request;
348 public void failure(String pdpName, String reason) {
349 if (requests.getPdpName().equals(pdpName)) {
350 disablePdp(requests);
355 public void success(String pdpName) {
356 if (requests.getPdpName().equals(pdpName)) {
357 if (pdp2requests.get(requests.getPdpName()) == requests) {
358 startNextRequest(requests, request);
361 logger.info("discard old requests for {}", pdpName);
362 requests.stopPublishing();
368 public void retryCountExhausted() {
369 disablePdp(requests);