diff --git a/SPR-13278/pom.xml b/SPR-13278/pom.xml
new file mode 100644
index 00000000..1a788d6a
--- /dev/null
+++ b/SPR-13278/pom.xml
@@ -0,0 +1,74 @@
+
+
+ 4.0.0
+
+ net.lkrnac.book.eiws
+ auto-acknowledge-listener-duplicate-fail
+ 0.0.2-SNAPSHOT
+ jar
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 1.2.5.RELEASE
+
+
+
+
+ UTF-8
+ 1.8
+
+
+
+
+
+ org.hornetq
+ hornetq-jms-server
+
+
+ org.springframework.boot
+ spring-boot-starter-hornetq
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.16.4
+
+
+
+
+ com.h2database
+ h2
+
+
+ org.springframework
+ spring-tx
+
+
+ org.springframework
+ spring-jdbc
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ junit
+ junit
+
+
+
+
+ org.testng
+ testng
+ 6.8.8
+ test
+
+
+
diff --git a/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/JmsApplication.java b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/JmsApplication.java
new file mode 100644
index 00000000..507563bc
--- /dev/null
+++ b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/JmsApplication.java
@@ -0,0 +1,13 @@
+package net.lkrnac.book.eiws.chapter06.text;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+@SpringBootApplication
+@EnableScheduling
+public class JmsApplication {
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(JmsApplication.class, args);
+ }
+}
diff --git a/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/JmsConfiguration.java b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/JmsConfiguration.java
new file mode 100644
index 00000000..22c6ae22
--- /dev/null
+++ b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/JmsConfiguration.java
@@ -0,0 +1,19 @@
+package net.lkrnac.book.eiws.chapter06.text;
+
+import javax.jms.ConnectionFactory;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jms.config.SimpleJmsListenerContainerFactory;
+
+@Configuration
+public class JmsConfiguration {
+ @Bean
+ public SimpleJmsListenerContainerFactory jmsListenerContainerFactory(
+ ConnectionFactory connectionFactory) {
+ SimpleJmsListenerContainerFactory factory =
+ new SimpleJmsListenerContainerFactory();
+ factory.setConnectionFactory(connectionFactory);
+ return factory;
+ }
+}
diff --git a/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleMessageListener.java b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleMessageListener.java
new file mode 100644
index 00000000..2bf33814
--- /dev/null
+++ b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleMessageListener.java
@@ -0,0 +1,33 @@
+package net.lkrnac.book.eiws.chapter06.text;
+
+import javax.jms.Session;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class SimpleMessageListener {
+ private SimpleService simpleService;
+ private boolean errorSimulated = false;
+
+ @Autowired
+ public SimpleMessageListener(SimpleService simpleService) {
+ super();
+ this.simpleService = simpleService;
+ }
+
+ @JmsListener(destination = "ExpiryQueue")
+ public void readMessage(String message, Session session) {
+ simpleService.processText(message);
+ postprocess(message);
+ }
+
+ private void postprocess(String message) {
+ // simulate error
+ if (!errorSimulated) {
+ errorSimulated = true;
+ throw new IllegalArgumentException(message);
+ }
+ }
+}
diff --git a/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleMessageSender.java b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleMessageSender.java
new file mode 100644
index 00000000..463a0282
--- /dev/null
+++ b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleMessageSender.java
@@ -0,0 +1,28 @@
+package net.lkrnac.book.eiws.chapter06.text;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@Slf4j
+@Component
+public class SimpleMessageSender {
+ private static final String SIMPLE_MESSAGE = "simple message";
+ private JmsTemplate jmsTemplate;
+
+ @Autowired
+ public SimpleMessageSender(JmsTemplate jmsTemplate) {
+ super();
+ this.jmsTemplate = jmsTemplate;
+ }
+
+ // @PostConstruct
+ @Scheduled(initialDelay = 1000, fixedRate = Long.MAX_VALUE)
+ public void send() {
+ log.info("Sending message: {}", SIMPLE_MESSAGE);
+ jmsTemplate.convertAndSend("ExpiryQueue", SIMPLE_MESSAGE);
+ }
+}
diff --git a/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleRepository.java b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleRepository.java
new file mode 100644
index 00000000..0d90b20a
--- /dev/null
+++ b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleRepository.java
@@ -0,0 +1,35 @@
+package net.lkrnac.book.eiws.chapter06.text;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class SimpleRepository {
+ private final JdbcTemplate jdbcTemplate;
+ private static final String SELECT_COUNT =
+ "select count(*) from TEXT_TABLE where text = ?";
+
+ @Autowired
+ public SimpleRepository(JdbcTemplate jdbcTemplate) {
+ super();
+ this.jdbcTemplate = jdbcTemplate;
+ }
+
+ @PostConstruct
+ public void initDbTable() {
+ jdbcTemplate.execute("drop table TEXT_TABLE if exists");
+ jdbcTemplate.execute("create table TEXT_TABLE(TEXT varchar(30))");
+ }
+
+ public void persistText(String text) {
+ jdbcTemplate.update("insert into TEXT_TABLE values (?)", text);
+ }
+
+ public boolean containsText(String text) {
+ long count = jdbcTemplate.queryForObject(SELECT_COUNT, Long.class, text);
+ return count != 0;
+ }
+}
diff --git a/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleService.java b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleService.java
new file mode 100644
index 00000000..7ad4ef71
--- /dev/null
+++ b/SPR-13278/src/main/java/net/lkrnac/book/eiws/chapter06/text/SimpleService.java
@@ -0,0 +1,27 @@
+package net.lkrnac.book.eiws.chapter06.text;
+
+import lombok.extern.slf4j.Slf4j;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class SimpleService {
+ private final SimpleRepository simpleRepository;
+
+ @Autowired
+ public SimpleService(SimpleRepository simpleRepository) {
+ super();
+ this.simpleRepository = simpleRepository;
+ }
+
+ public void processText(String text) {
+ log.info("Process Message: {}", text);
+ simpleRepository.persistText(text);
+ }
+
+ public boolean isProcessed(String text) {
+ return simpleRepository.containsText(text);
+ }
+}
diff --git a/SPR-13278/src/main/resources/application.properties b/SPR-13278/src/main/resources/application.properties
new file mode 100644
index 00000000..54c604a3
--- /dev/null
+++ b/SPR-13278/src/main/resources/application.properties
@@ -0,0 +1,3 @@
+spring.hornetq.mode=embedded
+spring.hornetq.embedded.enabled=true
+spring.hornetq.embedded.queues=ExpiryQueue
diff --git a/SPR-13278/src/main/resources/logback.xml b/SPR-13278/src/main/resources/logback.xml
new file mode 100644
index 00000000..f562acc7
--- /dev/null
+++ b/SPR-13278/src/main/resources/logback.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SPR-13278/src/test/java/net/lkrnac/book/eiws/chapter06/text/JmsApplicationTests.java b/SPR-13278/src/test/java/net/lkrnac/book/eiws/chapter06/text/JmsApplicationTests.java
new file mode 100644
index 00000000..067a10e3
--- /dev/null
+++ b/SPR-13278/src/test/java/net/lkrnac/book/eiws/chapter06/text/JmsApplicationTests.java
@@ -0,0 +1,32 @@
+package net.lkrnac.book.eiws.chapter06.text;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.SpringApplicationConfiguration;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+@SpringApplicationConfiguration(classes = JmsApplication.class)
+public class JmsApplicationTests extends AbstractTestNGSpringContextTests {
+ private static final String SELECT_COUNT =
+ "select count(*) from TEXT_TABLE where text = ?";
+
+ private static final String MESSAGE_TEXT = "simple message";
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @Test(timeOut = 3000)
+ public void testJms() throws Exception {
+ // GIVEN: Spring configuration
+
+ // WHEN
+ Thread.sleep(2000);
+
+ // THEN
+ long count =
+ jdbcTemplate.queryForObject(SELECT_COUNT, Long.class, MESSAGE_TEXT);
+ Assert.assertEquals(count, 2);
+ }
+}