diff options
Diffstat (limited to 'main/src/main/java')
7 files changed, 518 insertions, 108 deletions
diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java index 25a886bd..f97107f7 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java @@ -24,26 +24,58 @@ import lombok.Getter; import org.onap.policy.models.pdp.concepts.PdpGroup; /** - * PdpGroup data, which includes the old group, that's in the DB, and possibly a new - * group, that must be added to the DB. + * PdpGroup data, only the latest copy of the group is retained. */ -@Getter public class GroupData { + @Getter private PdpGroup group; + private enum State { + UNCHANGED, CREATED, UPDATED + } + /** - * {@code True} if the group has been updated, {@code false} otherwise. + * State of the group. */ - private boolean updated = false; + private State state; /** - * Constructs the object. + * Constructs the object, for an existing group. * * @param group the group that is in the DB */ public GroupData(PdpGroup group) { + this(group, false); + } + + /** + * Constructs the object. + * + * @param group the group that is in, or to be added to, the DB + * @param isNew {@code true} if this is a new group, {@code false} otherwise + */ + public GroupData(PdpGroup group, boolean isNew) { this.group = group; + this.state = (isNew ? State.CREATED : State.UNCHANGED); + } + + /** + * Determines if the group is new. + * + * @return {@code true} if the group is new, {@code false} otherwise + */ + public boolean isNew() { + return (state == State.CREATED); + } + + /** + * Determines if the group has been updated. + * + * @return {@code true} if the group has been updated, {@code false} otherwise + */ + public boolean isUpdated() { + return (state == State.UPDATED); } /** @@ -57,7 +89,10 @@ public class GroupData { "expected group " + this.group.getName() + ", but received " + newGroup.getName()); } - this.updated = true; this.group = newGroup; + + if (state == State.UNCHANGED) { + state = State.UPDATED; + } } } diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java index ca638f3e..08781857 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java @@ -82,51 +82,7 @@ public class PdpGroupDeleteControllerV1 extends PapRestControllerV1 { public Response deleteGroup(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, @ApiParam(value = "PDP Group Name", required = true) @PathParam("name") String groupName) { - Pair<Status, PdpGroupDeleteResponse> pair = provider.deleteGroup(groupName, null); - - return addLoggingHeaders(addVersionControlHeaders(Response.status(pair.getLeft())), requestId) - .entity(pair.getRight()).build(); - } - - /** - * Deletes a particular version of a PDP group. - * - * @param requestId request ID used in ONAP logging - * @param groupName name of the PDP group to be deleted - * @param version version to be deleted - * @return a response - */ - // @formatter:off - @DELETE - @Path("pdps/groups/{name}/versions/{version}") - @ApiOperation(value = "Delete version of a PDP Group", - notes = "Deletes a version of PDP Group, returning optional error details", - response = PdpGroupDeleteResponse.class, - tags = {"Policy Administration (PAP) API"}, - authorizations = @Authorization(value = AUTHORIZATION_TYPE), - responseHeaders = { - @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION, - response = String.class), - @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION, - response = String.class), - @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION, - response = UUID.class)}, - extensions = {@Extension(name = EXTENSION_NAME, - properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION), - @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})}) - @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE), - @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE), - @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)}) - // @formatter:on - - public Response deleteGroupVersion( - @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, - @ApiParam(value = "PDP Group Name", required = true) @PathParam("name") String groupName, - @ApiParam(value = "PDP Group Version", required = true) @PathParam("version") String version) { - - Pair<Status, PdpGroupDeleteResponse> pair = provider.deleteGroup(groupName, version); + Pair<Status, PdpGroupDeleteResponse> pair = provider.deleteGroup(groupName); return addLoggingHeaders(addVersionControlHeaders(Response.status(pair.getLeft())), requestId) .entity(pair.getRight()).build(); diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java index 6457efae..7d47b3e2 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java @@ -27,6 +27,7 @@ import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.pap.concepts.PdpGroupDeleteResponse; import org.onap.policy.models.pdp.concepts.PdpGroup; import org.onap.policy.models.pdp.concepts.PdpSubGroup; +import org.onap.policy.models.pdp.enums.PdpState; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; @@ -52,47 +53,73 @@ public class PdpGroupDeleteProvider extends ProviderBase<PdpGroupDeleteResponse> * Deletes a PDP group. * * @param groupName name of the PDP group to be deleted - * @param version group version to delete; may be {@code null} if the group has only - * one version * @return a pair containing the status and the response */ - public Pair<Response.Status, PdpGroupDeleteResponse> deleteGroup(String groupName, String version) { + public Pair<Response.Status, PdpGroupDeleteResponse> deleteGroup(String groupName) { - PdpGroupDeleteResponse resp = new PdpGroupDeleteResponse(); - resp.setErrorDetails("not implemented yet"); + return process(groupName, this::deleteGroup); + } + + /** + * Deletes a PDP group. + * + * @param data session data + * @param groupName name of the PDP group to be deleted + */ + private void deleteGroup(SessionData data, String groupName) { + try { + PdpGroup group = data.getGroup(groupName); + if (group == null) { + throw new PolicyPapRuntimeException("group not found"); + } + + if (group.getPdpGroupState() == PdpState.ACTIVE) { + throw new PolicyPapRuntimeException("group is still " + PdpState.ACTIVE); + } - return Pair.of(Response.Status.INTERNAL_SERVER_ERROR, resp); + data.deleteGroupFromDb(group); + + } catch (PfModelException e) { + // no need to log the error here, as it will be logged by the invoker + logger.warn("failed to delete group: {}", groupName); + throw new PolicyPapRuntimeException(DB_ERROR_MSG, e); + + } catch (RuntimeException e) { + // no need to log the error here, as it will be logged by the invoker + logger.warn("failed to delete group: {}", groupName); + throw e; + } } /** - * Deletes a PDP policy. + * Undeploys a policy. * * @param policyIdent identifier of the policy to be undeployed * @return a pair containing the status and the response */ public Pair<Response.Status, PdpGroupDeleteResponse> undeploy(ToscaPolicyIdentifierOptVersion policyIdent) { - return process(policyIdent, this::deletePolicy); + return process(policyIdent, this::undeployPolicy); } /** - * Deletes a policy from its groups. + * Undeploys a policy from its groups. * * @param data session data * @param ident identifier of the policy to be deleted */ - private void deletePolicy(SessionData data, ToscaPolicyIdentifierOptVersion ident) { + private void undeployPolicy(SessionData data, ToscaPolicyIdentifierOptVersion ident) { try { processPolicy(data, ident); } catch (PfModelException e) { // no need to log the error here, as it will be logged by the invoker - logger.warn("failed to deploy policy: {}", ident); + logger.warn("failed to undeploy policy: {}", ident); throw new PolicyPapRuntimeException(DB_ERROR_MSG, e); } catch (RuntimeException e) { // no need to log the error here, as it will be logged by the invoker - logger.warn("failed to deploy policy: {}", ident); + logger.warn("failed to undeploy policy: {}", ident); throw e; } } @@ -104,6 +131,9 @@ public class PdpGroupDeleteProvider extends ProviderBase<PdpGroupDeleteResponse> return resp; } + /** + * Returns a function that will remove the specified policy from a subgroup. + */ @Override protected BiFunction<PdpGroup, PdpSubGroup, Boolean> makeUpdater(ToscaPolicy policy) { ToscaPolicyIdentifier desiredIdent = policy.getIdentifier(); diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java index 6d4dc7ed..bdec3562 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java @@ -82,7 +82,7 @@ public class PdpGroupDeployControllerV1 extends PapRestControllerV1 { public Response deployGroup(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, @ApiParam(value = "List of PDP Group Configuration", required = true) PdpGroups groups) { - Pair<Status, PdpGroupDeployResponse> pair = provider.deployGroup(groups); + Pair<Status, PdpGroupDeployResponse> pair = provider.createOrUpdateGroups(groups); return addLoggingHeaders(addVersionControlHeaders(Response.status(pair.getLeft())), requestId) .entity(pair.getRight()).build(); diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java index eef14388..cb2d1e34 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java @@ -20,10 +20,22 @@ package org.onap.policy.pap.main.rest.depundep; +import com.att.aft.dme2.internal.apache.commons.lang.ObjectUtils; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.function.BiFunction; +import java.util.function.Consumer; import javax.ws.rs.core.Response; import org.apache.commons.lang3.tuple.Pair; +import org.onap.policy.common.parameters.BeanValidationResult; +import org.onap.policy.common.parameters.ObjectValidationResult; +import org.onap.policy.common.parameters.ValidationResult; +import org.onap.policy.common.parameters.ValidationStatus; import org.onap.policy.common.utils.services.Registry; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.pap.concepts.PdpDeployPolicies; @@ -31,7 +43,7 @@ import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse; import org.onap.policy.models.pdp.concepts.PdpGroup; import org.onap.policy.models.pdp.concepts.PdpGroups; import org.onap.policy.models.pdp.concepts.PdpSubGroup; -import org.onap.policy.models.pdp.concepts.PdpUpdate; +import org.onap.policy.models.pdp.enums.PdpState; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifier; import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyIdentifierOptVersion; @@ -61,28 +73,297 @@ public class PdpGroupDeployProvider extends ProviderBase<PdpGroupDeployResponse> } /** - * Deploys or updates PDP groups. + * Creates or updates PDP groups. * - * @param groups PDP group configurations + * @param groups PDP group configurations to be created or updated * @return a pair containing the status and the response */ - public Pair<Response.Status, PdpGroupDeployResponse> deployGroup(PdpGroups groups) { - return process(groups, this::deployGroups); + public Pair<Response.Status, PdpGroupDeployResponse> createOrUpdateGroups(PdpGroups groups) { + ValidationResult result = groups.validatePapRest(); + + if (!result.isValid()) { + String msg = result.getResult().trim(); + logger.warn(msg); + return Pair.of(Response.Status.INTERNAL_SERVER_ERROR, makeResponse(msg)); + } + + return process(groups, this::createOrUpdate); } /** - * Deploys or updates PDP groups. + * Creates or updates PDP groups. This is the method that does the actual work. * * @param data session data * @param groups PDP group configurations - * @return a list of requests that should be sent to configure the PDPs */ - private List<PdpUpdate> deployGroups(SessionData data, PdpGroups groups) { - throw new PolicyPapRuntimeException("not implemented yet"); + private void createOrUpdate(SessionData data, PdpGroups groups) { + BeanValidationResult result = new BeanValidationResult("groups", groups); + + for (PdpGroup group : groups.getGroups()) { + PdpGroup dbgroup = data.getGroup(group.getName()); + + if (dbgroup == null) { + result.addResult(addGroup(data, group)); + + } else { + result.addResult(updateGroup(data, dbgroup, group)); + } + } + + if (!result.isValid()) { + throw new PolicyPapRuntimeException(result.getResult().trim()); + } + } + + /** + * Adds a new group. + * + * @param data session data + * @param group the group to be added + * @return the validation result + */ + private ValidationResult addGroup(SessionData data, PdpGroup group) { + BeanValidationResult result = new BeanValidationResult(group.getName(), group); + + validateGroupOnly(group, result); + if (!result.isValid()) { + return result; + } + + // default to active + if (group.getPdpGroupState() == null) { + group.setPdpGroupState(PdpState.ACTIVE); + } + + for (PdpSubGroup subgrp : group.getPdpSubgroups()) { + result.addResult(addSubGroup(data, subgrp)); + } + + if (result.isValid()) { + data.create(group); + } + + return result; + } + + /** + * Performs additional validations of a group, but does not examine the subgroups. + * + * @param group the group to be validated + * @param result the validation result + */ + private void validateGroupOnly(PdpGroup group, BeanValidationResult result) { + if (group.getPdpGroupState() == null) { + return; + } + + switch (group.getPdpGroupState()) { + case ACTIVE: + case PASSIVE: + break; + + default: + result.addResult(new ObjectValidationResult("pdpGroupState", group.getPdpGroupState(), + ValidationStatus.INVALID, "must be null, ACTIVE, or PASSIVE")); + break; + } + } + + /** + * Updates an existing group. + * + * @param data session data + * @param dbgroup the group, as it appears within the DB + * @param group the group to be added + * @return the validation result + */ + private ValidationResult updateGroup(SessionData data, PdpGroup dbgroup, PdpGroup group) { + BeanValidationResult result = new BeanValidationResult(group.getName(), group); + + if (!ObjectUtils.equals(dbgroup.getProperties(), group.getProperties())) { + result.addResult(new ObjectValidationResult("properties", "", ValidationStatus.INVALID, + "cannot change properties")); + } + + // create a map of existing subgroups + Map<String, PdpSubGroup> type2sub = new HashMap<>(); + dbgroup.getPdpSubgroups().forEach(subgrp -> type2sub.put(subgrp.getPdpType(), subgrp)); + + boolean updated = updateField(dbgroup.getDescription(), group.getDescription(), dbgroup::setDescription); + + for (PdpSubGroup subgrp : group.getPdpSubgroups()) { + PdpSubGroup dbsub = type2sub.get(subgrp.getPdpType()); + BeanValidationResult subResult = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + if (dbsub == null) { + updated = true; + subResult.addResult(addSubGroup(data, subgrp)); + dbgroup.getPdpSubgroups().add(subgrp); + + } else { + updated = updateSubGroup(data, group, dbsub, subgrp, subResult) || updated; + } + + result.addResult(subResult); + } + + if (result.isValid() && updated) { + data.update(group); + } + + return result; + } + + /** + * Updates a field, if the new value is different than the old value. + * + * @param oldValue old value + * @param newValue new value + * @param setter function to set the field to the new value + * @return {@code true} if the field was updated, {@code false} if it already matched + * the new value + */ + private <T> boolean updateField(T oldValue, T newValue, Consumer<T> setter) { + if (oldValue == newValue) { + return false; + } + + if (oldValue != null && oldValue.equals(newValue)) { + return false; + } + + setter.accept(newValue); + return true; + } + + /** + * Adds a new subgroup. + * + * @param data session data + * @param subgrp the subgroup to be added + * @return the validation result + */ + private ValidationResult addSubGroup(SessionData data, PdpSubGroup subgrp) { + subgrp.setCurrentInstanceCount(0); + subgrp.setPdpInstances(Collections.emptyList()); + + BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + result.addResult(validatePolicies(data, subgrp)); + + return result; } /** - * Deploys or updates PDP policies. + * Updates an existing subgroup. + * + * @param data session data + * @param dbgroup the group, from the DB, containing the subgroup + * @param dbsub the subgroup, from the DB + * @param subgrp the subgroup to be updated + * @param container container for additional validation results + * @return {@code true} if the subgroup content was changed, {@code false} if there + * were no changes + */ + private boolean updateSubGroup(SessionData data, PdpGroup dbgroup, PdpSubGroup dbsub, PdpSubGroup subgrp, + BeanValidationResult container) { + + // perform additional validations first + if (!validateSubGroup(data, dbsub, subgrp, container)) { + return false; + } + + /* + * first, apply the changes about which the PDPs care + */ + boolean updated = updateList(dbsub.getPolicies(), subgrp.getPolicies(), dbsub::setPolicies); + + // publish any changes to the PDPs + if (updated) { + makeUpdates(data, dbgroup, dbsub); + } + + /* + * now make any remaining changes + */ + updated = updateList(dbsub.getSupportedPolicyTypes(), subgrp.getSupportedPolicyTypes(), + dbsub::setSupportedPolicyTypes) || updated; + + return updateField(dbsub.getDesiredInstanceCount(), subgrp.getDesiredInstanceCount(), + dbsub::setDesiredInstanceCount) || updated; + } + + /** + * Performs additional validations of a subgroup. + * + * @param data session data + * @param dbsub the subgroup, from the DB + * @param subgrp the subgroup to be validated + * @param container container for additional validation results + * @return {@code true} if the subgroup is valid, {@code false} otherwise + */ + private boolean validateSubGroup(SessionData data, PdpSubGroup dbsub, PdpSubGroup subgrp, + BeanValidationResult container) { + + BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + if (!ObjectUtils.equals(dbsub.getProperties(), subgrp.getProperties())) { + result.addResult(new ObjectValidationResult("properties", "", ValidationStatus.INVALID, + "cannot change properties")); + } + + result.addResult(validatePolicies(data, subgrp)); + container.addResult(result); + + return result.isValid(); + } + + /** + * Updates a DB list with items from a new list. + * + * @param dblist the list from the DB + * @param newList the new list + * @param setter function to set the new list + * @return {@code true} if the list changed, {@code false} if the lists were the same + */ + private <T> boolean updateList(List<T> dblist, List<T> newList, Consumer<List<T>> setter) { + + Set<T> dbTypes = new HashSet<T>(dblist); + Set<T> newTypes = new HashSet<T>(newList); + + if (dbTypes.equals(newTypes)) { + return false; + } + + setter.accept(new ArrayList<>(newTypes)); + + return true; + } + + /** + * Performs additional validations of the policies within a subgroup. + * + * @param data session data + * @param subgrp the subgroup to be validated + * @param result the validation result + */ + private ValidationResult validatePolicies(SessionData data, PdpSubGroup subgrp) { + BeanValidationResult result = new BeanValidationResult(subgrp.getPdpType(), subgrp); + + for (ToscaPolicyIdentifier ident : subgrp.getPolicies()) { + ToscaPolicy policy = data.getPolicy(ident); + + if (!subgrp.getSupportedPolicyTypes().contains(policy.getTypeIdentifier())) { + result.addResult(new ObjectValidationResult("policy", ident, ValidationStatus.INVALID, + "not a supported policy for the subgroup")); + } + } + + return result; + } + + /** + * Deploys or updates PDP policies using the simple API. * * @param policies PDP policies * @return a pair containing the status and the response @@ -92,7 +373,8 @@ public class PdpGroupDeployProvider extends ProviderBase<PdpGroupDeployResponse> } /** - * Deploys or updates PDP policies using the simple API. + * Deploys or updates PDP policies using the simple API. This is the method that does + * the actual work. * * @param data session data * @param extPolicies external PDP policies @@ -118,6 +400,9 @@ public class PdpGroupDeployProvider extends ProviderBase<PdpGroupDeployResponse> } } + /** + * Adds a policy to a subgroup, if it isn't there already. + */ @Override protected BiFunction<PdpGroup, PdpSubGroup, Boolean> makeUpdater(ToscaPolicy policy) { ToscaPolicyIdentifier desiredIdent = policy.getIdentifier(); diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java index d3519197..5e0fb71a 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java @@ -32,6 +32,7 @@ import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.pap.concepts.SimpleResponse; import org.onap.policy.models.pdp.concepts.Pdp; import org.onap.policy.models.pdp.concepts.PdpGroup; +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.provider.PolicyModelsProvider; @@ -59,7 +60,6 @@ import org.slf4j.LoggerFactory; */ public abstract class ProviderBase<R extends SimpleResponse> { private static final String DEPLOY_FAILED = "failed to deploy/undeploy policies"; - public static final String DB_ERROR_MSG = "DB error"; private static final Logger logger = LoggerFactory.getLogger(ProviderBase.class); @@ -100,7 +100,7 @@ public abstract class ProviderBase<R extends SimpleResponse> { synchronized (updateLock) { // list of requests to be published to the PDPs - Collection<PdpUpdate> requests = Collections.emptyList(); + Collection<Pair<PdpUpdate, PdpStateChange>> requests = Collections.emptyList(); try (PolicyModelsProvider dao = daoFactory.create()) { @@ -110,7 +110,7 @@ public abstract class ProviderBase<R extends SimpleResponse> { // make all of the DB updates data.updateDb(); - requests = data.getPdpUpdates(); + requests = data.getPdpRequests(); } catch (PfModelException e) { logger.warn(DEPLOY_FAILED, e); @@ -127,7 +127,7 @@ public abstract class ProviderBase<R extends SimpleResponse> { // publish the requests - requests.forEach(requestMap::addRequest); + requests.forEach(pair -> requestMap.addRequest(pair.getLeft(), pair.getRight())); } return Pair.of(Response.Status.OK, makeResponse(null)); @@ -236,13 +236,7 @@ public abstract class ProviderBase<R extends SimpleResponse> { updated = true; - /* - * generate an UPDATE for each PDP instance. Since the group is active, we - * assume that the PDP is, too, thus no need for a STATE-CHANGE. - */ - for (Pdp pdpInstance : subgroup.getPdpInstances()) { - data.addUpdate(makeUpdate(data, group, subgroup, pdpInstance)); - } + makeUpdates(data, group, subgroup); } @@ -253,19 +247,32 @@ public abstract class ProviderBase<R extends SimpleResponse> { } /** + * Makes UPDATE messages for each PDP in a subgroup. + * + * @param data session data + * @param group group containing the subgroup + * @param subgroup subgroup whose PDPs should receive messages + */ + protected void makeUpdates(SessionData data, PdpGroup group, PdpSubGroup subgroup) { + for (Pdp pdp : subgroup.getPdpInstances()) { + data.addUpdate(makeUpdate(data, group, subgroup, pdp)); + } + } + + /** * Makes an UPDATE message for a particular PDP. * * @param data session data * @param group group to which the PDP should belong * @param subgroup subgroup to which the PDP should belong - * @param pdpInstance identifies the PDP of interest + * @param pdp the PDP of interest * @return a new UPDATE message */ - private PdpUpdate makeUpdate(SessionData data, PdpGroup group, PdpSubGroup subgroup, Pdp pdpInstance) { + private PdpUpdate makeUpdate(SessionData data, PdpGroup group, PdpSubGroup subgroup, Pdp pdp) { PdpUpdate update = new PdpUpdate(); - update.setName(pdpInstance.getInstanceId()); + update.setName(pdp.getInstanceId()); update.setDescription(group.getDescription()); update.setPdpGroup(group.getName()); update.setPdpSubgroup(subgroup.getPdpType()); diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java index 6b42b19b..0537c80b 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java @@ -26,9 +26,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import org.apache.commons.lang3.tuple.Pair; import org.onap.policy.models.base.PfModelException; import org.onap.policy.models.pdp.concepts.PdpGroup; import org.onap.policy.models.pdp.concepts.PdpGroupFilter; +import org.onap.policy.models.pdp.concepts.PdpStateChange; import org.onap.policy.models.pdp.concepts.PdpUpdate; import org.onap.policy.models.pdp.enums.PdpState; import org.onap.policy.models.provider.PolicyModelsProvider; @@ -57,9 +59,9 @@ public class SessionData { private final Map<ToscaPolicyTypeIdentifier, List<GroupData>> type2groups = new HashMap<>(); /** - * Maps a PDP name to its most recently generated update request. + * Maps a PDP name to its most recently generated update and state-change requests. */ - private final Map<String, PdpUpdate> pdpUpdates = new HashMap<>(); + private final Map<String, Pair<PdpUpdate, PdpStateChange>> pdpRequests = new HashMap<>(); /** * Maps a policy's identifier to the policy. @@ -96,17 +98,11 @@ public class SessionData { try { List<ToscaPolicy> lst = dao.getPolicyList(ident.getName(), ident.getVersion()); - if (lst.isEmpty()) { throw new PolicyPapRuntimeException( "cannot find policy: " + ident.getName() + " " + ident.getVersion()); } - if (lst.size() > 1) { - throw new PolicyPapRuntimeException( - "too many policies match: " + ident.getName() + " " + ident.getVersion()); - } - return lst.get(0); } catch (PfModelException e) { @@ -117,22 +113,67 @@ public class SessionData { } /** + * Adds an update and state-change to the sets, replacing any previous entries for the + * given PDP. + * + * @param update the update to be added + * @param change the state-change to be added + */ + public void addRequests(PdpUpdate update, PdpStateChange change) { + if (!update.getName().equals(change.getName())) { + throw new IllegalArgumentException("PDP name mismatch " + update.getName() + ", " + change.getName()); + } + + pdpRequests.put(update.getName(), Pair.of(update, change)); + } + + /** * Adds an update to the set of updates, replacing any previous entry for the given * PDP. * * @param update the update to be added */ public void addUpdate(PdpUpdate update) { - pdpUpdates.put(update.getName(), update); + pdpRequests.compute(update.getName(), (name, data) -> Pair.of(update, (data == null ? null : data.getRight()))); } /** - * Gets the accumulated UPDATE requests. + * Adds a state-change to the set of state-change requests, replacing any previous entry for the given + * PDP. * - * @return the UPDATE requests + * @param change the state-change to be added */ - public Collection<PdpUpdate> getPdpUpdates() { - return pdpUpdates.values(); + public void addStateChange(PdpStateChange change) { + pdpRequests.compute(change.getName(), (name, data) -> Pair.of((data == null ? null : data.getLeft()), change)); + } + + /** + * Gets the accumulated PDP requests. + * + * @return the PDP requests + */ + public Collection<Pair<PdpUpdate, PdpStateChange>> getPdpRequests() { + return pdpRequests.values(); + } + + /** + * Gets the accumulated PDP update requests. + * + * @return the PDP requests + */ + public List<PdpUpdate> getPdpUpdates() { + return pdpRequests.values().stream().filter(req -> req.getLeft() != null).map(Pair::getLeft) + .collect(Collectors.toList()); + } + + /** + * Gets the accumulated PDP state-change requests. + * + * @return the PDP requests + */ + public List<PdpStateChange> getPdpStateChanges() { + return pdpRequests.values().stream().filter(req -> req.getRight() != null).map(Pair::getRight) + .collect(Collectors.toList()); } /** @@ -163,6 +204,19 @@ public class SessionData { } /** + * Creates a group. + * + * @param newGroup the new group + */ + public void create(PdpGroup newGroup) { + String name = newGroup.getName(); + + if (groupCache.put(name, new GroupData(newGroup, true)) != null) { + throw new IllegalStateException("group already cached: " + name); + } + } + + /** * Updates a group. * * @param newGroup the updated group @@ -178,6 +232,34 @@ public class SessionData { } /** + * Gets the group by the given name. + * + * @param name name of the group to get + * @return the group, or {@code null} if it does not exist + * @throws PolicyPapRuntimeException if an error occurs + */ + public PdpGroup getGroup(String name) { + + GroupData data = groupCache.computeIfAbsent(name, key -> { + + try { + List<PdpGroup> lst = dao.getPdpGroups(key); + if (lst.isEmpty()) { + return null; + } + + return new GroupData(lst.get(0)); + + } catch (PfModelException e) { + throw new PolicyPapRuntimeException("cannot get group: " + name, e); + } + + }); + + return (data == null ? null : data.getGroup()); + } + + /** * Gets the active groups supporting the given policy. * * @param type desired policy type @@ -225,13 +307,28 @@ public class SessionData { * @throws PfModelException if an error occurs */ public void updateDb() throws PfModelException { - List<GroupData> updatedGroups = + // create new groups + List<GroupData> created = groupCache.values().stream().filter(GroupData::isNew).collect(Collectors.toList()); + if (!created.isEmpty()) { + dao.createPdpGroups(created.stream().map(GroupData::getGroup).collect(Collectors.toList())); + } + + // update existing groups + List<GroupData> updated = groupCache.values().stream().filter(GroupData::isUpdated).collect(Collectors.toList()); - if (updatedGroups.isEmpty()) { - return; + if (!updated.isEmpty()) { + dao.updatePdpGroups(updated.stream().map(GroupData::getGroup).collect(Collectors.toList())); } + } - // update the groups - dao.updatePdpGroups(updatedGroups.stream().map(GroupData::getGroup).collect(Collectors.toList())); + /** + * Deletes a group from the DB, immediately (i.e., without caching the request to be + * executed later). + * + * @param group the group to be deleted + * @throws PfModelException if an error occurs + */ + public void deleteGroupFromDb(PdpGroup group) throws PfModelException { + dao.deletePdpGroup(group.getName()); } } |