INT-4042: Support Known Router Channels in Graph
JIRA: https://jira.spring.io/browse/INT-4042 ``` ... }, { "nodeId" : 24, "name" : "integrationGraphServerTests.Config.router.router", "stats" : { ... } }, "componentType" : "router", "output" : "discards", "input" : "four", "routes" : [ "barChannel", "bazChannel" ], "errors" : "myErrors" }, { ... "from" : 3, "to" : 24, "type" : "input" }, { "from" : 24, "to" : 7, "type" : "output" }, { "from" : 24, "to" : 2, "type" : "error" }, { "from" : 24, "to" : 5, "type" : "route" }, { "from" : 24, "to" : 6, "type" : "route" ... ``` Add Graph Support for RecipientListRouter The RLR is not an AMMR; it's the only router outside of that class hierarchy. Polishing Add Dynamically Routed-to Channels to Graph Add ExpressionBased and Expose Expression in Graph Polishing Add getExpressionString() to IOS Add ExpressionCapable; Set Primary Expression Polishing - PR Comments Router/Expression Docs * Simple Java Docs polishing
This commit is contained in:
committed by
Artem Bilan
parent
dae1a01003
commit
a30809be38
@@ -98,7 +98,9 @@ public class ServiceActivatorFactoryBean extends AbstractStandardMessageHandlerF
|
||||
protected MessageHandler createExpressionEvaluatingHandler(Expression expression) {
|
||||
ExpressionEvaluatingMessageProcessor<Object> processor = new ExpressionEvaluatingMessageProcessor<Object>(expression);
|
||||
processor.setBeanFactory(this.getBeanFactory());
|
||||
return this.configureHandler(new ServiceActivatingHandler(processor));
|
||||
ServiceActivatingHandler handler = new ServiceActivatingHandler(processor);
|
||||
handler.setPrimaryExpression(expression);
|
||||
return this.configureHandler(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -63,7 +63,9 @@ public class TransformerFactoryBean extends AbstractStandardMessageHandlerFactor
|
||||
@Override
|
||||
protected MessageHandler createExpressionEvaluatingHandler(Expression expression) {
|
||||
Transformer transformer = new ExpressionEvaluatingTransformer(expression);
|
||||
return this.createHandler(transformer);
|
||||
MessageTransformingHandler handler = this.createHandler(transformer);
|
||||
handler.setPrimaryExpression(expression);
|
||||
return handler;
|
||||
}
|
||||
|
||||
protected MessageTransformingHandler createHandler(Transformer transformer) {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.context;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
|
||||
/**
|
||||
* Components that implement this interface are capable of supporting a primary
|
||||
* SpEL expression as part of their configuration.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
public interface ExpressionCapable {
|
||||
|
||||
/**
|
||||
* Return the primary SpEL expression if this component is expression-based.
|
||||
* @return the expression as a String.
|
||||
*/
|
||||
Expression getExpression();
|
||||
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.support.DefaultMessageBuilderFactory;
|
||||
@@ -63,7 +64,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
public abstract class IntegrationObjectSupport implements BeanNameAware, NamedComponent,
|
||||
ApplicationContextAware, BeanFactoryAware, InitializingBean {
|
||||
ApplicationContextAware, BeanFactoryAware, InitializingBean, ExpressionCapable {
|
||||
|
||||
protected static final ExpressionParser EXPRESSION_PARSER = new SpelExpressionParser();
|
||||
|
||||
@@ -92,6 +93,8 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
|
||||
|
||||
private volatile MessageBuilderFactory messageBuilderFactory;
|
||||
|
||||
private Expression expression;
|
||||
|
||||
@Override
|
||||
public final void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
@@ -144,6 +147,20 @@ public abstract class IntegrationObjectSupport implements BeanNameAware, NamedCo
|
||||
this.channelResolver = channelResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression getExpression() {
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* For expression-based components, set the primary expression.
|
||||
* @param expression the expression.
|
||||
* @since 4.3
|
||||
*/
|
||||
public final void setPrimaryExpression(Expression expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void afterPropertiesSet() {
|
||||
this.integrationProperties = IntegrationContextUtils.getIntegrationProperties(this.beanFactory);
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.integration.endpoint;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.integration.context.IntegrationObjectSupport;
|
||||
import org.springframework.integration.core.MessageProducer;
|
||||
import org.springframework.integration.router.MessageRouter;
|
||||
import org.springframework.integration.support.context.NamedComponent;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
@@ -58,6 +59,9 @@ public class EventDrivenConsumer extends AbstractEndpoint implements Integration
|
||||
if (this.handler instanceof MessageProducer) {
|
||||
return ((MessageProducer) this.handler).getOutputChannel();
|
||||
}
|
||||
else if (this.handler instanceof MessageRouter) {
|
||||
return ((MessageRouter) this.handler).getDefaultOutputChannel();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.endpoint;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.context.ExpressionCapable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -24,7 +25,7 @@ import org.springframework.util.Assert;
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ExpressionEvaluatingMessageSource<T> extends AbstractMessageSource<T> {
|
||||
public class ExpressionEvaluatingMessageSource<T> extends AbstractMessageSource<T> implements ExpressionCapable {
|
||||
|
||||
private final Expression expression;
|
||||
|
||||
@@ -47,4 +48,9 @@ public class ExpressionEvaluatingMessageSource<T> extends AbstractMessageSource<
|
||||
return this.evaluateExpression(this.expression, this.expectedType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression getExpression() {
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.integration.channel.ExecutorChannelInterceptorAware;
|
||||
import org.springframework.integration.core.MessageProducer;
|
||||
import org.springframework.integration.router.MessageRouter;
|
||||
import org.springframework.integration.transaction.IntegrationResourceHolder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
@@ -83,6 +84,9 @@ public class PollingConsumer extends AbstractPollingEndpoint implements Integrat
|
||||
if (this.handler instanceof MessageProducer) {
|
||||
return ((MessageProducer) this.handler).getOutputChannel();
|
||||
}
|
||||
else if (this.handler instanceof MessageRouter) {
|
||||
return ((MessageRouter) this.handler).getDefaultOutputChannel();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.support.NameMatchMethodPointcutAdvisor;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.integration.aop.AbstractMessageSourceAdvice;
|
||||
import org.springframework.integration.context.ExpressionCapable;
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.history.MessageHistory;
|
||||
@@ -66,6 +67,9 @@ public class SourcePollingChannelAdapter extends AbstractPollingEndpoint
|
||||
*/
|
||||
public void setSource(MessageSource<?> source) {
|
||||
this.source = source;
|
||||
if (source instanceof ExpressionCapable) {
|
||||
setPrimaryExpression(((ExpressionCapable) source).getExpression());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -25,6 +25,7 @@ import org.springframework.util.Assert;
|
||||
* the provided {@link Expression} expecting a <b>void return</b>.
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @see MethodInvokingMessageHandler
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -36,9 +37,9 @@ public class ExpressionEvaluatingMessageHandler extends AbstractMessageHandler {
|
||||
|
||||
|
||||
public ExpressionEvaluatingMessageHandler(Expression expression) {
|
||||
Assert.notNull(expression, "Expression must not be null");
|
||||
this.processor = new ExpressionEvaluatingMessageProcessor<Void>(
|
||||
expression, Void.class);
|
||||
Assert.notNull(expression, "'expression' must not be null");
|
||||
this.processor = new ExpressionEvaluatingMessageProcessor<Void>(expression, Void.class);
|
||||
setPrimaryExpression(expression);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,9 +19,12 @@ package org.springframework.integration.router;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -50,6 +53,21 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter implements MappingMessageRouterManagement {
|
||||
|
||||
private static final int DEFAULT_DYNAMIC_CHANNEL_LIMIT = 100;
|
||||
|
||||
private int dynamicChannelLimit = DEFAULT_DYNAMIC_CHANNEL_LIMIT;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
private final Map<String, MessageChannel> dynamicChannels = Collections.<String, MessageChannel>synchronizedMap(
|
||||
new LinkedHashMap<String, MessageChannel>(DEFAULT_DYNAMIC_CHANNEL_LIMIT, 0.75f, true) {
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Entry<String, MessageChannel> eldest) {
|
||||
return this.size() > AbstractMappingMessageRouter.this.dynamicChannelLimit;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
protected volatile Map<String, String> channelMappings = new ConcurrentHashMap<String, String>();
|
||||
|
||||
private volatile String prefix;
|
||||
@@ -97,6 +115,18 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
|
||||
this.resolutionRequired = resolutionRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a limit for how many dynamic channels are retained (for reporting purposes).
|
||||
* When the limit is exceeded, the oldest channel is discarded.
|
||||
* <p><b>NOTE: this does not affect routing, just the reporting which dynamically
|
||||
* resolved channels have been routed to.</b> Default {@code 100}.
|
||||
* @param dynamicChannelLimit the limit.
|
||||
* @see #getDynamicChannelNames()
|
||||
*/
|
||||
public void setDynamicChannelLimit(int dynamicChannelLimit) {
|
||||
this.dynamicChannelLimit = dynamicChannelLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable version of the channel mappings.
|
||||
* This is intended for use by subclasses only.
|
||||
@@ -133,6 +163,12 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
|
||||
this.channelMappings = newChannelMappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ManagedAttribute
|
||||
public Collection<String> getDynamicChannelNames() {
|
||||
return Collections.unmodifiableSet(this.dynamicChannels.keySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must implement this method to return the channel keys.
|
||||
* A "key" might be present in this router's "channelMappings", or it
|
||||
@@ -208,8 +244,10 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
|
||||
// if the channelMappings contains a mapping, we'll use the mapped value
|
||||
// otherwise, the String-based channelKey itself will be used as the channel name
|
||||
String channelName = channelKey;
|
||||
boolean mapped = false;
|
||||
if (this.channelMappings.containsKey(channelKey)) {
|
||||
channelName = this.channelMappings.get(channelKey);
|
||||
mapped = true;
|
||||
}
|
||||
if (this.prefix != null) {
|
||||
channelName = this.prefix + channelName;
|
||||
@@ -220,6 +258,9 @@ public abstract class AbstractMappingMessageRouter extends AbstractMessageRouter
|
||||
MessageChannel channel = resolveChannelForName(channelName, message);
|
||||
if (channel != null) {
|
||||
channels.add(channel);
|
||||
if (!mapped && !(this.dynamicChannels.get(channelName) != null)) {
|
||||
this.dynamicChannels.put(channelName, channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
@ManagedResource
|
||||
@IntegrationManagedResource
|
||||
public abstract class AbstractMessageRouter extends AbstractMessageHandler {
|
||||
public abstract class AbstractMessageRouter extends AbstractMessageHandler implements MessageRouter {
|
||||
|
||||
private volatile MessageChannel defaultOutputChannel;
|
||||
|
||||
@@ -69,6 +69,24 @@ public abstract class AbstractMessageRouter extends AbstractMessageHandler {
|
||||
this.defaultOutputChannel = defaultOutputChannel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default output channel.
|
||||
* @return the channel.
|
||||
* @since 4.3
|
||||
*/
|
||||
@Override
|
||||
public MessageChannel getDefaultOutputChannel() {
|
||||
if (this.defaultOutputChannelName != null) {
|
||||
synchronized (this) {
|
||||
if (this.defaultOutputChannelName != null) {
|
||||
this.defaultOutputChannel = getChannelResolver().resolveDestination(this.defaultOutputChannelName);
|
||||
this.defaultOutputChannelName = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.defaultOutputChannel;
|
||||
}
|
||||
|
||||
public void setDefaultOutputChannelName(String defaultOutputChannelName) {
|
||||
Assert.hasText(defaultOutputChannelName, "'defaultOutputChannelName' must not be empty");
|
||||
this.defaultOutputChannelName = defaultOutputChannelName;
|
||||
@@ -188,14 +206,7 @@ public abstract class AbstractMessageRouter extends AbstractMessageHandler {
|
||||
}
|
||||
}
|
||||
if (!sent) {
|
||||
if (this.defaultOutputChannelName != null) {
|
||||
synchronized (this) {
|
||||
if (this.defaultOutputChannelName != null) {
|
||||
this.defaultOutputChannel = getChannelResolver().resolveDestination(this.defaultOutputChannelName);
|
||||
this.defaultOutputChannelName = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
getDefaultOutputChannel();
|
||||
if (this.defaultOutputChannel != null) {
|
||||
this.messagingTemplate.send(this.defaultOutputChannel, message);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -25,12 +25,14 @@ import org.springframework.integration.handler.ExpressionEvaluatingMessageProces
|
||||
* resolved to a channel name or a Collection (or Array) of strings.
|
||||
*
|
||||
* @author Mark Fisher
|
||||
* @author Gary Russell
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ExpressionEvaluatingRouter extends AbstractMessageProcessingRouter {
|
||||
|
||||
public ExpressionEvaluatingRouter(Expression expression) {
|
||||
super(new ExpressionEvaluatingMessageProcessor<Object>(expression));
|
||||
setPrimaryExpression(expression);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.router;
|
||||
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
/**
|
||||
* Routers implementing this interface have a default output channel.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
public interface MessageRouter {
|
||||
|
||||
/**
|
||||
* Get the default output channel.
|
||||
* @return the channel.
|
||||
*/
|
||||
MessageChannel getDefaultOutputChannel();
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -34,6 +34,7 @@ public class ExpressionEvaluatingSplitter extends AbstractMessageProcessingSplit
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
public ExpressionEvaluatingSplitter(Expression expression) {
|
||||
super(new ExpressionEvaluatingMessageProcessor(expression));
|
||||
setPrimaryExpression(expression);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.integration.support.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -53,7 +54,6 @@ public interface MappingMessageRouterManagement {
|
||||
/**
|
||||
* Provide mappings from channel keys to channel names.
|
||||
* @param channelMappings The channel mappings.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
@ManagedOperation
|
||||
@@ -61,7 +61,6 @@ public interface MappingMessageRouterManagement {
|
||||
|
||||
/**
|
||||
* @return an unmodifiable map of channel mappings.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
@ManagedAttribute
|
||||
@@ -70,12 +69,21 @@ public interface MappingMessageRouterManagement {
|
||||
/**
|
||||
* Provide mappings from channel keys to channel names.
|
||||
* Channel names will be resolved by the {@link DestinationResolver}.
|
||||
*
|
||||
* @param channelMappings The channel mappings.
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
@ManagedAttribute
|
||||
void setChannelMappings(Map<String, String> channelMappings);
|
||||
|
||||
/**
|
||||
* Provide a collection of channel names to which
|
||||
* we have routed messages where the channel was not explicitly mapped.
|
||||
* <p> Implementations may choose to return only the most recent channel names.
|
||||
* @return a collection of channel names to which
|
||||
* we have routed messages where the channel was not explicitly mapped.
|
||||
* @since 4.3
|
||||
*/
|
||||
@ManagedAttribute
|
||||
Collection<String> getDynamicChannelNames();
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.integration.support.management;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -62,4 +63,9 @@ public class RouterMetrics extends LifecycleMessageHandlerMetrics implements Map
|
||||
this.router.setChannelMappings(channelMappings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getDynamicChannelNames() {
|
||||
return this.router.getDynamicChannelNames();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.support.management.graph;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
|
||||
/**
|
||||
* Represents an endpoint that can route to multiple channels and can emit errors
|
||||
* (pollable endpoint).
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
public class ErrorCapableRoutingNode extends RoutingMessageHandlerNode implements ErrorCapableNode {
|
||||
|
||||
private final String errors;
|
||||
|
||||
public ErrorCapableRoutingNode(int nodeId, String name, MessageHandler handler, String input, String output,
|
||||
String errors, Collection<String> routes) {
|
||||
super(nodeId, name, handler, input, output, routes);
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getErrors() {
|
||||
return this.errors;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -38,7 +38,10 @@ import org.springframework.integration.gateway.GatewayProxyFactoryBean;
|
||||
import org.springframework.integration.gateway.MessagingGatewaySupport;
|
||||
import org.springframework.integration.handler.CompositeMessageHandler;
|
||||
import org.springframework.integration.handler.DiscardingMessageHandler;
|
||||
import org.springframework.integration.router.RecipientListRouter.Recipient;
|
||||
import org.springframework.integration.router.RecipientListRouterManagement;
|
||||
import org.springframework.integration.support.context.NamedComponent;
|
||||
import org.springframework.integration.support.management.MappingMessageRouterManagement;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -172,8 +175,14 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat
|
||||
for (Entry<Method, MessagingGatewaySupport> gwEntry : methodMap.entrySet()) {
|
||||
MessagingGatewaySupport gateway = gwEntry.getValue();
|
||||
Method method = gwEntry.getKey();
|
||||
Class<?>[] parameterTypes = method.getParameterTypes();
|
||||
String[] parameterTypeNames = new String[parameterTypes.length];
|
||||
int i = 0;
|
||||
for (Class<?> type : parameterTypes) {
|
||||
parameterTypeNames[i++] = type.getName();
|
||||
}
|
||||
String signature = method.getName() +
|
||||
"(" + StringUtils.arrayToCommaDelimitedString(method.getParameterTypes()) + ")";
|
||||
"(" + StringUtils.arrayToCommaDelimitedString(parameterTypeNames) + ")";
|
||||
MessageGatewayNode gatewayNode = this.nodeFactory.gatewayNode(
|
||||
entry.getKey().substring(1) + "." + signature, gateway);
|
||||
nodes.add(gatewayNode);
|
||||
@@ -232,6 +241,15 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat
|
||||
links.add(new LinkNode(endpointNode.getNodeId(), channelNode.getNodeId(), LinkNode.Type.discard));
|
||||
}
|
||||
}
|
||||
if (endpointNode instanceof RoutingMessageHandlerNode) {
|
||||
Collection<String> routes = ((RoutingMessageHandlerNode) endpointNode).getRoutes();
|
||||
for (String route : routes) {
|
||||
channelNode = channelNodes.get(route);
|
||||
if (channelNode != null) {
|
||||
links.add(new LinkNode(endpointNode.getNodeId(), channelNode.getNodeId(), LinkNode.Type.route));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -275,13 +293,26 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat
|
||||
MessageChannel outputChannel = consumer.getOutputChannel();
|
||||
String outputChannelName = outputChannel == null ? null : outputChannel.toString();
|
||||
MessageHandler handler = consumer.getHandler();
|
||||
return handler instanceof CompositeMessageHandler
|
||||
? compositeHandler(name, consumer, (CompositeMessageHandler) handler, outputChannelName, null, false)
|
||||
: handler instanceof DiscardingMessageHandler
|
||||
? discardingHandler(name, consumer, (DiscardingMessageHandler) handler, outputChannelName, null,
|
||||
false)
|
||||
: new MessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), outputChannelName);
|
||||
if (handler instanceof CompositeMessageHandler) {
|
||||
return compositeHandler(name, consumer, (CompositeMessageHandler) handler, outputChannelName, null,
|
||||
false);
|
||||
}
|
||||
else if (handler instanceof DiscardingMessageHandler) {
|
||||
return discardingHandler(name, consumer, (DiscardingMessageHandler) handler, outputChannelName, null,
|
||||
false);
|
||||
}
|
||||
else if (handler instanceof MappingMessageRouterManagement) {
|
||||
return routingHandler(name, consumer, handler, (MappingMessageRouterManagement) handler,
|
||||
outputChannelName, null, false);
|
||||
}
|
||||
else if (handler instanceof RecipientListRouterManagement) {
|
||||
return recipientListRoutingHandler(name, consumer, handler, (RecipientListRouterManagement) handler,
|
||||
outputChannelName, null, false);
|
||||
}
|
||||
else {
|
||||
return new MessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), outputChannelName);
|
||||
}
|
||||
}
|
||||
|
||||
private MessageHandlerNode polledHandlerNode(String name, PollingConsumer consumer) {
|
||||
@@ -290,14 +321,26 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat
|
||||
String errorChannel = consumer.getDefaultErrorChannel() != null
|
||||
? consumer.getDefaultErrorChannel().toString() : null;
|
||||
MessageHandler handler = consumer.getHandler();
|
||||
return handler instanceof CompositeMessageHandler
|
||||
? compositeHandler(name, consumer, (CompositeMessageHandler) handler, outputChannelName, errorChannel,
|
||||
true)
|
||||
: handler instanceof DiscardingMessageHandler
|
||||
? discardingHandler(name, consumer, (DiscardingMessageHandler) handler, outputChannelName,
|
||||
errorChannel, true)
|
||||
: new ErrorCapableMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), outputChannelName, errorChannel);
|
||||
if (handler instanceof CompositeMessageHandler) {
|
||||
return compositeHandler(name, consumer, (CompositeMessageHandler) handler, outputChannelName,
|
||||
errorChannel, true);
|
||||
}
|
||||
else if (handler instanceof DiscardingMessageHandler) {
|
||||
return discardingHandler(name, consumer, (DiscardingMessageHandler) handler, outputChannelName,
|
||||
errorChannel, true);
|
||||
}
|
||||
else if (handler instanceof MappingMessageRouterManagement) {
|
||||
return routingHandler(name, consumer, handler, (MappingMessageRouterManagement) handler,
|
||||
outputChannelName, errorChannel, true);
|
||||
}
|
||||
else if (handler instanceof RecipientListRouterManagement) {
|
||||
return recipientListRoutingHandler(name, consumer, handler, (RecipientListRouterManagement) handler,
|
||||
outputChannelName, errorChannel, true);
|
||||
}
|
||||
else {
|
||||
return new ErrorCapableMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), outputChannelName, errorChannel);
|
||||
}
|
||||
}
|
||||
|
||||
private MessageHandlerNode compositeHandler(String name, IntegrationConsumer consumer,
|
||||
@@ -314,18 +357,48 @@ public class IntegrationGraphServer implements ApplicationContextAware, Applicat
|
||||
}
|
||||
return polled
|
||||
? new ErrorCapableCompositeMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), output, errors, innerHandlers)
|
||||
consumer.getInputChannel().toString(), output, errors, innerHandlers)
|
||||
: new CompositeMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), output, innerHandlers);
|
||||
consumer.getInputChannel().toString(), output, innerHandlers);
|
||||
}
|
||||
|
||||
private MessageHandlerNode discardingHandler(String name, IntegrationConsumer consumer,
|
||||
DiscardingMessageHandler handler, String output, String errors, boolean polled) {
|
||||
return polled
|
||||
? new ErrorCapableDiscardingMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), output, handler.getDiscardChannel().toString(), errors)
|
||||
consumer.getInputChannel().toString(), output, handler.getDiscardChannel().toString(), errors)
|
||||
: new DiscardingMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), output, handler.getDiscardChannel().toString());
|
||||
consumer.getInputChannel().toString(), output, handler.getDiscardChannel().toString());
|
||||
}
|
||||
|
||||
private MessageHandlerNode routingHandler(String name, IntegrationConsumer consumer, MessageHandler handler,
|
||||
MappingMessageRouterManagement router, String output, String errors, boolean polled) {
|
||||
Collection<String> routes = router.getChannelMappings().values();
|
||||
Collection<String> dynamicChannelNames = router.getDynamicChannelNames();
|
||||
if (dynamicChannelNames.size() > 0) {
|
||||
routes = new ArrayList<String>(routes);
|
||||
routes.addAll(dynamicChannelNames);
|
||||
}
|
||||
return polled
|
||||
? new ErrorCapableRoutingNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), output, errors, routes)
|
||||
: new RoutingMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), output, routes);
|
||||
}
|
||||
|
||||
private MessageHandlerNode recipientListRoutingHandler(String name, IntegrationConsumer consumer,
|
||||
MessageHandler handler, RecipientListRouterManagement router, String output, String errors,
|
||||
boolean polled) {
|
||||
Collection<?> recipients = router.getRecipients();
|
||||
List<String> routes = new ArrayList<String>(recipients.size());
|
||||
for (Object recipient : recipients) {
|
||||
routes.add(((Recipient) recipient).getChannel().toString());
|
||||
}
|
||||
return polled
|
||||
? new ErrorCapableRoutingNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), output, errors, routes)
|
||||
: new RoutingMessageHandlerNode(this.nodeId.incrementAndGet(), name, handler,
|
||||
consumer.getInputChannel().toString(), output, routes);
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
|
||||
package org.springframework.integration.support.management.graph;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.integration.context.ExpressionCapable;
|
||||
import org.springframework.integration.support.context.NamedComponent;
|
||||
|
||||
/**
|
||||
@@ -35,12 +40,20 @@ public abstract class IntegrationNode {
|
||||
|
||||
private final String componentType;
|
||||
|
||||
private final Map<String, Object> properties = new HashMap<String, Object>();
|
||||
|
||||
protected IntegrationNode(int nodeId, String name, Object nodeObject, Stats stats) {
|
||||
this.nodeId = nodeId;
|
||||
this.name = name;
|
||||
this.componentType = nodeObject instanceof NamedComponent ? ((NamedComponent) nodeObject).getComponentType()
|
||||
: nodeObject.getClass().getSimpleName();
|
||||
this.stats = stats;
|
||||
if (nodeObject instanceof ExpressionCapable) {
|
||||
Expression expression = ((ExpressionCapable) nodeObject).getExpression();
|
||||
if (expression != null) {
|
||||
this.properties.put("expression", expression.getExpressionString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getNodeId() {
|
||||
@@ -59,6 +72,10 @@ public abstract class IntegrationNode {
|
||||
return this.stats.isAvailable() ? this.stats : null;
|
||||
}
|
||||
|
||||
public Map<String, Object> getProperties() {
|
||||
return this.properties.size() == 0 ? null : this.properties;
|
||||
}
|
||||
|
||||
public static class Stats {
|
||||
|
||||
protected boolean isAvailable() {
|
||||
|
||||
@@ -50,7 +50,7 @@ public class LinkNode {
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
input, output, error, discard
|
||||
input, output, error, discard, route
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.support.management.graph;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
|
||||
/**
|
||||
* Represents an endpoint that can route to multiple channels.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 4.3
|
||||
*
|
||||
*/
|
||||
public class RoutingMessageHandlerNode extends MessageHandlerNode {
|
||||
|
||||
private final Collection<String> routes;
|
||||
|
||||
public RoutingMessageHandlerNode(int nodeId, String name, MessageHandler handler, String input, String output,
|
||||
Collection<String> routes) {
|
||||
super(nodeId, name, handler, input, output);
|
||||
this.routes = routes;
|
||||
}
|
||||
|
||||
public Collection<String> getRoutes() {
|
||||
return this.routes;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-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.
|
||||
@@ -16,10 +16,14 @@
|
||||
|
||||
package org.springframework.integration.router;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
@@ -33,6 +37,7 @@ import org.springframework.messaging.core.DestinationResolver;
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
*/
|
||||
public class HeaderValueRouterTests {
|
||||
|
||||
@@ -51,6 +56,7 @@ public class HeaderValueRouterTests {
|
||||
Message<?> result = testChannel.receive(1000);
|
||||
assertNotNull(result);
|
||||
assertSame(message, result);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -84,6 +90,7 @@ public class HeaderValueRouterTests {
|
||||
result = channel.receive(1000);
|
||||
assertNotNull(result);
|
||||
assertSame(message, result);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -107,7 +114,9 @@ public class HeaderValueRouterTests {
|
||||
Message<?> result = channel.receive(1000);
|
||||
assertNotNull(result);
|
||||
assertSame(message, result);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public void resolveChannelNameFromMapAndCustomeResolver() {
|
||||
@@ -120,6 +129,7 @@ public class HeaderValueRouterTests {
|
||||
routerBeanDefinition.getPropertyValues().addPropertyValue("channelMappings", channelMappings);
|
||||
routerBeanDefinition.getPropertyValues().addPropertyValue("beanFactory", context);
|
||||
routerBeanDefinition.getPropertyValues().addPropertyValue("channelResolver", new DestinationResolver<MessageChannel>() {
|
||||
@Override
|
||||
public MessageChannel resolveDestination(String channelName) {
|
||||
return context.getBean("anotherChannel", MessageChannel.class);
|
||||
}
|
||||
@@ -135,6 +145,7 @@ public class HeaderValueRouterTests {
|
||||
Message<?> result = channel.receive(1000);
|
||||
assertNotNull(result);
|
||||
assertSame(message, result);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -159,6 +170,7 @@ public class HeaderValueRouterTests {
|
||||
assertNotNull(result2);
|
||||
assertSame(message, result1);
|
||||
assertSame(message, result2);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -183,7 +195,33 @@ public class HeaderValueRouterTests {
|
||||
assertNotNull(result2);
|
||||
assertSame(message, result1);
|
||||
assertSame(message, result2);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dynamicChannelCache() {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
RootBeanDefinition routerBeanDefinition = new RootBeanDefinition(HeaderValueRouter.class);
|
||||
routerBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue("testHeaderName");
|
||||
routerBeanDefinition.getPropertyValues().addPropertyValue("resolutionRequired", "true");
|
||||
routerBeanDefinition.getPropertyValues().addPropertyValue("dynamicChannelLimit", "2");
|
||||
context.registerBeanDefinition("router", routerBeanDefinition);
|
||||
context.registerBeanDefinition("channel1", new RootBeanDefinition(QueueChannel.class));
|
||||
context.registerBeanDefinition("channel2", new RootBeanDefinition(QueueChannel.class));
|
||||
context.registerBeanDefinition("channel3", new RootBeanDefinition(QueueChannel.class));
|
||||
context.refresh();
|
||||
MessageHandler handler = (MessageHandler) context.getBean("router");
|
||||
String channels = "channel1, channel2, channel1, channel3";
|
||||
Message<?> message = MessageBuilder.withPayload("test").setHeader("testHeaderName", channels).build();
|
||||
handler.handleMessage(message);
|
||||
QueueChannel channel1 = (QueueChannel) context.getBean("channel1");
|
||||
QueueChannel channel2 = (QueueChannel) context.getBean("channel2");
|
||||
QueueChannel channel3 = (QueueChannel) context.getBean("channel3");
|
||||
assertThat(channel1.getQueueSize(), equalTo(2));
|
||||
assertThat(channel2.getQueueSize(), equalTo(1));
|
||||
assertThat(channel3.getQueueSize(), equalTo(1));
|
||||
assertThat(context.getBean(HeaderValueRouter.class).getDynamicChannelNames(), contains("channel1", "channel3"));
|
||||
context.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -32,8 +33,10 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.annotation.IntegrationComponentScan;
|
||||
import org.springframework.integration.annotation.MessagingGateway;
|
||||
import org.springframework.integration.annotation.Router;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.channel.DirectChannel;
|
||||
import org.springframework.integration.channel.MessagePublishingErrorHandler;
|
||||
@@ -44,8 +47,13 @@ import org.springframework.integration.core.MessageProducer;
|
||||
import org.springframework.integration.endpoint.EventDrivenConsumer;
|
||||
import org.springframework.integration.endpoint.MessageProducerSupport;
|
||||
import org.springframework.integration.endpoint.PollingConsumer;
|
||||
import org.springframework.integration.router.ExpressionEvaluatingRouter;
|
||||
import org.springframework.integration.router.HeaderValueRouter;
|
||||
import org.springframework.integration.router.RecipientListRouter;
|
||||
import org.springframework.integration.scheduling.PollerMetadata;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.PollableChannel;
|
||||
@@ -69,6 +77,10 @@ public class IntegrationGraphServerTests {
|
||||
@Autowired
|
||||
private IntegrationGraphServer server;
|
||||
|
||||
@Autowired
|
||||
private MessageChannel toRouter;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void test() throws Exception {
|
||||
Graph graph = this.server.getGraph();
|
||||
@@ -76,17 +88,39 @@ public class IntegrationGraphServerTests {
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
objectMapper.writeValue(baos, graph);
|
||||
|
||||
// System . out . println(new String(baos.toByteArray()));
|
||||
|
||||
Map<?, ?> map = objectMapper.readValue(baos.toByteArray(), Map.class);
|
||||
assertThat(map.size(), is(equalTo(3)));
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<?, ?>> nodes = (List<Map<?, ?>>) map.get("nodes");
|
||||
assertThat(nodes, is(notNullValue()));
|
||||
assertThat(nodes.size(), is(equalTo(22)));
|
||||
@SuppressWarnings("unchecked")
|
||||
assertThat(nodes.size(), is(equalTo(31)));
|
||||
List<Map<?, ?>> links = (List<Map<?, ?>>) map.get("links");
|
||||
assertThat(links, is(notNullValue()));
|
||||
assertThat(links.size(), is(equalTo(20)));
|
||||
assertThat(links.size(), is(equalTo(32)));
|
||||
|
||||
toRouter.send(MessageBuilder.withPayload("foo").setHeader("foo", "bar").build());
|
||||
toRouter.send(MessageBuilder.withPayload("foo").setHeader("foo", "baz").build());
|
||||
toRouter.send(MessageBuilder.withPayload("foo").setHeader("foo", "quxChannel").build());
|
||||
toRouter.send(MessageBuilder.withPayload("foo").setHeader("foo", "fizChannel").build());
|
||||
|
||||
this.server.rebuild();
|
||||
graph = this.server.getGraph();
|
||||
baos = new ByteArrayOutputStream();
|
||||
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
objectMapper.writeValue(baos, graph);
|
||||
|
||||
// System . out . println(new String(baos.toByteArray()));
|
||||
|
||||
map = objectMapper.readValue(baos.toByteArray(), Map.class);
|
||||
assertThat(map.size(), is(equalTo(3)));
|
||||
nodes = (List<Map<?, ?>>) map.get("nodes");
|
||||
assertThat(nodes, is(notNullValue()));
|
||||
assertThat(nodes.size(), is(equalTo(31)));
|
||||
links = (List<Map<?, ?>>) map.get("links");
|
||||
assertThat(links, is(notNullValue()));
|
||||
assertThat(links.size(), is(equalTo(34)));
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -165,6 +199,64 @@ public class IntegrationGraphServerTests {
|
||||
return poller;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Router(inputChannel = "toRouter")
|
||||
public HeaderValueRouter router() {
|
||||
HeaderValueRouter router = new HeaderValueRouter("foo");
|
||||
router.setChannelMapping("bar", "barChannel");
|
||||
router.setChannelMapping("baz", "bazChannel");
|
||||
router.setDefaultOutputChannel(discards());
|
||||
return router;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Router(inputChannel = "four")
|
||||
public RecipientListRouter rlRouter() {
|
||||
RecipientListRouter router = new RecipientListRouter();
|
||||
router.setChannels(Arrays.asList(barChannel(), bazChannel()));
|
||||
router.setDefaultOutputChannel(discards());
|
||||
return router;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Router(inputChannel = "four")
|
||||
public ExpressionEvaluatingRouter expressionRouter() {
|
||||
ExpressionEvaluatingRouter router = new ExpressionEvaluatingRouter(
|
||||
new SpelExpressionParser().parseExpression("headers['foo']"));
|
||||
router.setDefaultOutputChannel(discards());
|
||||
return router;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel discards() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel toRouter() {
|
||||
return new DirectChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel barChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel bazChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel quxChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MessageChannel fizChannel() {
|
||||
return new QueueChannel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Services {
|
||||
|
||||
@@ -307,9 +307,11 @@ public abstract class AbstractRemoteFileOutboundGateway<F> extends AbstractReply
|
||||
Assert.notNull(remoteFileTemplate, "'remoteFileTemplate' cannot be null");
|
||||
this.remoteFileTemplate = remoteFileTemplate;
|
||||
this.command = command;
|
||||
Expression parsedExpression = new SpelExpressionParser().parseExpression(expression);
|
||||
this.fileNameProcessor = new ExpressionEvaluatingMessageProcessor<String>(
|
||||
new SpelExpressionParser().parseExpression(expression));
|
||||
parsedExpression);
|
||||
this.messageSessionCallback = null;
|
||||
setPrimaryExpression(parsedExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -217,6 +217,7 @@ public class JmsOutboundGateway extends AbstractReplyProducingMessageHandler imp
|
||||
Assert.notNull(requestDestinationExpression, "'requestDestinationExpression' must not be null");
|
||||
this.requestDestinationExpressionProcessor =
|
||||
new ExpressionEvaluatingMessageProcessor<Object>(requestDestinationExpression);
|
||||
setPrimaryExpression(requestDestinationExpression);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -70,6 +70,7 @@ public class JmsSendingMessageHandler extends AbstractMessageHandler {
|
||||
Assert.isTrue(this.destination == null && this.destinationName == null,
|
||||
"The 'destination', 'destinationName', and 'destinationExpression' properties are mutually exclusive.");
|
||||
this.destinationExpressionProcessor = new ExpressionEvaluatingMessageProcessor<Object>(destinationExpression);
|
||||
setPrimaryExpression(destinationExpression);
|
||||
}
|
||||
|
||||
public void setHeaderMapper(JmsHeaderMapper headerMapper) {
|
||||
|
||||
@@ -84,6 +84,10 @@ The possible types are:
|
||||
- _output_ - the direction from `MessageHandler`, `MessageProducer` or `SourcePollingChannelAdapter` to the `MessageChannel` via an `outputChannel` or `replyChannel` property;
|
||||
- _error_ - from `MessageHandler` on `PollingConsumer` or `MessageProducer` or `SourcePollingChannelAdapter` to the `MessageChannel` via an `errorChannel` property;
|
||||
- _discard_ - from `DiscardingMessageHandler` (e.g. `MessageFilter`) to the `MessageChannel` via `errorChannel` property.
|
||||
- _route_ - from `AbstractMappingMessageRouter` (e.g. `HeaderValueRouter`) to the `MessageChannel`.
|
||||
Similar to _output_ but determined at run-time.
|
||||
May be a configured channel mapping, or a dynamically resolved channel.
|
||||
Routers will typically only retain up to 100 dynamic routes for this purpose, but this can be modified using the `dynamicChannelLimit` property.
|
||||
|
||||
The information from this element can be used by a visualizing tool to render connections between nodes from the `nodes` graph element, where the `from` and `to` numbers represent the value from the `nodeId` property of the linked nodes.
|
||||
For example the link `type` can be used to determine the proper _port_ on the target node:
|
||||
@@ -105,6 +109,8 @@ For example the link `type` can be used to determine the proper _port_ on the ta
|
||||
----
|
||||
|
||||
The `nodes` graph element is perhaps the most interesting because its elements contain not only the runtime components with their `componentType` s and `name` s, but can also optionally contain metrics exposed by the component.
|
||||
Node elements contain various properties which are generally self-explanatory.
|
||||
For example, expression-based components include the `expression` property containing the primary expression string for the component.
|
||||
To enable the metrics, add an `@EnableIntegrationManagement` to some `@Configuration` class or add an `<int:management/>` element to your XML configuration.
|
||||
You can control exactly which components in the framework collect statistics.
|
||||
See <<metrics-management>> for complete information.
|
||||
|
||||
Reference in New Issue
Block a user