diff --git a/docs/src/reference/docbook/claim-check.xml b/docs/src/reference/docbook/claim-check.xml
index 585d65249c..9d9dad03ae 100644
--- a/docs/src/reference/docbook/claim-check.xml
+++ b/docs/src/reference/docbook/claim-check.xml
@@ -69,6 +69,20 @@
querying the Message store for a Message identified by the provided Claim Check. It then sends the newly checked-out Message to the
output-channel.
+ Claim Once
+
+ There are scenarios when a particular message must be claimed only once. Take the airplane luggage check-in/out process.
+ Checking-in your luggage on the departure and and then claiming it on the arrival is a classic example of such scenario.
+ Once the luggage was claimed it can no longer be claimed again without further check-in. To accommodate such cases we
+ introduced remove-message boolean attribute on claim-check-out transformer. This attribute is
+ set to false by default, however if set to true, the claimed Message will also be removed
+ from the MessageStore and can no longer be claimed again.
+ ]]>
+
Although we rarely care about the details of the claim checks as long as they work, it is still worth knowing that
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ClaimCheckOutParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ClaimCheckOutParser.java
index 6ca5e3f719..43c95abf7a 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ClaimCheckOutParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/ClaimCheckOutParser.java
@@ -26,6 +26,7 @@ import org.springframework.util.Assert;
* Parser for the <claim-check-out/> element.
*
* @author Mark Fisher
+ * @author Oleg Zhurakousky
* @since 2.0
*/
public class ClaimCheckOutParser extends AbstractTransformerParser {
@@ -39,6 +40,7 @@ public class ClaimCheckOutParser extends AbstractTransformerParser {
protected void parseTransformer(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
String messageStoreRef = element.getAttribute("message-store");
Assert.hasText(messageStoreRef, "The 'message-store' attribute is required.");
+ IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "remove-message");
builder.addConstructorArgReference(messageStoreRef);
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/transformer/ClaimCheckOutTransformer.java b/spring-integration-core/src/main/java/org/springframework/integration/transformer/ClaimCheckOutTransformer.java
index e57bbffda4..09aae080cb 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/transformer/ClaimCheckOutTransformer.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/transformer/ClaimCheckOutTransformer.java
@@ -29,11 +29,14 @@ import org.springframework.util.Assert;
* that ID can be retrieved from the given MessageStore.
*
* @author Mark Fisher
+ * @author Oleg Zhurakousky
* @since 2.0
*/
public class ClaimCheckOutTransformer extends AbstractTransformer {
private final MessageStore messageStore;
+
+ private volatile boolean removeMessage = false;
/**
@@ -43,7 +46,10 @@ public class ClaimCheckOutTransformer extends AbstractTransformer {
Assert.notNull(messageStore, "MessageStore must not be null");
this.messageStore = messageStore;
}
-
+
+ public void setRemoveMessage(boolean removeMessage) {
+ this.removeMessage = removeMessage;
+ }
@Override
protected Object doTransform(Message> message) throws Exception {
@@ -53,6 +59,10 @@ public class ClaimCheckOutTransformer extends AbstractTransformer {
Message> retrievedMessage = this.messageStore.getMessage(id);
Assert.notNull(retrievedMessage, "unable to locate Message for ID: " + id
+ " within MessageStore [" + this.messageStore + "]");
+ if (this.removeMessage){
+ this.messageStore.removeMessage(id);
+ logger.debug("Message with claim-check '" + id + "' was removed from MessageStore");
+ }
MessageBuilder> responseBuilder = MessageBuilder.fromMessage(retrievedMessage);
// headers on the 'current' message take precedence
responseBuilder.copyHeaders(message.getHeaders());
diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd
index cd7b049fac..e120d76d11 100644
--- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd
+++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd
@@ -1896,7 +1896,7 @@ endpoint itself is a Polling Consumer for a channel with a queue.
-
+
Defines a Transformer that accepts a Message whose payload is a UUID and
@@ -1905,6 +1905,20 @@ endpoint itself is a Polling Consumer for a channel with a queue.
available (else null).
+
+
+
+
+
+
+ If set to 'true' the Message will be removed from the MessageStore by
+ this transformer. Useful when Message can be 'claimed' only once. DFAULT is 'false'
+
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ClaimCheckParserTests-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ClaimCheckParserTests-context.xml
index 430ebea0d3..c3c80b96c2 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ClaimCheckParserTests-context.xml
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ClaimCheckParserTests-context.xml
@@ -25,6 +25,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ClaimCheckParserTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ClaimCheckParserTests.java
index bbcfa5b2bc..6267be6480 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ClaimCheckParserTests.java
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/ClaimCheckParserTests.java
@@ -16,9 +16,12 @@
package org.springframework.integration.config.xml;
+import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import java.util.UUID;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,6 +42,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Mark Fisher
+ * @author Oleg Zhurakousky
* @since 2.0
*/
@ContextConfiguration
@@ -50,6 +54,9 @@ public class ClaimCheckParserTests {
@Autowired
private MessageChannel checkinChannel;
+
+ @Autowired
+ private MessageChannel checkinChannelA;
@Autowired
private PollableChannel wiretap;
@@ -59,6 +66,9 @@ public class ClaimCheckParserTests {
@Autowired
private EventDrivenConsumer checkout;
+
+ @Autowired
+ private MessageStore sampleMessageStore;
@Test
@@ -86,10 +96,27 @@ public class ClaimCheckParserTests {
checkinChannel.send(message);
Message> wiretapMessage = wiretap.receive(0);
assertNotNull(wiretapMessage);
- assertEquals(message.getHeaders().getId(), wiretapMessage.getPayload());
+ UUID payload = (UUID) wiretapMessage.getPayload();
+ assertEquals(message.getHeaders().getId(), payload);
Message> resultMessage = replyChannel.receive(0);
assertNotNull(resultMessage);
assertEquals("test", resultMessage.getPayload());
+ assertNotNull(this.sampleMessageStore.getMessage(payload));
+ }
+
+ @Test
+ public void integrationTestWithRemoval() {
+ QueueChannel replyChannel = new QueueChannel();
+ Message> message = MessageBuilder.withPayload("test").setReplyChannel(replyChannel).build();
+ checkinChannelA.send(message);
+ Message> wiretapMessage = wiretap.receive(0);
+ assertNotNull(wiretapMessage);
+ UUID payload = (UUID) wiretapMessage.getPayload();
+ assertEquals(message.getHeaders().getId(), payload);
+ Message> resultMessage = replyChannel.receive(0);
+ assertNotNull(resultMessage);
+ assertEquals("test", resultMessage.getPayload());
+ assertNull(this.sampleMessageStore.getMessage(payload));
}
}