EventBridge accepts events in the CloudEvents v1.0 format. Use the CloudEvents SDK for Java to construct event objects and send them to EventBridge over HTTP in either binary or structured content mode.
Content modes
EventBridge supports two CloudEvents content modes for HTTP transport:
| Content mode | Content-Type header | Encoding | When to use |
|---|---|---|---|
| Binary | application/json | Event attributes map to HTTP headers. The event data is the HTTP body. | Intermediaries need to inspect or route events by header without parsing the body. |
| Structured | application/cloudevents+json | The entire event (attributes and data) is serialized as a single JSON object in the HTTP body. | Simpler to debug because the full event is visible in the body. |
Both modes carry the same information. If you have no specific routing requirements, use structured mode for easier debugging.
CloudEvents attributes
Each event requires the following CloudEvents v1.0 attributes:
| Attribute | Type | Description | Example |
|---|---|---|---|
id | String | Unique event identifier. Use a UUID. | 550e8400-e29b-41d4-a716-446655440000 |
source | URI | Identifies the event producer. | https://github.com/cloudevents/sdk-java/tree/master/examples/vertx |
type | String | Describes the type of event. | vertx.example |
subject | String | (Optional) Identifies the resource the event relates to. | acs:oss:cn-hangzhou:1234567:my-bucket/path/object.jpg |
aliyuneventbusname | String | (Alibaba Cloud extension) Name of the target event bus. | my-event-bus |
Prerequisites
Before you begin, make sure that you have:
IntelliJ IDEA or Eclipse installed (the examples below use IntelliJ IDEA)
The
ALIBABA_CLOUD_ACCESS_KEY_IDandALIBABA_CLOUD_ACCESS_KEY_SECRETenvironment variables set to your AccessKey ID and AccessKey secretThe following CloudEvents SDK dependencies added to the
pom.xmlfile of your project:<properties> <cloudevents.version>2.0.0-milestone1</cloudevents.version> </properties> <dependencies> <dependency> <groupId>io.cloudevents</groupId> <artifactId>cloudevents-core</artifactId> <version>${cloudevents.version}</version> </dependency> <dependency> <groupId>io.cloudevents</groupId> <artifactId>cloudevents-http-vertx</artifactId> <version>${cloudevents.version}</version> </dependency> <dependency> <groupId>io.cloudevents</groupId> <artifactId>cloudevents-api</artifactId> <version>${cloudevents.version}</version> </dependency> <dependency> <groupId>io.cloudevents</groupId> <artifactId>cloudevents-json-jackson</artifactId> <version>${cloudevents.version}</version> </dependency> </dependencies>
How it works
Both examples follow the same flow:
Read the AccessKey ID and AccessKey secret from environment variables.
Create a Vert.x HTTP client and point an
HttpClientRequestat the EventBridgeputEventsendpoint.Build a CloudEvent v1.0 object with the required attributes (
id,source,type) and optional attributes (subject,data, and the Alibaba Cloud extensionaliyuneventbusname).Sign the request with HMAC-SHA1 and set the
authorizationheader.Write the event to the request in binary or structured content mode.
Publish an event in binary content mode
Binary content mode sends event data as the HTTP body and maps CloudEvents attributes to HTTP headers.
import java.net.URI;
import java.util.UUID;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.http.vertx.VertxMessageFactory;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientRequest;
public class SampleBinaryHTTPClient{
private static String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
private static String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// Replace with your EventBridge endpoint, for example:
// http://eb-cn-hangzhou.eventbridge.aliyuncs.com/openapi/putEvents
private static String endpoint = "http://<your-endpoint>/openapi/putEvents";
public static void main(String[] args) throws Exception {
final Vertx vertx = Vertx.vertx();
final HttpClient httpClient = vertx.createHttpClient();
// Create an event template with default CloudEvents attributes.
CloudEventBuilder eventTemplate = CloudEventBuilder.v1()
.withSource(URI.create("https://github.com/cloudevents/sdk-java/tree/master/examples/vertx"))
.withType("vertx.example");
// Create an HTTP request to the putEvents endpoint.
final HttpClientRequest request = httpClient.postAbs(endpoint)
.handler(response -> {
System.out.println(response.statusMessage());
})
.exceptionHandler(System.err::println);
String id = UUID.randomUUID()
.toString();
String data = "{\"name\":\"Eventbridge\",\"number\":100}";
// Build the CloudEvent with required and optional attributes.
final CloudEvent event = eventTemplate.newBuilder()
.withId(id)
.withData("application/json", data.getBytes())
.withExtension("aliyuneventbusname", "jingluo-bus")
.withSource(URI.create("https://github.com/cloudevents/sdk-java/tree/master/examples/vertx"))
.withType("vertx.example")
.withSubject("acs:oss:cn-hangzhou:1234567:xls-papk/game_apk/123.jpg")
.build();
// Set the content-type for binary mode and add authorization.
request.putHeader("content-type", "application/json");
request.putHeader("authorization",
"acs" + ":" + accessKeyId + ":" + SignatureHelper.getSignature(SignatureHelper.getStringToSign(request),
accessKeySecret) + "");
VertxMessageFactory.createWriter(request)
.writeBinary(event);
}
}Replace the following values before you run the code:
| Placeholder | Description | Example |
|---|---|---|
endpoint | EventBridge endpoint URL in the format http://<your-endpoint>/openapi/putEvents | http://eb-cn-hangzhou.eventbridge.aliyuncs.com/openapi/putEvents |
aliyuneventbusname | Name of the target event bus | my-event-bus |
withSubject | Subject that identifies the source resource of the event | acs:oss:cn-hangzhou:1234567:my-bucket/path/object.jpg |
Publish an event in structured content mode
Structured content mode serializes the entire event -- attributes and data -- as a single JSON payload in the HTTP body.
Differences from binary mode:
The
content-typeheader is set toapplication/cloudevents+jsoninstead ofapplication/json.The event is written with
writeStructured()instead ofwriteBinary().
import java.net.URI;
import java.util.UUID;
import io.cloudevents.CloudEvent;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.cloudevents.http.vertx.VertxMessageFactory;
import io.cloudevents.jackson.JsonFormat;
import io.vertx.core.Vertx;
import io.vertx.core.http.HttpClient;
import io.vertx.core.http.HttpClientRequest;
public class SampleStructuredHTTPClient {
private static String accessKeyId = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_ID");
private static String accessKeySecret = System.getenv("ALIBABA_CLOUD_ACCESS_KEY_SECRET");
// Replace with your EventBridge endpoint, for example:
// http://eb-cn-hangzhou.eventbridge.aliyuncs.com/openapi/putEvents
private static String endpoint = "http://<your-endpoint>/openapi/putEvents";
public static void main(String[] args) throws Exception {
final Vertx vertx = Vertx.vertx();
final HttpClient httpClient = vertx.createHttpClient();
// Create an event template with default CloudEvents attributes.
CloudEventBuilder eventTemplate = CloudEventBuilder.v1()
.withSource(URI.create("https://github.com/cloudevents/sdk-java/tree/master/examples/vertx"))
.withType("vertx.example");
// Create an HTTP request to the putEvents endpoint.
final HttpClientRequest request = httpClient.postAbs(endpoint)
.handler(response -> {
System.out.println(response.statusMessage());
})
.exceptionHandler(System.err::println);
String id = UUID.randomUUID()
.toString();
String data = "{\"name\":\"Eventbridge\",\"number\":100}";
// Build the CloudEvent with required and optional attributes.
final CloudEvent event = eventTemplate.newBuilder()
.withId(id)
.withData("application/json", data.getBytes())
.withExtension("aliyuneventbusname", "jingluo-bus")
.withSource(URI.create("https://github.com/cloudevents/sdk-java/tree/master/examples/vertx"))
.withType("vertx.example")
.withSubject("acs:oss:cn-hangzhou:1234567:xls-papk/game_apk/123.jpg")
.build();
// Set the content-type for structured mode and add authorization.
request.putHeader("content-type", "application/cloudevents+json");
request.putHeader("authorization",
"acs" + ":" + accessKeyId + ":" + SignatureHelper.getSignature(SignatureHelper.getStringToSign(request),
accessKeySecret) + "");
VertxMessageFactory.createWriter(request)
.writeStructured(event, new JsonFormat());
}
}Signature helper
Both examples use a SignatureHelper class to generate the HMAC-SHA1 request signature required by EventBridge.
The class performs the following steps:
Builds a string-to-sign from the HTTP method,
content-md5,content-type,dateheaders, anyx-acs-prefixed headers, and the request path with query parameters.Computes the HMAC-SHA1 digest using your AccessKey secret.
Returns the Base64-encoded signature.
The authorization header follows the format acs:<AccessKey ID>:<signature>.
Add the following class to your project:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import io.netty.util.internal.StringUtil;
import io.vertx.core.MultiMap;
import io.vertx.core.http.HttpClientRequest;
public class SignatureHelper {
public static String getStringToSign(HttpClientRequest request) {
String method = request.method()
.name();
String pathname = request.path();
MultiMap headers = request.headers();
Map<String, String> query = buildQueryMap(request.query());
String contentMD5 = headers.get("content-md5") == null ? "" : (String)headers.get("content-md5");
String contentType = headers.get("content-type") == null ? "" : (String)headers.get("content-type");
String date = headers.get("date") == null ? "null" : (String)headers.get("date");
String header = method + "\n" + contentMD5 + "\n" + contentType + "\n" + date + "\n";
String canonicalizedHeaders = getCanonicalizedHeaders(headers);
String canonicalizedResource = getCanonicalizedResource(pathname, query);
String stringToSign = header + canonicalizedHeaders + canonicalizedResource;
return stringToSign;
}
private static Map<String, String> buildQueryMap(String query) {
Map<String, String> map = new HashMap<>();
if (!StringUtil.isNullOrEmpty(query)) {
String[] params = query.split("&");
Arrays.stream(params)
.forEach(param -> {
String[] kv = param.split("=");
map.put(kv[0], kv[1]);
});
}
return map;
}
protected static String getCanonicalizedHeaders(MultiMap headers) {
String prefix = "x-acs";
Set<String> keys = headers.names();
List<String> canonicalizedKeys = new ArrayList();
Iterator var4 = keys.iterator();
while (var4.hasNext()) {
String key = (String)var4.next();
if (key.startsWith(prefix)) {
canonicalizedKeys.add(key);
}
}
String[] canonicalizedKeysArray = (String[])canonicalizedKeys.toArray(new String[canonicalizedKeys.size()]);
Arrays.sort(canonicalizedKeysArray);
StringBuilder result = new StringBuilder();
for (int i = 0; i < canonicalizedKeysArray.length; ++i) {
String key = canonicalizedKeysArray[i];
result.append(key);
result.append(":");
result.append(((String)headers.get(key)).trim());
result.append("\n");
}
return result.toString();
}
protected static String getCanonicalizedResource(String pathname, Map<String, String> query) {
String[] keys = (String[])query.keySet()
.toArray(new String[query.size()]);
if (keys.length <= 0) {
return pathname;
} else {
Arrays.sort(keys);
StringBuilder result = new StringBuilder(pathname);
result.append("?");
for (int i = 0; i < keys.length; ++i) {
String key = keys[i];
result.append(key);
String value = (String)query.get(key);
if (!StringUtil.isNullOrEmpty(value) && !"".equals(value.trim())) {
result.append("=");
result.append(value);
}
result.append("&");
}
return result.deleteCharAt(result.length() - 1)
.toString();
}
}
public static String getSignature(String stringToSign, String secret) throws Exception {
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA1"));
byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
return Base64.getEncoder()
.encodeToString(signData);
}
}Error handling
The putEvents endpoint returns an HTTP status code and a response body. Check both to verify that the event was published.
| HTTP status code | Meaning | Action |
|---|---|---|
| 200 | The event was accepted. | No action required. |
| 4xx | Client error (invalid request, authentication failure, or missing permissions). | Check the request format, credentials, and permissions. Do not retry. |
| 5xx | Server error. | Retry with exponential backoff. |
The response handler in the examples above prints only statusMessage(). For production use, read and parse the full response body to capture error details and implement a retry strategy for transient failures.
What's next
Event rules overview -- Create rules to filter and route events in the EventBridge console.
API reference -- Full list of EventBridge API operations.