diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractTargetEndpointParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractTargetEndpointParser.java new file mode 100644 index 0000000000..ed63f18b8d --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/AbstractTargetEndpointParser.java @@ -0,0 +1,170 @@ +/* + * Copyright 2002-2008 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.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.ConfigurationException; +import org.springframework.integration.endpoint.ConcurrencyPolicy; +import org.springframework.integration.handler.DefaultMessageHandlerAdapter; +import org.springframework.integration.scheduling.PollingSchedule; +import org.springframework.integration.scheduling.Schedule; +import org.springframework.integration.scheduling.Subscription; +import org.springframework.util.StringUtils; + +/** + * Base class for target-endpoint and handler-endpoint parsers. + * + * @author Mark Fisher + */ +public abstract class AbstractTargetEndpointParser extends AbstractSingleBeanDefinitionParser { + + private static final String INPUT_CHANNEL_ATTRIBUTE = "input-channel"; + + private static final String SUBSCRIPTION_PROPERTY = "subscription"; + + private static final String SELECTOR_ELEMENT = "selector"; + + private static final String REF_ATTRIBUTE = "ref"; + + private static final String SELECTORS_PROPERTY = "messageSelectors"; + + private static final String ERROR_HANDLER_ATTRIBUTE = "error-handler"; + + private static final String ERROR_HANDLER_PROPERTY = "errorHandler"; + + private static final String PERIOD_ATTRIBUTE = "period"; + + private static final String SCHEDULE_ELEMENT = "schedule"; + + private static final String CONCURRENCY_ELEMENT = "concurrency"; + + private static final String CONCURRENCY_POLICY_PROPERTY = "concurrencyPolicy"; + + + @Override + protected boolean shouldGenerateId() { + return false; + } + + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; + } + + @Override + protected abstract Class getBeanClass(Element element); + + protected abstract String getTargetAttributeName(); + + protected abstract Class getAdapterClass(); + + protected void postProcess(BeanDefinitionBuilder builder, Element element) { + } + + @Override + protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { + this.parseTarget(element, this.getTargetAttributeName(), parserContext, builder); + String inputChannel = element.getAttribute(INPUT_CHANNEL_ATTRIBUTE); + Schedule schedule = null; + ManagedList selectors = 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 (CONCURRENCY_ELEMENT.equals(localName)) { + parseConcurrencyPolicy((Element) child, builder); + } + else if (SELECTOR_ELEMENT.equals(localName)) { + String ref = ((Element) child).getAttribute(REF_ATTRIBUTE); + selectors.add(new RuntimeBeanReference(ref)); + } + else if (SCHEDULE_ELEMENT.equals(localName)) { + schedule = this.parseSchedule((Element) child); + } + } + } + if (StringUtils.hasText(inputChannel)) { + RootBeanDefinition subscriptionDef = new RootBeanDefinition(Subscription.class); + subscriptionDef.getConstructorArgumentValues().addGenericArgumentValue(inputChannel); + if (schedule != null) { + subscriptionDef.getConstructorArgumentValues().addGenericArgumentValue(schedule); + } + String subscriptionBeanName = parserContext.getReaderContext().generateBeanName(subscriptionDef); + parserContext.registerBeanComponent(new BeanComponentDefinition(subscriptionDef, subscriptionBeanName)); + builder.addPropertyReference(SUBSCRIPTION_PROPERTY, subscriptionBeanName); + } + if (selectors.size() > 0) { + builder.addPropertyValue(SELECTORS_PROPERTY, selectors); + } + String errorHandlerRef = element.getAttribute(ERROR_HANDLER_ATTRIBUTE); + if (StringUtils.hasText(errorHandlerRef)) { + builder.addPropertyReference(ERROR_HANDLER_PROPERTY, errorHandlerRef); + } + this.postProcess(builder, element); + } + + private void parseTarget(Element element, String attribute, ParserContext parserContext, BeanDefinitionBuilder builder) { + String ref = element.getAttribute(attribute); + if (!StringUtils.hasText(ref)) { + throw new ConfigurationException("The '" + attribute + "' attribute is required."); + } + String method = element.getAttribute(attribute + "-method"); + if (StringUtils.hasText(method)) { + String adapterBeanName = this.parseAdapter(ref, method, parserContext); + builder.addConstructorArgReference(adapterBeanName); + } + else { + builder.addConstructorArgReference(ref); + } + } + + private String parseAdapter(String ref, String method, ParserContext parserContext) { + BeanDefinition adapterDef = new RootBeanDefinition(this.getAdapterClass()); + adapterDef.getPropertyValues().addPropertyValue("object", new RuntimeBeanReference(ref)); + adapterDef.getPropertyValues().addPropertyValue("methodName", method); + String adapterBeanName = parserContext.getReaderContext().generateBeanName(adapterDef); + parserContext.registerBeanComponent(new BeanComponentDefinition(adapterDef, adapterBeanName)); + return adapterBeanName; + } + + private void parseConcurrencyPolicy(Element concurrencyElement, BeanDefinitionBuilder builder) { + ConcurrencyPolicy policy = IntegrationNamespaceUtils.parseConcurrencyPolicy(concurrencyElement); + builder.addPropertyValue(CONCURRENCY_POLICY_PROPERTY, policy); + } + + private Schedule parseSchedule(Element scheduleElement) { + PollingSchedule schedule = new PollingSchedule(5); + String period = scheduleElement.getAttribute(PERIOD_ATTRIBUTE); + if (StringUtils.hasText(period)) { + schedule.setPeriod(Integer.parseInt(period)); + } + return schedule; + } + +} 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 cfe919d5b1..298038c950 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 @@ -17,23 +17,11 @@ 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.RuntimeBeanReference; -import org.springframework.beans.factory.parsing.BeanComponentDefinition; -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.ConfigurationException; -import org.springframework.integration.endpoint.ConcurrencyPolicy; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.integration.endpoint.HandlerEndpoint; import org.springframework.integration.handler.DefaultMessageHandlerAdapter; -import org.springframework.integration.scheduling.PollingSchedule; -import org.springframework.integration.scheduling.Schedule; -import org.springframework.integration.scheduling.Subscription; import org.springframework.util.StringUtils; /** @@ -41,13 +29,7 @@ import org.springframework.util.StringUtils; * * @author Mark Fisher */ -public class EndpointParser implements BeanDefinitionParser { - - private static final String ID_ATTRIBUTE = "id"; - - private static final String INPUT_CHANNEL_ATTRIBUTE = "input-channel"; - - private static final String SUBSCRIPTION_PROPERTY = "subscription"; +public class EndpointParser extends AbstractTargetEndpointParser { private static final String DEFAULT_OUTPUT_CHANNEL_ATTRIBUTE = "default-output-channel"; @@ -55,129 +37,38 @@ public class EndpointParser implements BeanDefinitionParser { private static final String RETURN_ADDRESS_OVERRIDES_ATTRIBUTE = "return-address-overrides"; - private static final String SELECTOR_ELEMENT = "selector"; - - private static final String SELECTORS_PROPERTY = "messageSelectors"; - - private static final String REF_ATTRIBUTE = "ref"; - - private static final String HANDLER_ATTRIBUTE = "handler"; - - private static final String HANDLER_METHOD_ATTRIBUTE = "handler-method"; - - private static final String ERROR_HANDLER_ATTRIBUTE = "error-handler"; - - private static final String ERROR_HANDLER_PROPERTY = "errorHandler"; - private static final String REPLY_HANDLER_ATTRIBUTE = "reply-handler"; private static final String REPLY_HANDLER_PROPERTY = "replyHandler"; - private static final String OBJECT_PROPERTY = "object"; - private static final String METHOD_NAME_PROPERTY = "methodName"; + @Override + protected Class getBeanClass(Element element) { + return HandlerEndpoint.class; + } - private static final String PERIOD_ATTRIBUTE = "period"; + protected String getTargetAttributeName() { + return "handler"; + } - private static final String SCHEDULE_ELEMENT = "schedule"; + @Override + protected Class getAdapterClass() { + return DefaultMessageHandlerAdapter.class; + } - private static final String CONCURRENCY_ELEMENT = "concurrency"; - - private static final String CONCURRENCY_POLICY_PROPERTY = "concurrencyPolicy"; - - - public BeanDefinition parse(Element element, ParserContext parserContext) { - String handlerRef = element.getAttribute(HANDLER_ATTRIBUTE); - if (!StringUtils.hasText(handlerRef)) { - throw new ConfigurationException("The '" + HANDLER_ATTRIBUTE + "' attribute is required."); - } - RootBeanDefinition endpointDef = new RootBeanDefinition(HandlerEndpoint.class); - endpointDef.setSource(parserContext.extractSource(element)); - String inputChannel = element.getAttribute(INPUT_CHANNEL_ATTRIBUTE); + @Override + protected void postProcess(BeanDefinitionBuilder builder, Element element) { String defaultOutputChannel = element.getAttribute(DEFAULT_OUTPUT_CHANNEL_ATTRIBUTE); - Schedule schedule = null; if (StringUtils.hasText(defaultOutputChannel)) { - endpointDef.getPropertyValues().addPropertyValue(DEFAULT_OUTPUT_CHANNEL_PROPERTY, defaultOutputChannel); + builder.addPropertyValue(DEFAULT_OUTPUT_CHANNEL_PROPERTY, defaultOutputChannel); } String returnAddressOverridesAttribute = element.getAttribute(RETURN_ADDRESS_OVERRIDES_ATTRIBUTE); boolean returnAddressOverrides = "true".equals(returnAddressOverridesAttribute); - endpointDef.getPropertyValues().addPropertyValue("returnAddressOverrides", returnAddressOverrides); - ManagedList selectors = 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 (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 (SCHEDULE_ELEMENT.equals(localName)) { - schedule = this.parseSchedule((Element) child); - } - } + builder.addPropertyValue("returnAddressOverrides", returnAddressOverrides); + String replyHandler = element.getAttribute(REPLY_HANDLER_ATTRIBUTE); + if (StringUtils.hasText(replyHandler)) { + builder.addPropertyValue(REPLY_HANDLER_PROPERTY, new RuntimeBeanReference(replyHandler)); } - if (StringUtils.hasText(inputChannel)) { - RootBeanDefinition subscriptionDef = new RootBeanDefinition(Subscription.class); - subscriptionDef.getConstructorArgumentValues().addGenericArgumentValue(inputChannel); - if (schedule != null) { - subscriptionDef.getConstructorArgumentValues().addGenericArgumentValue(schedule); - } - 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); - } - String handlerMethod = element.getAttribute(HANDLER_METHOD_ATTRIBUTE); - if (StringUtils.hasText(handlerMethod)) { - String adapterBeanName = this.parseHandlerAdapter(handlerRef, handlerMethod, parserContext); - endpointDef.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(adapterBeanName)); - } - else { - endpointDef.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(handlerRef)); - } - String errorHandlerRef = element.getAttribute(ERROR_HANDLER_ATTRIBUTE); - if (StringUtils.hasText(errorHandlerRef)) { - endpointDef.getPropertyValues().addPropertyValue(ERROR_HANDLER_PROPERTY, new RuntimeBeanReference(errorHandlerRef)); - } - String replyHandlerRef = element.getAttribute(REPLY_HANDLER_ATTRIBUTE); - if (StringUtils.hasText(replyHandlerRef)) { - endpointDef.getPropertyValues().addPropertyValue(REPLY_HANDLER_PROPERTY, new RuntimeBeanReference(replyHandlerRef)); - } - String beanName = element.getAttribute(ID_ATTRIBUTE); - if (!StringUtils.hasText(beanName)) { - beanName = parserContext.getReaderContext().generateBeanName(endpointDef); - } - parserContext.registerBeanComponent(new BeanComponentDefinition(endpointDef, beanName)); - return endpointDef; - } - - private void parseConcurrencyPolicy(Element concurrencyElement, RootBeanDefinition endpointDef) { - ConcurrencyPolicy policy = IntegrationNamespaceUtils.parseConcurrencyPolicy(concurrencyElement); - endpointDef.getPropertyValues().addPropertyValue(CONCURRENCY_POLICY_PROPERTY, policy); - } - - private Schedule parseSchedule(Element scheduleElement) { - PollingSchedule schedule = new PollingSchedule(5); - String period = scheduleElement.getAttribute(PERIOD_ATTRIBUTE); - if (StringUtils.hasText(period)) { - schedule.setPeriod(Integer.parseInt(period)); - } - return schedule; - } - - private String parseHandlerAdapter(String handlerRef, String handlerMethod, ParserContext parserContext) { - BeanDefinition handlerAdapterDef = new RootBeanDefinition(DefaultMessageHandlerAdapter.class); - handlerAdapterDef.getPropertyValues().addPropertyValue(OBJECT_PROPERTY, new RuntimeBeanReference(handlerRef)); - handlerAdapterDef.getPropertyValues().addPropertyValue(METHOD_NAME_PROPERTY, handlerMethod); - String adapterBeanName = parserContext.getReaderContext().generateBeanName(handlerAdapterDef); - parserContext.registerBeanComponent(new BeanComponentDefinition(handlerAdapterDef, adapterBeanName)); - return 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 92f491a259..9bfbfab1c3 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 @@ -53,6 +53,7 @@ public class IntegrationNamespaceHandler extends NamespaceHandlerSupport { registerBeanDefinitionParser("target-adapter", new MethodInvokingAdapterParser()); registerBeanDefinitionParser("source-endpoint", new SourceEndpointParser()); registerBeanDefinitionParser("endpoint", new EndpointParser()); + registerBeanDefinitionParser("target-endpoint", new TargetEndpointParser()); registerBeanDefinitionParser("handler", new HandlerParser()); registerBeanDefinitionParser("handler-chain", new HandlerParser()); registerBeanDefinitionParser("aggregator", new AggregatorParser()); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/TargetEndpointParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/TargetEndpointParser.java new file mode 100644 index 0000000000..6b24f217b9 --- /dev/null +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/TargetEndpointParser.java @@ -0,0 +1,46 @@ +/* + * Copyright 2002-2008 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.springframework.integration.adapter.MethodInvokingTarget; +import org.springframework.integration.endpoint.TargetEndpoint; + +/** + * Parser for the <target-endpoint> element. + * + * @author Mark Fisher + */ +public class TargetEndpointParser extends AbstractTargetEndpointParser { + + @Override + protected Class getBeanClass(Element element) { + return TargetEndpoint.class; + } + + @Override + protected String getTargetAttributeName() { + return "target"; + } + + @Override + protected Class getAdapterClass() { + return MethodInvokingTarget.class; + } + +} diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/spring-integration-core-1.0.xsd b/spring-integration-core/src/main/java/org/springframework/integration/config/spring-integration-core-1.0.xsd index c11d61ae8d..b6cec8cbe5 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/spring-integration-core-1.0.xsd +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/spring-integration-core-1.0.xsd @@ -115,6 +115,22 @@ + + + + + Defines a target endpoint. + + + + + + + + + + +