diff --git a/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationConfigurationBeanDefinitionParser.java b/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationConfigurationBeanDefinitionParser.java index a898c1080c..d4a4830e33 100644 --- a/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationConfigurationBeanDefinitionParser.java +++ b/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationConfigurationBeanDefinitionParser.java @@ -20,9 +20,11 @@ import org.axonframework.eventhandling.annotation.AnnotationEventListenerBeanPostProcessor; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; import org.w3c.dom.Element; import static org.axonframework.contextsupport.spring.SpringContextParameterResolverFactoryBuilder.getBeanReference; @@ -65,8 +67,16 @@ public class AnnotationConfigurationBeanDefinitionParser extends AbstractBeanDef */ @Override protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) { - registerAnnotationCommandHandlerBeanPostProcessor(element, parserContext); - registerAnnotationEventListenerBeanPostProcessor(element, parserContext); + String phase = element.hasAttribute(PHASE_ATTRIBUTE) ? element.getAttribute(PHASE_ATTRIBUTE) : null; + String unsubscribe = element.hasAttribute(UNSUBSCRIBE_ON_SHUTDOWN_ATTRIBUTE) ? element.getAttribute( + UNSUBSCRIBE_ON_SHUTDOWN_ATTRIBUTE) : null; + String eventBus = element.hasAttribute(EVENT_BUS_ATTRIBUTE) ? element.getAttribute(EVENT_BUS_ATTRIBUTE) : null; + String commandBus = element.hasAttribute(COMMAND_BUS_ATTRIBUTE) ? element + .getAttribute(COMMAND_BUS_ATTRIBUTE) : null; + registerAnnotationCommandHandlerBeanPostProcessor(commandBus, phase, + unsubscribe, parserContext.getRegistry()); + registerAnnotationEventListenerBeanPostProcessor(eventBus, phase, unsubscribe, + parserContext.getRegistry()); return null; } @@ -74,56 +84,61 @@ protected AbstractBeanDefinition parseInternal(Element element, ParserContext pa * Create the {@link org.springframework.beans.factory.config.BeanDefinition} for the {@link * AnnotationEventListenerBeanPostProcessor} and register it. * - * @param element The {@link Element} being parsed. - * @param parserContext The running {@link ParserContext}. + * @param eventBus The bean name of the event bus to subscribe to + * @param phase The lifecycle phase for the post processor + * @param unsubscribeOnShutdown Whether to unsubscribe beans on shutdown + * @param registry The registry containing bean definitions */ - private void registerAnnotationEventListenerBeanPostProcessor(Element element, ParserContext parserContext) { + public void registerAnnotationEventListenerBeanPostProcessor(String eventBus, String phase, + String unsubscribeOnShutdown, + BeanDefinitionRegistry registry) { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(AnnotationEventListenerBeanPostProcessor.class); beanDefinition.getPropertyValues().add("parameterResolverFactory", - getBeanReference(parserContext.getRegistry())); - if (element.hasAttribute(PHASE_ATTRIBUTE)) { - beanDefinition.getPropertyValues().add("phase", element.getAttribute(PHASE_ATTRIBUTE)); + getBeanReference(registry)); + if (StringUtils.hasText(phase)) { + beanDefinition.getPropertyValues().add("phase", phase); } - if (element.hasAttribute(UNSUBSCRIBE_ON_SHUTDOWN_ATTRIBUTE)) { - beanDefinition.getPropertyValues().add("unsubscribeOnShutdown", - element.getAttribute(UNSUBSCRIBE_ON_SHUTDOWN_ATTRIBUTE)); + if (StringUtils.hasText(unsubscribeOnShutdown)) { + beanDefinition.getPropertyValues().add("unsubscribeOnShutdown", unsubscribeOnShutdown); } - if (element.hasAttribute(EVENT_BUS_ATTRIBUTE)) { - String eventBusReference = element.getAttribute(EVENT_BUS_ATTRIBUTE); - RuntimeBeanReference beanReference = new RuntimeBeanReference(eventBusReference); + if (StringUtils.hasText(eventBus)) { + RuntimeBeanReference beanReference = new RuntimeBeanReference(eventBus); beanDefinition.getPropertyValues().addPropertyValue("eventBus", beanReference); } - parserContext.getRegistry().registerBeanDefinition(EVENT_LISTENER_BEAN_NAME, beanDefinition); + registry.registerBeanDefinition(EVENT_LISTENER_BEAN_NAME, beanDefinition); } /** * Create the {@link org.springframework.beans.factory.config.BeanDefinition} for the {@link * AnnotationCommandHandlerBeanPostProcessor} and register it. * - * @param element The {@link Element} being parsed. - * @param parserContext The running {@link ParserContext}. + * @param commandBus The bean name of the command bus to subscribe to + * @param phase The lifecycle phase for the post processor + * @param unsubscribeOnShutdown Whether to unsubscribe beans on shutdown + * @param registry The registry containing bean definitions */ - private void registerAnnotationCommandHandlerBeanPostProcessor(Element element, ParserContext parserContext) { + public void registerAnnotationCommandHandlerBeanPostProcessor(String commandBus, String phase, + String unsubscribeOnShutdown, + BeanDefinitionRegistry registry) { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClass(AnnotationCommandHandlerBeanPostProcessor.class); beanDefinition.getPropertyValues().add("parameterResolverFactory", getBeanReference( - parserContext.getRegistry())); - if (element.hasAttribute(PHASE_ATTRIBUTE)) { - beanDefinition.getPropertyValues().add("phase", element.getAttribute(PHASE_ATTRIBUTE)); + registry)); + if (StringUtils.hasText(phase)) { + beanDefinition.getPropertyValues().add("phase", phase); } - if (element.hasAttribute(UNSUBSCRIBE_ON_SHUTDOWN_ATTRIBUTE)) { + if (StringUtils.hasText(unsubscribeOnShutdown)) { beanDefinition.getPropertyValues().add("unsubscribeOnShutdown", - element.getAttribute(UNSUBSCRIBE_ON_SHUTDOWN_ATTRIBUTE)); + unsubscribeOnShutdown); } - if (element.hasAttribute(COMMAND_BUS_ATTRIBUTE)) { - String commandBusReference = element.getAttribute(COMMAND_BUS_ATTRIBUTE); - RuntimeBeanReference beanReference = new RuntimeBeanReference(commandBusReference); + if (StringUtils.hasText(commandBus)) { + RuntimeBeanReference beanReference = new RuntimeBeanReference(commandBus); beanDefinition.getPropertyValues().addPropertyValue("commandBus", beanReference); } - parserContext.getRegistry().registerBeanDefinition(COMMAND_HANDLER_BEAN_NAME, beanDefinition); + registry.registerBeanDefinition(COMMAND_HANDLER_BEAN_NAME, beanDefinition); } } diff --git a/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationDriven.java b/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationDriven.java new file mode 100644 index 0000000000..85495486ea --- /dev/null +++ b/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationDriven.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2010-2014. Axon Framework + * + * 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.axonframework.contextsupport.spring; + +import org.springframework.context.annotation.Import; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Annotation for {@link org.springframework.context.annotation.Configuration @Configuration} that will automatically + * subscribe {@link org.axonframework.commandhandling.annotation.CommandHandler @CommandHandler} and {@link + * org.axonframework.eventhandling.annotation.EventHandler @EventHandler} annotated beans with the CommandBus and + * EventBus, respectively. + *
+ * If a context contains multiple EventBus or CommandBus implementations, you must indicate the isntance to use as + * a property on this annotation. + * + * @author Allard Buijze + * @since 2.3 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Import(AnnotationDrivenConfiguration.class) +public @interface AnnotationDriven { + + /** + * The bean name of the Event Bus to register {@link + * org.axonframework.eventhandling.annotation.EventHandler @EventHandler} annotated beans with. + */ + String eventBus() default ""; + + /** + * The bean name of the Command Bus to register {@link + * org.axonframework.commandhandling.annotation.CommandHandler @CommandHandler} annotated beans with. + */ + String commandBus() default ""; + + /** + * Whether to unsubscribe beans on shutdown. Default tofalse
. Setting this to true
will
+ * explicitly unsubscribe beans from the Event- and CommandBus when shutting down the application context.
+ */
+ boolean unsubscribeOnShutdown() default false;
+
+ /**
+ * The phase in the application context lifecycle in which to subscribe (and possibly unsubscribe) the handlers
+ * with the CommandBus and EventBus.
+ */
+ int phase() default 0;
+}
diff --git a/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationDrivenConfiguration.java b/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationDrivenConfiguration.java
new file mode 100644
index 0000000000..dd83cbcd91
--- /dev/null
+++ b/core/src/main/java/org/axonframework/contextsupport/spring/AnnotationDrivenConfiguration.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2010-2014. Axon Framework
+ *
+ * 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.axonframework.contextsupport.spring;
+
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.core.type.AnnotationMetadata;
+
+import java.util.Map;
+
+/**
+ * Spring @Configuration related class that adds Axon Annotation PostProcessors to the BeanDefinitionRegistry.
+ *
+ * @author Allard Buijze
+ * @see org.axonframework.contextsupport.spring.AnnotationDriven
+ * @since 2.3
+ */
+public class AnnotationDrivenConfiguration implements ImportBeanDefinitionRegistrar {
+
+ private static final String ANNOTATION_TYPE = AnnotationDriven.class.getName();
+
+ @Override
+ public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
+ final AnnotationConfigurationBeanDefinitionParser parser = new AnnotationConfigurationBeanDefinitionParser();
+ Map