diff --git a/label-application-rule-config-service-impl/src/main/java/org/hypertrace/label/application/rule/config/service/LabelApplicationRuleConfigServiceImpl.java b/label-application-rule-config-service-impl/src/main/java/org/hypertrace/label/application/rule/config/service/LabelApplicationRuleConfigServiceImpl.java index 321bf4b3..f5cc0328 100644 --- a/label-application-rule-config-service-impl/src/main/java/org/hypertrace/label/application/rule/config/service/LabelApplicationRuleConfigServiceImpl.java +++ b/label-application-rule-config-service-impl/src/main/java/org/hypertrace/label/application/rule/config/service/LabelApplicationRuleConfigServiceImpl.java @@ -1,12 +1,20 @@ package org.hypertrace.label.application.rule.config.service; +import com.google.protobuf.util.JsonFormat; import com.typesafe.config.Config; import io.grpc.Channel; import io.grpc.Status; import io.grpc.stub.StreamObserver; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.UUID; +import java.util.function.Function; import java.util.stream.Collectors; +import lombok.SneakyThrows; import org.hypertrace.config.objectstore.ConfigObject; import org.hypertrace.config.objectstore.IdentifiedObjectStore; import org.hypertrace.config.service.change.event.api.ConfigChangeEventGenerator; @@ -31,10 +39,13 @@ public class LabelApplicationRuleConfigServiceImpl "label.application.rule.config.service"; static final String MAX_DYNAMIC_LABEL_APPLICATION_RULES_PER_TENANT = "max.dynamic.label.application.rules.per.tenant"; + private static final String SYSTEM_LABEL_APPLICATION_RULES = + "label.application.rule.config.service.system.label.application.rules"; static final int DEFAULT_MAX_DYNAMIC_LABEL_APPLICATION_RULES_PER_TENANT = 100; private final IdentifiedObjectStore labelApplicationRuleStore; private final LabelApplicationRuleValidator requestValidator; private final int maxDynamicLabelApplicationRulesAllowed; + private Map systemLabelApplicationRuleIdToRuleMap; public LabelApplicationRuleConfigServiceImpl( Channel configChannel, Config config, ConfigChangeEventGenerator configChangeEventGenerator) { @@ -56,6 +67,20 @@ public LabelApplicationRuleConfigServiceImpl( this.labelApplicationRuleStore = new LabelApplicationRuleStore(configServiceBlockingStub, configChangeEventGenerator); this.requestValidator = new LabelApplicationRuleValidatorImpl(); + + buildSystemLabelApplicationRuleConfigs(config); + } + + private void buildSystemLabelApplicationRuleConfigs(Config config) { + if (!config.hasPath(SYSTEM_LABEL_APPLICATION_RULES)) { + systemLabelApplicationRuleIdToRuleMap = Collections.emptyMap(); + return; + } + + List systemLabelApplicationRuleObjects = + config.getObjectList(SYSTEM_LABEL_APPLICATION_RULES); + systemLabelApplicationRuleIdToRuleMap = + buildSystemLabelApplicationRuleIdRuleMap(systemLabelApplicationRuleObjects); } @Override @@ -92,10 +117,16 @@ public void getLabelApplicationRules( try { RequestContext requestContext = RequestContext.CURRENT.get(); this.requestValidator.validateOrThrow(requestContext, request); - List labelApplicationRules = + List userLabelApplicationRules = this.labelApplicationRuleStore.getAllObjects(requestContext).stream() .map(ConfigObject::getData) .collect(Collectors.toUnmodifiableList()); + + // reorder user label application rules and system label application rules as per expected + // priority + List labelApplicationRules = + reorderLabelApplicationRules(userLabelApplicationRules); + responseObserver.onNext( GetLabelApplicationRulesResponse.newBuilder() .addAllLabelApplicationRules(labelApplicationRules) @@ -140,6 +171,12 @@ public void deleteLabelApplicationRule( try { RequestContext requestContext = RequestContext.CURRENT.get(); this.requestValidator.validateOrThrow(requestContext, request); + + // do not allow deleting system label application rules + if (systemLabelApplicationRuleIdToRuleMap.containsKey(request.getId())) { + throw Status.INVALID_ARGUMENT.asRuntimeException(); + } + this.labelApplicationRuleStore .deleteObject(requestContext, request.getId()) .orElseThrow(Status.NOT_FOUND::asRuntimeException); @@ -166,4 +203,56 @@ private void checkRequestForDynamicLabelsLimit( } } } + + private Map buildSystemLabelApplicationRuleIdRuleMap( + List configObjects) { + return configObjects.stream() + .map(this::buildLabelApplicationRuleFromConfig) + .collect(Collectors.toUnmodifiableMap(LabelApplicationRule::getId, Function.identity())); + } + + @SneakyThrows + private LabelApplicationRule buildLabelApplicationRuleFromConfig( + com.typesafe.config.ConfigObject configObject) { + String jsonString = configObject.render(); + LabelApplicationRule.Builder builder = LabelApplicationRule.newBuilder(); + JsonFormat.parser().merge(jsonString, builder); + return builder.build(); + } + + private List reorderLabelApplicationRules( + List userLabelApplicationRules) { + // This method sets the priority of rules. User label application rules -> user overridden + // system + // label application rules -> non overridden system label application rules + List labelApplicationRules = new ArrayList<>(); + List overriddenSystemLabelApplicationRules = new ArrayList<>(); + Set overriddenSystemLabelApplicationRuleIds = new HashSet<>(); + + for (LabelApplicationRule userLabelApplicationRule : userLabelApplicationRules) { + String id = userLabelApplicationRule.getId(); + if (systemLabelApplicationRuleIdToRuleMap.containsKey(id)) { + // user overridden system label application rules + overriddenSystemLabelApplicationRules.add(userLabelApplicationRule); + overriddenSystemLabelApplicationRuleIds.add(id); + } else { + // user label application rules + labelApplicationRules.add(userLabelApplicationRule); + } + } + + // non overridden system label application rules + List nonOverriddenSystemLabelApplicationRules = + systemLabelApplicationRuleIdToRuleMap.entrySet().stream() + .filter( + labelApplicationRuleEntry -> + !overriddenSystemLabelApplicationRuleIds.contains( + labelApplicationRuleEntry.getKey())) + .map(Map.Entry::getValue) + .collect(Collectors.toUnmodifiableList()); + + labelApplicationRules.addAll(overriddenSystemLabelApplicationRules); + labelApplicationRules.addAll(nonOverriddenSystemLabelApplicationRules); + return Collections.unmodifiableList(labelApplicationRules); + } }