aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/main
diff options
context:
space:
mode:
authorJim Hahn <jrh3@att.com>2019-04-12 10:00:05 -0400
committerJim Hahn <jrh3@att.com>2019-04-13 20:21:36 -0400
commitd641bd5f3c4f6333e56ea85d95abb3dc124d4f4b (patch)
treeb62566d613d90db4d03a87431c300f741dccfd81 /main/src/main
parentfb057952d747a91139bce6e259b775bf57fc158f (diff)
Support group-oriented REST API
Added code to support PDP group create/update & delete REST API calls. The create/update request can also be used to deploy/undeploy policies. It is assumed that the create/update request specifies a valid list of supported policy types for each subgroup (i.e., PDP type). Updated due to elimination of "version" from group in policy/models. Added/updated junits. Change-Id: I1916d9b17dfd5f12129c6f6a2fcf54e706662c10 Issue-ID: POLICY-1542 Signed-off-by: Jim Hahn <jrh3@att.com>
Diffstat (limited to 'main/src/main')
-rw-r--r--main/src/main/java/org/onap/policy/pap/main/rest/depundep/GroupData.java49
-rw-r--r--main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteControllerV1.java46
-rw-r--r--main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeleteProvider.java54
-rw-r--r--main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployControllerV1.java2
-rw-r--r--main/src/main/java/org/onap/policy/pap/main/rest/depundep/PdpGroupDeployProvider.java307
-rw-r--r--main/src/main/java/org/onap/policy/pap/main/rest/depundep/ProviderBase.java35
-rw-r--r--main/src/main/java/org/onap/policy/pap/main/rest/depundep/SessionData.java133
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());
}
}