/* * Copyright 2016 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.integration.dsl; import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.function.Function; import org.aopalliance.aop.Advice; import org.springframework.integration.aggregator.AbstractCorrelatingMessageHandler; import org.springframework.integration.aggregator.CorrelationStrategy; import org.springframework.integration.aggregator.ExpressionEvaluatingCorrelationStrategy; import org.springframework.integration.aggregator.ExpressionEvaluatingReleaseStrategy; import org.springframework.integration.aggregator.ReleaseStrategy; import org.springframework.integration.config.CorrelationStrategyFactoryBean; import org.springframework.integration.config.ReleaseStrategyFactoryBean; import org.springframework.integration.expression.FunctionExpression; import org.springframework.integration.expression.ValueExpression; import org.springframework.integration.store.MessageGroup; import org.springframework.integration.store.MessageGroupStore; import org.springframework.integration.support.locks.LockRegistry; import org.springframework.messaging.MessageChannel; import org.springframework.scheduling.TaskScheduler; import org.springframework.util.Assert; /** * A {@link MessageHandlerSpec} for an {@link AbstractCorrelatingMessageHandler}. * * @param <S> the target {@link CorrelationHandlerSpec} implementation type. * @param <H> the {@link AbstractCorrelatingMessageHandler} implementation type. * * @author Artem Bilan * * @since 5.0 */ public abstract class CorrelationHandlerSpec<S extends CorrelationHandlerSpec<S, H>, H extends AbstractCorrelatingMessageHandler> extends ConsumerEndpointSpec<S, H> { private final List<Advice> forceReleaseAdviceChain = new LinkedList<Advice>(); protected CorrelationHandlerSpec(H messageHandler) { super(messageHandler); messageHandler.setForceReleaseAdviceChain(this.forceReleaseAdviceChain); } /** * @param messageStore the message group store. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setMessageStore(MessageGroupStore) */ public S messageStore(MessageGroupStore messageStore) { Assert.notNull(messageStore, "'messageStore' must not be null."); this.handler.setMessageStore(messageStore); return _this(); } /** * @param sendPartialResultOnExpiry the sendPartialResultOnExpiry. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setSendPartialResultOnExpiry(boolean) */ public S sendPartialResultOnExpiry(boolean sendPartialResultOnExpiry) { this.handler.setSendPartialResultOnExpiry(sendPartialResultOnExpiry); return _this(); } /** * @param minimumTimeoutForEmptyGroups the minimumTimeoutForEmptyGroups * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setMinimumTimeoutForEmptyGroups(long) */ public S minimumTimeoutForEmptyGroups(long minimumTimeoutForEmptyGroups) { this.handler.setMinimumTimeoutForEmptyGroups(minimumTimeoutForEmptyGroups); return _this(); } /** * Configure the handler with a group timeout expression that evaluates to * this constant value. * @param groupTimeout the group timeout in milliseconds. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setGroupTimeoutExpression * @see ValueExpression */ public S groupTimeout(long groupTimeout) { this.handler.setGroupTimeoutExpression(new ValueExpression<>(groupTimeout)); return _this(); } /** * @param groupTimeoutExpression the group timeout expression string. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setGroupTimeoutExpression */ public S groupTimeoutExpression(String groupTimeoutExpression) { Assert.hasText(groupTimeoutExpression, "'groupTimeoutExpression' must not be empty string."); this.handler.setGroupTimeoutExpression(PARSER.parseExpression(groupTimeoutExpression)); return _this(); } /** * Configure the handler with a function that will be invoked to resolve the group timeout, * based on the message group. * Usually used with a JDK8 lambda: * <p>{@code .groupTimeout(g -> g.size() * 2000L)}. * @param groupTimeoutFunction a function invoked to resolve the group timeout in milliseconds. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setGroupTimeoutExpression */ public S groupTimeout(Function<MessageGroup, Long> groupTimeoutFunction) { this.handler.setGroupTimeoutExpression(new FunctionExpression<>(groupTimeoutFunction)); return _this(); } /** * @param taskScheduler the task scheduler. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setTaskScheduler(TaskScheduler) */ public S taskScheduler(TaskScheduler taskScheduler) { Assert.notNull(taskScheduler, "'taskScheduler' must not be null."); this.handler.setTaskScheduler(taskScheduler); return _this(); } /** * @param discardChannel the discard channel. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setDiscardChannel(MessageChannel) */ public S discardChannel(MessageChannel discardChannel) { Assert.notNull(discardChannel, "'discardChannel' must not be null."); this.handler.setDiscardChannel(discardChannel); return _this(); } /** * @param discardChannelName the discard channel. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setDiscardChannelName(String) */ public S discardChannel(String discardChannelName) { Assert.hasText(discardChannelName, "'discardChannelName' must not be empty."); this.handler.setDiscardChannelName(discardChannelName); return _this(); } /** * Configure the handler with {@link org.springframework.integration.aggregator.MethodInvokingCorrelationStrategy} * and {@link org.springframework.integration.aggregator.MethodInvokingReleaseStrategy} using the target * object which should have methods annotated appropriately for each function. * @param target the target object * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setCorrelationStrategy(CorrelationStrategy) * @see AbstractCorrelatingMessageHandler#setReleaseStrategy(ReleaseStrategy) */ public S processor(Object target) { try { CorrelationStrategyFactoryBean correlationStrategyFactoryBean = new CorrelationStrategyFactoryBean(); correlationStrategyFactoryBean.setTarget(target); correlationStrategyFactoryBean.afterPropertiesSet(); ReleaseStrategyFactoryBean releaseStrategyFactoryBean = new ReleaseStrategyFactoryBean(); releaseStrategyFactoryBean.setTarget(target); releaseStrategyFactoryBean.afterPropertiesSet(); return correlationStrategy(correlationStrategyFactoryBean.getObject()) .releaseStrategy(releaseStrategyFactoryBean.getObject()); } catch (Exception e) { throw new IllegalStateException(e); } } /** * Configure the handler with an {@link ExpressionEvaluatingCorrelationStrategy} * for the given expression. * @param correlationExpression the correlation expression. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setCorrelationStrategy(CorrelationStrategy) */ public S correlationExpression(String correlationExpression) { return correlationStrategy(new ExpressionEvaluatingCorrelationStrategy(correlationExpression)); } /** * Configure the handler with an * {@link org.springframework.integration.aggregator.MethodInvokingCorrelationStrategy} * for the target object and method name. * @param target the target object. * @param methodName the method name. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setCorrelationStrategy(CorrelationStrategy) */ public S correlationStrategy(Object target, String methodName) { try { CorrelationStrategyFactoryBean correlationStrategyFactoryBean = new CorrelationStrategyFactoryBean(); correlationStrategyFactoryBean.setTarget(target); correlationStrategyFactoryBean.setMethodName(methodName); correlationStrategyFactoryBean.afterPropertiesSet(); return correlationStrategy(correlationStrategyFactoryBean.getObject()); } catch (Exception e) { throw new IllegalStateException(e); } } /** * @param correlationStrategy the correlation strategy. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setCorrelationStrategy(CorrelationStrategy) */ public S correlationStrategy(CorrelationStrategy correlationStrategy) { this.handler.setCorrelationStrategy(correlationStrategy); return _this(); } /** * Configure the handler with an {@link ExpressionEvaluatingReleaseStrategy} for the * given expression. * * @param releaseExpression the correlation expression. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setReleaseStrategy(ReleaseStrategy) */ public S releaseExpression(String releaseExpression) { return releaseStrategy(new ExpressionEvaluatingReleaseStrategy(releaseExpression)); } /** * Configure the handler with an * {@link org.springframework.integration.aggregator.MethodInvokingReleaseStrategy} * for the target object and method name. * @param target the target object. * @param methodName the method name. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setReleaseStrategy(ReleaseStrategy) */ public S releaseStrategy(Object target, String methodName) { try { ReleaseStrategyFactoryBean releaseStrategyFactoryBean = new ReleaseStrategyFactoryBean(); releaseStrategyFactoryBean.setTarget(target); releaseStrategyFactoryBean.setMethodName(methodName); releaseStrategyFactoryBean.afterPropertiesSet(); return releaseStrategy(releaseStrategyFactoryBean.getObject()); } catch (Exception e) { throw new IllegalStateException(e); } } /** * @param releaseStrategy the release strategy. * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setReleaseStrategy(ReleaseStrategy) */ public S releaseStrategy(ReleaseStrategy releaseStrategy) { this.handler.setReleaseStrategy(releaseStrategy); return _this(); } /** * Expire (completely remove) a group if it is completed due to timeout. * Default {@code true} for aggregator and {@code false} for resequencer. * @param expireGroupsUponTimeout the expireGroupsUponTimeout to set * @return the handler spec. * @see AbstractCorrelatingMessageHandler#setExpireGroupsUponTimeout */ public S expireGroupsUponTimeout(boolean expireGroupsUponTimeout) { this.handler.setExpireGroupsUponTimeout(expireGroupsUponTimeout); return _this(); } /** * Configure a list of {@link Advice} objects to be applied to the * {@code forceComplete()} operation. * @param advice the advice chain. * @return the endpoint spec. */ public S forceReleaseAdvice(Advice... advice) { this.forceReleaseAdviceChain.addAll(Arrays.asList(advice)); return _this(); } /** * Used to obtain a {@code Lock} based on the {@code groupId} for concurrent operations * on the {@code MessageGroup}. * By default, an internal {@code DefaultLockRegistry} is used. * Use of a distributed {@link LockRegistry}, such as the {@code RedisLockRegistry}, * ensures only one instance of the aggregator will operate on a group concurrently. * @param lockRegistry the {@link LockRegistry} to use. * @return the endpoint spec. */ public S lockRegistry(LockRegistry lockRegistry) { Assert.notNull(lockRegistry, "'lockRegistry' must not be null."); this.handler.setLockRegistry(lockRegistry); return _this(); } }