diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index d30d09e20..000000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/spring-cloud-aws-dependencies/pom.xml b/spring-cloud-aws-dependencies/pom.xml
index a75606057..7bb837a40 100644
--- a/spring-cloud-aws-dependencies/pom.xml
+++ b/spring-cloud-aws-dependencies/pom.xml
@@ -31,7 +31,7 @@
Spring Cloud AWS Dependencies
Spring Cloud AWS Dependencies
- 1.11.415
+ 1.11.624
1.1.1
1.0.0
1.3.2.RELEASE
diff --git a/spring-cloud-aws-messaging/pom.xml b/spring-cloud-aws-messaging/pom.xml
index 69d8b7ff8..c33336239 100644
--- a/spring-cloud-aws-messaging/pom.xml
+++ b/spring-cloud-aws-messaging/pom.xml
@@ -42,6 +42,10 @@
com.amazonaws
aws-java-sdk-sqs
+
+ com.amazonaws
+ aws-java-sdk-events
+
org.springframework
spring-messaging
diff --git a/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/config/annotation/EnableEventBridge.java b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/config/annotation/EnableEventBridge.java
new file mode 100644
index 000000000..14f263608
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/config/annotation/EnableEventBridge.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.config.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.springframework.context.annotation.Import;
+
+/**
+ * @author Jakub Narloch
+ * @since 2.3.0
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Import({ EventBridgeConfiguration.class })
+public @interface EnableEventBridge {
+
+}
diff --git a/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/config/annotation/EventBridgeConfiguration.java b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/config/annotation/EventBridgeConfiguration.java
new file mode 100644
index 000000000..5d3d4d43b
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/config/annotation/EventBridgeConfiguration.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.config.annotation;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEventsClient;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.aws.context.annotation.ConditionalOnMissingAmazonClient;
+import org.springframework.cloud.aws.core.config.AmazonWebserviceClientFactoryBean;
+import org.springframework.cloud.aws.core.region.RegionProvider;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @author Jakub Narloch
+ * @since 2.3.0
+ */
+@Configuration(proxyBeanMethods = false)
+public class EventBridgeConfiguration {
+
+ @Autowired(required = false)
+ private AWSCredentialsProvider awsCredentialsProvider;
+
+ @Autowired(required = false)
+ private RegionProvider regionProvider;
+
+ @ConditionalOnMissingAmazonClient(AmazonCloudWatchEvents.class)
+ @Bean
+ public AmazonWebserviceClientFactoryBean amazonEvents() {
+ return new AmazonWebserviceClientFactoryBean<>(AmazonCloudWatchEventsClient.class,
+ this.awsCredentialsProvider, this.regionProvider);
+ }
+
+}
diff --git a/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/core/EventBusMessageChannel.java b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/core/EventBusMessageChannel.java
new file mode 100644
index 000000000..86c392c78
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/core/EventBusMessageChannel.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.core;
+
+import java.util.Optional;
+
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
+import com.amazonaws.services.cloudwatchevents.model.PutEventsRequest;
+import com.amazonaws.services.cloudwatchevents.model.PutEventsRequestEntry;
+
+import org.springframework.messaging.Message;
+import org.springframework.messaging.support.AbstractMessageChannel;
+
+/**
+ * @author Jakub Narloch
+ * @since 2.3.0
+ */
+public class EventBusMessageChannel extends AbstractMessageChannel {
+
+ /**
+ * The 'source' message header.
+ */
+ public static final String EVENT_SOURCE_HEADER = "EVENT_SOURCE_HEADER";
+
+ /**
+ * The 'detail-type' message header.
+ */
+ public static final String EVENT_DETAIL_TYPE_HEADER = "EVENT_DETAIL_TYPE_HEADER";
+
+ private final AmazonCloudWatchEvents amazonEvents;
+
+ private final String eventBus;
+
+ public EventBusMessageChannel(AmazonCloudWatchEvents amazonEvents, String eventBus) {
+ this.amazonEvents = amazonEvents;
+ this.eventBus = eventBus;
+ }
+
+ @Override
+ protected boolean sendInternal(Message> message, long timeout) {
+ PutEventsRequestEntry entry = new PutEventsRequestEntry()
+ .withEventBusName(eventBus).withSource(findEventSource(message))
+ .withDetailType(findEventDetailType(message))
+ .withDetail(message.getPayload().toString());
+ amazonEvents.putEvents(new PutEventsRequest().withEntries(entry));
+ return true;
+ }
+
+ private static String findEventSource(Message> message) {
+ return findHeaderValue(message, EVENT_SOURCE_HEADER);
+ }
+
+ private static String findEventDetailType(Message> message) {
+ return findHeaderValue(message, EVENT_DETAIL_TYPE_HEADER);
+ }
+
+ private static String findHeaderValue(Message> message, String header) {
+ return Optional.ofNullable(message.getHeaders().get(header)).map(Object::toString)
+ .orElse(null);
+ }
+
+}
diff --git a/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/core/EventsMessagingTemplate.java b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/core/EventsMessagingTemplate.java
new file mode 100644
index 000000000..44395a508
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/core/EventsMessagingTemplate.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.core;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
+
+import org.springframework.cloud.aws.core.env.ResourceIdResolver;
+import org.springframework.cloud.aws.messaging.core.support.AbstractMessageChannelMessagingSendingTemplate;
+import org.springframework.cloud.aws.messaging.support.destination.DynamicEventBusDestinationResolver;
+import org.springframework.messaging.converter.MessageConverter;
+import org.springframework.messaging.core.DestinationResolver;
+
+/**
+ * @author Jakub Narloch
+ * @since 2.3.0
+ */
+public class EventsMessagingTemplate
+ extends AbstractMessageChannelMessagingSendingTemplate {
+
+ private final AmazonCloudWatchEvents amazonEvents;
+
+ public EventsMessagingTemplate(AmazonCloudWatchEvents amazonEvents) {
+ this(amazonEvents, (ResourceIdResolver) null, null);
+ }
+
+ public EventsMessagingTemplate(AmazonCloudWatchEvents amazonEvents,
+ ResourceIdResolver resourceIdResolver, MessageConverter messageConverter) {
+ super(new DynamicEventBusDestinationResolver(amazonEvents, resourceIdResolver));
+ this.amazonEvents = amazonEvents;
+ initMessageConverter(messageConverter);
+ }
+
+ public EventsMessagingTemplate(AmazonCloudWatchEvents amazonEvents,
+ DestinationResolver destinationResolver,
+ MessageConverter messageConverter) {
+ super(destinationResolver);
+ this.amazonEvents = amazonEvents;
+ initMessageConverter(messageConverter);
+ }
+
+ @Override
+ protected EventBusMessageChannel resolveMessageChannel(
+ String physicalResourceIdentifier) {
+ return new EventBusMessageChannel(this.amazonEvents, physicalResourceIdentifier);
+ }
+
+ /**
+ * Convenience method that sends an event identified by {@literal source} and
+ * {@literal detailType} with the given {@literal message} to the
+ * {@literal destination}.
+ * @param source The event source
+ * @param detailType The event detail-type
+ * @param message The event body to send
+ */
+ public void sendEvent(String source, String detailType, Object message) {
+ Map headers = new HashMap<>();
+ headers.put(EventBusMessageChannel.EVENT_SOURCE_HEADER, source);
+ headers.put(EventBusMessageChannel.EVENT_DETAIL_TYPE_HEADER, detailType);
+ this.convertAndSend(getRequiredDefaultDestination(), message, headers);
+ }
+
+ /**
+ * Convenience method that sends an event identified by {@literal source} and
+ * {@literal detailType} with the given {@literal message} to the specific
+ * {@literal eventBus}.
+ * @param eventBus The event bus name
+ * @param source The event source
+ * @param detailType The event detail-type
+ * @param message The event body to send
+ */
+ public void sendEvent(String eventBus, String source, String detailType,
+ Object message) {
+ Map headers = new HashMap<>();
+ headers.put(EventBusMessageChannel.EVENT_SOURCE_HEADER, source);
+ headers.put(EventBusMessageChannel.EVENT_DETAIL_TYPE_HEADER, detailType);
+ this.convertAndSend(eventBus, message, headers);
+ }
+
+}
diff --git a/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/support/destination/DynamicEventBusDestinationResolver.java b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/support/destination/DynamicEventBusDestinationResolver.java
new file mode 100644
index 000000000..9921f5ac9
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/main/java/org/springframework/cloud/aws/messaging/support/destination/DynamicEventBusDestinationResolver.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.support.destination;
+
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
+import com.amazonaws.services.cloudwatchevents.model.CreateEventBusRequest;
+
+import org.springframework.cloud.aws.core.env.ResourceIdResolver;
+import org.springframework.cloud.aws.core.naming.AmazonResourceName;
+import org.springframework.messaging.core.DestinationResolutionException;
+import org.springframework.messaging.core.DestinationResolver;
+
+/**
+ * @author Jakub Narloch
+ * @since 2.3.0
+ */
+public class DynamicEventBusDestinationResolver implements DestinationResolver {
+
+ private final AmazonCloudWatchEvents amazonEvents;
+
+ private final ResourceIdResolver resourceIdResolver;
+
+ private boolean autoCreate;
+
+ public DynamicEventBusDestinationResolver(AmazonCloudWatchEvents amazonEvents) {
+ this(amazonEvents, null);
+ }
+
+ public DynamicEventBusDestinationResolver(AmazonCloudWatchEvents amazonEvents,
+ ResourceIdResolver resourceIdResolver) {
+ this.amazonEvents = amazonEvents;
+ this.resourceIdResolver = resourceIdResolver;
+ }
+
+ public void setAutoCreate(boolean autoCreate) {
+ this.autoCreate = autoCreate;
+ }
+
+ @Override
+ public String resolveDestination(String name) throws DestinationResolutionException {
+ if (autoCreate) {
+ amazonEvents.createEventBus(new CreateEventBusRequest().withName(name))
+ .getEventBusArn();
+ return name;
+ }
+
+ String eventBusName = name;
+ if (resourceIdResolver != null) {
+ eventBusName = resourceIdResolver.resolveToPhysicalResourceId(name);
+ }
+
+ if (eventBusName != null
+ && AmazonResourceName.isValidAmazonResourceName(eventBusName)) {
+ return AmazonResourceName.fromString(eventBusName).getResourceName();
+ }
+
+ return eventBusName;
+ }
+
+}
diff --git a/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/config/annotation/EventBridgeConfigurationTest.java b/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/config/annotation/EventBridgeConfigurationTest.java
new file mode 100644
index 000000000..6c32f22d0
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/config/annotation/EventBridgeConfigurationTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.config.annotation;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.regions.Region;
+import com.amazonaws.regions.Regions;
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.cloud.aws.context.config.annotation.EnableContextRegion;
+import org.springframework.context.annotation.Bean;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.test.util.ReflectionTestUtils;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+public class EventBridgeConfigurationTest {
+
+ private AnnotationConfigWebApplicationContext webApplicationContext;
+
+ @Before
+ public void setUp() throws Exception {
+ this.webApplicationContext = new AnnotationConfigWebApplicationContext();
+ this.webApplicationContext.setServletContext(new MockServletContext());
+ }
+
+ @Test
+ public void enableEventBridge_withMinimalConfig__shouldBeUsedToCreateClient()
+ throws Exception {
+ // Arrange & Act
+ this.webApplicationContext.register(MinimalEventBridgeConfiguration.class);
+ this.webApplicationContext.refresh();
+ AmazonCloudWatchEvents amazonEvents = this.webApplicationContext
+ .getBean(AmazonCloudWatchEvents.class);
+
+ // Assert
+ assertThat(amazonEvents).isNotNull();
+ }
+
+ @Test
+ public void enableEventBridge_withProvidedCredentials_shouldBeUsedToCreateClient()
+ throws Exception {
+ // Arrange & Act
+ this.webApplicationContext
+ .register(EventBridgeConfigurationWithCredentials.class);
+ this.webApplicationContext.refresh();
+ AmazonCloudWatchEvents amazonEvents = this.webApplicationContext
+ .getBean(AmazonCloudWatchEvents.class);
+
+ // Assert
+ assertThat(amazonEvents).isNotNull();
+ assertThat(ReflectionTestUtils.getField(amazonEvents, "awsCredentialsProvider"))
+ .isEqualTo(
+ EventBridgeConfigurationWithCredentials.AWS_CREDENTIALS_PROVIDER);
+ }
+
+ @Test
+ public void enableEventBridge_withCustomAmazonSnsClient_shouldBeUsedToCreateClient()
+ throws Exception {
+ // Arrange & Act
+ this.webApplicationContext
+ .register(EventBridgeConfigurationWithCustomAmazonClient.class);
+ this.webApplicationContext.refresh();
+ AmazonCloudWatchEvents amazonEvents = this.webApplicationContext
+ .getBean(AmazonCloudWatchEvents.class);
+
+ // Assert
+ assertThat(amazonEvents).isNotNull();
+ assertThat(amazonEvents)
+ .isEqualTo(EventBridgeConfigurationWithCustomAmazonClient.AMAZON_EVENTS);
+ }
+
+ @Test
+ public void enableSns_withRegionProvided_shouldBeUsedToCreateClient()
+ throws Exception {
+ // Arrange & Act
+ this.webApplicationContext
+ .register(EventBridgeConfigurationWithRegionProvider.class);
+ this.webApplicationContext.refresh();
+ AmazonCloudWatchEvents amazonEvents = this.webApplicationContext
+ .getBean(AmazonCloudWatchEvents.class);
+
+ // Assert
+ assertThat(ReflectionTestUtils.getField(amazonEvents, "endpoint").toString())
+ .isEqualTo("https://" + Region.getRegion(Regions.EU_WEST_1)
+ .getServiceEndpoint("events"));
+ }
+
+ @EnableWebMvc
+ @EnableEventBridge
+ protected static class MinimalEventBridgeConfiguration {
+
+ }
+
+ @EnableWebMvc
+ @EnableEventBridge
+ protected static class EventBridgeConfigurationWithCredentials {
+
+ public static final AWSCredentialsProvider AWS_CREDENTIALS_PROVIDER = mock(
+ AWSCredentialsProvider.class);
+
+ @Bean
+ public AWSCredentialsProvider awsCredentialsProvider() {
+ return AWS_CREDENTIALS_PROVIDER;
+ }
+
+ }
+
+ @EnableWebMvc
+ @EnableEventBridge
+ protected static class EventBridgeConfigurationWithCustomAmazonClient {
+
+ public static final AmazonCloudWatchEvents AMAZON_EVENTS = mock(
+ AmazonCloudWatchEvents.class);
+
+ @Bean
+ public AmazonCloudWatchEvents amazonEvents() {
+ return AMAZON_EVENTS;
+ }
+
+ }
+
+ @EnableWebMvc
+ @EnableContextRegion(region = "eu-west-1")
+ @EnableEventBridge
+ protected static class EventBridgeConfigurationWithRegionProvider {
+
+ }
+
+}
diff --git a/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/core/EventBusMessageChannelTest.java b/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/core/EventBusMessageChannelTest.java
new file mode 100644
index 000000000..d5ec6a77b
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/core/EventBusMessageChannelTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.core;
+
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
+import com.amazonaws.services.cloudwatchevents.model.PutEventsRequest;
+import com.amazonaws.services.cloudwatchevents.model.PutEventsRequestEntry;
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.messaging.Message;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.support.MessageBuilder;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.only;
+import static org.mockito.Mockito.verify;
+
+/**
+ * @author Jakub Narloch
+ */
+public class EventBusMessageChannelTest {
+
+ private Message message;
+
+ @Before
+ public void setUp() throws Exception {
+ message = MessageBuilder.withPayload("Message content")
+ .setHeader(EventBusMessageChannel.EVENT_SOURCE_HEADER, "custom")
+ .setHeader(EventBusMessageChannel.EVENT_DETAIL_TYPE_HEADER, "My Event")
+ .build();
+ }
+
+ @Test
+ public void sendMessage_validTextMessageAndSubject_returnsTrue() throws Exception {
+ // Arrange
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+
+ MessageChannel messageChannel = new EventBusMessageChannel(amazonEvents,
+ "default");
+
+ // Act
+ boolean sent = messageChannel.send(message);
+
+ // Assert
+ verify(amazonEvents, only())
+ .putEvents(new PutEventsRequest().withEntries(new PutEventsRequestEntry()
+ .withEventBusName("default").withSource("custom")
+ .withDetailType("My Event").withDetail(message.getPayload())));
+ assertThat(sent).isTrue();
+ }
+
+ @Test
+ public void sendMessage_validTextMessageAndTimeout_timeoutIsIgnored()
+ throws Exception {
+ // Arrange
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+ MessageChannel messageChannel = new EventBusMessageChannel(amazonEvents,
+ "default");
+
+ // Act
+ boolean sent = messageChannel.send(message, 10);
+
+ // Assert
+ verify(amazonEvents, only())
+ .putEvents(new PutEventsRequest().withEntries(new PutEventsRequestEntry()
+ .withEventBusName("default").withSource("custom")
+ .withDetailType("My Event").withDetail(message.getPayload())));
+ assertThat(sent).isTrue();
+ }
+
+}
diff --git a/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/core/EventsMessagingTemplateTest.java b/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/core/EventsMessagingTemplateTest.java
new file mode 100644
index 000000000..180699210
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/core/EventsMessagingTemplateTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.core;
+
+import java.util.Locale;
+
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
+import com.amazonaws.services.cloudwatchevents.model.EventBus;
+import com.amazonaws.services.cloudwatchevents.model.ListEventBusesRequest;
+import com.amazonaws.services.cloudwatchevents.model.ListEventBusesResult;
+import com.amazonaws.services.cloudwatchevents.model.PutEventsRequest;
+import com.amazonaws.services.cloudwatchevents.model.PutEventsRequestEntry;
+import org.junit.Test;
+
+import org.springframework.messaging.core.DestinationResolver;
+import org.springframework.messaging.support.MessageBuilder;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class EventsMessagingTemplateTest {
+
+ @Test
+ public void send_validTextMessage_usesEventBusChannel() throws Exception {
+ // Arrange
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+ EventsMessagingTemplate eventsMessagingTemplate = new EventsMessagingTemplate(
+ amazonEvents);
+ String physicalEventBusName = "arn:aws:events:us-east-1:123456789012:event-bus/default";
+ when(amazonEvents.listEventBuses(new ListEventBusesRequest()))
+ .thenReturn(new ListEventBusesResult().withEventBuses(new EventBus()
+ .withName("default").withArn(physicalEventBusName)));
+ eventsMessagingTemplate.setDefaultDestinationName("default");
+
+ // Act
+ eventsMessagingTemplate.send(MessageBuilder.withPayload("Message content")
+ .setHeader(EventBusMessageChannel.EVENT_SOURCE_HEADER, "custom")
+ .setHeader(EventBusMessageChannel.EVENT_DETAIL_TYPE_HEADER, "My Event")
+ .build());
+
+ // Assert
+ verify(amazonEvents)
+ .putEvents(new PutEventsRequest().withEntries(new PutEventsRequestEntry()
+ .withEventBusName("default").withSource("custom")
+ .withDetailType("My Event").withDetail("Message content")));
+ }
+
+ @Test
+ public void send_validTextMessageWithCustomDestinationResolver_usesEventBusChannel()
+ throws Exception {
+ // Arrange
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+ EventsMessagingTemplate eventsMessagingTemplate = new EventsMessagingTemplate(
+ amazonEvents,
+ (DestinationResolver) name -> name.toUpperCase(Locale.ENGLISH),
+ null);
+
+ // Act
+ eventsMessagingTemplate.send("test", MessageBuilder.withPayload("Message content")
+ .setHeader(EventBusMessageChannel.EVENT_SOURCE_HEADER, "custom")
+ .setHeader(EventBusMessageChannel.EVENT_DETAIL_TYPE_HEADER, "My Event")
+ .build());
+
+ // Assert
+ verify(amazonEvents).putEvents(new PutEventsRequest().withEntries(
+ new PutEventsRequestEntry().withEventBusName("TEST").withSource("custom")
+ .withDetailType("My Event").withDetail("Message content")));
+ }
+
+ @Test
+ public void convertAndSend_withDestinationPayloadAndSubject_shouldSetSourceAndDetailType()
+ throws Exception {
+ // Arrange
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+ EventsMessagingTemplate eventsMessagingTemplate = new EventsMessagingTemplate(
+ amazonEvents);
+ String physicalEventBusName = "arn:aws:events:us-east-1:123456789012:event-bus/default";
+ when(amazonEvents.listEventBuses(new ListEventBusesRequest()))
+ .thenReturn(new ListEventBusesResult().withEventBuses(new EventBus()
+ .withName("default").withArn(physicalEventBusName)));
+
+ // Act
+ eventsMessagingTemplate.sendEvent(physicalEventBusName, "custom", "My Event",
+ "Message content");
+
+ // Assert
+ verify(amazonEvents)
+ .putEvents(new PutEventsRequest().withEntries(new PutEventsRequestEntry()
+ .withEventBusName("default").withSource("custom")
+ .withDetailType("My Event").withDetail("Message content")));
+ }
+
+ @Test
+ public void convertAndSend_withPayloadAndSubject_shouldSetSourceAndDetailType()
+ throws Exception {
+ // Arrange
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+ EventsMessagingTemplate eventsMessagingTemplate = new EventsMessagingTemplate(
+ amazonEvents);
+ String physicalEventBusName = "arn:aws:events:us-east-1:123456789012:event-bus/default";
+ eventsMessagingTemplate.setDefaultDestinationName(physicalEventBusName);
+
+ // Act
+ eventsMessagingTemplate.sendEvent("custom", "My Event", "Message content");
+
+ // Assert
+ verify(amazonEvents)
+ .putEvents(new PutEventsRequest().withEntries(new PutEventsRequestEntry()
+ .withEventBusName("default").withSource("custom")
+ .withDetailType("My Event").withDetail("Message content")));
+ }
+
+}
diff --git a/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/support/destination/DynamicEventBusDestinationResolverTest.java b/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/support/destination/DynamicEventBusDestinationResolverTest.java
new file mode 100644
index 000000000..ddec22d69
--- /dev/null
+++ b/spring-cloud-aws-messaging/src/test/java/org/springframework/cloud/aws/messaging/support/destination/DynamicEventBusDestinationResolverTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2013-2019 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.
+ * You may obtain a copy of the License at
+ *
+ * https://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 org.springframework.cloud.aws.messaging.support.destination;
+
+import com.amazonaws.services.cloudwatchevents.AmazonCloudWatchEvents;
+import com.amazonaws.services.cloudwatchevents.model.CreateEventBusRequest;
+import com.amazonaws.services.cloudwatchevents.model.CreateEventBusResult;
+import com.amazonaws.services.cloudwatchevents.model.EventBus;
+import com.amazonaws.services.cloudwatchevents.model.ListEventBusesRequest;
+import com.amazonaws.services.cloudwatchevents.model.ListEventBusesResult;
+import org.junit.Test;
+
+import org.springframework.cloud.aws.core.env.ResourceIdResolver;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DynamicEventBusDestinationResolverTest {
+
+ @Test
+ public void resolveDestination_withAlreadyExistingArn_returnsArnWithoutValidatingIt()
+ throws Exception {
+ // Arrange
+ String eventBusArn = "arn:aws:events:us-east-1:123456789012:event-bus/test";
+ String eventBusName = "test";
+
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+ DynamicEventBusDestinationResolver resolver = new DynamicEventBusDestinationResolver(
+ amazonEvents);
+
+ // Act
+ String resolvedDestinationName = resolver.resolveDestination(eventBusArn);
+
+ // Assert
+ assertThat(resolvedDestinationName).isEqualTo(eventBusName);
+ }
+
+ @Test
+ public void resolveDestination_withAutoCreateEnabled_shouldCreateEventBusDirectly()
+ throws Exception {
+ // Arrange
+ String eventBusArn = "arn:aws:events:us-east-1:123456789012:event-bus/test";
+ String eventBusName = "test";
+
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+ when(amazonEvents.createEventBus(new CreateEventBusRequest().withName("test")))
+ .thenReturn(new CreateEventBusResult().withEventBusArn(eventBusArn));
+
+ DynamicEventBusDestinationResolver resolver = new DynamicEventBusDestinationResolver(
+ amazonEvents);
+ resolver.setAutoCreate(true);
+
+ // Act
+ String resolvedDestinationName = resolver.resolveDestination("test");
+
+ // Assert
+ assertThat(resolvedDestinationName).isEqualTo(eventBusName);
+ }
+
+ @Test
+ public void resolveDestination_withResourceIdResolver_shouldCallIt()
+ throws Exception {
+ // Arrange
+ String eventBusArn = "arn:aws:events:us-east-1:123456789012:event-bus/test";
+ String eventBusName = "test";
+
+ ResourceIdResolver resourceIdResolver = mock(ResourceIdResolver.class);
+ when(resourceIdResolver.resolveToPhysicalResourceId(eventBusName))
+ .thenReturn(eventBusArn);
+
+ AmazonCloudWatchEvents amazonEvents = mock(AmazonCloudWatchEvents.class);
+ when(amazonEvents.listEventBuses(new ListEventBusesRequest()))
+ .thenReturn(new ListEventBusesResult().withEventBuses(
+ new EventBus().withName(eventBusName).withArn(eventBusArn)));
+
+ DynamicEventBusDestinationResolver resolver = new DynamicEventBusDestinationResolver(
+ amazonEvents, resourceIdResolver);
+
+ // Assert
+ String resolvedDestinationName = resolver.resolveDestination(eventBusName);
+
+ // Assert
+ assertThat(resolvedDestinationName).isEqualTo(eventBusName);
+ }
+
+}