diff options
Diffstat (limited to 'main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java')
-rw-r--r-- | main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java | 457 |
1 files changed, 222 insertions, 235 deletions
diff --git a/main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java b/main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java index 24443cc2..6a743a31 100644 --- a/main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java +++ b/main/src/main/java/org/onap/policy/pap/main/comm/PdpModifyRequestMap.java @@ -20,26 +20,43 @@ package org.onap.policy.pap.main.comm; -import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.pdp.concepts.Pdp; +import org.onap.policy.models.pdp.concepts.PdpGroup; +import org.onap.policy.models.pdp.concepts.PdpGroupFilter; +import org.onap.policy.models.pdp.concepts.PdpMessage; import org.onap.policy.models.pdp.concepts.PdpStateChange; +import org.onap.policy.models.pdp.concepts.PdpSubGroup; import org.onap.policy.models.pdp.concepts.PdpUpdate; -import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; -import org.onap.policy.pap.main.comm.msgdata.StateChangeData; -import org.onap.policy.pap.main.comm.msgdata.UpdateData; +import org.onap.policy.models.pdp.enums.PdpState; +import org.onap.policy.models.provider.PolicyModelsProvider; +import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper; +import org.onap.policy.pap.main.comm.msgdata.Request; +import org.onap.policy.pap.main.comm.msgdata.RequestListener; +import org.onap.policy.pap.main.comm.msgdata.StateChangeReq; +import org.onap.policy.pap.main.comm.msgdata.UpdateReq; import org.onap.policy.pap.main.parameters.PdpModifyRequestMapParams; +import org.onap.policy.pap.main.parameters.RequestParams; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Maps a PDP name to requests that modify PDPs. */ public class PdpModifyRequestMap { + private static final Logger logger = LoggerFactory.getLogger(PdpModifyRequestMap.class); + + private static final String UNEXPECTED_BROADCAST = "unexpected broadcast message: "; /** - * Maps a PDP name to its request data. An entry is removed once all of the requests - * within the data have been completed. + * Maps a PDP name to its outstanding requests. */ - private final Map<String, ModifyReqData> name2data = new HashMap<>(); + private final Map<String, PdpRequests> pdp2requests = new HashMap<>(); /** * PDP modification lock. @@ -52,7 +69,13 @@ public class PdpModifyRequestMap { private final PdpModifyRequestMapParams params; /** - * Constructs the data. + * Factory for PAP DAO. + */ + private final PolicyModelsProviderFactoryWrapper daoFactory; + + + /** + * Constructs the object. * * @param params configuration parameters * @@ -63,24 +86,21 @@ public class PdpModifyRequestMap { this.params = params; this.modifyLock = params.getModifyLock(); + this.daoFactory = params.getDaoFactory(); } /** - * Adds an UPDATE request to the map. - * - * @param update the UPDATE request or {@code null} - */ - public void addRequest(PdpUpdate update) { - addRequest(update, null); - } - - /** - * Adds STATE-CHANGE request to the map. + * Stops publishing requests to the given PDP. * - * @param stateChange the STATE-CHANGE request or {@code null} + * @param pdpName PDP name */ - public void addRequest(PdpStateChange stateChange) { - addRequest(null, stateChange); + public void stopPublishing(String pdpName) { + synchronized (modifyLock) { + PdpRequests requests = pdp2requests.remove(pdpName); + if (requests != null) { + requests.stopPublishing(); + } + } } /** @@ -90,288 +110,255 @@ public class PdpModifyRequestMap { * @param stateChange the STATE-CHANGE request or {@code null} */ public void addRequest(PdpUpdate update, PdpStateChange stateChange) { - if (update == null && stateChange == null) { - return; - } + if (update == null) { + addRequest(stateChange); - synchronized (modifyLock) { - String pdpName = getPdpName(update, stateChange); - - ModifyReqData data = name2data.get(pdpName); - if (data != null) { - // update the existing request - data.add(update); - data.add(stateChange); - - } else { - data = makeRequestData(update, stateChange); - name2data.put(pdpName, data); - data.startPublishing(); + } else { + synchronized (modifyLock) { + addRequest(update); + addRequest(stateChange); } } } /** - * Gets the PDP name from two requests. + * Adds an UPDATE request to the map. * - * @param update the update request, or {@code null} - * @param stateChange the state-change request, or {@code null} - * @return the PDP name, or {@code null} if both requests are {@code null} + * @param update the UPDATE request or {@code null} */ - private static String getPdpName(PdpUpdate update, PdpStateChange stateChange) { - String pdpName; + public void addRequest(PdpUpdate update) { + if (update == null) { + return; + } - if (update != null) { - if ((pdpName = update.getName()) == null) { - throw new IllegalArgumentException("missing name in " + update); - } + if (isBroadcast(update)) { + throw new IllegalArgumentException(UNEXPECTED_BROADCAST + update); + } - if (stateChange != null && !pdpName.equals(stateChange.getName())) { - throw new IllegalArgumentException( - "name " + stateChange.getName() + " does not match " + pdpName + " " + stateChange); - } + // @formatter:off + RequestParams reqparams = new RequestParams() + .setMaxRetryCount(params.getParams().getUpdateParameters().getMaxRetryCount()) + .setTimers(params.getUpdateTimers()) + .setModifyLock(params.getModifyLock()) + .setPublisher(params.getPublisher()) + .setResponseDispatcher(params.getResponseDispatcher()); + // @formatter:on - } else { - if ((pdpName = stateChange.getName()) == null) { - throw new IllegalArgumentException("missing name in " + stateChange); - } - } + String name = update.getName() + " " + PdpUpdate.class.getSimpleName(); + UpdateReq request = new UpdateReq(reqparams, name, update); - return pdpName; + addSingleton(request); } /** - * Determines if two requests are the "same", which is does not necessarily mean - * "equals". + * Adds a STATE-CHANGE request to the map. * - * @param first first request to check - * @param second second request to check - * @return {@code true} if the requests are the "same", {@code false} otherwise + * @param stateChange the STATE-CHANGE request or {@code null} */ - protected static boolean isSame(PdpUpdate first, PdpUpdate second) { - if (first.getPolicies().size() != second.getPolicies().size()) { - return false; + public void addRequest(PdpStateChange stateChange) { + if (stateChange == null) { + return; } - if (!first.getPdpGroup().equals(second.getPdpGroup())) { - return false; + if (isBroadcast(stateChange)) { + throw new IllegalArgumentException(UNEXPECTED_BROADCAST + stateChange); } - if (!first.getPdpSubgroup().equals(second.getPdpSubgroup())) { - return false; - } + // @formatter:off + RequestParams reqparams = new RequestParams() + .setMaxRetryCount(params.getParams().getStateChangeParameters().getMaxRetryCount()) + .setTimers(params.getStateChangeTimers()) + .setModifyLock(params.getModifyLock()) + .setPublisher(params.getPublisher()) + .setResponseDispatcher(params.getResponseDispatcher()); + // @formatter:on - // see if the other has any policies that this does not have - ArrayList<ToscaPolicy> lst = new ArrayList<>(second.getPolicies()); - lst.removeAll(first.getPolicies()); + String name = stateChange.getName() + " " + PdpStateChange.class.getSimpleName(); + StateChangeReq request = new StateChangeReq(reqparams, name, stateChange); - return lst.isEmpty(); + addSingleton(request); } /** - * Determines if two requests are the "same", which is does not necessarily mean - * "equals". + * Determines if a message is a broadcast message. * - * @param first first request to check - * @param second second request to check - * @return {@code true} if this update subsumes the other, {@code false} otherwise + * @param message the message to examine + * @return {@code true} if the message is a broadcast message, {@code false} if + * destined for a single PDP */ - protected static boolean isSame(PdpStateChange first, PdpStateChange second) { - return (first.getState() == second.getState()); + private boolean isBroadcast(PdpMessage message) { + return (message.getName() == null); } /** - * Request data, which contains an UPDATE or a STATE-CHANGE request, or both. The - * UPDATE is always published before the STATE-CHANGE. In addition, both requests may - * be changed at any point, possibly triggering a restart of the publishing. + * Configures and adds a request to the map. + * + * @param request the request to be added */ - public class ModifyReqData extends RequestData { - - /** - * The UPDATE message to be published, or {@code null}. - */ - private PdpUpdate update; - - /** - * The STATE-CHANGE message to be published, or {@code null}. - */ - private PdpStateChange stateChange; - - - /** - * Constructs the object. - * - * @param newUpdate the UPDATE message to be sent, or {@code null} - * @param newState the STATE-CHANGE message to be sent, or {@code null} - */ - public ModifyReqData(PdpUpdate newUpdate, PdpStateChange newState) { - super(params); - - if (newUpdate != null) { - this.stateChange = newState; - setName(newUpdate.getName()); - update = newUpdate; - configure(new ModUpdateData(newUpdate)); - - } else { - this.update = null; - setName(newState.getName()); - stateChange = newState; - configure(new ModStateChangeData(newState)); - } - } + private void addSingleton(Request request) { - /** - * Determines if this request is still in the map. - */ - @Override - protected boolean isActive() { - return (name2data.get(getName()) == this); + synchronized (modifyLock) { + PdpRequests requests = pdp2requests.computeIfAbsent(request.getMessage().getName(), this::makePdpRequests); + + request.setListener(new SingletonListener(requests, request)); + requests.addSingleton(request); } + } - /** - * Removes this request from the map. - */ - @Override - protected void allCompleted() { - name2data.remove(getName(), this); + /** + * Starts the next request associated with a PDP. + * + * @param requests current set of requests + * @param request the request that just completed + */ + private void startNextRequest(PdpRequests requests, Request request) { + if (!requests.startNextRequest(request)) { + pdp2requests.remove(requests.getPdpName(), requests); } + } - /** - * Adds an UPDATE to the request data, replacing any existing UPDATE, if - * appropriate. If the UPDATE is replaced, then publishing is restarted. - * - * @param newRequest the new UPDATE request - */ - private void add(PdpUpdate newRequest) { - if (newRequest == null) { - return; - } + /** + * Disables a PDP by removing it from its subgroup and then sending it a PASSIVE + * request. + * + * @param requests the requests associated with the PDP to be disabled + */ + private void disablePdp(PdpRequests requests) { - synchronized (modifyLock) { - if (update != null && isSame(update, newRequest)) { - // already have this update - discard it - return; - } + // remove the requests from the map + if (!pdp2requests.remove(requests.getPdpName(), requests)) { + // don't have the info we need to disable it + logger.warn("no requests with which to disable {}", requests.getPdpName()); + return; + } - // must restart from scratch - stopPublishing(); + logger.warn("disabling {}", requests.getPdpName()); - update = newRequest; - configure(new ModUpdateData(newRequest)); + requests.stopPublishing(); - startPublishing(); - } + // don't do anything if we don't have a group + String name = requests.getLastGroupName(); + if (name == null) { + logger.warn("no group with which to disable {}", requests.getPdpName()); + return; } - /** - * Adds a STATE-CHANGE to the request data, replacing any existing UPDATE, if - * appropriate. If the STATE-CHANGE is replaced, and we're currently publishing - * the STATE-CHANGE, then publishing is restarted. - * - * @param newRequest the new STATE-CHANGE request - */ - private void add(PdpStateChange newRequest) { - if (newRequest == null) { + // remove the PDP from the group + removeFromGroup(requests.getPdpName(), name); + + // send the state change + PdpStateChange change = new PdpStateChange(); + change.setName(requests.getPdpName()); + change.setState(PdpState.PASSIVE); + addRequest(change); + } + + /** + * Removes a PDP from its group. + * + * @param pdpName name of the PDP to be removed + * @param groupName name of the group from which it should be removed + */ + private void removeFromGroup(String pdpName, String groupName) { + + try (PolicyModelsProvider dao = daoFactory.create()) { + + PdpGroupFilter filter = PdpGroupFilter.builder().name(groupName).groupState(PdpState.ACTIVE) + .version(PdpGroupFilter.LATEST_VERSION).build(); + + List<PdpGroup> groups = dao.getFilteredPdpGroups(filter); + if (groups.isEmpty()) { return; } - synchronized (modifyLock) { - if (stateChange != null && isSame(stateChange, newRequest)) { - // already have this update - discard it + PdpGroup group = groups.get(0); + + for (PdpSubGroup subgrp : group.getPdpSubgroups()) { + if (removeFromSubgroup(pdpName, group, subgrp)) { + dao.updatePdpGroups(Collections.singletonList(group)); return; } + } - if (getWrapper() instanceof StateChangeData) { - // we were publishing STATE-CHANGE, thus must restart it - stopPublishing(); + } catch (PfModelException e) { + logger.info("unable to remove PDP {} from subgroup", pdpName, e); + } + } - stateChange = newRequest; - configure(new ModStateChangeData(newRequest)); + /** + * Removes a PDP from a subgroup. + * + * @param pdpName name of the PDP to be removed + * @param group group from which to attempt to remove the PDP + * @param subgrp subgroup from which to attempt to remove the PDP + * @return {@code true} if the PDP was removed, {@code false} if the PDP was not in + * the group + * @throws PfModelException if a DB error occurs + */ + private boolean removeFromSubgroup(String pdpName, PdpGroup group, PdpSubGroup subgrp) throws PfModelException { - startPublishing(); + Iterator<Pdp> iter = subgrp.getPdpInstances().iterator(); - } else { - // haven't started publishing STATE-CHANGE yet, just replace it - stateChange = newRequest; - } + while (iter.hasNext()) { + Pdp instance = iter.next(); + + if (pdpName.equals(instance.getInstanceId())) { + logger.info("removed {} from group={} version={} subgroup={}", pdpName, group.getName(), + group.getVersion(), subgrp.getPdpType()); + iter.remove(); + subgrp.setCurrentInstanceCount(subgrp.getPdpInstances().size()); + return true; } } - /** - * Indicates that the retry count was exhausted. - */ - protected void retryCountExhausted() { - // remove this request data from the PDP request map - allCompleted(); + return false; + } - // TODO what to do? - } + /** + * Creates a new set of requests for a PDP. May be overridden by junit tests. + * + * @param pdpName PDP name + * @return a new set of requests + */ + protected PdpRequests makePdpRequests(String pdpName) { + return new PdpRequests(pdpName); + } - /** - * Indicates that a response did not match the data. - * - * @param reason the reason for the mismatch - */ - protected void mismatch(String reason) { - // remove this request data from the PDP request map - allCompleted(); + /** + * Listener for singleton request events. + */ + private class SingletonListener implements RequestListener { + private final PdpRequests requests; + private final Request request; - // TODO what to do? + public SingletonListener(PdpRequests requests, Request request) { + this.requests = requests; + this.request = request; } - /** - * Wraps an UPDATE. - */ - private class ModUpdateData extends UpdateData { - - public ModUpdateData(PdpUpdate message) { - super(message, params); - } - - @Override - public void mismatch(String reason) { - ModifyReqData.this.mismatch(reason); + @Override + public void failure(String pdpName, String reason) { + if (requests.getPdpName().equals(pdpName)) { + disablePdp(requests); } + } - @Override - public void completed() { - if (stateChange == null) { - // no STATE-CHANGE request - we're done - allCompleted(); + @Override + public void success(String pdpName) { + if (requests.getPdpName().equals(pdpName)) { + if (pdp2requests.get(requests.getPdpName()) == requests) { + startNextRequest(requests, request); } else { - // now process the STATE-CHANGE request - configure(new ModStateChangeData(stateChange)); - startPublishing(); + logger.info("discard old requests for {}", pdpName); + requests.stopPublishing(); } } } - /** - * Wraps a STATE-CHANGE. - */ - private class ModStateChangeData extends StateChangeData { - - public ModStateChangeData(PdpStateChange message) { - super(message, params); - } - - @Override - public void mismatch(String reason) { - ModifyReqData.this.mismatch(reason); - } - - @Override - public void completed() { - allCompleted(); - } + @Override + public void retryCountExhausted() { + disablePdp(requests); } } - - // these may be overridden by junit tests - - protected ModifyReqData makeRequestData(PdpUpdate update, PdpStateChange stateChange) { - return new ModifyReqData(update, stateChange); - } } |