Skip to content

Commit 928ebcf

Browse files
epaulson10JemDay
andauthored
formats: Add support for protobuf format (#348)
* formats: Add support for protobuf format Adds support for the Protocol Buffer CloudEvent format defined at https://github.com/cloudevents/spec/blob/v1.0.1/protobuf-format.md. Compiles the Proto3 file taken from the spec repo into generated Java protobuf classes. These classes are used to convert the SDK representation of a CloudEvent to and from the protobuf format. Signed-off-by: Erik Paulson <[email protected]> * Address feedback in PR #348 - Adds service file for event format autoloading - Addresses some field access issues - Treats unset fields as omitted - Updates and adds documentation Signed-off-by: Erik Paulson <[email protected]> * Add missing attribute writer methods for CloudEventBuilders Without these methods, binary attributes are interpreted as Strings instead of byte[]. Signed-off-by: Erik Paulson <[email protected]> * Added test data files. Signed-off-by: Day, Jeremy(jday) <[email protected]> * - Now executes tests related to wire-format files. - Supports V03 dialect Signed-off-by: Day, Jeremy(jday) <[email protected]> * - Added new ProtoCloudEventData construct to support proto message based data. - Added some more test files. - When the PR related to binary context attributes is merged we can extend the test use-cases appropriately. Signed-off-by: Day, Jeremy(jday) <[email protected]> * - Merged changes related to binary context attributes. - Modified proto format to process binary context attributes - Added CloudEventData varient to hold proto messages (requires tests) - Will add further tests once the failing test is addressed Signed-off-by: Day, Jeremy(jday) <[email protected]> * Added test for protobuf data Signed-off-by: Day, Jeremy(jday) <[email protected]> * Indicate that v0.3 events are supported by Protobuf Format Even though the protobuf spec came out for v1, the attributes are fairly easily mapped back to v0.3. Signed-off-by: Erik Paulson <[email protected]> * Add missing comments; fix formatting; minor refactoring Signed-off-by: Erik Paulson <[email protected]> * Create a full Protobuf CloudEventWriter Converts the ProtoContextWriter class to a ProtoCloudEventWriter class and modifies the format code to use it instead of manually writing data to the output. Signed-off-by: Erik Paulson <[email protected]> * - Addressed Review Comments. - Introduced a default ProtoDataWrapper - Tests updated. Signed-off-by: Day, Jeremy(jday) <[email protected]> * Address Review Comments Signed-off-by: Day, Jeremy(jday) <[email protected]> * Test cleanup and timezone testing This does some tweaking to tests by moving to using assertj and fixing whitespace. It also adds a new test to ensure that timezones are handled correctly. Signed-off-by: Erik Paulson <[email protected]> * Formatting cleanup - Remove unecessary whitespace - Fix Javadocs - Delete unused code Signed-off-by: Erik Paulson <[email protected]> Co-authored-by: Day, Jeremy(jday) <[email protected]>
1 parent a4613c0 commit 928ebcf

27 files changed

+1433
-1
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ Supported features of the specification:
4343
| - [Jakarta Restful WS](http/restful-ws) | :heavy_check_mark: | :heavy_check_mark: |
4444
| - [Basic](http/basic) | :heavy_check_mark: | :heavy_check_mark: |
4545
| - [Spring](spring) | :heavy_check_mark: | :heavy_check_mark: |
46-
| - [http4k][http4k]<sup>†</sup> | :heavy_check_mark: | :heavy_check_mark: |
46+
| - [http4k][http4k]<sup>†</sup>| :heavy_check_mark: | :heavy_check_mark: |
4747
| JSON Event Format | :heavy_check_mark: | :heavy_check_mark: |
4848
| - [Jackson](formats/json-jackson) | :heavy_check_mark: | :heavy_check_mark: |
49+
| Protobuf Event Format | :heavy_check_mark: | :heavy_check_mark: |
50+
| - [Proto](formats/protobuf) | :heavy_check_mark: | :heavy_check_mark: |
4951
| [Kafka Protocol Binding](kafka) | :heavy_check_mark: | :heavy_check_mark: |
5052
| MQTT Protocol Binding | :x: | :x: |
5153
| NATS Protocol Binding | :x: | :x: |
@@ -62,6 +64,7 @@ Javadocs are available on [javadoc.io](https://www.javadoc.io):
6264
- [cloudevents-api](https://www.javadoc.io/doc/io.cloudevents/cloudevents-api)
6365
- [cloudevents-core](https://www.javadoc.io/doc/io.cloudevents/cloudevents-core)
6466
- [cloudevents-json-jackson](https://www.javadoc.io/doc/io.cloudevents/cloudevents-json-jackson)
67+
- [cloudevents-protobuf](https://www.javadoc.io/doc/io.cloudevents/cloudevents-protobuf)
6568
- [cloudevents-http-basic](https://www.javadoc.io/doc/io.cloudevents/cloudevents-http-basic)
6669
- [cloudevents-http-restful-ws](https://www.javadoc.io/doc/io.cloudevents/cloudevents-http-restful-ws)
6770
- [cloudevents-http-vertx](https://www.javadoc.io/doc/io.cloudevents/cloudevents-http-vertx)

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,23 @@ public CloudEventContextWriter withContextAttribute(String name, Boolean value)
284284
return this;
285285
}
286286
}
287+
288+
@Override
289+
public CloudEventContextWriter withContextAttribute(String name, byte[] value) throws CloudEventRWException {
290+
requireValidAttributeWrite(name);
291+
switch (name) {
292+
case TIME:
293+
case SCHEMAURL:
294+
case ID:
295+
case TYPE:
296+
case DATACONTENTTYPE:
297+
case DATACONTENTENCODING:
298+
case SUBJECT:
299+
case SOURCE:
300+
throw CloudEventRWException.newInvalidAttributeType(name, byte[].class);
301+
default:
302+
withExtension(name, value);
303+
return this;
304+
}
305+
}
287306
}

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,4 +274,23 @@ public CloudEventContextWriter withContextAttribute(String name, Boolean value)
274274
return this;
275275
}
276276
}
277+
278+
@Override
279+
public CloudEventContextWriter withContextAttribute(String name, byte[] value)
280+
throws CloudEventRWException {
281+
requireValidAttributeWrite(name);
282+
switch (name) {
283+
case TIME:
284+
case DATASCHEMA:
285+
case ID:
286+
case TYPE:
287+
case DATACONTENTTYPE:
288+
case SUBJECT:
289+
case SOURCE:
290+
throw CloudEventRWException.newInvalidAttributeType(name, byte[].class);
291+
default:
292+
withExtension(name, value);
293+
return this;
294+
}
295+
}
277296
}

docs/index.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ Using the Java SDK you can:
4040
| - [http4k][http4k]<sup>†</sup> | :heavy_check_mark: | :heavy_check_mark: |
4141
| JSON Event Format | :heavy_check_mark: | :heavy_check_mark: |
4242
| - [Jackson](json-jackson.md) | :heavy_check_mark: | :heavy_check_mark: |
43+
| Protobuf Event Format | :heavy_check_mark: | :heavy_check_mark: |
44+
| - [Proto](protobuf.md) | :heavy_check_mark: | :heavy_check_mark: |
4345
| [Kafka Protocol Binding](kafka.md) | :heavy_check_mark: | :heavy_check_mark: |
4446
| MQTT Protocol Binding | :x: | :x: |
4547
| NATS Protocol Binding | :x: | :x: |
@@ -88,6 +90,8 @@ a different feature from the different sub specs of
8890
[Protocol bindings](https://github.com/cloudevents/spec/blob/v1.0/spec.md#protocol-binding)
8991
- [`cloudevents-json-jackson`] Implementation of [JSON Event format] with
9092
[Jackson](https://github.com/FasterXML/jackson)
93+
- [`cloudevents-protobuf`] Implementation of [Protobuf Event format] using code generated
94+
from the standard [protoc](https://github.com/protocolbuffers/protobuf) compiler.
9195
- [`cloudevents-http-vertx`] Implementation of [HTTP Protocol Binding] with
9296
[Vert.x Core](https://vertx.io/)
9397
- [`cloudevents-http-restful-ws`] Implementation of [HTTP Protocol Binding]
@@ -104,6 +108,7 @@ You can look at the latest published artifacts on
104108
[Maven Central](https://search.maven.org/search?q=g:io.cloudevents).
105109

106110
[JSON Event format]: https://github.com/cloudevents/spec/blob/v1.0/json-format.md
111+
[Protobuf Event format]: https://github.com/cloudevents/spec/blob/v1.0.1/protobuf-format.md
107112
[HTTP Protocol Binding]: https://github.com/cloudevents/spec/blob/v1.0/http-protocol-binding.md
108113
[Kafka Protocol Binding]: https://github.com/cloudevents/spec/blob/v1.0/kafka-protocol-binding.md
109114
[AMQP Protocol Binding]: https://github.com/cloudevents/spec/blob/v1.0/amqp-protocol-binding.md

docs/protobuf.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
title: CloudEvents Protocol Buffers
3+
nav_order: 4
4+
---
5+
6+
# CloudEvents Protocol Buffers
7+
8+
[![Javadocs](http://www.javadoc.io/badge/io.cloudevents/cloudevents-protobuf.svg?color=green)](http://www.javadoc.io/doc/io.cloudevents/cloudevents-protobuf)
9+
10+
This module provides the Protocol Buffer (protobuf) `EventFormat` implementation using the Java
11+
Protobuf runtime and classes generated from the CloudEvents
12+
[proto spec](https://github.com/cloudevents/spec/blob/v1.0.1/spec.proto).
13+
14+
For Maven based projects, use the following dependency:
15+
16+
```xml
17+
<dependency>
18+
<groupId>io.cloudevents</groupId>
19+
<artifactId>cloudevents-protobuf</artifactId>
20+
<version>2.0.0</version>
21+
</dependency>
22+
```
23+
24+
## Using the Protobuf Event Format
25+
26+
You don't need to perform any operation to configure the module, more than
27+
adding the dependency to your project:
28+
29+
```java
30+
import io.cloudevents.CloudEvent;
31+
import io.cloudevents.core.format.EventFormatProvider;
32+
import io.cloudevents.core.builder.CloudEventBuilder;
33+
import io.cloudevents.protobuf.ProtobufFormat;
34+
35+
CloudEvent event = CloudEventBuilder.v1()
36+
.withId("hello")
37+
.withType("example.vertx")
38+
.withSource(URI.create("http://localhost"))
39+
.build();
40+
41+
byte[]serialized = EventFormatProvider
42+
.getInstance()
43+
.resolveFormat(ProtobufFormat.CONTENT_TYPE)
44+
.serialize(event);
45+
```
46+
47+
The `EventFormatProvider` will resolve automatically the `ProtobufFormat` using the
48+
`ServiceLoader` APIs.

formats/protobuf/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# CloudEvents Protocol Buffers Format
2+
3+
This project provides functionality for the Java SDK to handle the
4+
[protobuf format](https://github.com/cloudevents/spec/blob/v1.0.1/protobuf-format.md).
5+
6+
The protobuf definition file is located in src/main/proto/spec.proto. The file was directly
7+
copied from [https://github.com/cloudevents/spec/blob/v1.0.1/spec.proto]() and is built using
8+
[the Maven proto plugin](https://www.xolstice.org/protobuf-maven-plugin/).

formats/protobuf/pom.xml

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2021-Present The CloudEvents Authors
4+
~ <p>
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~ <p>
9+
~ http://www.apache.org/licenses/LICENSE-2.0
10+
~ <p>
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
~
17+
-->
18+
<project xmlns="http://maven.apache.org/POM/4.0.0"
19+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
21+
<modelVersion>4.0.0</modelVersion>
22+
23+
<parent>
24+
<groupId>io.cloudevents</groupId>
25+
<artifactId>cloudevents-parent</artifactId>
26+
<version>2.1.0-SNAPSHOT</version>
27+
<relativePath>../../pom.xml</relativePath>
28+
</parent>
29+
30+
<artifactId>cloudevents-protobuf</artifactId>
31+
<name>CloudEvents - Protocol Buffers</name>
32+
<packaging>jar</packaging>
33+
34+
<properties>
35+
<protobuf.version>3.15.0</protobuf.version>
36+
<module-name>io.cloudevents.formats.protobuf</module-name>
37+
</properties>
38+
39+
<build>
40+
<extensions>
41+
<extension>
42+
<groupId>kr.motd.maven</groupId>
43+
<artifactId>os-maven-plugin</artifactId>
44+
<version>1.6.0</version>
45+
</extension>
46+
</extensions>
47+
<plugins>
48+
<plugin>
49+
<groupId>org.xolstice.maven.plugins</groupId>
50+
<artifactId>protobuf-maven-plugin</artifactId>
51+
<version>0.6.1</version>
52+
<executions>
53+
<execution>
54+
<goals>
55+
<goal>compile</goal>
56+
<goal>test-compile</goal>
57+
</goals>
58+
</execution>
59+
</executions>
60+
<configuration>
61+
<protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
62+
</configuration>
63+
</plugin>
64+
</plugins>
65+
</build>
66+
67+
<dependencyManagement>
68+
<dependencies>
69+
<dependency>
70+
<groupId>com.google.protobuf</groupId>
71+
<artifactId>protobuf-bom</artifactId>
72+
<version>${protobuf.version}</version>
73+
<scope>import</scope>
74+
<type>pom</type>
75+
</dependency>
76+
</dependencies>
77+
</dependencyManagement>
78+
79+
<dependencies>
80+
<dependency>
81+
<groupId>io.cloudevents</groupId>
82+
<artifactId>cloudevents-core</artifactId>
83+
<version>${project.version}</version>
84+
</dependency>
85+
86+
<dependency>
87+
<groupId>com.google.protobuf</groupId>
88+
<artifactId>protobuf-java</artifactId>
89+
</dependency>
90+
91+
<dependency>
92+
<groupId>com.google.protobuf</groupId>
93+
<artifactId>protobuf-java-util</artifactId>
94+
<version>${protobuf.version}</version>
95+
</dependency>
96+
97+
<!-- Test deps -->
98+
<dependency>
99+
<groupId>org.junit.jupiter</groupId>
100+
<artifactId>junit-jupiter</artifactId>
101+
<version>${junit-jupiter.version}</version>
102+
<scope>test</scope>
103+
</dependency>
104+
105+
<dependency>
106+
<groupId>org.assertj</groupId>
107+
<artifactId>assertj-core</artifactId>
108+
<version>${assertj-core.version}</version>
109+
<scope>test</scope>
110+
</dependency>
111+
112+
<dependency>
113+
<groupId>com.google.truth.extensions</groupId>
114+
<artifactId>truth-proto-extension</artifactId>
115+
<version>1.1</version>
116+
<scope>test</scope>
117+
</dependency>
118+
119+
<dependency>
120+
<groupId>io.cloudevents</groupId>
121+
<artifactId>cloudevents-core</artifactId>
122+
<classifier>tests</classifier>
123+
<type>test-jar</type>
124+
<version>${project.version}</version>
125+
<scope>test</scope>
126+
</dependency>
127+
128+
</dependencies>
129+
130+
</project>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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.protobuf;
18+
19+
import com.google.protobuf.Message;
20+
import io.cloudevents.CloudEventData;
21+
22+
/**
23+
* A {@link CloudEventData} that supports access to a protocol
24+
* buffer message.
25+
*/
26+
public interface ProtoCloudEventData extends CloudEventData {
27+
28+
/**
29+
* Gets the protobuf {@link Message} representation of this data.
30+
* @return The data as a {@link Message}
31+
*/
32+
Message getMessage();
33+
34+
/**
35+
* Convenience helper to wrap a Protobuf Message as
36+
* CloudEventData.
37+
*
38+
* @param protoMessage The message to wrap
39+
* @return The wrapping CloudEventData
40+
*/
41+
static CloudEventData wrap(Message protoMessage) {
42+
return new ProtoDataWrapper(protoMessage);
43+
}
44+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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.protobuf;
18+
19+
import com.google.protobuf.Message;
20+
21+
class ProtoDataWrapper implements ProtoCloudEventData {
22+
23+
private final Message protoMessage;
24+
25+
ProtoDataWrapper(Message protoMessage) {
26+
this.protoMessage = protoMessage;
27+
}
28+
29+
@Override
30+
public Message getMessage() {
31+
return protoMessage;
32+
}
33+
34+
@Override
35+
public byte[] toBytes() {
36+
return protoMessage.toByteArray();
37+
}
38+
}

0 commit comments

Comments
 (0)