diff --git a/2022-11/spring-30/.gitignore b/2022-11/spring-30/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/2022-11/spring-30/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/2022-11/spring-30/pom.xml b/2022-11/spring-30/pom.xml new file mode 100644 index 00000000..56dbc7bd --- /dev/null +++ b/2022-11/spring-30/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + ru.otus + spring-30 + 1.0 + + pom + + + spring-30-exercise + spring-30-solution + + diff --git a/2022-11/spring-30/spring-30-exercise/pom.xml b/2022-11/spring-30/spring-30-exercise/pom.xml new file mode 100644 index 00000000..0ea46312 --- /dev/null +++ b/2022-11/spring-30/spring-30-exercise/pom.xml @@ -0,0 +1,54 @@ + + + 4.0.0 + + ru.otus + spring-30-exercise + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.7.9 + + + + + 11 + 11 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-integration + + + org.springframework + spring-messaging + + + + org.springframework.boot + spring-boot-starter-test + + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-11/spring-30/spring-30-exercise/src/main/java/ru/otus/spring/integration/App.java b/2022-11/spring-30/spring-30-exercise/src/main/java/ru/otus/spring/integration/App.java new file mode 100644 index 00000000..f39acb46 --- /dev/null +++ b/2022-11/spring-30/spring-30-exercise/src/main/java/ru/otus/spring/integration/App.java @@ -0,0 +1,70 @@ +package ru.otus.spring.integration; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.integration.annotation.IntegrationComponentScan; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.dsl.MessageChannels; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.PollableChannel; +import org.springframework.messaging.SubscribableChannel; + +import lombok.extern.slf4j.Slf4j; + + +@SpringBootApplication +@IntegrationComponentScan +@Slf4j +public class App { + + public static void main(String[] args) throws InterruptedException { + ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args); + + PollableChannel queueChannel = ctx.getBean("queueChannel", PollableChannel.class); + SubscribableChannel directChannel = ctx.getBean("directChannel", SubscribableChannel.class); + + + log.warn("INIT"); + for (int i = 0; i < 10; i++) { + queueChannel.send(MessageBuilder.withPayload("Start " + i).build()); + } + log.warn("INIT FINISH"); + Thread.sleep(5000); + + log.warn("START"); + directChannel.subscribe((msg) -> log.warn("Receive msg: {}", msg)); + new Thread(() -> { + while (true) { + directChannel.send(queueChannel.receive()); + } + }).start(); + log.warn("START FINISH"); + Thread.sleep(5000); + + log.warn(""); + queueChannel.send(MessageBuilder.withPayload("Hello").build()); + Thread.sleep(5000); + + log.warn(""); + queueChannel.send(MessageBuilder.withPayload("Hello2").build()); + Thread.sleep(5000); + + log.warn(""); + queueChannel.send(MessageBuilder.withPayload("Hello3").build()); + + } + + @Bean + public PollableChannel queueChannel() { + return new QueueChannel(10); + } + + @Bean + public SubscribableChannel directChannel() { + return MessageChannels.direct("channel2").get(); + } + +} + diff --git a/2022-11/spring-30/spring-30-exercise/src/main/resources/application.yml b/2022-11/spring-30/spring-30-exercise/src/main/resources/application.yml new file mode 100644 index 00000000..1a9aeb48 --- /dev/null +++ b/2022-11/spring-30/spring-30-exercise/src/main/resources/application.yml @@ -0,0 +1,5 @@ +logging: + level: + root: info + + org.springframework.integration: debug \ No newline at end of file diff --git a/2022-11/spring-30/spring-30-exercise/src/test/java/ru/otus/spring/integration/MessagesTest.java b/2022-11/spring-30/spring-30-exercise/src/test/java/ru/otus/spring/integration/MessagesTest.java new file mode 100644 index 00000000..ffff36c7 --- /dev/null +++ b/2022-11/spring-30/spring-30-exercise/src/test/java/ru/otus/spring/integration/MessagesTest.java @@ -0,0 +1,98 @@ +package ru.otus.spring.integration; + + +import org.junit.jupiter.api.Test; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.ErrorMessage; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.messaging.support.MessageBuilder; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +@SuppressWarnings("all") +public class MessagesTest { + + @Test + public void testCreateSimpleGenericMessage() { + // TODO: Создайте сообщение с payload-ом "Hello" с помощью конструктора + Message message = null; + + assertNotNull(message); + assertEquals(GenericMessage.class, message.getClass()); + assertNotNull(message.getPayload()); + assertEquals("Hello", message.getPayload()); + } + + @Test + public void testCreateGenericMessage() { + // TODO: Создайте сообщение с пользователем с помощью конструктора + Message message = null; + + assertNotNull(message); + assertEquals(GenericMessage.class, message.getClass()); + assertNotNull(message.getPayload()); + assertEquals(new User("John", 23), message.getPayload()); + } + + @Test + public void testGenericMessageWithHeaders() { + // TODO: Создайте сообщение с payload-ом "Hello" и header-ом "to":"World" + Map headers = null; + Message message = null; + + assertNotNull(message); + assertEquals("Hello", message.getPayload()); + assertEquals("World", message.getHeaders().get("to", String.class)); + } + + @Test + public void testGenericMessageWithMessageHeaders() { + // TODO: Создайте сообщение с payload-ом "Hello" и header-ом "to":"World" + MessageHeaders headers = null; + Message message = null; + + assertNotNull(message); + assertEquals("Hello", message.getPayload()); + assertEquals("World", message.getHeaders().get("to", String.class)); + } + + @Test + public void testErrorMessage() { + // TODO: Создайте сообщение об ошибки с объектом NullPointerException внутри + Message errorMessage = null; + + assertNotNull(errorMessage); + assertEquals(ErrorMessage.class, errorMessage.getClass()); + assertEquals(NullPointerException.class, errorMessage.getPayload().getClass()); + } + + @Test + public void testMessageBuilder() { + // TODO: Создайте сообщение с payload-ом "Hello" и header-ом "to":"World" с помощью MessageBuilder + Message message = null; + + assertNotNull(message); + assertEquals("Hello", message.getPayload()); + assertEquals("World", message.getHeaders().get("to", String.class)); + } + + @Test + public void testBuildFromMessage() { + Message original = MessageBuilder + .withPayload(new User("Kate", 30)) + .setHeader("processor", "userService") + .build(); + + // TODO: Создайте новое сообщение с теми же payload и header-ами c помощью MessageBuilder + Message newMessage = null; + + assertNotNull(newMessage); + assertEquals(original.getPayload(), newMessage.getPayload()); + assertEquals(original.getHeaders().get("processor"), newMessage.getHeaders().get("processor")); + } +} diff --git a/2022-11/spring-30/spring-30-exercise/src/test/java/ru/otus/spring/integration/User.java b/2022-11/spring-30/spring-30-exercise/src/test/java/ru/otus/spring/integration/User.java new file mode 100644 index 00000000..5dd81ef8 --- /dev/null +++ b/2022-11/spring-30/spring-30-exercise/src/test/java/ru/otus/spring/integration/User.java @@ -0,0 +1,36 @@ +package ru.otus.spring.integration; + +import java.util.Objects; + +public class User { + + private final String name; + private final int age; + + public User(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof User)) return false; + User user = (User) o; + return age == user.age && + Objects.equals(name, user.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } +} diff --git a/2022-11/spring-30/spring-30-solution/pom.xml b/2022-11/spring-30/spring-30-solution/pom.xml new file mode 100644 index 00000000..d280368c --- /dev/null +++ b/2022-11/spring-30/spring-30-solution/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + ru.otus + spring-30-solution + 1.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.7.9 + + + + 11 + 11 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-integration + + + org.springframework + spring-messaging + + + + org.springframework.boot + spring-boot-starter-test + + + org.projectlombok + lombok + true + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/2022-11/spring-30/spring-30-solution/src/main/java/ru/otus/spring/integration/App.java b/2022-11/spring-30/spring-30-solution/src/main/java/ru/otus/spring/integration/App.java new file mode 100644 index 00000000..49630427 --- /dev/null +++ b/2022-11/spring-30/spring-30-solution/src/main/java/ru/otus/spring/integration/App.java @@ -0,0 +1,70 @@ +package ru.otus.spring.integration; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.integration.annotation.IntegrationComponentScan; +import org.springframework.integration.channel.QueueChannel; +import org.springframework.integration.dsl.MessageChannels; +import org.springframework.integration.support.MessageBuilder; +import org.springframework.messaging.PollableChannel; +import org.springframework.messaging.SubscribableChannel; + +import lombok.extern.slf4j.Slf4j; + + +@SpringBootApplication +@IntegrationComponentScan +@Slf4j +public class App { + + public static void main(String[] args) throws InterruptedException { + ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args); + + PollableChannel queueChannel = ctx.getBean("queueChannel", PollableChannel.class); + SubscribableChannel directChannel = ctx.getBean("directChannel", SubscribableChannel.class); + + + log.warn("INIT"); + for (int i = 0; i < 10; i++) { + queueChannel.send(MessageBuilder.withPayload("Start " + i).build()); + } + log.warn("INIT FINISH"); + Thread.sleep(5000); + + log.warn("START"); + directChannel.subscribe((msg) -> log.warn("Receive msg: {}", msg)); + new Thread(() -> { + while (true) { + directChannel.send(queueChannel.receive()); + } + }).start(); + log.warn("START FINISH"); + Thread.sleep(5000); + + log.warn(""); + queueChannel.send(MessageBuilder.withPayload("Hello").build()); + Thread.sleep(5000); + + log.warn(""); + queueChannel.send(MessageBuilder.withPayload("Hello2").build()); + Thread.sleep(5000); + + log.warn(""); + queueChannel.send(MessageBuilder.withPayload("Hello3").build()); + + } + + @Bean + public PollableChannel queueChannel() { + return new QueueChannel(10); + } + + @Bean + public SubscribableChannel directChannel() { + return MessageChannels.direct("channel2").get(); + } + +} + diff --git a/2022-11/spring-30/spring-30-solution/src/main/resources/application.yml b/2022-11/spring-30/spring-30-solution/src/main/resources/application.yml new file mode 100644 index 00000000..1a9aeb48 --- /dev/null +++ b/2022-11/spring-30/spring-30-solution/src/main/resources/application.yml @@ -0,0 +1,5 @@ +logging: + level: + root: info + + org.springframework.integration: debug \ No newline at end of file diff --git a/2022-11/spring-30/spring-30-solution/src/test/java/ru/otus/spring/integration/MessagesTest.java b/2022-11/spring-30/spring-30-solution/src/test/java/ru/otus/spring/integration/MessagesTest.java new file mode 100644 index 00000000..496c003f --- /dev/null +++ b/2022-11/spring-30/spring-30-solution/src/test/java/ru/otus/spring/integration/MessagesTest.java @@ -0,0 +1,101 @@ +package ru.otus.spring.integration; + + +import org.junit.jupiter.api.Test; +import org.springframework.messaging.Message; +import org.springframework.messaging.MessageHeaders; +import org.springframework.messaging.support.ErrorMessage; +import org.springframework.messaging.support.GenericMessage; +import org.springframework.messaging.support.MessageBuilder; + +import java.util.Collections; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + + +@SuppressWarnings("all") +public class MessagesTest { + + @Test + public void testCreateSimpleGenericMessage() { + // TODO: Создайте сообщение с payload-ом "Hello" с помощью конструктора + Message message = new GenericMessage("Hello"); + + assertNotNull(message); + assertEquals(GenericMessage.class, message.getClass()); + assertNotNull(message.getPayload()); + assertEquals("Hello", message.getPayload()); + } + + @Test + public void testCreateGenericMessage() { + // TODO: Создайте сообщение с пользователем с помощью конструктора + Message message = new GenericMessage(new User("John", 23)); + + assertNotNull(message); + assertEquals(GenericMessage.class, message.getClass()); + assertNotNull(message.getPayload()); + assertEquals(new User("John", 23), message.getPayload()); + } + + @Test + public void testGenericMessageWithHeaders() { + // TODO: Создайте сообщение с payload-ом "Hello" и header-ом "to":"World" + Map headers = Collections.singletonMap("to", "World"); + Message message = new GenericMessage<>("Hello", headers); + + assertNotNull(message); + assertEquals("Hello", message.getPayload()); + assertEquals("World", message.getHeaders().get("to", String.class)); + } + + @Test + public void testGenericMessageWithMessageHeaders() { + // TODO: Создайте сообщение с payload-ом "Hello" и header-ом "to":"World" + MessageHeaders headers = new MessageHeaders(Collections.singletonMap("to", "World")); + Message message = new GenericMessage<>("Hello", headers); + + assertNotNull(message); + assertEquals("Hello", message.getPayload()); + assertEquals("World", message.getHeaders().get("to", String.class)); + } + + @Test + public void testErrorMessage() { + // TODO: Создайте сообщение об ошибки с объектом NullPointerException внутри + Message errorMessage = new ErrorMessage(new NullPointerException()); + + assertNotNull(errorMessage); + assertEquals(ErrorMessage.class, errorMessage.getClass()); + assertEquals(NullPointerException.class, errorMessage.getPayload().getClass()); + } + + @Test + public void testMessageBuilder() { + // TODO: Создайте сообщение с payload-ом "Hello" и header-ом "to":"World" с помощью MessageBuilder + Message message = MessageBuilder.withPayload("Hello") + .setHeader("to", "World") + .build(); + + assertNotNull(message); + assertEquals("Hello", message.getPayload()); + assertEquals("World", message.getHeaders().get("to", String.class)); + } + + @Test + public void testBuildFromMessage() { + Message original = MessageBuilder + .withPayload(new User("Kate", 30)) + .setHeader("processor", "userService") + .build(); + + // TODO: Создайте новое сообщение с теми же payload и header-ами c помощью MessageBuilder + Message newMessage = MessageBuilder.fromMessage(original).build(); + + assertNotNull(newMessage); + assertEquals(original.getPayload(), newMessage.getPayload()); + assertEquals(original.getHeaders().get("processor"), newMessage.getHeaders().get("processor")); + } +} diff --git a/2022-11/spring-30/spring-30-solution/src/test/java/ru/otus/spring/integration/User.java b/2022-11/spring-30/spring-30-solution/src/test/java/ru/otus/spring/integration/User.java new file mode 100644 index 00000000..5dd81ef8 --- /dev/null +++ b/2022-11/spring-30/spring-30-solution/src/test/java/ru/otus/spring/integration/User.java @@ -0,0 +1,36 @@ +package ru.otus.spring.integration; + +import java.util.Objects; + +public class User { + + private final String name; + private final int age; + + public User(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public int getAge() { + return age; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof User)) return false; + User user = (User) o; + return age == user.age && + Objects.equals(name, user.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } +}