Skip to content

Commit 9005d4c

Browse files
Merge branch '8.1.x' into master by rayokota
2 parents 6bcb923 + 6c90367 commit 9005d4c

File tree

13 files changed

+1131
-2
lines changed

13 files changed

+1131
-2
lines changed

checkstyle/suppressions.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
files="(.*).java"/>
2929

3030
<suppress checks="JavaNCSS"
31-
files="(AbstractKafkaAvroSerializer|AbstractKafkaJsonSchemaSerializer|AbstractKafkaJsonSchemaDeserializer|AbstractKafkaProtobufSerializer|AbstractKafkaProtobufDeserializer|AbstractKafkaSchemaSerDe|AvroData|AvroSchema|AvroSchemaUtils|ProtobufData|SchemaDiff|NumberSchemaDiff|JsonSchema|JsonSchemaData|KafkaSchemaRegistry|KafkaStoreReaderThread|ProtobufSchema|ProtobufSchemaUtils|JsonSchemaComparator|SchemaMessageFormatter|SchemaMessageReader|SchemaTranslator|SubjectVersionsResource|CachedSchemaRegistryClient).java"/>
31+
files="(AbstractKafkaAvroSerializer|AbstractKafkaJsonSchemaSerializer|AbstractKafkaJsonSchemaDeserializer|AbstractKafkaProtobufSerializer|AbstractKafkaProtobufDeserializer|AbstractKafkaSchemaSerDe|AvroData|AvroSchema|AvroSchemaUtils|ProtobufData|SchemaDiff|NumberSchemaDiff|JsonSchema|JsonSchemaData|KafkaSchemaRegistry|KafkaStoreReaderThread|ProtobufSchema|ProtobufSchemaUtils|JsonSchemaComparator|SchemaMessageFormatter|SchemaMessageReader|SchemaTranslator|SubjectVersionsResource|CachedSchemaRegistryClient|AssociationKey).java"/>
3232

3333
<suppress checks="MethodLength"
3434
files="(AvroData|ProtobufSchema|ProtobufSchemaUtils).java"/>
@@ -40,7 +40,7 @@
4040
files="(KafkaSchemaRegistry|SchemaRegistryConfig|ProtobufData|JsonSchemaData).java"/>
4141

4242
<suppress checks="BooleanExpressionComplexity"
43-
files="(AvroData|JsonSchema|KafkaSchemaRegistry|ProtobufData|ProtobufSchema|CelExecutor|FieldRuleExecutor|MetadataEncoderService|MockDekRegistryClient|DataEncryptionKey|KeyEncryptionKey|Rule|CombinedSchemaDiff|RegisterSchemaRequest|RuleSet).java"/>
43+
files="(AvroData|JsonSchema|KafkaSchemaRegistry|ProtobufData|ProtobufSchema|CelExecutor|FieldRuleExecutor|MetadataEncoderService|MockDekRegistryClient|DataEncryptionKey|KeyEncryptionKey|Rule|CombinedSchemaDiff|RegisterSchemaRequest|RuleSet|Association).java"/>
4444

4545
<suppress checks="MemberName"
4646
files="(DynamicSchema|EnumDefinition|FieldDefinition|MessageDefinition|ServiceDefinition).java"/>

