diff --git a/api/src/main/java/io/cloudevents/Attributes.java b/api/src/main/java/io/cloudevents/Attributes.java index 5ecbc5a3..25782574 100644 --- a/api/src/main/java/io/cloudevents/Attributes.java +++ b/api/src/main/java/io/cloudevents/Attributes.java @@ -60,4 +60,8 @@ public interface Attributes { Optional getTime(); + Attributes toV03(); + + Attributes toV1(); + } diff --git a/api/src/main/java/io/cloudevents/CloudEvent.java b/api/src/main/java/io/cloudevents/CloudEvent.java index 025ed2d4..132c5a48 100644 --- a/api/src/main/java/io/cloudevents/CloudEvent.java +++ b/api/src/main/java/io/cloudevents/CloudEvent.java @@ -54,23 +54,23 @@ public interface CloudEvent { */ Map getExtensions(); - /** - * Write an extension into this cloud event - * @param e - */ - default void writeExtension(Extension e) { - e.writeToEvent(this); - } + CloudEvent toV03(); - static io.cloudevents.v1.CloudEventBuilder build() { - return buildV1(); - } + CloudEvent toV1(); static io.cloudevents.v1.CloudEventBuilder buildV1() { return new io.cloudevents.v1.CloudEventBuilder(); } + static io.cloudevents.v1.CloudEventBuilder buildV1(CloudEvent event) { + return new io.cloudevents.v1.CloudEventBuilder(event); + } + static io.cloudevents.v03.CloudEventBuilder buildV03() { return new io.cloudevents.v03.CloudEventBuilder(); } + + static io.cloudevents.v03.CloudEventBuilder buildV03(CloudEvent event) { + return new io.cloudevents.v03.CloudEventBuilder(event); + } } diff --git a/api/src/main/java/io/cloudevents/Extension.java b/api/src/main/java/io/cloudevents/Extension.java index f99fd0d7..5f1f8d85 100644 --- a/api/src/main/java/io/cloudevents/Extension.java +++ b/api/src/main/java/io/cloudevents/Extension.java @@ -1,9 +1,11 @@ package io.cloudevents; +import java.util.Map; + public interface Extension { void readFromEvent(CloudEvent event); - void writeToEvent(CloudEvent event); + Map asMap(); } diff --git a/api/src/main/java/io/cloudevents/extensions/DistributedTracingExtension.java b/api/src/main/java/io/cloudevents/extensions/DistributedTracingExtension.java index 4b09e54e..5915696b 100644 --- a/api/src/main/java/io/cloudevents/extensions/DistributedTracingExtension.java +++ b/api/src/main/java/io/cloudevents/extensions/DistributedTracingExtension.java @@ -3,6 +3,10 @@ package io.cloudevents.extensions; import io.cloudevents.CloudEvent; import io.cloudevents.Extension; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + public final class DistributedTracingExtension implements Extension { public static final String TRACEPARENT = "traceparent"; @@ -42,13 +46,11 @@ public final class DistributedTracingExtension implements Extension { } @Override - public void writeToEvent(CloudEvent event) { - if (traceparent != null) { - event.getExtensions().put(TRACEPARENT, this.traceparent); - } - if (tracestate != null) { - event.getExtensions().put(TRACESTATE, this.tracestate); - } + public Map asMap() { + HashMap map = new HashMap<>(); + map.put(TRACEPARENT, this.traceparent); + map.put(TRACESTATE, this.tracestate); + return Collections.unmodifiableMap(map); } @Override diff --git a/api/src/main/java/io/cloudevents/extensions/ExtensionsParser.java b/api/src/main/java/io/cloudevents/extensions/ExtensionsParser.java index a0d2fa7d..218151cf 100644 --- a/api/src/main/java/io/cloudevents/extensions/ExtensionsParser.java +++ b/api/src/main/java/io/cloudevents/extensions/ExtensionsParser.java @@ -18,6 +18,8 @@ public final class ExtensionsParser { private HashMap, Supplier> extensionFactories; + + // TODO SPI in future? private ExtensionsParser() { this.extensionFactories = new HashMap<>(); registerExtension(DistributedTracingExtension.class, DistributedTracingExtension::new); diff --git a/api/src/main/java/io/cloudevents/impl/BaseCloudEventBuilder.java b/api/src/main/java/io/cloudevents/impl/BaseCloudEventBuilder.java index 105c59a0..9c1052d1 100644 --- a/api/src/main/java/io/cloudevents/impl/BaseCloudEventBuilder.java +++ b/api/src/main/java/io/cloudevents/impl/BaseCloudEventBuilder.java @@ -6,9 +6,7 @@ import io.cloudevents.CloudEvent; import io.cloudevents.Extension; import java.net.URI; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; public abstract class BaseCloudEventBuilder, T extends Attributes> { @@ -18,15 +16,25 @@ public abstract class BaseCloudEventBuilder extensions; - private List materializedExtensions; @SuppressWarnings("unchecked") public BaseCloudEventBuilder() { this.self = (B)this; this.extensions = new HashMap<>(); - this.materializedExtensions = new ArrayList<>(); } + @SuppressWarnings("unchecked") + public BaseCloudEventBuilder(CloudEvent event) { + this.self = (B)this; + + CloudEventImpl ev = (CloudEventImpl) event; + this.setAttributes(ev.getAttributes()); + this.data = ev.getRawData(); + this.extensions = new HashMap<>(ev.getExtensions()); + } + + protected abstract void setAttributes(Attributes attributes); + protected abstract B withDataContentType(String contentType); protected abstract B withDataSchema(URI dataSchema); @@ -49,15 +57,15 @@ public abstract class BaseCloudEventBuilder getExtensions() { - return extensions; + return Collections.unmodifiableMap(extensions); + } + + @Override + public CloudEvent toV03() { + return new CloudEventImpl( + attributes.toV03(), + data, + extensions + ); + } + + @Override + public CloudEvent toV1() { + return new CloudEventImpl( + attributes.toV1(), + data, + extensions + ); + } + + protected Object getRawData() { + return data; } } diff --git a/api/src/main/java/io/cloudevents/v03/AttributesImpl.java b/api/src/main/java/io/cloudevents/v03/AttributesImpl.java index 7697a8f6..d527585a 100644 --- a/api/src/main/java/io/cloudevents/v03/AttributesImpl.java +++ b/api/src/main/java/io/cloudevents/v03/AttributesImpl.java @@ -32,21 +32,16 @@ import java.util.Optional; public class AttributesImpl implements Attributes { private final String id; - private final URI source; - private final String type; - private final ZonedDateTime time; private final URI schemaurl; - private final String datacontenttype; - private final String subject; - AttributesImpl(String id, URI source, String type, - ZonedDateTime time, URI schemaurl, - String datacontenttype, String subject) { + public AttributesImpl(String id, URI source, String type, + ZonedDateTime time, URI schemaurl, + String datacontenttype, String subject) { this.id = id; this.source = source; this.type = type; @@ -72,6 +67,25 @@ public class AttributesImpl implements Attributes { public Optional getTime() { return Optional.ofNullable(time); } + + @Override + public Attributes toV03() { + return this; + } + + @Override + public Attributes toV1() { + return new io.cloudevents.v1.AttributesImpl( + this.id, + this.source, + this.type, + this.datacontenttype, + this.schemaurl, + this.subject, + this.time + ); + } + public Optional getDataSchema() { return getSchemaUrl(); } diff --git a/api/src/main/java/io/cloudevents/v03/CloudEventBuilder.java b/api/src/main/java/io/cloudevents/v03/CloudEventBuilder.java index f0ce06d2..7a8b443d 100644 --- a/api/src/main/java/io/cloudevents/v03/CloudEventBuilder.java +++ b/api/src/main/java/io/cloudevents/v03/CloudEventBuilder.java @@ -15,6 +15,8 @@ */ package io.cloudevents.v03; +import io.cloudevents.Attributes; +import io.cloudevents.CloudEvent; import io.cloudevents.impl.BaseCloudEventBuilder; import java.net.URI; @@ -29,20 +31,35 @@ import java.time.ZonedDateTime; */ public final class CloudEventBuilder extends BaseCloudEventBuilder { - public CloudEventBuilder() { - super(); - } - private String id; private URI source; - private String type; - private ZonedDateTime time; private URI schemaurl; private String datacontenttype; private String subject; + public CloudEventBuilder() { + super(); + } + + public CloudEventBuilder(CloudEvent event) { + super(event); + } + + @Override + protected void setAttributes(Attributes attributes) { + AttributesImpl attr = (AttributesImpl) attributes.toV03(); + this + .withId(attr.getId()) + .withSource(attr.getSource()) + .withType(attr.getType()); + attr.getDataContentType().ifPresent(this::withDataContentType); + attr.getSchemaUrl().ifPresent(this::withSchemaUrl); + attr.getSubject().ifPresent(this::withSubject); + attr.getTime().ifPresent(this::withTime); + } + public CloudEventBuilder withId(String id) { this.id = id; return this; diff --git a/api/src/main/java/io/cloudevents/v03/http/AttributeMapper.java b/api/src/main/java/io/cloudevents/v03/http/AttributeMapper.java deleted file mode 100644 index 9e00b206..00000000 --- a/api/src/main/java/io/cloudevents/v03/http/AttributeMapper.java +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright 2019 The CloudEvents Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudevents.v03.http; - -import static java.util.stream.Collectors.toMap; - -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.AbstractMap.SimpleEntry; -import java.util.Map.Entry; -import java.util.concurrent.atomic.AtomicReference; - -import io.cloudevents.fun.BinaryFormatAttributeMapper; -import io.cloudevents.v03.ContextAttributes; - -/** - * - * @author fabiojose - * @version 0.3 - */ -public class AttributeMapper { - private AttributeMapper() {} - - static final String HEADER_PREFIX = "ce-"; - - /** - * Following the signature of {@link BinaryFormatAttributeMapper#map(Map)} - * @param headers Map of HTTP request - * @return Map with spec attributes and values without parsing - * @see ContextAttributes - */ - public static Map map(final Map headers) { - Objects.requireNonNull(headers); - - final AtomicReference>> ct = - new AtomicReference<>(); - - ct.set(Optional.empty()); - - Map result = headers.entrySet() - .stream() - .filter(header -> null!= header.getValue()) - .map(header -> new SimpleEntry<>(header.getKey() - .toLowerCase(Locale.US), header.getValue())) - .peek(header -> { - if("content-type".equals(header.getKey())) { - ct.set(Optional.ofNullable(header)); - } - }) - .filter(header -> header.getKey().startsWith(HEADER_PREFIX)) - .map(header -> new SimpleEntry<>(header.getKey() - .substring(HEADER_PREFIX.length()), header.getValue())) - .map(header -> new SimpleEntry<>(header.getKey(), - header.getValue().toString())) - .collect(toMap(Entry::getKey, Entry::getValue)); - - ct.get().ifPresent(contentType -> { - result.put(ContextAttributes.DATACONTENTTYPE.name(), - contentType.getValue().toString()); - }); - - return result; - } - -} diff --git a/api/src/main/java/io/cloudevents/v03/http/ExtensionMapper.java b/api/src/main/java/io/cloudevents/v03/http/ExtensionMapper.java deleted file mode 100644 index 4a7a2215..00000000 --- a/api/src/main/java/io/cloudevents/v03/http/ExtensionMapper.java +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2019 The CloudEvents Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudevents.v03.http; - -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.AbstractMap.SimpleEntry; -import java.util.Map.Entry; -import java.util.stream.Collectors; - -import io.cloudevents.fun.FormatExtensionMapper; -import io.cloudevents.v03.ContextAttributes; - -/** - * - * @author fabiojose - * @version 0.3 - */ -public class ExtensionMapper { - private ExtensionMapper() {} - - private static final List RESERVED_HEADERS = - ContextAttributes.VALUES.stream() - .map(attribute -> AttributeMapper - .HEADER_PREFIX + attribute) - .collect(Collectors.toList()); - static { - RESERVED_HEADERS.add("content-type"); - }; - - /** - * Following the signature of {@link FormatExtensionMapper} - * @param headers The HTTP headers - * @return The potential extensions without parsing - */ - public static Map map(Map headers) { - Objects.requireNonNull(headers); - - // remove all reserved words and the remaining may be extensions - return - headers.entrySet() - .stream() - .filter(header -> null!= header.getValue()) - .map(header -> new SimpleEntry<>(header.getKey() - .toLowerCase(Locale.US), header.getValue().toString())) - .filter(header -> !RESERVED_HEADERS.contains(header.getKey())) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); - } - -} diff --git a/api/src/main/java/io/cloudevents/v03/http/HeaderMapper.java b/api/src/main/java/io/cloudevents/v03/http/HeaderMapper.java deleted file mode 100644 index d073dae7..00000000 --- a/api/src/main/java/io/cloudevents/v03/http/HeaderMapper.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright 2019 The CloudEvents Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudevents.v03.http; - -import static io.cloudevents.v03.http.AttributeMapper.HEADER_PREFIX; - -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.AbstractMap.SimpleEntry; -import java.util.Map.Entry; -import java.util.stream.Collectors; - -import io.cloudevents.fun.FormatHeaderMapper; -import io.cloudevents.v03.ContextAttributes; - -/** - * - * @author fabiojose - * - */ -public class HeaderMapper { - private HeaderMapper() {} - - private static final String HTTP_CONTENT_TYPE = "Content-Type"; - - /** - * Following the signature of {@link FormatHeaderMapper} - * @param attributes The map of attributes created by {@link AttributeMapper} - * @param extensions The map of extensions created by {@link ExtensionMapper} - * @return The map of HTTP Headers - */ - public static Map map(Map attributes, - Map extensions) { - Objects.requireNonNull(attributes); - Objects.requireNonNull(extensions); - - Map result = attributes.entrySet() - .stream() - .filter(attribute -> null!= attribute.getValue()) - .map(header -> new SimpleEntry<>(header.getKey() - .toLowerCase(Locale.US), header.getValue())) - .filter(header -> !header.getKey() - .equals(ContextAttributes.DATACONTENTTYPE.name())) - .map(header -> new SimpleEntry<>(HEADER_PREFIX+header.getKey(), - header.getValue())) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); - - result.putAll( - extensions.entrySet() - .stream() - .filter(extension -> null!= extension.getValue()) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)) - ); - - Optional.ofNullable(attributes - .get(ContextAttributes.DATACONTENTTYPE.name())) - .ifPresent((dct) -> { - result.put(HTTP_CONTENT_TYPE, dct); - }); - - return result; - } - -} diff --git a/api/src/main/java/io/cloudevents/v03/http/Marshallers.java b/api/src/main/java/io/cloudevents/v03/http/Marshallers.java deleted file mode 100644 index 1404b12e..00000000 --- a/api/src/main/java/io/cloudevents/v03/http/Marshallers.java +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Copyright 2019 The CloudEvents Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudevents.v03.http; - -import java.util.HashMap; -import java.util.Map; - -import io.cloudevents.CloudEvent; -import io.cloudevents.extensions.ExtensionFormat; -import io.cloudevents.format.BinaryMarshaller; -import io.cloudevents.format.StructuredMarshaller; -import io.cloudevents.format.Wire; -import io.cloudevents.format.builder.EventStep; -import io.cloudevents.json.Json; -import io.cloudevents.v03.Accessor; -import io.cloudevents.v03.AttributesImpl; -import io.cloudevents.v03.CloudEventImpl; - -/** - * - * @author fabiojose - * @version 0.3 - */ -public class Marshallers { - private Marshallers() {} - - private static final Map NO_HEADERS = - new HashMap(); - - /** - * Builds a Binary Content Mode marshaller to marshal cloud events as JSON for - * HTTP Transport Binding - * - * @param The 'data' type - * @return A step to provide the {@link CloudEventImpl} and marshal as JSON - * @see BinaryMarshaller - */ - public static EventStep binary() { - return - BinaryMarshaller. - builder() - .map(AttributesImpl::marshal) - .map(Accessor::extensionsOf) - .map(ExtensionFormat::marshal) - .map(HeaderMapper::map) - .map(Json.marshaller()::marshal) - .builder(Wire::new); - } - - /** - * Builds a Structured Content Mode marshaller to marshal cloud event as JSON for - * HTTP Transport Binding - * @param The 'data' type - * @return A step to provider the {@link CloudEventImpl} and marshal as JSON - * @see StructuredMarshaller - */ - public static EventStep structured() { - return - StructuredMarshaller. - builder() - .mime("Content-Type", "application/cloudevents+json") - .map((event) -> { - return Json., String> - marshaller().marshal(event, NO_HEADERS); - }) - .map(Accessor::extensionsOf) - .map(ExtensionFormat::marshal) - .map(HeaderMapper::map); - } -} diff --git a/api/src/main/java/io/cloudevents/v03/http/Unmarshallers.java b/api/src/main/java/io/cloudevents/v03/http/Unmarshallers.java deleted file mode 100644 index b40ca81e..00000000 --- a/api/src/main/java/io/cloudevents/v03/http/Unmarshallers.java +++ /dev/null @@ -1,123 +0,0 @@ -/** - * Copyright 2019 The CloudEvents Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudevents.v03.http; - -import javax.validation.Validator; - -import io.cloudevents.extensions.DistributedTracingExtension; -import io.cloudevents.format.BinaryUnmarshaller; -import io.cloudevents.format.StructuredUnmarshaller; -import io.cloudevents.format.builder.HeadersStep; -import io.cloudevents.json.Json; -import io.cloudevents.v03.AttributesImpl; -import io.cloudevents.v03.CloudEventBuilder; -import io.cloudevents.v03.CloudEventImpl; - -/** - * - * @author fabiojose - * @version 0.3 - */ -public class Unmarshallers { - private Unmarshallers() {} - - /** - * Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data - * for HTTP Transport Binding - * - * @param The 'data' type - * @param type The type reference to use for 'data' unmarshal - * @return A step to supply the headers, payload and to unmarshal - * @see BinaryUnmarshaller - */ - public static HeadersStep - binary(Class type) { - return binary(type, null); - } - - /** - * Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data - * for HTTP Transport Binding - * - * @param The 'data' type - * @param type The type reference to use for 'data' unmarshal - * @param validator Provided instance of a {@link Validator} - * @return A step to supply the headers, payload and to unmarshal - * @see BinaryUnmarshaller - */ - public static HeadersStep - binary(Class type, Validator validator) { - return - BinaryUnmarshaller.builder() - .map(AttributeMapper::map) - .map(AttributesImpl::unmarshal) - .map("application/json", Json.umarshaller(type)::unmarshal) - .next() - .map(ExtensionMapper::map) - .map(DistributedTracingExtension::unmarshall) - .next() - .builder(CloudEventBuilder.builder().withValidator(validator)::build); - } - - /** - * Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data - * for HTTP Transport Binding - * - * @param The 'data' type - * @param typeOfData The type reference to use for 'data' unmarshal - * @return A step to supply the headers, payload and to unmarshal - * @see StructuredUnmarshaller - */ - public static HeadersStep - structured(Class typeOfData) { - return structured(typeOfData, null); - } - - /** - * Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data - * for HTTP Transport Binding - * - * @param The 'data' type - * @param typeOfData The type reference to use for 'data' unmarshal - * @param validator Provided instance of a {@link Validator} - * @return A step to supply the headers, payload and to unmarshal - * @see StructuredUnmarshaller - */ - public static HeadersStep - structured(Class typeOfData, Validator validator) { - - return - StructuredUnmarshaller. - builder() - .map(ExtensionMapper::map) - .map(DistributedTracingExtension::unmarshall) - .next() - .map((payload, extensions) -> { - CloudEventImpl event = - Json.> - decodeValue(payload, CloudEventImpl.class, typeOfData); - - CloudEventBuilder builder = - CloudEventBuilder.builder(event); - - extensions.get().forEach(extension -> { - builder.withExtension(extension); - }); - - return builder.withValidator(validator).build(); - }); - } -} diff --git a/api/src/main/java/io/cloudevents/v1/AttributesImpl.java b/api/src/main/java/io/cloudevents/v1/AttributesImpl.java index 6a4f492d..73ea5cda 100644 --- a/api/src/main/java/io/cloudevents/v1/AttributesImpl.java +++ b/api/src/main/java/io/cloudevents/v1/AttributesImpl.java @@ -31,17 +31,11 @@ import java.util.Optional; public class AttributesImpl implements Attributes { private final String id; - private final URI source; - private final String type; - private final String datacontenttype; - private final URI dataschema; - private final String subject; - private final ZonedDateTime time; public AttributesImpl(String id, URI source, @@ -91,7 +85,25 @@ public class AttributesImpl implements Attributes { return Optional.ofNullable(time); } - @Override + @Override + public Attributes toV03() { + return new io.cloudevents.v03.AttributesImpl( + this.id, + this.source, + this.type, + this.time, + this.dataschema, + this.datacontenttype, + this.subject + ); + } + + @Override + public Attributes toV1() { + return this; + } + + @Override public String toString() { return "Attibutes V1.0 [id=" + id + ", source=" + source + ", type=" + type diff --git a/api/src/main/java/io/cloudevents/v1/CloudEventBuilder.java b/api/src/main/java/io/cloudevents/v1/CloudEventBuilder.java index bde664da..fa0ee921 100644 --- a/api/src/main/java/io/cloudevents/v1/CloudEventBuilder.java +++ b/api/src/main/java/io/cloudevents/v1/CloudEventBuilder.java @@ -1,5 +1,7 @@ package io.cloudevents.v1; +import io.cloudevents.Attributes; +import io.cloudevents.CloudEvent; import io.cloudevents.impl.BaseCloudEventBuilder; import java.net.URI; @@ -15,7 +17,6 @@ public final class CloudEventBuilder extends BaseCloudEventBuilder map(final Map headers) { - Objects.requireNonNull(headers); - - final AtomicReference>> ct = - new AtomicReference<>(); - - ct.set(Optional.empty()); - - Map result = headers.entrySet() - .stream() - .filter(header -> null!= header.getValue()) - .map(header -> new SimpleEntry<>(header.getKey() - .toLowerCase(Locale.US), header.getValue())) - .peek(header -> { - if("content-type".equals(header.getKey())) { - ct.set(Optional.ofNullable(header)); - } - }) - .filter(header -> header.getKey().startsWith(HEADER_PREFIX)) - .map(header -> new SimpleEntry<>(header.getKey() - .substring(HEADER_PREFIX.length()), header.getValue())) - .map(header -> new SimpleEntry<>(header.getKey(), - header.getValue().toString())) - .collect(toMap(Entry::getKey, Entry::getValue)); - - ct.get().ifPresent(contentType -> { - result.put(ContextAttributes.DATACONTENTTYPE.name(), - contentType.getValue().toString()); - }); - - return result; - } - -} diff --git a/api/src/main/java/io/cloudevents/v1/http/ExtensionMapper.java b/api/src/main/java/io/cloudevents/v1/http/ExtensionMapper.java deleted file mode 100644 index ff4c7a28..00000000 --- a/api/src/main/java/io/cloudevents/v1/http/ExtensionMapper.java +++ /dev/null @@ -1,50 +0,0 @@ -package io.cloudevents.v1.http; - -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.AbstractMap.SimpleEntry; -import java.util.Map.Entry; -import java.util.stream.Collectors; - -import io.cloudevents.fun.FormatExtensionMapper; -import io.cloudevents.v1.ContextAttributes; -import io.cloudevents.v1.http.AttributeMapper; - -/** - * - * @author fabiojose - * @version 1.0 - */ -public class ExtensionMapper { - private ExtensionMapper() {} - - private static final List RESERVED_HEADERS = - ContextAttributes.VALUES.stream() - .map(attribute -> AttributeMapper - .HEADER_PREFIX + attribute) - .collect(Collectors.toList()); - static { - RESERVED_HEADERS.add("content-type"); - }; - - /** - * Following the signature of {@link FormatExtensionMapper} - * @param headers The HTTP headers - * @return The potential extensions without parsing - */ - public static Map map(Map headers) { - Objects.requireNonNull(headers); - - // remove all reserved words and the remaining may be extensions - return - headers.entrySet() - .stream() - .filter(header -> null!= header.getValue()) - .map(header -> new SimpleEntry<>(header.getKey() - .toLowerCase(Locale.US), header.getValue().toString())) - .filter(header -> !RESERVED_HEADERS.contains(header.getKey())) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); - } -} diff --git a/api/src/main/java/io/cloudevents/v1/http/HeaderMapper.java b/api/src/main/java/io/cloudevents/v1/http/HeaderMapper.java deleted file mode 100644 index 201ff895..00000000 --- a/api/src/main/java/io/cloudevents/v1/http/HeaderMapper.java +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright 2019 The CloudEvents Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudevents.v1.http; - -import static io.cloudevents.v1.http.AttributeMapper.HEADER_PREFIX; - -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.AbstractMap.SimpleEntry; -import java.util.Map.Entry; -import java.util.stream.Collectors; - -import io.cloudevents.fun.FormatHeaderMapper; -import io.cloudevents.v1.ContextAttributes; - -/** - * - * @author fabiojose - * - */ -public class HeaderMapper { - private HeaderMapper() {} - - private static final String HTTP_CONTENT_TYPE = "Content-Type"; - - /** - * Following the signature of {@link FormatHeaderMapper} - * @param attributes The map of attributes created by {@link AttributeMapper} - * @param extensions The map of extensions created by {@link ExtensionMapper} - * @return The map of HTTP Headers - */ - public static Map map(Map attributes, - Map extensions) { - Objects.requireNonNull(attributes); - Objects.requireNonNull(extensions); - - Map result = attributes.entrySet() - .stream() - .filter(attribute -> null!= attribute.getValue()) - .map(header -> new SimpleEntry<>(header.getKey() - .toLowerCase(Locale.US), header.getValue())) - .filter(header -> !header.getKey() - .equals(ContextAttributes.DATACONTENTTYPE.name())) - .map(header -> new SimpleEntry<>(HEADER_PREFIX + header.getKey(), - header.getValue())) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); - - result.putAll( - extensions.entrySet() - .stream() - .filter(extension -> null != extension.getValue()) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue)) - ); - - Optional.ofNullable(attributes - .get(ContextAttributes.DATACONTENTTYPE.name())) - .ifPresent((dct) -> { - result.put(HTTP_CONTENT_TYPE, dct); - }); - - return result; - } - -} diff --git a/api/src/main/java/io/cloudevents/v1/http/Marshallers.java b/api/src/main/java/io/cloudevents/v1/http/Marshallers.java deleted file mode 100644 index 1bb8a69f..00000000 --- a/api/src/main/java/io/cloudevents/v1/http/Marshallers.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.cloudevents.v1.http; - -import java.util.HashMap; -import java.util.Map; - -import io.cloudevents.CloudEvent; -import io.cloudevents.extensions.ExtensionFormat; -import io.cloudevents.format.BinaryMarshaller; -import io.cloudevents.format.StructuredMarshaller; -import io.cloudevents.format.Wire; -import io.cloudevents.format.builder.EventStep; -import io.cloudevents.json.Json; -import io.cloudevents.v1.Accessor; -import io.cloudevents.v1.AttributesImpl; -import io.cloudevents.v1.CloudEventImpl; -import io.cloudevents.v1.http.HeaderMapper; - -/** - * - * @author fabiojose - * @version 1.0 - */ -public class Marshallers { - private Marshallers() {} - - private static final Map NO_HEADERS = - new HashMap(); - - /** - * Builds a Binary Content Mode marshaller to marshal cloud events as JSON for - * HTTP Transport Binding - * - * @param The 'data' type - * @return A step to provide the {@link CloudEventImpl} and marshal as JSON - * @see BinaryMarshaller - */ - public static EventStep binary() { - return - BinaryMarshaller. - builder() - .map(AttributesImpl::marshal) - .map(Accessor::extensionsOf) - .map(ExtensionFormat::marshal) - .map(HeaderMapper::map) - .map(Json.marshaller()::marshal) - .builder(Wire::new); - } - - /** - * Builds a Structured Content Mode marshaller to marshal cloud event as JSON for - * HTTP Transport Binding - * @param The 'data' type - * @return A step to provider the {@link CloudEventImpl} and marshal as JSON - * @see StructuredMarshaller - */ - public static EventStep structured() { - return - StructuredMarshaller. - builder() - .mime("Content-Type", "application/cloudevents+json") - .map((event) -> Json., String> - marshaller().marshal(event, NO_HEADERS)) - .map(Accessor::extensionsOf) - .map(ExtensionFormat::marshal) - .map(HeaderMapper::map); - } -} diff --git a/api/src/main/java/io/cloudevents/v1/http/Unmarshallers.java b/api/src/main/java/io/cloudevents/v1/http/Unmarshallers.java deleted file mode 100644 index 90412c32..00000000 --- a/api/src/main/java/io/cloudevents/v1/http/Unmarshallers.java +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Copyright 2019 The CloudEvents Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package io.cloudevents.v1.http; - -import javax.validation.Validator; - -import io.cloudevents.extensions.DistributedTracingExtension; -import io.cloudevents.format.BinaryUnmarshaller; -import io.cloudevents.format.StructuredUnmarshaller; -import io.cloudevents.format.builder.HeadersStep; -import io.cloudevents.json.Json; -import io.cloudevents.v1.AttributesImpl; -import io.cloudevents.v1.CloudEventBuilder; -import io.cloudevents.v1.CloudEventImpl; - -/** - * - * @author fabiojose - * @version 1.0 - */ -public class Unmarshallers { - private Unmarshallers() {} - - /** - * Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data - * for HTTP Transport Binding - * - * @param The 'data' type - * @param type The type reference to use for 'data' unmarshal - * @return A step to supply the headers, payload and to unmarshal - * @see BinaryUnmarshaller - */ - public static HeadersStep - binary(Class type) { - return binary(type, null); - } - - /** - * Builds a Binary Content Mode unmarshaller to unmarshal JSON as CloudEvents data - * for HTTP Transport Binding - * - * @param The 'data' type - * @param type The type reference to use for 'data' unmarshal - * @param validator Provided instance of a {@link Validator} - * @return A step to supply the headers, payload and to unmarshal - * @see BinaryUnmarshaller - */ - public static HeadersStep - binary(Class type, Validator validator) { - return - BinaryUnmarshaller.builder() - .map(AttributeMapper::map) - .map(AttributesImpl::unmarshal) - .map("application/json", Json.umarshaller(type)::unmarshal) - .next() - .map(ExtensionMapper::map) - .map(DistributedTracingExtension::unmarshall) - .next() - .builder(CloudEventBuilder.builder().withValidator(validator)::build); - } - - /** - * Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data - * for HTTP Transport Binding - * - * @param The 'data' type - * @param typeOfData The type reference to use for 'data' unmarshal - * @return A step to supply the headers, payload and to unmarshal - * @see StructuredUnmarshaller - */ - public static HeadersStep - structured(Class typeOfData) { - return structured(typeOfData, null); - } - - /** - * Builds a Structured Content Mode unmarshaller to unmarshal JSON as CloudEvents data - * for HTTP Transport Binding - * - * @param The 'data' type - * @param typeOfData The type reference to use for 'data' unmarshal - * @param validator Provided instance of a {@link Validator} - * @return A step to supply the headers, payload and to unmarshal - * @see StructuredUnmarshaller - */ - public static HeadersStep - structured(Class typeOfData, Validator validator) { - return - StructuredUnmarshaller. - builder() - .map(ExtensionMapper::map) - .map(DistributedTracingExtension::unmarshall) - .next() - .map((payload, extensions) -> { - CloudEventImpl event = - Json.> - decodeValue(payload, CloudEventImpl.class, typeOfData); - - CloudEventBuilder builder = - CloudEventBuilder.builder(event); - - extensions.get().forEach(extension -> { - builder.withExtension(extension); - }); - - return builder.withValidator(validator).build(); - }); - } -} diff --git a/api/src/test/java/io/cloudevents/extensions/DistributedTracingExtensionTest.java b/api/src/test/java/io/cloudevents/extensions/DistributedTracingExtensionTest.java index e58cbc7d..f277191d 100644 --- a/api/src/test/java/io/cloudevents/extensions/DistributedTracingExtensionTest.java +++ b/api/src/test/java/io/cloudevents/extensions/DistributedTracingExtensionTest.java @@ -33,8 +33,7 @@ public class DistributedTracingExtensionTest { tracing.setTraceparent("parent"); tracing.setTracestate("state"); - CloudEvent event = CloudEvent.build().build(); - tracing.writeToEvent(event); + CloudEvent event = CloudEvent.buildV1().withExtension(tracing).build(); assertThat(event.getExtensions()) .containsEntry(DistributedTracingExtension.TRACEPARENT, "parent") @@ -43,7 +42,7 @@ public class DistributedTracingExtensionTest { @Test public void parseExtension() { - CloudEvent event = CloudEvent.build() + CloudEvent event = CloudEvent.buildV1() .withExtension(DistributedTracingExtension.TRACEPARENT, "parent") .withExtension(DistributedTracingExtension.TRACESTATE, "state") .build();