Javadoc-ed cloudevents-api (#181)

* Javadoc-ed cloudevents-api

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>

* nit

Signed-off-by: Francesco Guardiani <francescoguard@gmail.com>
This commit is contained in:
Francesco Guardiani 2020-06-23 17:20:09 +02:00 committed by GitHub
parent c632f56f8b
commit 98a6b87d5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 139 additions and 79 deletions

View File

@ -19,7 +19,8 @@ package io.cloudevents;
import io.cloudevents.lang.Nullable;
/**
* An abstract event envelope
* Interface representing an in memory read only representation of a CloudEvent,
* as specified by the <a href="https://github.com/cloudevents/spec/blob/v1.0/spec.md">CloudEvents specification</a>
*/
public interface CloudEvent extends CloudEventAttributes, CloudEventExtensions {

View File

@ -23,6 +23,7 @@ import javax.annotation.ParametersAreNonnullByDefault;
import java.net.URI;
import java.time.ZonedDateTime;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Interface which defines CloudEvent attributes as per specification
@ -78,9 +79,25 @@ public interface CloudEventAttributes {
@Nullable
ZonedDateTime getTime();
/**
* Get the <a href="https://github.com/cloudevents/spec/blob/v1.0/spec.md#context-attributes">context attribute</a> named {@code attributeName}
*
* @param attributeName a valid attribute name
* @return the attribute value or null if this instance doesn't contain such attribute
* @throws IllegalArgumentException if the provided attribute name it's not a valid attribute for this spec
*/
@Nullable
Object getAttribute(String extensionName);
Object getAttribute(String attributeName) throws IllegalArgumentException;
Set<String> getAttributeNames();
/**
* @return The non-null <a href="https://github.com/cloudevents/spec/blob/v1.0/spec.md#context-attributes">context attributes</a> names in this instance
*/
default Set<String> getAttributeNames() {
return getSpecVersion()
.getAllAttributes()
.stream()
.filter(s -> getAttribute(s) != null)
.collect(Collectors.toSet());
}
}

View File

@ -30,9 +30,18 @@ import java.util.Set;
@ParametersAreNonnullByDefault
public interface CloudEventExtensions {
/**
* Get the extension attribute named {@code extensionName}
*
* @param extensionName the extension name
* @return the extension value or null if this instance doesn't contain such extension
*/
@Nullable
Object getExtension(String extensionName);
/**
* @return The non-null extension attributes names in this instance
*/
Set<String> getExtensionNames();
}

View File

@ -17,10 +17,15 @@
package io.cloudevents;
import javax.annotation.ParametersAreNonnullByDefault;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Represents one of the supported CloudEvents specification versions by this library
*/
@ParametersAreNonnullByDefault
public enum SpecVersion {
V03(
"0.3",

View File

@ -25,23 +25,23 @@ public interface CloudEventReader {
/**
* Visit self using the provided visitor factory
*
* @param visitorFactory a factory that generates a visitor starting from the SpecVersion of the event
* @param writerFactory a factory that generates a visitor starting from the SpecVersion of the event
* @throws CloudEventRWException if something went wrong during the visit.
*/
<V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> visitorFactory) throws CloudEventRWException;
<V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> writerFactory) throws CloudEventRWException;
/**
* Visit self attributes using the provided visitor
* Visit self attributes using the provided writer
*
* @param visitor Attributes visitor
* @param writer Attributes writer
* @throws CloudEventRWException if something went wrong during the visit.
*/
void readAttributes(CloudEventAttributesWriter visitor) throws CloudEventRWException;
void readAttributes(CloudEventAttributesWriter writer) throws CloudEventRWException;
/**
* Visit self extensions using the provided visitor
* Visit self extensions using the provided writer
*
* @param visitor Extensions visitor
* @param visitor Extensions writer
* @throws CloudEventRWException if something went wrong during the visit.
*/
void readExtensions(CloudEventExtensionsWriter visitor) throws CloudEventRWException;

View File

@ -23,14 +23,31 @@ import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
/**
* Utilities to handle the <a href="https://github.com/cloudevents/spec/blob/v1.0/spec.md#type-system">CloudEvent Attribute Timestamp type</a>
*/
public final class Time {
private Time() {
}
public static final DateTimeFormatter RFC3339_DATE_FORMAT = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd'T'HH:mm:ss")
.appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true)
.appendZoneOrOffsetId()
.toFormatter();
/**
* Parse a {@link String} RFC3339 compliant as {@link ZonedDateTime}
*/
public static ZonedDateTime parseTime(String time) throws DateTimeParseException {
return ZonedDateTime.parse(time, RFC3339_DATE_FORMAT);
}
/**
* Convert a {@link ZonedDateTime} to {@link String}
*/
public static String writeTime(ZonedDateTime time) throws DateTimeParseException {
return time.format(RFC3339_DATE_FORMAT);
}
}

View File

@ -49,8 +49,8 @@ public abstract class BaseCloudEvent implements CloudEvent, CloudEventReader {
return this.extensions.keySet();
}
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> visitorFactory) throws CloudEventRWException, IllegalStateException {
CloudEventWriter<V> visitor = visitorFactory.create(this.getSpecVersion());
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> writerFactory) throws CloudEventRWException, IllegalStateException {
CloudEventWriter<V> visitor = writerFactory.create(this.getSpecVersion());
this.readAttributes(visitor);
this.readExtensions(visitor);

View File

@ -29,8 +29,8 @@ public class CloudEventReaderAdapter implements CloudEventReader {
}
@Override
public <V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> visitorFactory) throws RuntimeException {
CloudEventWriter<R> visitor = visitorFactory.create(event.getSpecVersion());
public <V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> writerFactory) throws RuntimeException {
CloudEventWriter<R> visitor = writerFactory.create(event.getSpecVersion());
this.readAttributes(visitor);
this.readExtensions(visitor);
@ -42,21 +42,21 @@ public class CloudEventReaderAdapter implements CloudEventReader {
}
@Override
public void readAttributes(CloudEventAttributesWriter visitor) throws RuntimeException {
visitor.setAttribute("id", event.getId());
visitor.setAttribute("source", event.getSource());
visitor.setAttribute("type", event.getType());
public void readAttributes(CloudEventAttributesWriter writer) throws RuntimeException {
writer.setAttribute("id", event.getId());
writer.setAttribute("source", event.getSource());
writer.setAttribute("type", event.getType());
if (event.getDataContentType() != null) {
visitor.setAttribute("datacontenttype", event.getDataContentType());
writer.setAttribute("datacontenttype", event.getDataContentType());
}
if (event.getDataSchema() != null) {
visitor.setAttribute("dataschema", event.getDataSchema());
writer.setAttribute("dataschema", event.getDataSchema());
}
if (event.getSubject() != null) {
visitor.setAttribute("subject", event.getSubject());
writer.setAttribute("subject", event.getSubject());
}
if (event.getTime() != null) {
visitor.setAttribute("time", event.getTime());
writer.setAttribute("time", event.getTime());
}
}

View File

@ -30,20 +30,20 @@ public interface MessageReader extends StructuredMessageReader, CloudEventReader
/**
* Visit the message as binary encoded event using the provided visitor factory.
*
* @param visitorFactory a factory that generates a visitor starting from the SpecVersion of the event
* @param writerFactory a factory that generates a visitor starting from the SpecVersion of the event
* @throws CloudEventRWException if something went wrong during the visit.
* @throws IllegalStateException if the message is not in binary encoding.
*/
<V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> visitorFactory) throws CloudEventRWException, IllegalStateException;
<V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> writerFactory) throws CloudEventRWException, IllegalStateException;
/**
* Visit the message attributes as binary encoded event using the provided visitor.
*
* @param visitor Attributes visitor
* @param writer Attributes visitor
* @throws CloudEventRWException if something went wrong during the visit.
* @throws IllegalStateException if the message is not in binary encoding.
* @throws IllegalStateException if the message is not in binary encoding.
*/
void readAttributes(CloudEventAttributesWriter visitor) throws CloudEventRWException, IllegalStateException;
void readAttributes(CloudEventAttributesWriter writer) throws CloudEventRWException, IllegalStateException;
/**
* Visit the message extensions as binary encoded event using the provided visitor.

View File

@ -43,8 +43,8 @@ public abstract class BaseGenericBinaryMessageReaderImpl<HK, HV> extends BaseBin
}
@Override
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> visitorFactory) throws CloudEventRWException, IllegalStateException {
CloudEventWriter<V> visitor = visitorFactory.create(this.version);
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> writerFactory) throws CloudEventRWException, IllegalStateException {
CloudEventWriter<V> visitor = writerFactory.create(this.version);
// Grab from headers the attributes and extensions
// This implementation avoids to use visitAttributes and visitExtensions
@ -74,17 +74,17 @@ public abstract class BaseGenericBinaryMessageReaderImpl<HK, HV> extends BaseBin
}
@Override
public void readAttributes(CloudEventAttributesWriter visitor) throws RuntimeException {
public void readAttributes(CloudEventAttributesWriter writer) throws RuntimeException {
this.forEachHeader((key, value) -> {
if (isContentTypeHeader(key)) {
visitor.setAttribute("datacontenttype", toCloudEventsValue(value));
writer.setAttribute("datacontenttype", toCloudEventsValue(value));
} else if (isCloudEventsHeader(key)) {
String name = toCloudEventsKey(key);
if (name.equals("specversion")) {
return;
}
if (this.version.getAllAttributes().contains(name)) {
visitor.setAttribute(name, toCloudEventsValue(value));
writer.setAttribute(name, toCloudEventsValue(value));
}
}
});

View File

@ -32,12 +32,12 @@ public abstract class BaseStructuredMessageReader implements MessageReader {
}
@Override
public <V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> visitorFactory) {
public <V extends CloudEventWriter<R>, R> R read(CloudEventWriterFactory<V, R> writerFactory) {
throw MessageUtils.generateWrongEncoding(Encoding.BINARY, Encoding.STRUCTURED);
}
@Override
public void readAttributes(CloudEventAttributesWriter visitor) throws RuntimeException {
public void readAttributes(CloudEventAttributesWriter writer) throws RuntimeException {
throw MessageUtils.generateWrongEncoding(Encoding.BINARY, Encoding.STRUCTURED);
}

View File

@ -29,12 +29,12 @@ public class UnknownEncodingMessageReader implements MessageReader {
}
@Override
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> visitorFactory) throws CloudEventRWException, IllegalStateException {
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> writerFactory) throws CloudEventRWException, IllegalStateException {
throw new IllegalStateException("Unknown encoding");
}
@Override
public void readAttributes(CloudEventAttributesWriter visitor) throws CloudEventRWException {
public void readAttributes(CloudEventAttributesWriter writer) throws CloudEventRWException {
throw new IllegalStateException("Unknown encoding");
}

View File

@ -27,7 +27,6 @@ import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* CloudEvent implementation for v0.3
@ -99,8 +98,10 @@ public final class CloudEventV03 extends BaseCloudEvent {
}
@Override
public Object getAttribute(String name) {
switch (name) {
public Object getAttribute(String attributeName) {
switch (attributeName) {
case "specversion":
return getSpecVersion();
case "id":
return this.id;
case "source":
@ -116,48 +117,43 @@ public final class CloudEventV03 extends BaseCloudEvent {
case "time":
return this.time;
}
throw new IllegalArgumentException("Spec version v0.3 doesn't have attribute named " + name);
throw new IllegalArgumentException("Spec version v0.3 doesn't have attribute named " + attributeName);
}
@Override
public Set<String> getAttributeNames() {
return ContextAttributes.VALUES;
}
@Override
public void readAttributes(CloudEventAttributesWriter visitor) throws CloudEventRWException {
visitor.setAttribute(
public void readAttributes(CloudEventAttributesWriter writer) throws CloudEventRWException {
writer.setAttribute(
ContextAttributes.ID.name().toLowerCase(),
this.id
);
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.SOURCE.name().toLowerCase(),
this.source
);
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.TYPE.name().toLowerCase(),
this.type
);
if (this.datacontenttype != null) {
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.DATACONTENTTYPE.name().toLowerCase(),
this.datacontenttype
);
}
if (this.schemaurl != null) {
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.SCHEMAURL.name().toLowerCase(),
this.schemaurl
);
}
if (this.subject != null) {
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.SUBJECT.name().toLowerCase(),
this.subject
);
}
if (this.time != null) {
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.TIME.name().toLowerCase(),
this.time
);

View File

@ -26,7 +26,6 @@ import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
* @author fabiojose
@ -93,8 +92,10 @@ public final class CloudEventV1 extends BaseCloudEvent {
}
@Override
public Object getAttribute(String name) {
switch (name) {
public Object getAttribute(String attributeName) {
switch (attributeName) {
case "specversion":
return getSpecVersion();
case "id":
return this.id;
case "source":
@ -110,48 +111,43 @@ public final class CloudEventV1 extends BaseCloudEvent {
case "time":
return this.time;
}
throw new IllegalArgumentException("Spec version v1 doesn't have attribute named " + name);
throw new IllegalArgumentException("Spec version v1 doesn't have attribute named " + attributeName);
}
@Override
public Set<String> getAttributeNames() {
return ContextAttributes.VALUES;
}
@Override
public void readAttributes(CloudEventAttributesWriter visitor) throws CloudEventRWException {
visitor.setAttribute(
public void readAttributes(CloudEventAttributesWriter writer) throws CloudEventRWException {
writer.setAttribute(
ContextAttributes.ID.name().toLowerCase(),
this.id
);
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.SOURCE.name().toLowerCase(),
this.source
);
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.TYPE.name().toLowerCase(),
this.type
);
if (this.datacontenttype != null) {
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.DATACONTENTTYPE.name().toLowerCase(),
this.datacontenttype
);
}
if (this.dataschema != null) {
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.DATASCHEMA.name().toLowerCase(),
this.dataschema
);
}
if (this.subject != null) {
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.SUBJECT.name().toLowerCase(),
this.subject
);
}
if (this.time != null) {
visitor.setAttribute(
writer.setAttribute(
ContextAttributes.TIME.name().toLowerCase(),
this.time
);

View File

@ -72,4 +72,23 @@ public class CloudEventImplTest {
assertThat(event1).isEqualTo(event2);
}
@Test
public void testGetAttributeNames() {
CloudEvent event = CloudEventBuilder.v1()
.withId(ID)
.withType(TYPE)
.withSource(SOURCE)
.withTime(TIME)
.build();
assertThat(event.getAttributeNames())
.containsExactlyInAnyOrder(
"specversion",
"id",
"type",
"source",
"time"
);
}
}

View File

@ -56,12 +56,12 @@ public class MockBinaryMessageWriter extends BaseBinaryMessageReader implements
}
@Override
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> visitorFactory) throws CloudEventRWException, IllegalStateException {
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> writerFactory) throws CloudEventRWException, IllegalStateException {
if (version == null) {
throw new IllegalStateException("MockBinaryMessage is empty");
}
CloudEventWriter<V> visitor = visitorFactory.create(version);
CloudEventWriter<V> visitor = writerFactory.create(version);
this.readAttributes(visitor);
this.readExtensions(visitor);
@ -73,14 +73,14 @@ public class MockBinaryMessageWriter extends BaseBinaryMessageReader implements
}
@Override
public void readAttributes(CloudEventAttributesWriter visitor) throws CloudEventRWException, IllegalStateException {
public void readAttributes(CloudEventAttributesWriter writer) throws CloudEventRWException, IllegalStateException {
for (Map.Entry<String, Object> e : this.attributes.entrySet()) {
if (e.getValue() instanceof String) {
visitor.setAttribute(e.getKey(), (String) e.getValue());
writer.setAttribute(e.getKey(), (String) e.getValue());
} else if (e.getValue() instanceof ZonedDateTime) {
visitor.setAttribute(e.getKey(), (ZonedDateTime) e.getValue());
writer.setAttribute(e.getKey(), (ZonedDateTime) e.getValue());
} else if (e.getValue() instanceof URI) {
visitor.setAttribute(e.getKey(), (URI) e.getValue());
writer.setAttribute(e.getKey(), (URI) e.getValue());
} else {
// This should never happen because we build that map only through our builders
throw new IllegalStateException("Illegal value inside attributes map: " + e);

View File

@ -49,10 +49,10 @@ public class CloudEventDeserializer extends StdDeserializer<CloudEvent> {
}
@Override
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> visitorFactory) throws CloudEventRWException, IllegalStateException {
public <T extends CloudEventWriter<V>, V> V read(CloudEventWriterFactory<T, V> writerFactory) throws CloudEventRWException, IllegalStateException {
try {
SpecVersion specVersion = SpecVersion.parse(getStringNode(this.node, this.p, "specversion"));
CloudEventWriter<V> visitor = visitorFactory.create(specVersion);
CloudEventWriter<V> visitor = writerFactory.create(specVersion);
// Read mandatory attributes
for (String attr : specVersion.getMandatoryAttributes()) {
@ -150,7 +150,7 @@ public class CloudEventDeserializer extends StdDeserializer<CloudEvent> {
}
@Override
public void readAttributes(CloudEventAttributesWriter visitor) throws CloudEventRWException {
public void readAttributes(CloudEventAttributesWriter writer) throws CloudEventRWException {
// no-op no need for that
}