client/src/main/java/io/confluent/kafka/schemaregistry/client/rest/RestService.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.common.base.Charsets;
2525
import com.google.common.io.CharStreams;
2626
import io.confluent.kafka.schemaregistry.client.SchemaRegistryClientConfig;
27+
import io.confluent.kafka.schemaregistry.client.rest.entities.Association;
2728
import io.confluent.kafka.schemaregistry.client.rest.entities.Config;
2829
import io.confluent.kafka.schemaregistry.client.rest.entities.ContextId;
2930
import io.confluent.kafka.schemaregistry.client.rest.entities.ErrorMessage;
@@ -35,6 +36,10 @@
3536
import io.confluent.kafka.schemaregistry.client.rest.entities.ServerClusterId;
3637
import io.confluent.kafka.schemaregistry.client.rest.entities.SchemaReference;
3738
import io.confluent.kafka.schemaregistry.client.rest.entities.SubjectVersion;
39+
import io.confluent.kafka.schemaregistry.client.rest.entities.requests.AssociationBatchCreateRequest;
40+
import io.confluent.kafka.schemaregistry.client.rest.entities.requests.AssociationBatchResponse;
41+
import io.confluent.kafka.schemaregistry.client.rest.entities.requests.AssociationCreateOrUpdateRequest;
42+
import io.confluent.kafka.schemaregistry.client.rest.entities.requests.AssociationResponse;
3843
import io.confluent.kafka.schemaregistry.client.rest.entities.requests.TagSchemaRequest;
3944
import io.confluent.kafka.schemaregistry.client.security.basicauth.BasicAuthCredentialProviderFactory;
4045
import io.confluent.kafka.schemaregistry.client.security.bearerauth.BearerAuthCredentialProvider;
@@ -187,6 +192,15 @@ public class RestService implements Closeable, Configurable {
187192
private static final TypeReference<Config> DELETE_SUBJECT_CONFIG_RESPONSE_TYPE =
188193
new TypeReference<Config>() {
189194
};
195+
private static final TypeReference<AssociationResponse> ASSOCIATION_RESPONSE_TYPE =
196+
new TypeReference<AssociationResponse>() {
197+
};
198+
private static final TypeReference<List<Association>> ASSOCIATIONS_RESPONSE_TYPE =
199+
new TypeReference<List<Association>>() {
200+
};
201+
private static final TypeReference<AssociationBatchResponse> ASSOCIATION_BATCH_RESPONSE_TYPE =
202+
new TypeReference<AssociationBatchResponse>() {
203+
};
190204
private static final TypeReference<ServerClusterId> GET_CLUSTER_ID_RESPONSE_TYPE =
191205
new TypeReference<ServerClusterId>() {
192206
};
@@ -1824,6 +1838,67 @@ public void deleteContext(
18241838
httpRequest(path, "DELETE", null, requestProperties, VOID_RESPONSE_TYPE);
18251839
}
18261840

1841+
public AssociationResponse createOrUpdateAssociation(
1842+
Map<String, String> requestProperties,
1843+
String context, Boolean dryRun, AssociationCreateOrUpdateRequest request
1844+
) throws IOException,
1845+
RestClientException {
1846+
UriBuilder builder = UriBuilder.fromPath("/associations");
1847+
String path = builder.build().toString();
1848+
if (context != null) {
1849+
builder.queryParam("context", context);
1850+
}
1851+
if (dryRun != null) {
1852+
builder.queryParam("dryRun", dryRun);
1853+
}
1854+
1855+
AssociationResponse response = httpRequest(path, "POST",
1856+
request.toJson().getBytes(StandardCharsets.UTF_8),
1857+
requestProperties, ASSOCIATION_RESPONSE_TYPE);
1858+
return response;
1859+
}
1860+
1861+
public AssociationBatchResponse createOrUpdateAssociations(
1862+
Map<String, String> requestProperties,
1863+
String context, Boolean dryRun, AssociationBatchCreateRequest request
1864+
) throws IOException,
1865+
RestClientException {
1866+
UriBuilder builder = UriBuilder.fromPath("/associations:batch");
1867+
String path = builder.build().toString();
1868+
if (context != null) {
1869+
builder.queryParam("context", context);
1870+
}
1871+
if (dryRun != null) {
1872+
builder.queryParam("dryRun", dryRun);
1873+
}
1874+
1875+
AssociationBatchResponse response = httpRequest(path, "POST",
1876+
request.toJson().getBytes(StandardCharsets.UTF_8),
1877+
requestProperties, ASSOCIATION_BATCH_RESPONSE_TYPE);
1878+
return response;
1879+
}
1880+
1881+
public void deleteAssociations(
1882+
Map<String, String> requestProperties,
1883+
String resourceId, String resourceType, List<String> associationTypes,
1884+
boolean cascadeLifecycle
1885+
) throws IOException,
1886+
RestClientException {
1887+
UriBuilder builder =
1888+
UriBuilder.fromPath("/associations/resources/{resourceId}");
1889+
if (resourceType != null) {
1890+
builder.queryParam("resourceType", resourceType);
1891+
}
1892+
for (String associationType : associationTypes) {
1893+
builder.queryParam("associationType", associationType);
1894+
}
1895+
builder.queryParam("cascadeLifecycle", cascadeLifecycle);
1896+
String path = builder.build(resourceId).toString();
1897+
1898+
httpRequest(path, "DELETE", null,
1899+
requestProperties, VOID_RESPONSE_TYPE);
1900+
}
1901+
18271902
public ServerClusterId getClusterId() throws IOException, RestClientException {
18281903
return getClusterId(DEFAULT_REQUEST_PROPERTIES);
18291904
}
Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
/*
2+
* Copyright 2025 Confluent Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.confluent.kafka.schemaregistry.client.rest.entities;
18+
19+
import com.fasterxml.jackson.annotation.JsonCreator;
20+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21+
import com.fasterxml.jackson.annotation.JsonInclude;
22+
import com.fasterxml.jackson.annotation.JsonProperty;
23+
import io.confluent.kafka.schemaregistry.client.rest.entities.requests.AssociationCreateOrUpdateInfo;
24+
import java.util.Objects;
25+
26+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
27+
@JsonIgnoreProperties(ignoreUnknown = true)
28+
public class Association {
29+
30+
private String subject;
31+
private String guid;
32+
private String resourceName;
33+
private String resourceNamespace;
34+
private String resourceId;
35+
private String resourceType;
36+
private String associationType;
37+
private LifecyclePolicy lifecycle;
38+
private boolean frozen;
39+
40+
@JsonCreator
41+
public Association(@JsonProperty("subject") String subject,
42+
@JsonProperty("guid") String guid,
43+
@JsonProperty("resourceName") String resourceName,
44+
@JsonProperty("resourceNamespace") String resourceNamespace,
45+
@JsonProperty("resourceId") String resourceId,
46+
@JsonProperty("resourceType") String resourceType,
47+
@JsonProperty("associationType") String associationType,
48+
@JsonProperty("lifecycle") LifecyclePolicy lifecycle,
49+
@JsonProperty("frozen") boolean frozen) {
50+
this.subject = subject;
51+
this.guid = guid;
52+
this.resourceName = resourceName;
53+
this.resourceNamespace = resourceNamespace;
54+
this.resourceId = resourceId;
55+
this.resourceType = resourceType;
56+
this.associationType = associationType;
57+
this.lifecycle = lifecycle;
58+
this.frozen = frozen;
59+
}
60+
61+
@JsonProperty("subject")
62+
public String getSubject() {
63+
return subject;
64+
}
65+
66+
@JsonProperty("subject")
67+
public void setSubject(String subject) {
68+
this.subject = subject;
69+
}
70+
71+
@JsonProperty("guid")
72+
public String getGuid() {
73+
return guid;
74+
}
75+
76+
@JsonProperty("guid")
77+
public void setGuid(String guid) {
78+
this.guid = guid;
79+
}
80+
81+
@JsonProperty("resourceName")
82+
public String getResourceName() {
83+
return resourceName;
84+
}
85+
86+
@JsonProperty("resourceName")
87+
public void setResourceName(String resourceName) {
88+
this.resourceName = resourceName;
89+
}
90+
91+
@JsonProperty("resourceNamespace")
92+
public String getResourceNamespace() {
93+
return resourceNamespace;
94+
}
95+
96+
@JsonProperty("resourceNamespace")
97+
public void setResourceNamespace(String resourceNamespace) {
98+
this.resourceNamespace = resourceNamespace;
99+
}
100+
101+
@JsonProperty("resourceId")
102+
public String getResourceId() {
103+
return resourceId;
104+
}
105+
106+
@JsonProperty("resourceId")
107+
public void setResourceId(String resourceId) {
108+
this.resourceId = resourceId;
109+
}
110+
111+
@JsonProperty("resourceType")
112+
public String getResourceType() {
113+
return resourceType;
114+
}
115+
116+
@JsonProperty("resourceType")
117+
public void setResourceType(String resourceType) {
118+
this.resourceType = resourceType;
119+
}
120+
121+
@JsonProperty("associationType")
122+
public String getAssociationType() {
123+
return associationType;
124+
}
125+
126+
@JsonProperty("associationType")
127+
public void setAssociationType(String associationType) {
128+
this.associationType = associationType;
129+
}
130+
131+
@JsonProperty("lifecycle")
132+
public LifecyclePolicy getLifecycle() {
133+
return lifecycle;
134+
}
135+
136+
@JsonProperty("lifecycle")
137+
public void setLifecycle(LifecyclePolicy lifecycle) {
138+
this.lifecycle = lifecycle;
139+
}
140+
141+
@JsonProperty("frozen")
142+
public boolean isFrozen() {
143+
return frozen;
144+
}
145+
146+
@JsonProperty("frozen")
147+
public void setFrozen(boolean frozen) {
148+
this.frozen = frozen;
149+
}
150+
151+
@Override
152+
public boolean equals(Object o) {
153+
if (o == null || getClass() != o.getClass()) {
154+
return false;
155+
}
156+
Association that = (Association) o;
157+
return frozen == that.frozen
158+
&& Objects.equals(subject, that.subject)
159+
&& Objects.equals(guid, that.guid)
160+
&& Objects.equals(resourceName, that.resourceName)
161+
&& Objects.equals(resourceNamespace, that.resourceNamespace)
162+
&& Objects.equals(resourceId, that.resourceId)
163+
&& Objects.equals(resourceType, that.resourceType)
164+
&& Objects.equals(associationType, that.associationType)
165+
&& lifecycle == that.lifecycle;
166+
}
167+
168+
@Override
169+
public int hashCode() {
170+
return Objects.hash(
171+
subject, guid, resourceName, resourceNamespace, resourceId,
172+
resourceType, associationType, lifecycle, frozen);
173+
}
174+
175+
public boolean isEquivalent(AssociationCreateOrUpdateInfo info) {
176+
return Objects.equals(subject, info.getSubject())
177+
&& Objects.equals(associationType, info.getAssociationType())
178+
&& (info.getLifecycle() == null || Objects.equals(info.getLifecycle(), getLifecycle()))
179+
&& (info.getFrozen() == null || Objects.equals(info.getFrozen(), isFrozen()));
180+
}
181+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2025 Confluent Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.confluent.kafka.schemaregistry.client.rest.entities;
18+
19+
public enum LifecyclePolicy {
20+
STRONG,
21+
WEAK
22+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2025 Confluent Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.confluent.kafka.schemaregistry.client.rest.entities.requests;
18+
19+
import com.fasterxml.jackson.annotation.JsonCreator;
20+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21+
import com.fasterxml.jackson.annotation.JsonInclude;
22+
import com.fasterxml.jackson.annotation.JsonProperty;
23+
import io.confluent.kafka.schemaregistry.utils.JacksonMapper;
24+
import java.io.IOException;
25+
import java.util.List;
26+
import java.util.Objects;
27+
28+
@JsonInclude(JsonInclude.Include.NON_EMPTY)
29+
@JsonIgnoreProperties(ignoreUnknown = true)
30+
public class AssociationBatchCreateRequest {
31+
32+
private List<AssociationCreateOrUpdateRequest> requests;
33+
34+
@JsonCreator
35+
public AssociationBatchCreateRequest(
36+
@JsonProperty("requests") List<AssociationCreateOrUpdateRequest> requests) {
37+
this.requests = requests;
38+
}
39+
40+
@JsonProperty("requests")
41+
public List<AssociationCreateOrUpdateRequest> getRequests() {
42+
return requests;
43+
}
44+
45+
@JsonProperty("requests")
46+
public void setRequests(List<AssociationCreateOrUpdateRequest> requests) {
47+
this.requests = requests;
48+
}
49+
50+
@Override
51+
public boolean equals(Object o) {
52+
if (o == null || getClass() != o.getClass()) {
53+
return false;
54+
}
55+
AssociationBatchCreateRequest that = (AssociationBatchCreateRequest) o;
56+
return Objects.equals(requests, that.requests);
57+
}
58+
59+
@Override
60+
public int hashCode() {
61+
return Objects.hash(requests);
62+
}
63+
64+
public String toJson() throws IOException {
65+
return JacksonMapper.INSTANCE.writeValueAsString(this);
66+
}
67+
}

0 commit comments

Comments
 (0)