diff --git a/amqp/pom.xml b/amqp/pom.xml index a2b1c19c..44fd6b56 100644 --- a/amqp/pom.xml +++ b/amqp/pom.xml @@ -16,8 +16,10 @@ 0.33.7 3.0.2 + io.cloudevents.amqp.proton - + + org.apache.qpid proton-j diff --git a/api/src/main/java/io/cloudevents/CloudEvent.java b/api/src/main/java/io/cloudevents/CloudEvent.java index 74ee8cd6..c642731d 100644 --- a/api/src/main/java/io/cloudevents/CloudEvent.java +++ b/api/src/main/java/io/cloudevents/CloudEvent.java @@ -20,12 +20,12 @@ import io.cloudevents.lang.Nullable; /** * Interface representing an in memory read only representation of a CloudEvent, - * as specified by the CloudEvents specification + * as specified by the CloudEvents specification. */ public interface CloudEvent extends CloudEventContext { /** - * The event data + * @return The event data, if any, otherwise {@code null} */ @Nullable CloudEventData getData(); diff --git a/api/src/main/java/io/cloudevents/SpecVersion.java b/api/src/main/java/io/cloudevents/SpecVersion.java index 6a60650b..667af9ce 100644 --- a/api/src/main/java/io/cloudevents/SpecVersion.java +++ b/api/src/main/java/io/cloudevents/SpecVersion.java @@ -29,11 +29,17 @@ import java.util.stream.Stream; */ @ParametersAreNonnullByDefault public enum SpecVersion { + /** + * @see CloudEvents release v0.3 + */ V03( "0.3", Arrays.asList("specversion", "id", "type", "source"), Arrays.asList("datacontenttype", "datacontentencoding", "schemaurl", "subject", "time") ), + /** + * @see CloudEvents release v1.0 + */ V1( "1.0", Arrays.asList("specversion", "id", "type", "source"), diff --git a/api/src/main/java/io/cloudevents/lang/Nullable.java b/api/src/main/java/io/cloudevents/lang/Nullable.java index b978e5ab..a82f3d4e 100644 --- a/api/src/main/java/io/cloudevents/lang/Nullable.java +++ b/api/src/main/java/io/cloudevents/lang/Nullable.java @@ -27,6 +27,9 @@ import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; import static javax.annotation.meta.When.MAYBE; +/** + * This annotation is used to define a method parameter or return type as nullable. + */ @Target(value = {METHOD, PARAMETER, FIELD}) @Retention(value = RUNTIME) @Documented diff --git a/api/src/main/java/io/cloudevents/rw/CloudEventDataMapper.java b/api/src/main/java/io/cloudevents/rw/CloudEventDataMapper.java index f427f76e..c7b51ca6 100644 --- a/api/src/main/java/io/cloudevents/rw/CloudEventDataMapper.java +++ b/api/src/main/java/io/cloudevents/rw/CloudEventDataMapper.java @@ -23,6 +23,8 @@ import javax.annotation.ParametersAreNonnullByDefault; /** * Interface to convert a {@link CloudEventData} instance to another one. + * + * @param the returned {@link CloudEventData} from this mapper. */ @FunctionalInterface @ParametersAreNonnullByDefault @@ -38,7 +40,7 @@ public interface CloudEventDataMapper { R map(CloudEventData data) throws CloudEventRWException; /** - * No-op identity mapper which can be used as default when no mapper is provided. + * @return No-op identity mapper which can be used as default when no mapper is provided. */ static CloudEventDataMapper identity() { return d -> d; diff --git a/api/src/main/java/io/cloudevents/rw/CloudEventRWException.java b/api/src/main/java/io/cloudevents/rw/CloudEventRWException.java index 0a88a396..bd8d50f7 100644 --- a/api/src/main/java/io/cloudevents/rw/CloudEventRWException.java +++ b/api/src/main/java/io/cloudevents/rw/CloudEventRWException.java @@ -17,6 +17,8 @@ package io.cloudevents.rw; +import io.cloudevents.lang.Nullable; + /** * This class is the exception Protocol Binding and Event Format implementers can use to signal errors while serializing/deserializing CloudEvent. */ @@ -35,9 +37,9 @@ public class CloudEventRWException extends RuntimeException { */ INVALID_ATTRIBUTE_NAME, /** - * The extension name is not valid, - * because it doesn't follow the naming convention - * enforced by the CloudEvents spec. + * The extension name is not valid because it doesn't follow the naming convention enforced by the CloudEvents spec. + * + * @see naming convention */ INVALID_EXTENSION_NAME, /** @@ -83,10 +85,17 @@ public class CloudEventRWException extends RuntimeException { this.kind = kind; } + /** + * @return the {@link CloudEventRWExceptionKind} associated to this exception instance. + */ public CloudEventRWExceptionKind getKind() { return kind; } + /** + * @param specVersion the invalid input spec version + * @return a new {@link CloudEventRWException} instance + */ public static CloudEventRWException newInvalidSpecVersion(String specVersion) { return new CloudEventRWException( CloudEventRWExceptionKind.INVALID_SPEC_VERSION, @@ -94,6 +103,10 @@ public class CloudEventRWException extends RuntimeException { ); } + /** + * @param attributeName the invalid attribute name + * @return a new {@link CloudEventRWException} instance + */ public static CloudEventRWException newInvalidAttributeName(String attributeName) { return new CloudEventRWException( CloudEventRWExceptionKind.INVALID_ATTRIBUTE_NAME, @@ -101,6 +114,10 @@ public class CloudEventRWException extends RuntimeException { ); } + /** + * @param extensionName the invalid extension name + * @return a new {@link CloudEventRWException} instance + */ public static CloudEventRWException newInvalidExtensionName(String extensionName) { return new CloudEventRWException( CloudEventRWExceptionKind.INVALID_EXTENSION_NAME, @@ -108,6 +125,11 @@ public class CloudEventRWException extends RuntimeException { ); } + /** + * @param attributeName the invalid attribute name + * @param clazz the type of the attribute + * @return a new {@link CloudEventRWException} instance + */ public static CloudEventRWException newInvalidAttributeType(String attributeName, Class clazz) { return new CloudEventRWException( CloudEventRWExceptionKind.INVALID_ATTRIBUTE_TYPE, @@ -115,7 +137,13 @@ public class CloudEventRWException extends RuntimeException { ); } - public static CloudEventRWException newInvalidAttributeValue(String attributeName, Object value, Throwable cause) { + /** + * @param attributeName the invalid attribute name + * @param value the value of the attribute + * @param cause an optional cause identifying the eventual validation error + * @return a new {@link CloudEventRWException} instance + */ + public static CloudEventRWException newInvalidAttributeValue(String attributeName, Object value, @Nullable Throwable cause) { return new CloudEventRWException( CloudEventRWExceptionKind.INVALID_ATTRIBUTE_VALUE, "Invalid attribute/extension value for \"" + attributeName + "\": " + value, @@ -123,6 +151,11 @@ public class CloudEventRWException extends RuntimeException { ); } + /** + * @param actual the actual data type + * @param allowed the list of allowed data types + * @return a new {@link CloudEventRWException} instance + */ public static CloudEventRWException newInvalidDataType(String actual, String... allowed) { String message; if (allowed.length == 0) { @@ -136,6 +169,12 @@ public class CloudEventRWException extends RuntimeException { ); } + /** + * @param cause the cause of the conversion failure + * @param from the input data type + * @param to the target data type + * @return a new {@link CloudEventRWException} instance + */ public static CloudEventRWException newDataConversion(Throwable cause, String from, String to) { return new CloudEventRWException( CloudEventRWExceptionKind.DATA_CONVERSION, @@ -144,17 +183,26 @@ public class CloudEventRWException extends RuntimeException { ); } - public static CloudEventRWException newOther(Throwable cause) { - return new CloudEventRWException( - CloudEventRWExceptionKind.OTHER, - cause - ); - } - + /** + * @return a new {@link CloudEventRWException} instance. + */ public static CloudEventRWException newUnknownEncodingException() { return new CloudEventRWException( CloudEventRWExceptionKind.UNKNOWN_ENCODING, "Could not parse. Unknown encoding. Invalid content type or spec version" ); } + + /** + * This wraps a {@link Throwable} in a new generic instance of this exception. + * + * @param cause the cause of the exception + * @return a new {@link CloudEventRWException} instance + */ + public static CloudEventRWException newOther(Throwable cause) { + return new CloudEventRWException( + CloudEventRWExceptionKind.OTHER, + cause + ); + } } diff --git a/api/src/main/java/io/cloudevents/rw/CloudEventReader.java b/api/src/main/java/io/cloudevents/rw/CloudEventReader.java index 53d22916..bcd008b1 100644 --- a/api/src/main/java/io/cloudevents/rw/CloudEventReader.java +++ b/api/src/main/java/io/cloudevents/rw/CloudEventReader.java @@ -30,18 +30,24 @@ import javax.annotation.ParametersAreNonnullByDefault; public interface CloudEventReader { /** - * Visit self using the provided visitor factory + * Like {@link #read(CloudEventWriterFactory, CloudEventDataMapper)}, but with the identity {@link CloudEventDataMapper}. * - * @param writerFactory a factory that generates a visitor starting from the SpecVersion of the event - * @throws CloudEventRWException if something went wrong during the read. + * @see #read(CloudEventWriterFactory, CloudEventDataMapper) */ - default , R> R read(CloudEventWriterFactory writerFactory) throws CloudEventRWException { + default , R> R read(CloudEventWriterFactory writerFactory) throws CloudEventRWException { return read(writerFactory, CloudEventDataMapper.identity()); } /** - * Like {@link CloudEventReader#read(CloudEventWriterFactory)}, but providing a mapper for {@link io.cloudevents.CloudEventData} to be invoked when the data field is available. + * Read self using the provided writer factory. + * + * @param the {@link CloudEventWriter} type + * @param the return type of the {@link CloudEventWriter} + * @param writerFactory a factory that generates a visitor starting from the SpecVersion of the event + * @param mapper the mapper to invoke when building the {@link CloudEventData} + * @return the value returned by {@link CloudEventWriter#end()} or {@link CloudEventWriter#end(CloudEventData)} + * @throws CloudEventRWException if something went wrong during the read. */ - , R> R read(CloudEventWriterFactory writerFactory, CloudEventDataMapper mapper) throws CloudEventRWException; + , R> R read(CloudEventWriterFactory writerFactory, CloudEventDataMapper mapper) throws CloudEventRWException; } diff --git a/api/src/main/java/io/cloudevents/rw/CloudEventWriter.java b/api/src/main/java/io/cloudevents/rw/CloudEventWriter.java index d61216c8..d4ca05bb 100644 --- a/api/src/main/java/io/cloudevents/rw/CloudEventWriter.java +++ b/api/src/main/java/io/cloudevents/rw/CloudEventWriter.java @@ -28,15 +28,16 @@ import io.cloudevents.CloudEventData; public interface CloudEventWriter extends CloudEventContextWriter { /** - * End the visit with a data field + * End the write with a data payload. * + * @param data the data to write * @return an eventual return value * @throws CloudEventRWException if the message writer cannot be ended. */ R end(CloudEventData data) throws CloudEventRWException; /** - * End the visit + * End the write. * * @return an eventual return value * @throws CloudEventRWException if the message writer cannot be ended. diff --git a/api/src/main/java/io/cloudevents/rw/CloudEventWriterFactory.java b/api/src/main/java/io/cloudevents/rw/CloudEventWriterFactory.java index cfbf5a09..328e1f4c 100644 --- a/api/src/main/java/io/cloudevents/rw/CloudEventWriterFactory.java +++ b/api/src/main/java/io/cloudevents/rw/CloudEventWriterFactory.java @@ -19,8 +19,14 @@ package io.cloudevents.rw; import io.cloudevents.SpecVersion; +/** + * This factory is used to enforce setting the {@link SpecVersion} as first step in the writing process. + * + * @param The type of the {@link CloudEventWriter} created by this factory + * @param The return value of the {@link CloudEventWriter} created by this factory + */ @FunctionalInterface -public interface CloudEventWriterFactory, R> { +public interface CloudEventWriterFactory, R> { /** * Create a {@link CloudEventWriter} starting from the provided {@link SpecVersion} @@ -29,5 +35,5 @@ public interface CloudEventWriterFactory, R> { * @return the new writer * @throws CloudEventRWException if the spec version is invalid or the writer cannot be instantiated. */ - V create(SpecVersion version) throws CloudEventRWException; + W create(SpecVersion version) throws CloudEventRWException; } diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index 0e0a2f1d..a47a8c42 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -34,6 +34,7 @@ 1.8 benchmarks + true diff --git a/core/src/main/java/io/cloudevents/core/CloudEventUtils.java b/core/src/main/java/io/cloudevents/core/CloudEventUtils.java index 96d1a287..92de5591 100644 --- a/core/src/main/java/io/cloudevents/core/CloudEventUtils.java +++ b/core/src/main/java/io/cloudevents/core/CloudEventUtils.java @@ -30,7 +30,7 @@ import io.cloudevents.rw.CloudEventRWException; import io.cloudevents.rw.CloudEventReader; /** - * This class contains a set of utility methods to deal with conversions of io.cloudevents related interfaces + * This class contains a set of utility methods to deal with conversions of {@link io.cloudevents} related interfaces */ public final class CloudEventUtils { @@ -38,8 +38,7 @@ public final class CloudEventUtils { /** * Convert a {@link CloudEvent} to a {@link CloudEventReader}. This method provides a default implementation - * for CloudEvent that doesn't implement {@link CloudEventReader} - * for CloudEvent that doesn't implement CloudEventVisitable. + * for CloudEvent that doesn't implement {@link CloudEventReader}. *

* It's safe to use the returned {@link CloudEventReader} multiple times. * @@ -94,6 +93,11 @@ public final class CloudEventUtils { /** * Get the data contained in {@code event} and map it using the provided mapper. + * + * @param event the event eventually containing the data + * @param mapper the mapper to use to map the data + * @param the returned {@link CloudEventData} implementation from the provided mapper + * @return the data contained in {@code event} and mapped with {@code mapper}, if any, otherwise null */ @Nullable public static R mapData(CloudEvent event, CloudEventDataMapper mapper) { diff --git a/core/src/main/java/io/cloudevents/core/data/BytesCloudEventData.java b/core/src/main/java/io/cloudevents/core/data/BytesCloudEventData.java index aa1c73ca..c6df2974 100644 --- a/core/src/main/java/io/cloudevents/core/data/BytesCloudEventData.java +++ b/core/src/main/java/io/cloudevents/core/data/BytesCloudEventData.java @@ -5,11 +5,15 @@ import io.cloudevents.CloudEventData; import java.util.Arrays; import java.util.Objects; +/** + * An implementation of {@link CloudEventData} that wraps a byte array. + */ public class BytesCloudEventData implements CloudEventData { private final byte[] value; /** + * @param value the bytes to wrap * @deprecated use {@link BytesCloudEventData#wrap(byte[])} */ public BytesCloudEventData(byte[] value) { diff --git a/core/src/main/java/io/cloudevents/core/data/PojoCloudEventData.java b/core/src/main/java/io/cloudevents/core/data/PojoCloudEventData.java index 87fcb690..ee2c55a7 100644 --- a/core/src/main/java/io/cloudevents/core/data/PojoCloudEventData.java +++ b/core/src/main/java/io/cloudevents/core/data/PojoCloudEventData.java @@ -5,6 +5,11 @@ import io.cloudevents.rw.CloudEventRWException; import java.util.Objects; +/** + * An implementation of {@link CloudEventData} that wraps any POJO. + * + * @param the type of the wrapped POJO. + */ public class PojoCloudEventData implements CloudEventData { /** @@ -15,6 +20,11 @@ public class PojoCloudEventData implements CloudEventData { */ @FunctionalInterface public interface ToBytes { + /** + * @param data the POJO to convert + * @return the serialized byte array. + * @throws Exception when something goes wrong during the conversion. + */ byte[] convert(T data) throws Exception; } @@ -36,6 +46,9 @@ public class PojoCloudEventData implements CloudEventData { this.mapper = mapper; } + /** + * @return the wrapped POJO + */ public T getValue() { return value; } @@ -67,6 +80,11 @@ public class PojoCloudEventData implements CloudEventData { /** * Wrap the provided data in a {@link PojoCloudEventData} serializable by the provided mapper. + * + * @param The type of {@code data} + * @param data the POJO to wrap + * @param mapper converter from {@code data} to bytes, used to implement {@link #toBytes()} + * @return the new {@link PojoCloudEventData} */ public static PojoCloudEventData wrap(T data, ToBytes mapper) { return new PojoCloudEventData<>(data, mapper); diff --git a/core/src/main/java/io/cloudevents/core/extensions/DatarefExtension.java b/core/src/main/java/io/cloudevents/core/extensions/DatarefExtension.java index 92c497f9..61b8a93c 100644 --- a/core/src/main/java/io/cloudevents/core/extensions/DatarefExtension.java +++ b/core/src/main/java/io/cloudevents/core/extensions/DatarefExtension.java @@ -20,6 +20,7 @@ package io.cloudevents.core.extensions; import io.cloudevents.CloudEventExtensions; import io.cloudevents.Extension; import io.cloudevents.core.extensions.impl.ExtensionUtils; + import java.net.URI; import java.util.Collections; import java.util.HashSet; @@ -27,19 +28,30 @@ import java.util.Set; /** * This extension supports the "Claim Check Pattern". It allows to specify a reference to a location where the event payload is stored. + * * @see https://github.com/cloudevents/spec/blob/v1.0/extensions/dataref.md */ public final class DatarefExtension implements Extension { + /** + * The key of the {@code dataref} extension + */ public static final String DATAREF = "dataref"; + private static final Set KEY_SET = Collections.unmodifiableSet(new HashSet<>(Collections.singletonList(DATAREF))); private URI dataref; + /** + * @return the {@code dataref} contained in this extension. + */ public URI getDataref() { return dataref; } + /** + * @param dataref the uri to set as {@code dataref}. + */ public void setDataref(URI dataref) { this.dataref = dataref; } @@ -57,7 +69,7 @@ public final class DatarefExtension implements Extension { if (DATAREF.equals(key)) { return this.dataref.toString(); } - throw ExtensionUtils.generateInvalidKeyException(this.getClass().getSimpleName(), key); + throw ExtensionUtils.generateInvalidKeyException(this.getClass(), key); } @Override diff --git a/core/src/main/java/io/cloudevents/core/extensions/DistributedTracingExtension.java b/core/src/main/java/io/cloudevents/core/extensions/DistributedTracingExtension.java index 2165a8f0..beaecdf8 100644 --- a/core/src/main/java/io/cloudevents/core/extensions/DistributedTracingExtension.java +++ b/core/src/main/java/io/cloudevents/core/extensions/DistributedTracingExtension.java @@ -21,10 +21,7 @@ import io.cloudevents.CloudEventExtensions; import io.cloudevents.Extension; import io.cloudevents.core.extensions.impl.ExtensionUtils; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import java.util.*; /** * This extension embeds context from Distributed Tracing so that distributed systems can include traces that span an event-driven system. @@ -33,25 +30,45 @@ import java.util.Set; */ public final class DistributedTracingExtension implements Extension { + /** + * The key of the {@code traceparent} extension + */ public static final String TRACEPARENT = "traceparent"; + + /** + * The key of the {@code tracestate} extension + */ public static final String TRACESTATE = "tracestate"; + private static final Set KEY_SET = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(TRACEPARENT, TRACESTATE))); private String traceparent; private String tracestate; + /** + * @return the {@code traceparent} contained in this extension. + */ public String getTraceparent() { return traceparent; } + /** + * @param traceparent the string to set as {@code traceparent}. + */ public void setTraceparent(String traceparent) { this.traceparent = traceparent; } + /** + * @return the {@code tracestate} contained in this extension. + */ public String getTracestate() { return tracestate; } + /** + * @param tracestate the string to set as {@code tracestate}. + */ public void setTracestate(String tracestate) { this.tracestate = tracestate; } @@ -76,7 +93,7 @@ public final class DistributedTracingExtension implements Extension { case TRACESTATE: return this.tracestate; } - throw ExtensionUtils.generateInvalidKeyException(this.getClass().getSimpleName(), key); + throw ExtensionUtils.generateInvalidKeyException(this.getClass(), key); } @Override @@ -93,35 +110,16 @@ public final class DistributedTracingExtension implements Extension { } @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((traceparent == null) ? 0 - : traceparent.hashCode()); - result = prime * result + ((tracestate == null) ? 0 - : tracestate.hashCode()); - return result; + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DistributedTracingExtension that = (DistributedTracingExtension) o; + return Objects.equals(getTraceparent(), that.getTraceparent()) && + Objects.equals(getTracestate(), that.getTracestate()); } @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - DistributedTracingExtension other = (DistributedTracingExtension) obj; - if (traceparent == null) { - if (other.traceparent != null) - return false; - } else if (!traceparent.equals(other.traceparent)) - return false; - if (tracestate == null) { - if (other.tracestate != null) - return false; - } else if (!tracestate.equals(other.tracestate)) - return false; - return true; + public int hashCode() { + return Objects.hash(getTraceparent(), getTracestate()); } } diff --git a/core/src/main/java/io/cloudevents/core/extensions/impl/ExtensionUtils.java b/core/src/main/java/io/cloudevents/core/extensions/impl/ExtensionUtils.java index 9d9415c0..cdba08bb 100644 --- a/core/src/main/java/io/cloudevents/core/extensions/impl/ExtensionUtils.java +++ b/core/src/main/java/io/cloudevents/core/extensions/impl/ExtensionUtils.java @@ -17,13 +17,23 @@ package io.cloudevents.core.extensions.impl; +import io.cloudevents.Extension; + +/** + * Collection of utilities to deal with materialized extensions + */ public final class ExtensionUtils { private ExtensionUtils() { } - public static IllegalArgumentException generateInvalidKeyException(String extensionName, String key) { - return new IllegalArgumentException(extensionName + " doesn't expect the attribute key \"" + key + "\""); + /** + * @param clazz the {@link Extension} class + * @param key the invalid key + * @return an {@link IllegalArgumentException} when trying to access a key of the extension not existing. + */ + public static IllegalArgumentException generateInvalidKeyException(Class clazz, String key) { + return new IllegalArgumentException(clazz.getName() + " doesn't expect the attribute key \"" + key + "\""); } } diff --git a/core/src/main/java/io/cloudevents/core/format/EventDeserializationException.java b/core/src/main/java/io/cloudevents/core/format/EventDeserializationException.java index ce51c064..98f31e0b 100644 --- a/core/src/main/java/io/cloudevents/core/format/EventDeserializationException.java +++ b/core/src/main/java/io/cloudevents/core/format/EventDeserializationException.java @@ -21,7 +21,10 @@ package io.cloudevents.core.format; * Exception representing a deserialization error while using an {@link EventFormat}. */ public class EventDeserializationException extends RuntimeException { - public EventDeserializationException(Throwable e) { - super(e); + /** + * @param cause the cause of the exception + */ + public EventDeserializationException(Throwable cause) { + super(cause); } } diff --git a/core/src/main/java/io/cloudevents/core/format/EventFormat.java b/core/src/main/java/io/cloudevents/core/format/EventFormat.java index f99915aa..fd0711b2 100644 --- a/core/src/main/java/io/cloudevents/core/format/EventFormat.java +++ b/core/src/main/java/io/cloudevents/core/format/EventFormat.java @@ -48,18 +48,21 @@ public interface EventFormat { byte[] serialize(CloudEvent event) throws EventSerializationException; /** - * Deserialize a byte array to a {@link CloudEvent}. + * Like {@link #deserialize(byte[], CloudEventDataMapper)}, but with the identity {@link CloudEventDataMapper}. * - * @param bytes the serialized event. - * @return the deserialized event. - * @throws EventDeserializationException if something goes wrong during deserialization. + * @see #deserialize(byte[], CloudEventDataMapper) */ default CloudEvent deserialize(byte[] bytes) throws EventDeserializationException { - return this.deserialize(bytes, null); + return this.deserialize(bytes, CloudEventDataMapper.identity()); } /** - * Like {@link EventFormat#deserialize(byte[])}, but allows a mapper that maps the parsed {@link io.cloudevents.CloudEventData} to another one. + * Deserialize a byte array to a {@link CloudEvent}. + * + * @param bytes the serialized event. + * @param mapper the mapper to use to map the data. + * @return the deserialized event. + * @throws EventDeserializationException if something goes wrong during deserialization. */ CloudEvent deserialize(byte[] bytes, CloudEventDataMapper mapper) throws EventDeserializationException; diff --git a/core/src/main/java/io/cloudevents/core/format/EventSerializationException.java b/core/src/main/java/io/cloudevents/core/format/EventSerializationException.java index 4fe9d26b..d4a6f319 100644 --- a/core/src/main/java/io/cloudevents/core/format/EventSerializationException.java +++ b/core/src/main/java/io/cloudevents/core/format/EventSerializationException.java @@ -21,7 +21,10 @@ package io.cloudevents.core.format; * Exception representing a serialization error while using an {@link EventFormat}. */ public class EventSerializationException extends RuntimeException { - public EventSerializationException(Throwable e) { - super(e); + /** + * @param cause the cause of the exception + */ + public EventSerializationException(Throwable cause) { + super(cause); } } diff --git a/core/src/main/java/io/cloudevents/core/impl/BaseCloudEventBuilder.java b/core/src/main/java/io/cloudevents/core/impl/BaseCloudEventBuilder.java index c1c46a48..e9a05ab7 100644 --- a/core/src/main/java/io/cloudevents/core/impl/BaseCloudEventBuilder.java +++ b/core/src/main/java/io/cloudevents/core/impl/BaseCloudEventBuilder.java @@ -181,10 +181,11 @@ public abstract class BaseCloudEventBuilderattribute-naming-convention + * Validates the extension name as defined in CloudEvents spec. + * * @param name the extension name * @return true if extension name is valid, false otherwise + * @see attribute-naming-convention */ private static boolean isValidExtensionName(String name) { if(name.length() > 20){ diff --git a/core/src/main/java/io/cloudevents/core/message/Encoding.java b/core/src/main/java/io/cloudevents/core/message/Encoding.java index 456e3abe..abd618d1 100644 --- a/core/src/main/java/io/cloudevents/core/message/Encoding.java +++ b/core/src/main/java/io/cloudevents/core/message/Encoding.java @@ -21,6 +21,12 @@ package io.cloudevents.core.message; * One of the possible encodings of a CloudEvent message */ public enum Encoding { + /** + * Structured mode + */ STRUCTURED, + /** + * Binary mode + */ BINARY } diff --git a/core/src/main/java/io/cloudevents/core/message/MessageReader.java b/core/src/main/java/io/cloudevents/core/message/MessageReader.java index 85f2bc24..6cfb6e01 100644 --- a/core/src/main/java/io/cloudevents/core/message/MessageReader.java +++ b/core/src/main/java/io/cloudevents/core/message/MessageReader.java @@ -19,41 +19,50 @@ package io.cloudevents.core.message; import io.cloudevents.CloudEvent; import io.cloudevents.CloudEventData; +import io.cloudevents.SpecVersion; import io.cloudevents.core.CloudEventUtils; import io.cloudevents.rw.*; import javax.annotation.ParametersAreNonnullByDefault; /** - * Represents a CloudEvent message. + * Represents a CloudEvent message reader. + *

+ * This class expands the {@link CloudEventReader} to define reading both binary and structured messages. */ @ParametersAreNonnullByDefault public interface MessageReader extends StructuredMessageReader, CloudEventReader { /** - * Visit the message as binary encoded event using the provided visitor factory. + * Like {@link #read(CloudEventWriterFactory, CloudEventDataMapper)}, but with the identity {@link CloudEventDataMapper}. * - * @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. + * @see #read(CloudEventWriterFactory, CloudEventDataMapper) */ - default , R> R read(CloudEventWriterFactory writerFactory) throws CloudEventRWException, IllegalStateException { + default , R> R read(CloudEventWriterFactory writerFactory) throws CloudEventRWException, IllegalStateException { return read(writerFactory, CloudEventDataMapper.identity()); } /** - * Like {@link MessageReader#read(CloudEventWriterFactory)}, but providing a mapper for {@link io.cloudevents.CloudEventData} to be invoked when the data field is available. + * Read the message as binary encoded message using the provided writer factory. + * + * @param the {@link CloudEventWriter} type + * @param the return type of the {@link CloudEventWriter} + * @param writerFactory a factory that generates a reader starting from the {@link SpecVersion} of the event + * @param mapper the mapper to use to map the data, if any. + * @throws CloudEventRWException if something went wrong during the visit. + * @throws IllegalStateException if the message is not in binary encoding. */ - , R> R read(CloudEventWriterFactory writerFactory, CloudEventDataMapper mapper) throws CloudEventRWException, IllegalStateException; + , R> R read(CloudEventWriterFactory writerFactory, CloudEventDataMapper mapper) throws CloudEventRWException, IllegalStateException; /** - * Visit the message as structured encoded event using the provided visitor + * Read the message as structured encoded message using the provided writer * - * @param visitor Structured Message visitor + * @param the return type of the {@link StructuredMessageWriter} + * @param writer Structured Message writer * @throws CloudEventRWException if something went wrong during the visit. - * @throws IllegalStateException if the message is not in structured encoding. + * @throws IllegalStateException if the message is not in structured encoding. */ - T read(StructuredMessageWriter visitor) throws CloudEventRWException, IllegalStateException; + R read(StructuredMessageWriter writer) throws CloudEventRWException, IllegalStateException; /** * @return The message encoding @@ -64,38 +73,41 @@ public interface MessageReader extends StructuredMessageReader, CloudEventReader * Read the content of this object using a {@link MessageWriter}. This method allows to transcode an event from one transport to another without * converting it to {@link CloudEvent}. The resulting encoding will be the same as the original encoding. * - * @param visitor the MessageVisitor accepting this Message - * @return The return value of the MessageVisitor + * @param the {@link CloudEventWriter} type + * @param the return type of both {@link CloudEventWriter} and {@link StructuredMessageWriter} + * @param writer the {@link MessageWriter} accepting this Message + * @return The return value of the {@link MessageWriter} * @throws CloudEventRWException if something went wrong during the visit. * @throws IllegalStateException if the message has an unknown encoding. */ - default , R> R read(MessageWriter visitor) throws CloudEventRWException, IllegalStateException { + default , R> R read(MessageWriter writer) throws CloudEventRWException, IllegalStateException { switch (getEncoding()) { case BINARY: - return this.read((CloudEventWriterFactory) visitor); + return this.read((CloudEventWriterFactory) writer); case STRUCTURED: - return this.read((StructuredMessageWriter) visitor); + return this.read((StructuredMessageWriter) writer); default: - throw new IllegalStateException("Unknown encoding"); + throw new IllegalStateException( + "The provided Encoding doesn't exist. Please make sure your io.cloudevents deps versions are aligned." + ); } } /** - * Translate this message into a {@link CloudEvent} representation. + * Like {@link #toEvent(CloudEventDataMapper)}, but with the identity {@link CloudEventDataMapper}. * - * @return A {@link CloudEvent} with the contents of this message. - * @throws CloudEventRWException if something went wrong during the visit. - * @throws IllegalStateException if the message has an unknown encoding. + * @see #toEvent(CloudEventDataMapper) */ default CloudEvent toEvent() throws CloudEventRWException, IllegalStateException { return toEvent(CloudEventDataMapper.identity()); } /** - * Translate this message into a {@link CloudEvent} representation. + * Translate this message into a {@link CloudEvent} representation, mapping the data with the provided {@code mapper}. * + * @param mapper the mapper to use to map the data, if any. * @return A {@link CloudEvent} with the contents of this message. - * @throws CloudEventRWException if something went wrong during the visit. + * @throws CloudEventRWException if something went wrong during the read. * @throws IllegalStateException if the message has an unknown encoding. */ default CloudEvent toEvent(CloudEventDataMapper mapper) throws CloudEventRWException, IllegalStateException { @@ -105,7 +117,9 @@ public interface MessageReader extends StructuredMessageReader, CloudEventReader case STRUCTURED: return this.read((format, value) -> format.deserialize(value, mapper)); default: - throw new IllegalStateException("Unknown encoding"); + throw new IllegalStateException( + "The provided Encoding doesn't exist. Please make sure your io.cloudevents deps versions are aligned." + ); } } diff --git a/core/src/main/java/io/cloudevents/core/message/StructuredMessageReader.java b/core/src/main/java/io/cloudevents/core/message/StructuredMessageReader.java index c81e71f5..b8fb911a 100644 --- a/core/src/main/java/io/cloudevents/core/message/StructuredMessageReader.java +++ b/core/src/main/java/io/cloudevents/core/message/StructuredMessageReader.java @@ -34,11 +34,15 @@ import javax.annotation.ParametersAreNonnullByDefault; public interface StructuredMessageReader { /** - * @param visitor + * Read self using the provided writer. + * + * @param the return type of the {@link StructuredMessageWriter} + * @param writer the writer to use to write out the message + * @return the return value returned by {@link StructuredMessageWriter#setEvent(EventFormat, byte[])} * @throws CloudEventRWException If something went wrong when * @throws IllegalStateException If the message is not a valid structured message */ - T read(StructuredMessageWriter visitor) throws CloudEventRWException, IllegalStateException; + R read(StructuredMessageWriter writer) throws CloudEventRWException, IllegalStateException; default CloudEvent toEvent() throws CloudEventRWException, IllegalStateException { return this.read(EventFormat::deserialize); @@ -49,9 +53,9 @@ public interface StructuredMessageReader { } /** - * Create a generic structured message from a {@link CloudEvent} + * Create a generic structured message from a {@link CloudEvent}. * - * @param event + * @param event the event to convert to {@link StructuredMessageReader} * @param contentType content type to use to resolve the {@link EventFormat} * @return null if format was not found, otherwise returns the built message */ @@ -60,10 +64,10 @@ public interface StructuredMessageReader { } /** - * Create a generic structured message from a {@link CloudEvent} + * Create a generic structured message from a {@link CloudEvent}. * - * @param event - * @param format + * @param event the event to convert to {@link StructuredMessageReader} + * @param format the format to use to perform the conversion * @return null if format was not found, otherwise returns the built message */ static StructuredMessageReader from(CloudEvent event, EventFormat format) { diff --git a/core/src/main/java/io/cloudevents/core/message/StructuredMessageWriter.java b/core/src/main/java/io/cloudevents/core/message/StructuredMessageWriter.java index 35598ad5..c28854cd 100644 --- a/core/src/main/java/io/cloudevents/core/message/StructuredMessageWriter.java +++ b/core/src/main/java/io/cloudevents/core/message/StructuredMessageWriter.java @@ -25,15 +25,15 @@ import javax.annotation.ParametersAreNonnullByDefault; /** * Interface to write the {@link MessageReader} content (CloudEvents attributes, extensions and payload) to a new representation structured representation. * - * @param return value at the end of the write process. + * @param return value at the end of the write process. */ @ParametersAreNonnullByDefault @FunctionalInterface -public interface StructuredMessageWriter { +public interface StructuredMessageWriter { /** * Write an event using the provided {@link EventFormat}. */ - T setEvent(EventFormat format, byte[] value) throws CloudEventRWException; + R setEvent(EventFormat format, byte[] value) throws CloudEventRWException; } diff --git a/core/src/main/java/io/cloudevents/core/message/impl/BaseBinaryMessageReader.java b/core/src/main/java/io/cloudevents/core/message/impl/BaseBinaryMessageReader.java index cc01d0f9..abbec530 100644 --- a/core/src/main/java/io/cloudevents/core/message/impl/BaseBinaryMessageReader.java +++ b/core/src/main/java/io/cloudevents/core/message/impl/BaseBinaryMessageReader.java @@ -22,6 +22,9 @@ import io.cloudevents.core.message.MessageReader; import io.cloudevents.core.message.StructuredMessageWriter; import io.cloudevents.rw.CloudEventRWException; +/** + * Base {@link MessageReader} implementation for a binary message + */ public abstract class BaseBinaryMessageReader implements MessageReader { @Override @@ -30,7 +33,7 @@ public abstract class BaseBinaryMessageReader implements MessageReader { } @Override - public T read(StructuredMessageWriter visitor) throws CloudEventRWException, IllegalStateException { + public T read(StructuredMessageWriter writer) throws CloudEventRWException, IllegalStateException { throw MessageUtils.generateWrongEncoding(Encoding.STRUCTURED, Encoding.BINARY); } } diff --git a/core/src/main/java/io/cloudevents/core/message/impl/BaseGenericBinaryMessageReaderImpl.java b/core/src/main/java/io/cloudevents/core/message/impl/BaseGenericBinaryMessageReaderImpl.java index 2bcd79bb..38b1506f 100644 --- a/core/src/main/java/io/cloudevents/core/message/impl/BaseGenericBinaryMessageReaderImpl.java +++ b/core/src/main/java/io/cloudevents/core/message/impl/BaseGenericBinaryMessageReaderImpl.java @@ -75,14 +75,35 @@ public abstract class BaseGenericBinaryMessageReaderImpl extends BaseBin return visitor.end(); } + /** + * @param key header key + * @return true if this header is the content type header, false otherwise + */ protected abstract boolean isContentTypeHeader(HK key); + /** + * @param key header key + * @return true if this header is a CloudEvents header, false otherwise + */ protected abstract boolean isCloudEventsHeader(HK key); + /** + * @param key header key + * @return the key converted to a CloudEvents context attribute/extension name + */ protected abstract String toCloudEventsKey(HK key); + /** + * Iterate over all the headers in the headers map. + * + * @param fn header consumer + */ protected abstract void forEachHeader(BiConsumer fn); + /** + * @param value header key + * @return the value converted to a valid CloudEvents attribute value as {@link String}. + */ protected abstract String toCloudEventsValue(HV value); } diff --git a/core/src/main/java/io/cloudevents/core/message/impl/BaseStructuredMessageReader.java b/core/src/main/java/io/cloudevents/core/message/impl/BaseStructuredMessageReader.java index 68f99569..548015ea 100644 --- a/core/src/main/java/io/cloudevents/core/message/impl/BaseStructuredMessageReader.java +++ b/core/src/main/java/io/cloudevents/core/message/impl/BaseStructuredMessageReader.java @@ -24,6 +24,9 @@ import io.cloudevents.rw.CloudEventDataMapper; import io.cloudevents.rw.CloudEventWriter; import io.cloudevents.rw.CloudEventWriterFactory; +/** + * Base {@link MessageReader} implementation for a structured message + */ public abstract class BaseStructuredMessageReader implements MessageReader { @Override diff --git a/core/src/main/java/io/cloudevents/core/message/impl/GenericStructuredMessageReader.java b/core/src/main/java/io/cloudevents/core/message/impl/GenericStructuredMessageReader.java index a78902be..6b8a80e8 100644 --- a/core/src/main/java/io/cloudevents/core/message/impl/GenericStructuredMessageReader.java +++ b/core/src/main/java/io/cloudevents/core/message/impl/GenericStructuredMessageReader.java @@ -24,6 +24,9 @@ import io.cloudevents.core.provider.EventFormatProvider; import io.cloudevents.lang.Nullable; import io.cloudevents.rw.CloudEventRWException; +/** + * Generic implementation of a structured message. + */ public class GenericStructuredMessageReader extends BaseStructuredMessageReader { private final EventFormat format; @@ -35,8 +38,8 @@ public class GenericStructuredMessageReader extends BaseStructuredMessageReader } @Override - public T read(StructuredMessageWriter visitor) throws CloudEventRWException, IllegalStateException { - return visitor.setEvent(format, payload); + public T read(StructuredMessageWriter writer) throws CloudEventRWException, IllegalStateException { + return writer.setEvent(format, payload); } /** diff --git a/core/src/main/java/io/cloudevents/core/message/impl/MessageUtils.java b/core/src/main/java/io/cloudevents/core/message/impl/MessageUtils.java index cdc93836..25153f9b 100644 --- a/core/src/main/java/io/cloudevents/core/message/impl/MessageUtils.java +++ b/core/src/main/java/io/cloudevents/core/message/impl/MessageUtils.java @@ -22,6 +22,7 @@ import io.cloudevents.core.format.EventFormat; import io.cloudevents.core.message.Encoding; import io.cloudevents.core.message.MessageReader; import io.cloudevents.core.provider.EventFormatProvider; +import io.cloudevents.rw.CloudEventRWException; import java.util.Map; import java.util.function.Function; @@ -31,17 +32,27 @@ import java.util.stream.Stream; import static io.cloudevents.rw.CloudEventRWException.newUnknownEncodingException; +/** + * Collection of utilities useful to implement {@link MessageReader} and {@link io.cloudevents.core.message.MessageWriter} related code. + */ public class MessageUtils { /** * Common flow to parse an incoming message that could be structured or binary. + * + * @param contentTypeHeaderReader supplier that returns the content type header, if any + * @param structuredMessageFactory factory to create the structured {@link MessageReader} from the provided {@link EventFormat} + * @param specVersionHeaderReader supplier that returns the spec version header, if any + * @param binaryMessageFactory factory to create the binary {@link MessageReader} from the provided {@link SpecVersion} + * @return the instantiated {@link MessageReader} + * @throws CloudEventRWException if something goes wrong while resolving the {@link SpecVersion} or if the message has unknown encoding */ public static MessageReader parseStructuredOrBinaryMessage( Supplier contentTypeHeaderReader, Function structuredMessageFactory, Supplier specVersionHeaderReader, Function binaryMessageFactory - ) { + ) throws CloudEventRWException { // Let's try structured mode String ct = contentTypeHeaderReader.get(); if (ct != null) { @@ -49,7 +60,6 @@ public class MessageUtils { if (format != null) { return structuredMessageFactory.apply(format); } - } // Let's try binary mode @@ -77,6 +87,11 @@ public class MessageUtils { .collect(Collectors.toMap(Function.identity(), headerNameMapping)); } + /** + * @param expected the expected encoding + * @param actual the actual encoding + * @return a new instance of {@link IllegalStateException}. + */ public static IllegalStateException generateWrongEncoding(Encoding expected, Encoding actual) { return new IllegalStateException("Cannot visit message as " + expected + " because the actual encoding is " + actual); } diff --git a/core/src/main/java/io/cloudevents/core/provider/ExtensionProvider.java b/core/src/main/java/io/cloudevents/core/provider/ExtensionProvider.java index 5d52d82c..01da2567 100644 --- a/core/src/main/java/io/cloudevents/core/provider/ExtensionProvider.java +++ b/core/src/main/java/io/cloudevents/core/provider/ExtensionProvider.java @@ -39,6 +39,9 @@ public final class ExtensionProvider { private static final ExtensionProvider INSTANCE = new ExtensionProvider(); } + /** + * @return instance of {@link ExtensionProvider} + */ public static ExtensionProvider getInstance() { return SingletonContainer.INSTANCE; } @@ -55,9 +58,9 @@ public final class ExtensionProvider { /** * Register a new extension type. * + * @param the type of the extension * @param extensionClass the class implementing {@link Extension} - * @param factory the empty arguments factory - * @param the type of the extension + * @param factory the empty arguments factory */ public void registerExtension(Class extensionClass, Supplier factory) { this.extensionFactories.put(extensionClass, factory); @@ -66,9 +69,10 @@ public final class ExtensionProvider { /** * Parse an extension from the {@link CloudEventExtensions}, materializing the corresponding POJO. * + * @param the type of the extension * @param extensionClass the class implementing {@link Extension} * @param eventExtensions the event extensions to read - * @param the type of the extension + * @return the parsed extension */ @SuppressWarnings("unchecked") @Nullable diff --git a/core/src/test/java/io/cloudevents/core/mock/MockStructuredMessageReader.java b/core/src/test/java/io/cloudevents/core/mock/MockStructuredMessageReader.java index 95f2b614..7e170173 100644 --- a/core/src/test/java/io/cloudevents/core/mock/MockStructuredMessageReader.java +++ b/core/src/test/java/io/cloudevents/core/mock/MockStructuredMessageReader.java @@ -41,12 +41,12 @@ public class MockStructuredMessageReader extends BaseStructuredMessageReader imp } @Override - public T read(StructuredMessageWriter visitor) throws CloudEventRWException, IllegalStateException { + public T read(StructuredMessageWriter writer) throws CloudEventRWException, IllegalStateException { if (this.format == null) { throw new IllegalStateException("MockStructuredMessage is empty"); } - return visitor.setEvent(this.format, this.payload); + return writer.setEvent(this.format, this.payload); } @Override diff --git a/examples/pom.xml b/examples/pom.xml index ba2a8f1f..3bd4dc05 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -13,6 +13,11 @@ Cloudevents - Examples pom + + + true + + kafka restful-ws-quarkus diff --git a/http/restful-ws-integration-tests/pom.xml b/http/restful-ws-integration-tests/pom.xml index 63a6f640..e5df3abe 100644 --- a/http/restful-ws-integration-tests/pom.xml +++ b/http/restful-ws-integration-tests/pom.xml @@ -31,6 +31,11 @@ CloudEvents - JAX-RS Web Http Binding Integration Tests pom + + + true + + restful-ws-common restful-ws-spring diff --git a/pom.xml b/pom.xml index 6cb7d840..fcba4ac4 100644 --- a/pom.xml +++ b/pom.xml @@ -78,8 +78,8 @@ - 1.8 - 1.8 + 8 + 8 UTF-8 @@ -155,7 +155,10 @@ org.apache.maven.plugins maven-javadoc-plugin - 2.10.4 + 3.2.0 + + + attach-javadocs