GH-3241: MetadataStoreSelector - compare old/new (#3242)
Resolves: https://github.com/spring-projects/spring-integration/issues/3241 * Docs and XML namespace support.
This commit is contained in:
@@ -59,6 +59,8 @@ public class IdempotentReceiverInterceptorParser extends AbstractBeanDefinitionP
|
||||
boolean hasValueStrategy = StringUtils.hasText(valueStrategy);
|
||||
String valueExpression = element.getAttribute("value-expression");
|
||||
boolean hasValueExpression = StringUtils.hasText(valueExpression);
|
||||
String compareValues = element.getAttribute("compare-values");
|
||||
boolean hasCompareValues = StringUtils.hasText(compareValues);
|
||||
|
||||
String endpoints = element.getAttribute("endpoint");
|
||||
|
||||
@@ -68,10 +70,10 @@ public class IdempotentReceiverInterceptorParser extends AbstractBeanDefinitionP
|
||||
}
|
||||
|
||||
if (hasSelector && (hasStore || hasKeyStrategy || hasKeyExpression || hasValueStrategy // NOSONAR complexity
|
||||
|| hasValueExpression)) {
|
||||
|| hasValueExpression || hasCompareValues)) {
|
||||
parserContext.getReaderContext().error("The 'selector' attribute is mutually exclusive with " +
|
||||
"'metadata-store', 'key-strategy', 'key-expression', 'value-strategy' " +
|
||||
"or 'value-expression'", source);
|
||||
"'metadata-store', 'key-strategy', 'key-expression', 'value-strategy', " +
|
||||
"'value-expression', and 'compare-values'", source);
|
||||
}
|
||||
|
||||
if (hasKeyStrategy && hasKeyExpression) {
|
||||
@@ -133,6 +135,7 @@ public class IdempotentReceiverInterceptorParser extends AbstractBeanDefinitionP
|
||||
else {
|
||||
selectorBuilder.addConstructorArgValue(new RootBeanDefinition(SimpleMetadataStore.class));
|
||||
}
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(selectorBuilder, element, "compare-values");
|
||||
selectorBeanDefinition = selectorBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2019 the original author or authors.
|
||||
* Copyright 2014-2020 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.
|
||||
@@ -16,10 +16,13 @@
|
||||
|
||||
package org.springframework.integration.selector;
|
||||
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
import org.springframework.integration.core.MessageSelector;
|
||||
import org.springframework.integration.handler.MessageProcessor;
|
||||
import org.springframework.integration.metadata.ConcurrentMetadataStore;
|
||||
import org.springframework.integration.metadata.SimpleMetadataStore;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -58,6 +61,9 @@ public class MetadataStoreSelector implements MessageSelector {
|
||||
|
||||
private final MessageProcessor<String> valueStrategy;
|
||||
|
||||
@Nullable
|
||||
private BiPredicate<String, String> compareValues;
|
||||
|
||||
public MetadataStoreSelector(MessageProcessor<String> keyStrategy) {
|
||||
this(keyStrategy, (MessageProcessor<String>) null);
|
||||
}
|
||||
@@ -79,6 +85,26 @@ public class MetadataStoreSelector implements MessageSelector {
|
||||
this.valueStrategy = valueStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link BiPredicate} to compare old and new values in the metadata store for
|
||||
* the key. The first parameter is the old value; return true if we should accept this
|
||||
* message and replace the old value with the new value.
|
||||
* @param compareValues the {@link BiPredicate}.
|
||||
* @since 5.3
|
||||
*/
|
||||
public void setCompareValues(@Nullable BiPredicate<String, String> compareValues) {
|
||||
this.compareValues = compareValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fluent version of {@link #setCompareValues(BiPredicate)}.
|
||||
* @param compareValues the {@link BiPredicate}.
|
||||
* @return this.
|
||||
*/
|
||||
public MetadataStoreSelector compareValues(@Nullable BiPredicate<String, String> compareValues) {
|
||||
setCompareValues(compareValues);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(Message<?> message) {
|
||||
@@ -88,7 +114,21 @@ public class MetadataStoreSelector implements MessageSelector {
|
||||
? this.valueStrategy.processMessage(message)
|
||||
: (timestamp == null ? "0" : Long.toString(timestamp));
|
||||
|
||||
return this.metadataStore.putIfAbsent(key, value) == null;
|
||||
if (this.compareValues == null) {
|
||||
return this.metadataStore.putIfAbsent(key, value) == null;
|
||||
}
|
||||
else {
|
||||
synchronized (this) {
|
||||
String oldValue = this.metadataStore.get(key);
|
||||
if (oldValue == null) {
|
||||
return this.metadataStore.putIfAbsent(key, value) == null;
|
||||
}
|
||||
if (this.compareValues.test(oldValue, value)) {
|
||||
return this.metadataStore.replace(key, oldValue, value);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4853,6 +4853,19 @@ The list of component name patterns you want to track (e.g., tracked-components
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="compare-values">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="java.util.function.BiPredicate"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
<xsd:documentation><![CDATA[
|
||||
A 'BiPredicate<String, String>' which is called if a value exists to determine whether the message
|
||||
should be accepted and the old value replaced with the new value in the metadata store.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="discard-channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
|
||||
Reference in New Issue
Block a user