diff --git a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Polled.java b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Polled.java
index 1917127091..c1ebbf2e2a 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/annotation/Polled.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/annotation/Polled.java
@@ -23,6 +23,8 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import org.springframework.integration.scheduling.PollingSchedule;
+
/**
* Indicates that a method is capable of providing messages. The method must not
* accept any parameters but can return either a single object or collection.
@@ -39,4 +41,8 @@ public @interface Polled {
int period() default 1000;
+ long initialDelay() default PollingSchedule.DEFAULT_INITIAL_DELAY;
+
+ boolean fixedRate() default PollingSchedule.DEFAULT_FIXED_RATE;
+
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/bus/MessageBus.java b/spring-integration-core/src/main/java/org/springframework/integration/bus/MessageBus.java
index d25cf3e036..a9c04fc814 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/bus/MessageBus.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/bus/MessageBus.java
@@ -73,6 +73,8 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
private boolean autoCreateChannels;
+ private volatile boolean autoStartup = true;
+
private volatile boolean initialized;
private volatile boolean starting;
@@ -84,9 +86,16 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Assert.notNull(applicationContext, "'applicationContext' must not be null");
+ if (applicationContext.getBeanNamesForType(this.getClass()).length > 1) {
+ throw new MessagingConfigurationException("Only one instance of '" + this.getClass().getSimpleName()
+ + "' is allowed per ApplicationContext.");
+ }
this.registerChannels(applicationContext);
this.registerEndpoints(applicationContext);
this.registerSourceAdapters(applicationContext);
+ if (this.autoStartup) {
+ this.start();
+ }
}
public void setMessagingTaskScheduler(MessagingTaskScheduler taskScheduler) {
@@ -108,6 +117,15 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
}
}
+ /**
+ * Set whether to automatically start the bus after initialization.
+ *
Default is 'true'; set this to 'false' to allow for manual startup
+ * through the {@link #start()} method.
+ */
+ public void setAutoStartup(boolean autoStartup) {
+ this.autoStartup = autoStartup;
+ }
+
/**
* Set whether the bus should automatically create a channel when a
* subscription contains the name of a previously unregistered channel.
@@ -226,6 +244,9 @@ public class MessageBus implements ChannelRegistry, ApplicationContextAware, Lif
((ChannelRegistryAware) endpoint).setChannelRegistry(this.channelRegistry);
}
this.endpoints.put(name, endpoint);
+ if (this.isRunning()) {
+ activateEndpoint(endpoint);
+ }
if (logger.isInfoEnabled()) {
logger.info("registered endpoint '" + name + "'");
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/ChannelParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/ChannelParser.java
index b28606eab5..3e3a43673a 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/ChannelParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/ChannelParser.java
@@ -52,6 +52,8 @@ public class ChannelParser implements BeanDefinitionParser {
private static final String DATATYPE_ATTRIBUTE = "datatype";
+ private static final String INTERCEPTOR_ELEMENT = "interceptor";
+
private static final String INTERCEPTORS_PROPERTY = "interceptors";
@@ -60,6 +62,7 @@ public class ChannelParser implements BeanDefinitionParser {
channelDef.setSource(parserContext.extractSource(element));
boolean isPublishSubscribe = "true".equals(element.getAttribute(PUBLISH_SUBSCRIBE_ATTRIBUTE));
DispatcherPolicy dispatcherPolicy = new DispatcherPolicy(isPublishSubscribe);
+ ManagedList interceptors = new ManagedList();
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node child = childNodes.item(i);
@@ -68,13 +71,16 @@ public class ChannelParser implements BeanDefinitionParser {
if (DISPATCHER_POLICY_ELEMENT.equals(localName)) {
configureDispatcherPolicy((Element) child, dispatcherPolicy);
}
+ else if (INTERCEPTOR_ELEMENT.equals(localName)) {
+ String ref = ((Element) child).getAttribute("ref");
+ interceptors.add(new RuntimeBeanReference(ref));
+ }
}
}
String capAttr = element.getAttribute(CAPACITY_ATTRIBUTE);
int capacity = (StringUtils.hasText(capAttr)) ? Integer.parseInt(capAttr) : SimpleChannel.DEFAULT_CAPACITY;
channelDef.getConstructorArgumentValues().addIndexedArgumentValue(0, capacity);
channelDef.getConstructorArgumentValues().addIndexedArgumentValue(1, dispatcherPolicy);
- ManagedList interceptors = new ManagedList();
String datatypeAttr = element.getAttribute(DATATYPE_ATTRIBUTE);
if (StringUtils.hasText(datatypeAttr)) {
String[] datatypes = StringUtils.commaDelimitedListToStringArray(datatypeAttr);
@@ -90,7 +96,6 @@ public class ChannelParser implements BeanDefinitionParser {
parserContext.registerBeanComponent(interceptorComponent);
interceptors.add(new RuntimeBeanReference(interceptorBeanName));
}
- // TODO: parse interceptor sub-elements
channelDef.getPropertyValues().addPropertyValue(INTERCEPTORS_PROPERTY, interceptors);
String beanName = element.getAttribute(ID_ATTRIBUTE);
parserContext.registerBeanComponent(new BeanComponentDefinition(channelDef, beanName));
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/EndpointParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/EndpointParser.java
index c37d62487f..fbeee52ab4 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/EndpointParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/EndpointParser.java
@@ -58,6 +58,10 @@ public class EndpointParser implements BeanDefinitionParser {
private static final String DEFAULT_OUTPUT_CHANNEL_PROPERTY = "defaultOutputChannelName";
+ private static final String SELECTOR_ELEMENT = "selector";
+
+ private static final String SELECTORS_PROPERTY = "messageSelectors";
+
private static final String HANDLER_ELEMENT = "handler";
private static final String REF_ATTRIBUTE = "ref";
@@ -107,6 +111,7 @@ public class EndpointParser implements BeanDefinitionParser {
if (StringUtils.hasText(defaultOutputChannel)) {
endpointDef.getPropertyValues().addPropertyValue(DEFAULT_OUTPUT_CHANNEL_PROPERTY, defaultOutputChannel);
}
+ ManagedList selectors = new ManagedList();
List childHandlerRefs = new ArrayList();
NodeList childNodes = element.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
@@ -116,10 +121,19 @@ public class EndpointParser implements BeanDefinitionParser {
if (CONCURRENCY_ELEMENT.equals(localName)) {
parseConcurrencyPolicy((Element) child, endpointDef);
}
+ else if (SELECTOR_ELEMENT.equals(localName)) {
+ String ref = ((Element) child).getAttribute(REF_ATTRIBUTE);
+ selectors.add(new RuntimeBeanReference(ref));
+ }
else if (HANDLER_ELEMENT.equals(localName)) {
String ref = ((Element) child).getAttribute(REF_ATTRIBUTE);
String method = ((Element) child).getAttribute(METHOD_ATTRIBUTE);
- childHandlerRefs.add(this.parseHandlerAdapter(ref, method, parserContext));
+ if (StringUtils.hasText(method)) {
+ childHandlerRefs.add(this.parseHandlerAdapter(ref, method, parserContext));
+ }
+ else {
+ childHandlerRefs.add(ref);
+ }
}
else if (SCHEDULE_ELEMENT.equals(localName)) {
this.parseSchedule((Element) child, subscriptionDef);
@@ -129,6 +143,9 @@ public class EndpointParser implements BeanDefinitionParser {
String subscriptionBeanName = parserContext.getReaderContext().generateBeanName(subscriptionDef);
parserContext.registerBeanComponent(new BeanComponentDefinition(subscriptionDef, subscriptionBeanName));
endpointDef.getPropertyValues().addPropertyValue(SUBSCRIPTION_PROPERTY, new RuntimeBeanReference(subscriptionBeanName));
+ if (selectors.size() > 0) {
+ endpointDef.getPropertyValues().addPropertyValue(SELECTORS_PROPERTY, selectors);
+ }
if (childHandlerRefs.size() > 0) {
if (childHandlerRefs.size() == 1) {
endpointDef.getPropertyValues().addPropertyValue(
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/HandlerParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/HandlerParser.java
new file mode 100644
index 0000000000..e19bc808a3
--- /dev/null
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/HandlerParser.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2002-2007 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.config;
+
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.parsing.BeanComponentDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
+import org.springframework.beans.factory.support.ManagedList;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.integration.handler.DefaultMessageHandlerAdapter;
+import org.springframework.integration.handler.MessageHandlerChain;
+import org.springframework.util.StringUtils;
+
+/**
+ * Parser for the <handler/> element.
+ *
+ * @author Mark Fisher
+ */
+public class HandlerParser implements BeanDefinitionParser {
+
+ private static final String HANDLER_CHAIN_ELEMENT = "handler-chain";
+
+ private static final String HANDLER_ELEMENT = "handler";
+
+ private static final String HANDLERS_PROPERTY = "handlers";
+
+ private static final String OBJECT_PROPERTY = "object";
+
+ private static final String METHOD_NAME_PROPERTY = "methodName";
+
+
+ public BeanDefinition parse(Element element, ParserContext parserContext) {
+ if (HANDLER_CHAIN_ELEMENT.equals(element.getLocalName())) {
+ return this.parseHandlerChain(element, parserContext);
+ }
+ else if (HANDLER_ELEMENT.equals(element.getLocalName())) {
+ return this.parseHandler(element, parserContext, null);
+ }
+ return null;
+ }
+
+ private BeanDefinition parseHandlerChain(Element element, ParserContext parserContext) {
+ RootBeanDefinition beanDefinition = new RootBeanDefinition(MessageHandlerChain.class);
+ ManagedList handlers = new ManagedList();
+ NodeList childNodes = element.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node child = childNodes.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ String localName = child.getLocalName();
+ if (HANDLER_ELEMENT.equals(localName)) {
+ parseHandler((Element) child, parserContext, handlers);
+ }
+ }
+ }
+ beanDefinition.getPropertyValues().addPropertyValue(HANDLERS_PROPERTY, handlers);
+ String id = element.getAttribute("id");
+ String beanName = (StringUtils.hasText(id)) ? id : parserContext.getReaderContext().generateBeanName(beanDefinition);
+ parserContext.registerBeanComponent(new BeanComponentDefinition(beanDefinition, beanName));
+ return beanDefinition;
+ }
+
+ private BeanDefinition parseHandler(Element element, ParserContext parserContext, ManagedList handlers) {
+ boolean isInnerHandler = (handlers != null);
+ String ref = element.getAttribute("ref");
+ String method = element.getAttribute("method");
+ String id = element.getAttribute("id");
+ if (!isInnerHandler && (!StringUtils.hasText(id) || !StringUtils.hasText(ref) || !StringUtils.hasText(method))) {
+ parserContext.getReaderContext().error("Top-level elements must provide 'id', 'ref', and 'method' attributes.",
+ parserContext.extractSource(element));
+ }
+ if (isInnerHandler && StringUtils.hasText(id)) {
+ parserContext.getReaderContext().error("The 'id' attribute is only supported for top-level elements.",
+ parserContext.extractSource(element));
+ }
+ if (StringUtils.hasText(method)) {
+ BeanDefinitionHolder bdh = this.parseHandlerAdapter(id, ref, method, parserContext, isInnerHandler);
+ if (handlers != null) {
+ handlers.add(bdh.getBeanDefinition());
+ return null;
+ }
+ return bdh.getBeanDefinition();
+ }
+ if (StringUtils.hasText(id)) {
+ parserContext.getReaderContext().error("The 'id' attribute is only supported for handler adapters (when 'method' is also provided).",
+ parserContext.extractSource(element));
+ }
+ if (handlers != null) {
+ handlers.add(new RuntimeBeanReference(ref));
+ }
+ return null;
+ }
+
+ private BeanDefinitionHolder parseHandlerAdapter(String id, String handlerRef, String handlerMethod, ParserContext parserContext, boolean isInnerHandler) {
+ BeanDefinition handlerAdapterDef = new RootBeanDefinition(DefaultMessageHandlerAdapter.class);
+ handlerAdapterDef.getPropertyValues().addPropertyValue(OBJECT_PROPERTY, new RuntimeBeanReference(handlerRef));
+ handlerAdapterDef.getPropertyValues().addPropertyValue(METHOD_NAME_PROPERTY, handlerMethod);
+ String adapterBeanName = (StringUtils.hasText(id)) ? id :
+ BeanDefinitionReaderUtils.generateBeanName(handlerAdapterDef, parserContext.getRegistry(), isInnerHandler);
+ if (!isInnerHandler) {
+ parserContext.registerBeanComponent(new BeanComponentDefinition(handlerAdapterDef, adapterBeanName));
+ }
+ return new BeanDefinitionHolder(handlerAdapterDef, adapterBeanName);
+ }
+
+}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationNamespaceHandler.java b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationNamespaceHandler.java
index c3fe2fce70..182a59bb72 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationNamespaceHandler.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/IntegrationNamespaceHandler.java
@@ -36,6 +36,8 @@ public class IntegrationNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("source-adapter", new ChannelAdapterParser(true));
registerBeanDefinitionParser("target-adapter", new ChannelAdapterParser(false));
registerBeanDefinitionParser("endpoint", new EndpointParser());
+ registerBeanDefinitionParser("handler", new HandlerParser());
+ registerBeanDefinitionParser("handler-chain", new HandlerParser());
registerBeanDefinitionParser("file-source", new FileSourceAdapterParser());
registerBeanDefinitionParser("file-target", new FileTargetAdapterParser());
registerBeanDefinitionParser("jms-source", new JmsSourceAdapterParser());
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/MessageBusParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/MessageBusParser.java
index 4e3038ba07..4643ede564 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/MessageBusParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/MessageBusParser.java
@@ -24,6 +24,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
+import org.springframework.integration.MessagingConfigurationException;
import org.springframework.integration.bus.MessageBus;
import org.springframework.util.StringUtils;
@@ -36,18 +37,24 @@ public class MessageBusParser extends AbstractSimpleBeanDefinitionParser {
public static final String MESSAGE_BUS_BEAN_NAME = "internal.MessageBus";
+ private static final Class> MESSAGE_BUS_CLASS = MessageBus.class;
+
private static final String ERROR_CHANNEL_ATTRIBUTE = "error-channel";
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
throws BeanDefinitionStoreException {
+ if (parserContext.getRegistry().containsBeanDefinition(MESSAGE_BUS_BEAN_NAME)) {
+ throw new MessagingConfigurationException("Only one instance of '" + MESSAGE_BUS_CLASS.getSimpleName()
+ + "' is allowed per ApplicationContext.");
+ }
return MESSAGE_BUS_BEAN_NAME;
}
@Override
protected Class> getBeanClass(Element element) {
- return MessageBus.class;
+ return MESSAGE_BUS_CLASS;
}
@Override
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/MessageEndpointAnnotationPostProcessor.java b/spring-integration-core/src/main/java/org/springframework/integration/config/MessageEndpointAnnotationPostProcessor.java
index 093beb9aaf..7d92c48c3f 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/MessageEndpointAnnotationPostProcessor.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/MessageEndpointAnnotationPostProcessor.java
@@ -134,7 +134,10 @@ public class MessageEndpointAnnotationPostProcessor implements BeanPostProcessor
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
Annotation annotation = AnnotationUtils.getAnnotation(method, Polled.class);
if (annotation != null) {
- int period = ((Polled) annotation).period();
+ Polled polledAnnotation = (Polled) annotation;
+ int period = polledAnnotation.period();
+ long initialDelay = polledAnnotation.initialDelay();
+ boolean fixedRate = polledAnnotation.fixedRate();
MethodInvokingSource