fix(manager-api): ensure correct behaviour of ApiPlans after publication
Issue identified by
MODIFY
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/ApiPlanBean.java
manager/api/beans/src/main/java/io/apiman/manager/api/beans/apis/ApiPlanBean.java
@@ -105,11 +105,6 @@ public class ApiPlanBean implements Serializable {
.toString();
}
- @Override
- public int hashCode() {
- return Objects.hash(planId, version);
- }
-
@Override
public boolean equals(Object o) {
if (this == o) {
@@ -119,6 +114,12 @@ public class ApiPlanBean implements Serializable {
return false;
}
ApiPlanBean that = (ApiPlanBean) o;
- return Objects.equals(planId, that.planId) && Objects.equals(version, that.version);
+ return Objects.equals(planId, that.planId) && Objects.equals(version, that.version) && Objects.equals(exposeInPortal,
+ that.exposeInPortal) && Objects.equals(requiresApproval, that.requiresApproval);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(planId, version, exposeInPortal, requiresApproval);
}
}

MODIFY
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ApiService.java
manager/api/rest-impl/src/main/java/io/apiman/manager/api/service/ApiService.java
@@ -93,7 +93,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.Objects;
import java.util.Set;
+import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
@@ -614,7 +616,12 @@ public class ApiService implements DataAccessUtilMixin {
if (bean.getPlans().size() != avb.getPlans().size()) {
throw new InvalidParameterException("Can not attach or remove plans from an API Version after it has been published");
}
- if (!avb.getPlans().containsAll(bean.getPlans())) {
+
+ // Collect just the ID and Versions (as these must be the same). Other fields can change freely.
+ Set<PlanIdVersion> existingPIV = avb.getPlans().stream().map(PlanIdVersion::new).collect(Collectors.toSet());
+ Set<PlanIdVersion> updatedPIV = bean.getPlans().stream().map(PlanIdVersion::new).collect(Collectors.toSet());
+
+ if (!existingPIV.containsAll(updatedPIV)) {
throw new InvalidParameterException("Plan IDs and versions must not change after publication");
}
// If published, then mapper copies across only fields that are safe for changed after publication.
@@ -1107,4 +1114,31 @@ public class ApiService implements DataAccessUtilMixin {
return definition;
}
}
+
+ private static final class PlanIdVersion {
+ public final String id;
+ public final String version;
+
+ public PlanIdVersion(ApiPlanBean pvb) {
+ this.id = pvb.getPlanId();
+ this.version = pvb.getVersion();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ PlanIdVersion that = (PlanIdVersion) o;
+ return Objects.equals(id, that.id) && Objects.equals(version, that.version);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, version);
+ }
+ }
}

fix(manager-api): ensure correct behaviour of ApiPlans after publication

Issue identified by @volkflo