diff --git a/spring-all/README.md b/spring-all/README.md index ded5e26285..34e5c3435e 100644 --- a/spring-all/README.md +++ b/spring-all/README.md @@ -4,10 +4,12 @@ This project is used to replicate Spring Exceptions only. -###The Course +### The Course + The "REST With Spring" Classes: http://bit.ly/restwithspring - -### Relevant articles: + +### Relevant articles: + - [Guide to Spring @Autowired](http://www.baeldung.com/spring-autowire) - [Properties with Spring](http://www.baeldung.com/properties-with-spring) - checkout the `org.baeldung.properties` package for all scenarios of properties injection and usage - [Spring Profiles](http://www.baeldung.com/spring-profiles) @@ -30,3 +32,4 @@ The "REST With Spring" Classes: http://bit.ly/restwithspring - [Spring Web Contexts](http://www.baeldung.com/spring-web-contexts) - [Spring Cache – Creating a Custom KeyGenerator](http://www.baeldung.com/spring-cache-custom-keygenerator) - [Spring @Primary Annotation](http://www.baeldung.com/spring-primary) +- [Spring Events](https://www.baeldung.com/spring-events) diff --git a/spring-all/src/main/java/org/baeldung/springevents/synchronous/AnnotationDrivenEventListener.java b/spring-all/src/main/java/org/baeldung/springevents/synchronous/AnnotationDrivenEventListener.java new file mode 100644 index 0000000000..f750c40a6e --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springevents/synchronous/AnnotationDrivenEventListener.java @@ -0,0 +1,46 @@ +package org.baeldung.springevents.synchronous; + +import org.springframework.context.event.ContextStartedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; +import org.springframework.transaction.event.TransactionPhase; +import org.springframework.transaction.event.TransactionalEventListener; + +@Component +public class AnnotationDrivenEventListener { + + // for tests + private boolean hitContextStartedHandler = false; + private boolean hitSuccessfulEventHandler = false; + private boolean hitCustomEventHandler = false; + + @EventListener + public void handleContextStart(final ContextStartedEvent cse) { + System.out.println("Handling context started event."); + hitContextStartedHandler = true; + } + + @EventListener(condition = "#event.success") + public void handleSuccessful(final GenericSpringEvent event) { + System.out.println("Handling generic event (conditional): " + event.getWhat()); + hitSuccessfulEventHandler = true; + } + + @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT) + public void handleCustom(final CustomSpringEvent event) { + System.out.println("Handling event inside a transaction BEFORE COMMIT."); + hitCustomEventHandler = true; + } + + boolean isHitContextStartedHandler() { + return hitContextStartedHandler; + } + + boolean isHitSuccessfulEventHandler() { + return hitSuccessfulEventHandler; + } + + boolean isHitCustomEventHandler() { + return hitCustomEventHandler; + } +} diff --git a/spring-all/src/main/java/org/baeldung/springevents/synchronous/ContextRefreshedListener.java b/spring-all/src/main/java/org/baeldung/springevents/synchronous/ContextRefreshedListener.java index 052437e555..9f8b2e6e83 100644 --- a/spring-all/src/main/java/org/baeldung/springevents/synchronous/ContextRefreshedListener.java +++ b/spring-all/src/main/java/org/baeldung/springevents/synchronous/ContextRefreshedListener.java @@ -7,9 +7,16 @@ import org.springframework.stereotype.Component; @Component public class ContextRefreshedListener implements ApplicationListener { + // for tests + private boolean hitContextRefreshedHandler = false; + @Override public void onApplicationEvent(final ContextRefreshedEvent cse) { System.out.println("Handling context re-freshed event. "); + hitContextRefreshedHandler = true; } + boolean isHitContextRefreshedHandler() { + return hitContextRefreshedHandler; + } } \ No newline at end of file diff --git a/spring-all/src/main/java/org/baeldung/springevents/synchronous/CustomSpringEventPublisher.java b/spring-all/src/main/java/org/baeldung/springevents/synchronous/CustomSpringEventPublisher.java index 4569de1d5e..3182090d5d 100644 --- a/spring-all/src/main/java/org/baeldung/springevents/synchronous/CustomSpringEventPublisher.java +++ b/spring-all/src/main/java/org/baeldung/springevents/synchronous/CustomSpringEventPublisher.java @@ -16,4 +16,16 @@ public class CustomSpringEventPublisher { applicationEventPublisher.publishEvent(customSpringEvent); } + public void publishGenericEvent(final String message, boolean success) { + System.out.println("Publishing generic event."); + final GenericSpringEvent genericSpringEvent = new GenericStringSpringEvent(message, success); + applicationEventPublisher.publishEvent(genericSpringEvent); + } + + public void publishGenericAppEvent(final String message) { + System.out.println("Publishing generic event."); + final GenericSpringAppEvent genericSpringEvent = new GenericStringSpringAppEvent(this, message); + applicationEventPublisher.publishEvent(genericSpringEvent); + } + } diff --git a/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringAppEvent.java b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringAppEvent.java new file mode 100644 index 0000000000..6804312189 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringAppEvent.java @@ -0,0 +1,18 @@ +package org.baeldung.springevents.synchronous; + +import org.springframework.context.ApplicationEvent; + +public class GenericSpringAppEvent extends ApplicationEvent { + + private final T what; + + public GenericSpringAppEvent(final Object source, final T what) { + super(source); + this.what = what; + } + + public T getWhat() { + return what; + } + +} diff --git a/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringEvent.java b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringEvent.java new file mode 100644 index 0000000000..ce2c223fec --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringEvent.java @@ -0,0 +1,21 @@ +package org.baeldung.springevents.synchronous; + +public class GenericSpringEvent { + + private final T what; + protected final boolean success; + + public GenericSpringEvent(final T what, final boolean success) { + this.what = what; + this.success = success; + } + + public T getWhat() { + return what; + } + + public boolean isSuccess() { + return success; + } + +} diff --git a/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringEventListener.java b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringEventListener.java new file mode 100644 index 0000000000..1f5e3e7068 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericSpringEventListener.java @@ -0,0 +1,22 @@ +package org.baeldung.springevents.synchronous; + +import org.springframework.context.ApplicationListener; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; + +@Component +public class GenericSpringEventListener implements ApplicationListener> { + + // for testing + private boolean hitEventHandler = false; + + @Override + public void onApplicationEvent(@NonNull final GenericSpringAppEvent event) { + System.out.println("Received spring generic event - " + event.getWhat()); + hitEventHandler = true; + } + + boolean isHitEventHandler() { + return hitEventHandler; + } +} \ No newline at end of file diff --git a/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericStringSpringAppEvent.java b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericStringSpringAppEvent.java new file mode 100644 index 0000000000..fd214696e7 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericStringSpringAppEvent.java @@ -0,0 +1,9 @@ +package org.baeldung.springevents.synchronous; + +class GenericStringSpringAppEvent extends GenericSpringAppEvent { + + GenericStringSpringAppEvent(final Object source, final String what) { + super(source, what); + } + +} diff --git a/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericStringSpringEvent.java b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericStringSpringEvent.java new file mode 100644 index 0000000000..dd4e4e3ed4 --- /dev/null +++ b/spring-all/src/main/java/org/baeldung/springevents/synchronous/GenericStringSpringEvent.java @@ -0,0 +1,9 @@ +package org.baeldung.springevents.synchronous; + +public class GenericStringSpringEvent extends GenericSpringEvent { + + GenericStringSpringEvent(final String what, final boolean success) { + super(what, success); + } + +} diff --git a/spring-all/src/test/java/org/baeldung/springevents/synchronous/ContextRefreshedListenerIntegrationTest.java b/spring-all/src/test/java/org/baeldung/springevents/synchronous/ContextRefreshedListenerIntegrationTest.java index ac8758bbf6..e8e6f91b06 100644 --- a/spring-all/src/test/java/org/baeldung/springevents/synchronous/ContextRefreshedListenerIntegrationTest.java +++ b/spring-all/src/test/java/org/baeldung/springevents/synchronous/ContextRefreshedListenerIntegrationTest.java @@ -3,16 +3,23 @@ package org.baeldung.springevents.synchronous; import org.baeldung.springevents.synchronous.SynchronousSpringEventsConfig; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; +import static org.springframework.util.Assert.isTrue; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { SynchronousSpringEventsConfig.class }, loader = AnnotationConfigContextLoader.class) public class ContextRefreshedListenerIntegrationTest { + @Autowired + private ContextRefreshedListener listener; + @Test - public void testContextRefreshedListener() throws InterruptedException { + public void testContextRefreshedListener() { System.out.println("Test context re-freshed listener."); + isTrue(listener.isHitContextRefreshedHandler(), "Refresh should be called once"); } } \ No newline at end of file diff --git a/spring-all/src/test/java/org/baeldung/springevents/synchronous/GenericAppEventListenerIntegrationTest.java b/spring-all/src/test/java/org/baeldung/springevents/synchronous/GenericAppEventListenerIntegrationTest.java new file mode 100644 index 0000000000..f183314b6d --- /dev/null +++ b/spring-all/src/test/java/org/baeldung/springevents/synchronous/GenericAppEventListenerIntegrationTest.java @@ -0,0 +1,28 @@ +package org.baeldung.springevents.synchronous; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +import static org.springframework.util.Assert.isTrue; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes = { SynchronousSpringEventsConfig.class }, loader = AnnotationConfigContextLoader.class) +public class GenericAppEventListenerIntegrationTest { + + @Autowired + private CustomSpringEventPublisher publisher; + @Autowired + private GenericSpringEventListener listener; + + @Test + public void testGenericSpringEvent() { + isTrue(!listener.isHitEventHandler(), "The initial value should be false"); + publisher.publishGenericAppEvent("Hello world!!!"); + isTrue(listener.isHitEventHandler(), "Now the value should be changed to true"); + } + +} \ No newline at end of file diff --git a/spring-all/src/test/java/org/baeldung/springevents/synchronous/SynchronousCustomSpringEventsIntegrationTest.java b/spring-all/src/test/java/org/baeldung/springevents/synchronous/SynchronousCustomSpringEventsIntegrationTest.java index f9783f57dc..b169cfec36 100644 --- a/spring-all/src/test/java/org/baeldung/springevents/synchronous/SynchronousCustomSpringEventsIntegrationTest.java +++ b/spring-all/src/test/java/org/baeldung/springevents/synchronous/SynchronousCustomSpringEventsIntegrationTest.java @@ -1,5 +1,6 @@ package org.baeldung.springevents.synchronous; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -7,16 +8,42 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.support.AnnotationConfigContextLoader; +import static org.springframework.util.Assert.isTrue; + @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { SynchronousSpringEventsConfig.class }, loader = AnnotationConfigContextLoader.class) public class SynchronousCustomSpringEventsIntegrationTest { @Autowired private CustomSpringEventPublisher publisher; + @Autowired + private AnnotationDrivenEventListener listener; @Test - public void testCustomSpringEvents() throws InterruptedException { + public void testCustomSpringEvents() { + isTrue(!listener.isHitCustomEventHandler(), "The value should be false"); publisher.publishEvent("Hello world!!"); System.out.println("Done publishing synchronous custom event. "); + isTrue(listener.isHitCustomEventHandler(), "Now the value should be changed to true"); + } + + @Test + public void testGenericSpringEvent() { + isTrue(!listener.isHitSuccessfulEventHandler(), "The initial value should be false"); + publisher.publishGenericEvent("Hello world!!!", true); + isTrue(listener.isHitSuccessfulEventHandler(), "Now the value should be changed to true"); + } + + @Test + public void testGenericSpringEventNotProcessed() { + isTrue(!listener.isHitSuccessfulEventHandler(), "The initial value should be false"); + publisher.publishGenericEvent("Hello world!!!", false); + isTrue(!listener.isHitSuccessfulEventHandler(), "The value should still be false"); + } + + @Ignore("fix me") + @Test + public void testContextStartedEvent() { + isTrue(listener.isHitContextStartedHandler(), "Start should be called once"); } }