Skip to content

Commit 4ef61b7

Browse files
committed
Implemented group-level rules in the REST and storage layers
1 parent d1148a5 commit 4ef61b7

35 files changed

+1579
-72
lines changed

app/src/main/java/io/apicurio/registry/rest/v2/AdminResourceImpl.java

+23-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package io.apicurio.registry.rest.v2;
22

3-
import io.apicurio.common.apps.config.*;
3+
import io.apicurio.common.apps.config.Dynamic;
4+
import io.apicurio.common.apps.config.DynamicConfigPropertyDef;
5+
import io.apicurio.common.apps.config.DynamicConfigPropertyDto;
6+
import io.apicurio.common.apps.config.DynamicConfigPropertyIndex;
7+
import io.apicurio.common.apps.config.Info;
48
import io.apicurio.common.apps.logging.Logged;
59
import io.apicurio.common.apps.logging.audit.Audited;
610
import io.apicurio.registry.auth.Authorized;
@@ -10,7 +14,13 @@
1014
import io.apicurio.registry.metrics.health.liveness.ResponseErrorLivenessCheck;
1115
import io.apicurio.registry.metrics.health.readiness.ResponseTimeoutReadinessCheck;
1216
import io.apicurio.registry.rest.MissingRequiredParameterException;
13-
import io.apicurio.registry.rest.v2.beans.*;
17+
import io.apicurio.registry.rest.v2.beans.ArtifactTypeInfo;
18+
import io.apicurio.registry.rest.v2.beans.ConfigurationProperty;
19+
import io.apicurio.registry.rest.v2.beans.DownloadRef;
20+
import io.apicurio.registry.rest.v2.beans.RoleMapping;
21+
import io.apicurio.registry.rest.v2.beans.Rule;
22+
import io.apicurio.registry.rest.v2.beans.UpdateConfigurationProperty;
23+
import io.apicurio.registry.rest.v2.beans.UpdateRole;
1424
import io.apicurio.registry.rest.v2.shared.DataExporter;
1525
import io.apicurio.registry.rules.DefaultRuleDeletionException;
1626
import io.apicurio.registry.rules.RulesProperties;
@@ -46,12 +56,19 @@
4656
import java.util.HashMap;
4757
import java.util.List;
4858
import java.util.Map;
59+
import java.util.Set;
4960
import java.util.function.Supplier;
5061
import java.util.stream.Collectors;
5162
import java.util.stream.Stream;
5263
import java.util.zip.ZipInputStream;
5364

54-
import static io.apicurio.common.apps.logging.audit.AuditingConstants.*;
65+
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_FOR_BROWSER;
66+
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_NAME;
67+
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_PRINCIPAL_ID;
68+
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_ROLE_MAPPING;
69+
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_RULE;
70+
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_RULE_TYPE;
71+
import static io.apicurio.common.apps.logging.audit.AuditingConstants.KEY_UPDATE_ROLE;
5572
import static io.apicurio.registry.utils.DtoUtil.appAuthPropertyToRegistry;
5673
import static io.apicurio.registry.utils.DtoUtil.registryAuthPropertyToApp;
5774

@@ -117,8 +134,9 @@ public List<ArtifactTypeInfo> listArtifactTypes() {
117134
@Authorized(style = AuthorizedStyle.None, level = AuthorizedLevel.Read)
118135
public List<RuleType> listGlobalRules() {
119136
List<RuleType> rules = storage.getGlobalRules();
120-
List<RuleType> defaultRules = rulesProperties.getFilteredDefaultGlobalRules(rules);
121-
return Stream.concat(rules.stream(), defaultRules.stream()).sorted().collect(Collectors.toList());
137+
Set<RuleType> defaultRules = rulesProperties.getDefaultGlobalRules();
138+
return Stream.concat(rules.stream(), defaultRules.stream()).collect(Collectors.toSet()).stream()
139+
.sorted().collect(Collectors.toList());
122140
}
123141

124142
/**

app/src/main/java/io/apicurio/registry/rest/v3/AdminResourceImpl.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import java.util.HashMap;
6161
import java.util.List;
6262
import java.util.Map;
63+
import java.util.Set;
6364
import java.util.function.Supplier;
6465
import java.util.stream.Collectors;
6566
import java.util.stream.Stream;
@@ -144,8 +145,9 @@ public SnapshotMetaData triggerSnapshot() {
144145
@Authorized(style = AuthorizedStyle.None, level = AuthorizedLevel.Read)
145146
public List<RuleType> listGlobalRules() {
146147
List<RuleType> rules = storage.getGlobalRules();
147-
List<RuleType> defaultRules = rulesProperties.getFilteredDefaultGlobalRules(rules);
148-
return Stream.concat(rules.stream(), defaultRules.stream()).sorted().collect(Collectors.toList());
148+
Set<RuleType> defaultRules = rulesProperties.getDefaultGlobalRules();
149+
return Stream.concat(rules.stream(), defaultRules.stream()).collect(Collectors.toSet()).stream()
150+
.sorted().collect(Collectors.toList());
149151
}
150152

151153
/**

app/src/main/java/io/apicurio/registry/rest/v3/GroupsResourceImpl.java

+70
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import io.apicurio.registry.storage.dto.VersionSearchResultsDto;
7474
import io.apicurio.registry.storage.error.ArtifactAlreadyExistsException;
7575
import io.apicurio.registry.storage.error.ArtifactNotFoundException;
76+
import io.apicurio.registry.storage.error.GroupNotFoundException;
7677
import io.apicurio.registry.storage.error.InvalidArtifactIdException;
7778
import io.apicurio.registry.storage.error.InvalidGroupIdException;
7879
import io.apicurio.registry.storage.error.VersionNotFoundException;
@@ -307,6 +308,75 @@ public GroupMetaData createGroup(CreateGroup data) {
307308
return V3ApiUtil.groupDtoToGroup(storage.getGroupMetaData(data.getGroupId()));
308309
}
309310

311+
@Override
312+
public List<RuleType> listGroupRules(String groupId) {
313+
requireParameter("groupId", groupId);
314+
315+
return storage.getGroupRules(new GroupId(groupId).getRawGroupIdWithNull());
316+
}
317+
318+
@Override
319+
public void createGroupRule(String groupId, CreateRule data) {
320+
requireParameter("groupId", groupId);
321+
requireParameter("ruleType", data.getRuleType());
322+
requireParameter("config", data.getConfig());
323+
324+
if (data.getConfig() == null || data.getConfig().isEmpty()) {
325+
throw new MissingRequiredParameterException("config");
326+
}
327+
328+
RuleConfigurationDto config = new RuleConfigurationDto();
329+
config.setConfiguration(data.getConfig());
330+
331+
if (!storage.isGroupExists(new GroupId(groupId).getRawGroupIdWithNull())) {
332+
throw new GroupNotFoundException(groupId);
333+
}
334+
335+
storage.createGroupRule(new GroupId(groupId).getRawGroupIdWithNull(), data.getRuleType(), config);
336+
}
337+
338+
@Override
339+
public Rule updateGroupRuleConfig(String groupId, RuleType ruleType, Rule data) {
340+
requireParameter("groupId", groupId);
341+
requireParameter("ruleType", ruleType);
342+
requireParameter("config", data.getConfig());
343+
344+
RuleConfigurationDto dto = new RuleConfigurationDto(data.getConfig());
345+
storage.updateGroupRule(new GroupId(groupId).getRawGroupIdWithNull(), ruleType, dto);
346+
Rule rval = new Rule();
347+
rval.setRuleType(ruleType);
348+
rval.setConfig(data.getConfig());
349+
return rval;
350+
}
351+
352+
@Override
353+
public void deleteGroupRules(String groupId) {
354+
requireParameter("groupId", groupId);
355+
356+
storage.deleteGroupRules(new GroupId(groupId).getRawGroupIdWithNull());
357+
}
358+
359+
@Override
360+
public Rule getGroupRuleConfig(String groupId, RuleType ruleType) {
361+
requireParameter("groupId", groupId);
362+
requireParameter("ruleType", ruleType);
363+
364+
RuleConfigurationDto dto = storage.getGroupRule(new GroupId(groupId).getRawGroupIdWithNull(),
365+
ruleType);
366+
Rule rval = new Rule();
367+
rval.setConfig(dto.getConfiguration());
368+
rval.setRuleType(ruleType);
369+
return rval;
370+
}
371+
372+
@Override
373+
public void deleteGroupRule(String groupId, RuleType rule) {
374+
requireParameter("groupId", groupId);
375+
requireParameter("rule", rule);
376+
377+
storage.deleteGroupRule(new GroupId(groupId).getRawGroupIdWithNull(), rule);
378+
}
379+
310380
/**
311381
* @see io.apicurio.registry.rest.v3.GroupsResource#listArtifactRules(java.lang.String, java.lang.String)
312382
*/

app/src/main/java/io/apicurio/registry/rules/RulesProperties.java

+4-8
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import io.apicurio.registry.storage.dto.RuleConfigurationDto;
44
import io.apicurio.registry.types.RuleType;
55

6-
import java.util.List;
6+
import java.util.Set;
77

88
/**
99
* A service used to retrieve the default global rules that have been set via registry.rules.global
@@ -15,15 +15,11 @@
1515
public interface RulesProperties {
1616

1717
/**
18-
* Get the list of configured default global RuleType enums. A list of RuleType enums can be supplied that
19-
* will be filtered out of the returned list.
18+
* Get the list of configured default global RuleType enums.
2019
*
21-
* @param excludeRulesFilter a list of RuleType enums to filter from the returned list. If null, the
22-
* entire configured list of default global RuleTypes is returned.
23-
* @return The list of configured default global RuleTypes with any matching the excludeRules list
24-
* removed.
20+
* @return The list of configured default global RuleTypes.
2521
*/
26-
List<RuleType> getFilteredDefaultGlobalRules(List<RuleType> excludeRulesFilter);
22+
Set<RuleType> getDefaultGlobalRules();
2723

2824
/**
2925
* Whether the supplied RuleType has been configured as a global rule.

app/src/main/java/io/apicurio/registry/rules/RulesPropertiesImpl.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
import io.apicurio.registry.storage.dto.RuleConfigurationDto;
44
import io.apicurio.registry.types.RuleType;
55

6-
import java.util.List;
76
import java.util.Map;
87
import java.util.Properties;
8+
import java.util.Set;
99
import java.util.stream.Collectors;
1010

1111
public class RulesPropertiesImpl implements RulesProperties {
@@ -22,10 +22,8 @@ public RulesPropertiesImpl(Properties properties) {
2222
}
2323

2424
@Override
25-
public List<RuleType> getFilteredDefaultGlobalRules(List<RuleType> excludeRulesFilter) {
26-
return defaultGlobalRules.keySet().stream()
27-
.filter(ruleType -> excludeRulesFilter == null || !excludeRulesFilter.contains(ruleType))
28-
.collect(Collectors.toList());
25+
public Set<RuleType> getDefaultGlobalRules() {
26+
return defaultGlobalRules.keySet();
2927
}
3028

3129
@Override

app/src/main/java/io/apicurio/registry/rules/RulesServiceImpl.java

+41-34
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,11 @@
1313
import jakarta.inject.Inject;
1414

1515
import java.util.Collections;
16+
import java.util.HashMap;
17+
import java.util.HashSet;
1618
import java.util.List;
1719
import java.util.Map;
18-
import java.util.stream.Collectors;
20+
import java.util.Set;
1921

2022
/**
2123
* Implements the {@link RulesService} interface.
@@ -45,9 +47,9 @@ public void applyRules(String groupId, String artifactId, String artifactType, T
4547
RuleApplicationType ruleApplicationType, List<ArtifactReference> references,
4648
Map<String, TypedContent> resolvedReferences) throws RuleViolationException {
4749
@SuppressWarnings("unchecked")
48-
List<RuleType> rules = Collections.EMPTY_LIST;
50+
Set<RuleType> artifactRules = Collections.EMPTY_SET;
4951
if (ruleApplicationType == RuleApplicationType.UPDATE) {
50-
rules = storage.getArtifactRules(groupId, artifactId);
52+
artifactRules = new HashSet<>(storage.getArtifactRules(groupId, artifactId));
5153
}
5254
LazyContentList currentContent = null;
5355
if (ruleApplicationType == RuleApplicationType.UPDATE) {
@@ -57,39 +59,44 @@ public void applyRules(String groupId, String artifactId, String artifactType, T
5759
currentContent = new LazyContentList(storage, Collections.emptyList());
5860
}
5961

60-
applyGlobalAndArtifactRules(groupId, artifactId, artifactType, currentContent, content, rules,
61-
references, resolvedReferences);
62+
applyAllRules(groupId, artifactId, artifactType, currentContent, content, artifactRules, references,
63+
resolvedReferences);
6264
}
6365

64-
private void applyGlobalAndArtifactRules(String groupId, String artifactId, String artifactType,
65-
List<TypedContent> currentContent, TypedContent updatedContent, List<RuleType> artifactRules,
66+
private void applyAllRules(String groupId, String artifactId, String artifactType,
67+
List<TypedContent> currentContent, TypedContent updatedContent, Set<RuleType> artifactRules,
6668
List<ArtifactReference> references, Map<String, TypedContent> resolvedReferences) {
6769

68-
Map<RuleType, RuleConfigurationDto> globalOrArtifactRulesMap = artifactRules.stream()
69-
.collect(Collectors.toMap(ruleType -> ruleType,
70-
ruleType -> storage.getArtifactRule(groupId, artifactId, ruleType)));
71-
72-
if (globalOrArtifactRulesMap.isEmpty()) {
73-
List<RuleType> globalRules = storage.getGlobalRules();
74-
globalOrArtifactRulesMap = globalRules.stream()
75-
.collect(Collectors.toMap(ruleType -> ruleType, storage::getGlobalRule));
76-
77-
// Add any default global rules to the map (after filtering out any global rules from
78-
// artifactStore)
79-
Map<RuleType, RuleConfigurationDto> filteredDefaultGlobalRulesMap = rulesProperties
80-
.getFilteredDefaultGlobalRules(globalRules).stream().collect(Collectors
81-
.toMap(ruleType -> ruleType, rulesProperties::getDefaultGlobalRuleConfiguration));
82-
globalOrArtifactRulesMap.putAll(filteredDefaultGlobalRulesMap);
83-
}
84-
85-
if (globalOrArtifactRulesMap.isEmpty()) {
86-
return;
87-
}
88-
89-
for (RuleType ruleType : globalOrArtifactRulesMap.keySet()) {
70+
// TODO Getting the list of rules to apply results in several (admittedly fast) DB calls.
71+
// Can we perhaps do a single DB call to get the map of rules to apply?
72+
73+
Map<RuleType, RuleConfigurationDto> allRules = new HashMap<>();
74+
75+
// Get the group rules (we already have the artifact rules)
76+
Set<RuleType> groupRules = storage.isGroupExists(groupId)
77+
? new HashSet<>(storage.getGroupRules(groupId)) : Set.of();
78+
// Get the global rules
79+
Set<RuleType> globalRules = new HashSet<>(storage.getGlobalRules());
80+
// Get the configured default global rules
81+
Set<RuleType> defaultGlobalRules = rulesProperties.getDefaultGlobalRules();
82+
83+
// Build the map of rules to apply (may be empty)
84+
List.of(RuleType.values()).forEach(rt -> {
85+
if (artifactRules.contains(rt)) {
86+
allRules.put(rt, storage.getArtifactRule(groupId, artifactId, rt));
87+
} else if (groupRules.contains(rt)) {
88+
allRules.put(rt, storage.getGroupRule(groupId, rt));
89+
} else if (globalRules.contains(rt)) {
90+
allRules.put(rt, storage.getGlobalRule(rt));
91+
} else if (defaultGlobalRules.contains(rt)) {
92+
allRules.put(rt, rulesProperties.getDefaultGlobalRuleConfiguration(rt));
93+
}
94+
});
95+
96+
// Apply rules
97+
for (RuleType ruleType : allRules.keySet()) {
9098
applyRule(groupId, artifactId, artifactType, currentContent, updatedContent, ruleType,
91-
globalOrArtifactRulesMap.get(ruleType).getConfiguration(), references,
92-
resolvedReferences);
99+
allRules.get(ruleType).getConfiguration(), references, resolvedReferences);
93100
}
94101
}
95102

@@ -138,8 +145,8 @@ public void applyRules(String groupId, String artifactId, String artifactVersion
138145
artifactVersion);
139146
TypedContent typedVersionContent = TypedContent.create(versionContent.getContent(),
140147
versionContent.getContentType());
141-
applyGlobalAndArtifactRules(groupId, artifactId, artifactType,
142-
Collections.singletonList(typedVersionContent), updatedContent,
143-
storage.getArtifactRules(groupId, artifactId), references, resolvedReferences);
148+
Set<RuleType> artifactRules = new HashSet<>(storage.getArtifactRules(groupId, artifactId));
149+
applyAllRules(groupId, artifactId, artifactType, Collections.singletonList(typedVersionContent),
150+
updatedContent, artifactRules, references, resolvedReferences);
144151
}
145152
}

0 commit comments

Comments
 (0)