Skip to content

Commit 111fb55

Browse files
authored
feat: Customizing Cloudevents validation (#594)
Add SPI for custom CloudEvent validation. Signed-off-by: vbhat6 <[email protected]>
1 parent 55fddb3 commit 111fb55

File tree

7 files changed

+131
-2
lines changed

7 files changed

+131
-2
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright 2018-Present The CloudEvents Authors
3+
* <p>
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+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
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.cloudevents.core.provider;
18+
19+
import io.cloudevents.CloudEvent;
20+
import io.cloudevents.core.validator.CloudEventValidator;
21+
22+
import java.util.Iterator;
23+
import java.util.ServiceConfigurationError;
24+
import java.util.ServiceLoader;
25+
26+
/**
27+
* CloudEventValidatorProvider is a singleton class which loads and access CE Validator service providers on behalf of service clients.
28+
*/
29+
public class CloudEventValidatorProvider {
30+
31+
private static final CloudEventValidatorProvider cloudEventValidatorProvider = new CloudEventValidatorProvider();
32+
33+
private final ServiceLoader<CloudEventValidator> loader;
34+
35+
private CloudEventValidatorProvider(){
36+
loader = ServiceLoader.load(CloudEventValidator.class);
37+
}
38+
39+
public static CloudEventValidatorProvider getInstance() {
40+
return cloudEventValidatorProvider;
41+
}
42+
43+
/**
44+
* iterates through available Cloudevent validators.
45+
* @param cloudEvent
46+
*/
47+
public void validate(CloudEvent cloudEvent){
48+
for (final CloudEventValidator validator : loader) {
49+
validator.validate(cloudEvent);
50+
}
51+
}
52+
}

core/src/main/java/io/cloudevents/core/v03/CloudEventBuilder.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
*/
1717
package io.cloudevents.core.v03;
1818

19+
import io.cloudevents.CloudEvent;
1920
import io.cloudevents.SpecVersion;
2021
import io.cloudevents.core.CloudEventUtils;
2122
import io.cloudevents.core.impl.BaseCloudEventBuilder;
23+
import io.cloudevents.core.provider.CloudEventValidatorProvider;
24+
import io.cloudevents.core.v1.CloudEventV1;
2225
import io.cloudevents.rw.CloudEventContextReader;
2326
import io.cloudevents.rw.CloudEventContextWriter;
2427
import io.cloudevents.rw.CloudEventRWException;
@@ -122,7 +125,11 @@ public CloudEventV03 build() {
122125
throw createMissingAttributeException("type");
123126
}
124127

125-
return new CloudEventV03(id, source, type, time, schemaurl, datacontenttype, subject, this.data, this.extensions);
128+
CloudEventV03 cloudEvent = new CloudEventV03(id, source, type, time, schemaurl, datacontenttype, subject, this.data, this.extensions);
129+
final CloudEventValidatorProvider validator = CloudEventValidatorProvider.getInstance();
130+
validator.validate(cloudEvent);
131+
132+
return cloudEvent;
126133
}
127134

128135
@Override

core/src/main/java/io/cloudevents/core/v1/CloudEventBuilder.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import io.cloudevents.SpecVersion;
2222
import io.cloudevents.core.CloudEventUtils;
2323
import io.cloudevents.core.impl.BaseCloudEventBuilder;
24+
import io.cloudevents.core.provider.CloudEventValidatorProvider;
25+
import io.cloudevents.core.validator.CloudEventValidator;
2426
import io.cloudevents.rw.CloudEventContextReader;
2527
import io.cloudevents.rw.CloudEventContextWriter;
2628
import io.cloudevents.rw.CloudEventRWException;
@@ -119,7 +121,12 @@ public CloudEvent build() {
119121
throw createMissingAttributeException(TYPE);
120122
}
121123

122-
return new CloudEventV1(id, source, type, datacontenttype, dataschema, subject, time, this.data, this.extensions);
124+
CloudEvent cloudEvent = new CloudEventV1(id, source, type, datacontenttype, dataschema, subject, time, this.data, this.extensions);
125+
126+
final CloudEventValidatorProvider validator = CloudEventValidatorProvider.getInstance();
127+
validator.validate(cloudEvent);
128+
129+
return cloudEvent;
123130
}
124131

125132
@Override
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2018-Present The CloudEvents Authors
3+
* <p>
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+
* <p>
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
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.cloudevents.core.validator;
18+
19+
import io.cloudevents.CloudEvent;
20+
21+
/**
22+
* @author Vinay Bhat
23+
* Interface which defines validation for CloudEvents attributes and extensions.
24+
*/
25+
public interface CloudEventValidator {
26+
27+
/**
28+
* Validate the attributes of a CloudEvent.
29+
*
30+
* @param cloudEvent the CloudEvent to validate
31+
*/
32+
void validate(CloudEvent cloudEvent);
33+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.cloudevents.core.test;
2+
3+
import io.cloudevents.CloudEvent;
4+
import io.cloudevents.core.validator.CloudEventValidator;
5+
6+
public class CloudEventCustomValidator implements CloudEventValidator {
7+
8+
@Override
9+
public void validate(CloudEvent cloudEvent) {
10+
String namespace = null;
11+
if ((namespace = (String) cloudEvent.getExtension("namespace")) != null &&
12+
!namespace.equals("sales")){
13+
throw new IllegalStateException("Expecting sales in namespace extension");
14+
}
15+
}
16+
17+
}

core/src/test/java/io/cloudevents/core/v1/CloudEventBuilderTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,16 @@ void testMissingType() {
142142
).hasMessageContaining("Attribute 'type' cannot be null");
143143
}
144144

145+
@Test
146+
void testValidatorProvider(){
147+
assertThatCode(() -> CloudEventBuilder
148+
.v1()
149+
.withId("000")
150+
.withSource(URI.create("http://localhost"))
151+
.withType(TYPE)
152+
.withExtension("namespace", "order")
153+
.build()
154+
).hasMessageContaining("Expecting sales in namespace extension");
155+
}
156+
145157
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
io.cloudevents.core.test.CloudEventCustomValidator

0 commit comments

Comments
 (0)