Make CloudEventAttributesProvider a FunctionalInterface

Related to #422 and #606
This commit is contained in:
Oleg Zhurakousky
2020-11-16 08:41:42 +01:00
parent 1d67b8070f
commit b9f417a4da
7 changed files with 112 additions and 93 deletions

View File

@@ -19,48 +19,14 @@ package org.springframework.cloud.function.cloudevent;
import java.util.Map;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
/**
*
* @author Oleg Zhurakousky
* @since 3.1
*/
@FunctionalInterface
public interface CloudEventAttributesProvider {
/**
* Will construct instance of {@link CloudEventAttributes} setting its required attributes.
*
* @param ce_id value for Cloud Event 'id' attribute
* @param ce_specversion value for Cloud Event 'specversion' attribute
* @param ce_source value for Cloud Event 'source' attribute
* @param ce_type value for Cloud Event 'type' attribute
* @return instance of {@link CloudEventAttributes}
*/
CloudEventAttributes get(String ce_id, String ce_specversion, String ce_source, String ce_type);
/**
* Will construct instance of {@link CloudEventAttributes}
* Should default/generate cloud event ID and SPECVERSION.
*
* @param ce_source value for Cloud Event 'source' attribute
* @param ce_type value for Cloud Event 'type' attribute
* @return instance of {@link CloudEventAttributes}
*/
CloudEventAttributes get(String ce_source, String ce_type);
/**
* Will construct instance of {@link CloudEventAttributes} from {@link MessageHeaders}.
*
* Should copy Cloud Event related headers into an instance of {@link CloudEventAttributes}
* NOTE: Certain headers must not be copied.
*
* @param headers instance of {@link MessageHeaders}
* @return modifiable instance of {@link CloudEventAttributes}
*/
RequiredAttributeAccessor get(MessageHeaders headers);
/**
*
* @param inputMessage input message used to invoke user functionality (e.g., function)

View File

@@ -16,9 +16,13 @@
package org.springframework.cloud.function.cloudevent;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
@@ -155,4 +159,52 @@ public final class CloudEventMessageUtils {
&& headers.containsKey(CE_SPECVERSION)
&& headers.containsKey(CE_TYPE));
}
/**
* Will construct instance of {@link CloudEventAttributes} setting its required attributes.
*
* @param ce_id value for Cloud Event 'id' attribute
* @param ce_specversion value for Cloud Event 'specversion' attribute
* @param ce_source value for Cloud Event 'source' attribute
* @param ce_type value for Cloud Event 'type' attribute
* @return instance of {@link CloudEventAttributes}
*/
public static CloudEventAttributes get(String ce_id, String ce_specversion, String ce_source, String ce_type) {
Assert.hasText(ce_id, "'ce_id' must not be null or empty");
Assert.hasText(ce_specversion, "'ce_specversion' must not be null or empty");
Assert.hasText(ce_source, "'ce_source' must not be null or empty");
Assert.hasText(ce_type, "'ce_type' must not be null or empty");
Map<String, Object> requiredAttributes = new HashMap<>();
requiredAttributes.put(CloudEventMessageUtils.CE_ID, ce_id);
requiredAttributes.put(CloudEventMessageUtils.CE_SPECVERSION, ce_specversion);
requiredAttributes.put(CloudEventMessageUtils.CE_SOURCE, ce_source);
requiredAttributes.put(CloudEventMessageUtils.CE_TYPE, ce_type);
return new CloudEventAttributes(requiredAttributes);
}
/**
* Will construct instance of {@link CloudEventAttributes}
* Should default/generate cloud event ID and SPECVERSION.
*
* @param ce_source value for Cloud Event 'source' attribute
* @param ce_type value for Cloud Event 'type' attribute
* @return instance of {@link CloudEventAttributes}
*/
public static CloudEventAttributes get(String ce_source, String ce_type) {
return get(UUID.randomUUID().toString(), "1.0", ce_source, ce_type);
}
/**
* Will construct instance of {@link CloudEventAttributes} from {@link MessageHeaders}.
*
* Should copy Cloud Event related headers into an instance of {@link CloudEventAttributes}
* NOTE: Certain headers must not be copied.
*
* @param headers instance of {@link MessageHeaders}
* @return modifiable instance of {@link CloudEventAttributes}
*/
public static RequiredAttributeAccessor get(MessageHeaders headers) {
return new RequiredAttributeAccessor(headers);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019-2019 the original author or authors.
* Copyright 2020-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@
package org.springframework.cloud.function.cloudevent;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@@ -27,8 +26,6 @@ import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -41,38 +38,12 @@ public class DefaultCloudEventAttributesProvider implements CloudEventAttributes
private ConfigurableApplicationContext applicationContext;
@Override
public CloudEventAttributes get(String ce_id, String ce_specversion, String ce_source, String ce_type) {
Assert.hasText(ce_id, "'ce_id' must not be null or empty");
Assert.hasText(ce_specversion, "'ce_specversion' must not be null or empty");
Assert.hasText(ce_source, "'ce_source' must not be null or empty");
Assert.hasText(ce_type, "'ce_type' must not be null or empty");
Map<String, Object> requiredAttributes = new HashMap<>();
requiredAttributes.put(CloudEventMessageUtils.CE_ID, ce_id);
requiredAttributes.put(CloudEventMessageUtils.CE_SPECVERSION, ce_specversion);
requiredAttributes.put(CloudEventMessageUtils.CE_SOURCE, ce_source);
requiredAttributes.put(CloudEventMessageUtils.CE_TYPE, ce_type);
return new CloudEventAttributes(requiredAttributes);
}
@Override
public CloudEventAttributes get(String ce_source, String ce_type) {
return this.get(UUID.randomUUID().toString(), "1.0", ce_source, ce_type);
}
/**
* By default it will copy all the headers while exposing accessor to allow user to modify any of them.
*/
@Override
public RequiredAttributeAccessor get(MessageHeaders headers) {
return new RequiredAttributeAccessor(headers);
}
@Override
public Map<String, Object> generateDefaultCloudEventHeaders(Message<?> inputMessage, Object result) {
if (inputMessage.getHeaders().containsKey(CloudEventMessageUtils.CE_ID)) { // input is a cloud event
String applicationName = this.getApplicationName();
return this.get(inputMessage.getHeaders())
return CloudEventMessageUtils.get(inputMessage.getHeaders())
.setId(UUID.randomUUID().toString())
.setType(result.getClass().getName())
.setSource(applicationName);

View File

@@ -45,8 +45,7 @@ public class CloudEventTypeConversionTests {
@Test
public void testFromMessageBinaryPayloadMatchesType() {
SmartCompositeMessageConverter messageConverter = this.configure(DummyConfiguration.class);
CloudEventAttributesProvider ceAttrProvider = new DefaultCloudEventAttributesProvider();
CloudEventAttributes ceAttributes = ceAttrProvider
CloudEventAttributes ceAttributes = CloudEventMessageUtils
.get(UUID.randomUUID().toString(), "1.0", "https://spring.io/", "org.springframework");
ceAttributes.setDataContentType("text/plain");
Message<String> message = MessageBuilder.withPayload("Hello Ricky").copyHeaders(ceAttributes).build();
@@ -58,8 +57,7 @@ public class CloudEventTypeConversionTests {
@Test
public void testFromMessageBinaryPayloadDoesNotMatchType() {
SmartCompositeMessageConverter messageConverter = this.configure(DummyConfiguration.class);
CloudEventAttributesProvider ceAttrProvider = new DefaultCloudEventAttributesProvider();
CloudEventAttributes ceAttributes = ceAttrProvider
CloudEventAttributes ceAttributes = CloudEventMessageUtils
.get(UUID.randomUUID().toString(), "1.0", "https://spring.io/", "org.springframework");
Message<byte[]> message = MessageBuilder.withPayload("Hello Ricky".getBytes())
.copyHeaders(ceAttributes)
@@ -70,12 +68,10 @@ public class CloudEventTypeConversionTests {
assertThat(converted).isEqualTo("Hello Ricky");
}
@Test // JsonMessageConverter does some special things between byte[] and String so
// this works
@Test // JsonMessageConverter does some special things between byte[] and String so this works
public void testFromMessageBinaryPayloadNoDataContentTypeToString() {
SmartCompositeMessageConverter messageConverter = this.configure(DummyConfiguration.class);
CloudEventAttributesProvider ceAttrProvider = new DefaultCloudEventAttributesProvider();
CloudEventAttributes ceAttributes = ceAttrProvider
CloudEventAttributes ceAttributes = CloudEventMessageUtils
.get(UUID.randomUUID().toString(), "1.0", "https://spring.io/", "org.springframework");
Message<byte[]> message = MessageBuilder.withPayload("Hello Ricky".getBytes())
.copyHeaders(ceAttributes)
@@ -89,8 +85,7 @@ public class CloudEventTypeConversionTests {
@Test // Unlike the previous test the type here is POJO so no special treatement
public void testFromMessageBinaryPayloadNoDataContentTypeToPOJO() {
SmartCompositeMessageConverter messageConverter = this.configure(DummyConfiguration.class);
CloudEventAttributesProvider ceAttrProvider = new DefaultCloudEventAttributesProvider();
CloudEventAttributes ceAttributes = ceAttrProvider.get("https://spring.io/", "org.springframework");
CloudEventAttributes ceAttributes = CloudEventMessageUtils.get("https://spring.io/", "org.springframework");
Message<byte[]> message = MessageBuilder.withPayload("Hello Ricky".getBytes())
.copyHeaders(ceAttributes)
.setHeader(MessageHeaders.CONTENT_TYPE,
@@ -103,8 +98,7 @@ public class CloudEventTypeConversionTests {
@Test // will fall on default CT which is json
public void testFromMessageBinaryPayloadNoDataContentTypeToPOJOThatWorks() {
SmartCompositeMessageConverter messageConverter = this.configure(DummyConfiguration.class);
CloudEventAttributesProvider ceAttrProvider = new DefaultCloudEventAttributesProvider();
CloudEventAttributes ceAttributes = ceAttrProvider.get("https://spring.io/", "org.springframework");
CloudEventAttributes ceAttributes = CloudEventMessageUtils.get("https://spring.io/", "org.springframework");
Message<byte[]> message = MessageBuilder.withPayload("{\"name\":\"Ricky\"}".getBytes())
.copyHeaders(ceAttributes)
.setHeader(MessageHeaders.CONTENT_TYPE,