Skip to content

Commit

Permalink
AxonConfigurer created default ResourceInjector that injects componen…
Browse files Browse the repository at this point in the history
…ts from Configuration

The Spring configuration default to a SpringResourceInjector instead, which autowires Saga instances.
  • Loading branch information
abuijze committed Oct 12, 2016
1 parent 0c1e8fd commit 663c6f8
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 63 deletions.
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.axonframework.config; package org.axonframework.config;


import org.axonframework.commandhandling.CommandBus; import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.commandhandling.model.Repository; import org.axonframework.commandhandling.model.Repository;
import org.axonframework.common.AxonConfigurationException; import org.axonframework.common.AxonConfigurationException;
import org.axonframework.eventhandling.EventBus; import org.axonframework.eventhandling.EventBus;
Expand Down Expand Up @@ -83,6 +84,10 @@ default ResourceInjector resourceInjector() {
return getComponent(ResourceInjector.class, NoResourceInjector::new); return getComponent(ResourceInjector.class, NoResourceInjector::new);
} }


default CommandGateway commandGateway() {
return getComponent(CommandGateway.class);
}

/** /**
* Returns the Repository configured for the given {@code aggregateType}. * Returns the Repository configured for the given {@code aggregateType}.
* *
Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.axonframework.config;

import org.axonframework.eventhandling.saga.AbstractResourceInjector;

import java.util.Optional;

/**
* ResourceInjector implementation that injects resources defined in the Axon Configuration.
*/
public class ConfigurationResourceInjector extends AbstractResourceInjector {

private final Configuration configuration;

/**
* Initializes the ResourceInjector to inject the resources found in the given {@code configuration}.
*
* @param configuration the Configuration to find injectable resources in
*/
public ConfigurationResourceInjector(Configuration configuration) {
this.configuration = configuration;
}

@Override
protected <R> Optional<R> findResource(Class<R> requiredType) {
return Optional.ofNullable(configuration.getComponent(requiredType));
}
}
14 changes: 14 additions & 0 deletions core/src/main/java/org/axonframework/config/DefaultConfigurer.java
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@
import org.axonframework.commandhandling.AnnotationCommandHandlerAdapter; import org.axonframework.commandhandling.AnnotationCommandHandlerAdapter;
import org.axonframework.commandhandling.CommandBus; import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.SimpleCommandBus; import org.axonframework.commandhandling.SimpleCommandBus;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.commandhandling.gateway.DefaultCommandGateway;
import org.axonframework.commandhandling.model.Repository; import org.axonframework.commandhandling.model.Repository;
import org.axonframework.common.Registration; import org.axonframework.common.Registration;
import org.axonframework.common.jpa.EntityManagerProvider; import org.axonframework.common.jpa.EntityManagerProvider;
import org.axonframework.common.transaction.NoTransactionManager; import org.axonframework.common.transaction.NoTransactionManager;
import org.axonframework.common.transaction.TransactionManager; import org.axonframework.common.transaction.TransactionManager;
import org.axonframework.eventhandling.EventBus; import org.axonframework.eventhandling.EventBus;
import org.axonframework.eventhandling.SimpleEventBus; import org.axonframework.eventhandling.SimpleEventBus;
import org.axonframework.eventhandling.saga.ResourceInjector;
import org.axonframework.eventhandling.saga.repository.SagaStore; import org.axonframework.eventhandling.saga.repository.SagaStore;
import org.axonframework.eventhandling.saga.repository.jpa.JpaSagaStore; import org.axonframework.eventhandling.saga.repository.jpa.JpaSagaStore;
import org.axonframework.eventhandling.tokenstore.TokenStore; import org.axonframework.eventhandling.tokenstore.TokenStore;
Expand All @@ -47,6 +50,7 @@
import org.axonframework.serialization.Serializer; import org.axonframework.serialization.Serializer;
import org.axonframework.serialization.xml.XStreamSerializer; import org.axonframework.serialization.xml.XStreamSerializer;


import javax.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
Expand Down Expand Up @@ -136,6 +140,12 @@ protected DefaultConfigurer() {
components.put(Serializer.class, new Component<>(config, "serializer", this::defaultSerializer)); components.put(Serializer.class, new Component<>(config, "serializer", this::defaultSerializer));
components.put(CommandBus.class, new Component<>(config, "commandBus", this::defaultCommandBus)); components.put(CommandBus.class, new Component<>(config, "commandBus", this::defaultCommandBus));
components.put(EventBus.class, new Component<>(config, "eventBus", this::defaultEventBus)); components.put(EventBus.class, new Component<>(config, "eventBus", this::defaultEventBus));
components.put(CommandGateway.class, new Component<>(config, "resourceInjector", this::defaultCommandGateway));
components.put(ResourceInjector.class, new Component<>(config, "resourceInjector", this::defaultResourceInjector));
}

protected CommandGateway defaultCommandGateway(Configuration config) {
return new DefaultCommandGateway(config.commandBus());
} }


/** /**
Expand Down Expand Up @@ -163,6 +173,10 @@ protected CommandBus defaultCommandBus(Configuration config) {
return cb; return cb;
} }


protected ResourceInjector defaultResourceInjector(Configuration config) {
return new ConfigurationResourceInjector(config);
}

/** /**
* Provides the default EventBus implementation. Subclasses may override this method to provide their own default * Provides the default EventBus implementation. Subclasses may override this method to provide their own default
* *
Expand Down
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class SagaConfiguration<S> implements ModuleConfiguration {
* @return a SagaConfiguration instance, ready for further configuration * @return a SagaConfiguration instance, ready for further configuration
*/ */
public static <S> SagaConfiguration<S> subscribingSagaManager(Class<S> sagaType) { public static <S> SagaConfiguration<S> subscribingSagaManager(Class<S> sagaType) {
return new SagaConfiguration<S>(sagaType); return new SagaConfiguration<>(sagaType);
} }




Expand Down
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (c) 2010-2016. 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.eventhandling.saga;

import org.axonframework.common.ReflectionUtils;
import org.axonframework.common.annotation.AnnotationUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Optional;

import static org.axonframework.common.ReflectionUtils.fieldsOf;
import static org.axonframework.common.ReflectionUtils.methodsOf;

public abstract class AbstractResourceInjector implements ResourceInjector {

private static final Logger logger = LoggerFactory.getLogger(AbstractResourceInjector.class);

private static final String FULLY_QUALIFIED_CLASS_NAME_INJECT = "javax.inject.Inject";

@Override
public void injectResources(Object saga) {
injectFieldResources(saga);
injectMethodResources(saga);
}

private void injectFieldResources(Object saga) {
fieldsOf(saga.getClass()).forEach(
field -> Optional.ofNullable(AnnotationUtils.findAnnotation(field, FULLY_QUALIFIED_CLASS_NAME_INJECT))
.ifPresent(annotatedFields -> {
Class<?> requiredType = field.getType();
findResource(requiredType).ifPresent(resource -> injectFieldResource(saga, field, resource));
}));
}

protected abstract <R> Optional<R> findResource(Class<R> requiredType);

private void injectFieldResource(Object saga, Field injectField, Object resource) {
try {
ReflectionUtils.ensureAccessible(injectField);
injectField.set(saga, resource);
} catch (IllegalAccessException e) {
logger.warn("Unable to inject resource. Exception while setting field: ", e);
}
}

private void injectMethodResources(Object saga) {
methodsOf(saga.getClass()).forEach(
method -> Optional.ofNullable(AnnotationUtils.findAnnotation(method, FULLY_QUALIFIED_CLASS_NAME_INJECT))
.ifPresent(annotatedMethods -> {
Class<?> requiredType = method.getParameterTypes()[0];
findResource(requiredType).ifPresent(resource -> injectMethodResource(saga, method, resource));
}));
}

private void injectMethodResource(Object saga, Method injectMethod, Object resource) {
try {
ReflectionUtils.ensureAccessible(injectMethod);
injectMethod.invoke(saga, resource);
} catch (IllegalAccessException e) {
logger.warn("Unable to inject resource. Exception while invoking setter: ", e);
} catch (InvocationTargetException e) {
logger.warn("Unable to inject resource. Exception while invoking setter: ", e.getCause());
}
}

}
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -16,23 +16,15 @@


package org.axonframework.eventhandling.saga; package org.axonframework.eventhandling.saga;


import org.axonframework.common.ReflectionUtils;
import org.axonframework.common.annotation.AnnotationUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Optional; import java.util.Optional;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;


import static org.axonframework.common.ReflectionUtils.fieldsOf;
import static org.axonframework.common.ReflectionUtils.methodsOf;

/** /**
* A resource injector that checks for {@see javax.inject.Inject} annotated fields and setter methods to inject * A resource injector that checks for {@see javax.inject.Inject} annotated fields and setter methods to inject
* resources. If a field is annotated with {@see javax.inject.Inject}, a Resource of the type of that field is injected * resources. If a field is annotated with {@see javax.inject.Inject}, a Resource of the type of that field is injected
Expand All @@ -42,7 +34,7 @@
* @author Allard Buijze * @author Allard Buijze
* @since 1.1 * @since 1.1
*/ */
public class SimpleResourceInjector implements ResourceInjector { public class SimpleResourceInjector extends AbstractResourceInjector {


private static final Logger logger = LoggerFactory.getLogger(SimpleResourceInjector.class); private static final Logger logger = LoggerFactory.getLogger(SimpleResourceInjector.class);


Expand All @@ -68,50 +60,12 @@ public SimpleResourceInjector(Collection<?> resources) {
this.resources = new ArrayList<>(resources); this.resources = new ArrayList<>(resources);
} }


@SuppressWarnings("unchecked")
@Override @Override
public void injectResources(Object saga) { protected <R> Optional<R> findResource(Class<R> requiredType) {
injectFieldResources(saga); return (Optional<R>) StreamSupport.stream(resources.spliterator(), false)
injectMethodResources(saga); .filter(requiredType::isInstance)
} .findFirst();

private void injectFieldResources(Object saga) {
fieldsOf(saga.getClass()).forEach(
field -> Optional.ofNullable(AnnotationUtils.findAnnotation(field, FULLY_QUALIFIED_CLASS_NAME_INJECT))
.ifPresent(annotatedFields -> {
Class<?> requiredType = field.getType();
StreamSupport.stream(resources.spliterator(), false).filter(requiredType::isInstance)
.forEach(resource -> injectFieldResource(saga, field, resource));
}));
}

private void injectFieldResource(Object saga, Field injectField, Object resource) {
try {
ReflectionUtils.ensureAccessible(injectField);
injectField.set(saga, resource);
} catch (IllegalAccessException e) {
logger.warn("Unable to inject resource. Exception while setting field: ", e);
}
}

private void injectMethodResources(Object saga) {
methodsOf(saga.getClass()).forEach(
method -> Optional.ofNullable(AnnotationUtils.findAnnotation(method, FULLY_QUALIFIED_CLASS_NAME_INJECT))
.ifPresent(annotatedMethods -> {
Class<?> requiredType = method.getParameterTypes()[0];
StreamSupport.stream(resources.spliterator(), false).filter(requiredType::isInstance)
.forEach(resource -> injectMethodResource(saga, method, resource));
}));
}

private void injectMethodResource(Object saga, Method injectMethod, Object resource) {
try {
ReflectionUtils.ensureAccessible(injectMethod);
injectMethod.invoke(saga, resource);
} catch (IllegalAccessException e) {
logger.warn("Unable to inject resource. Exception while invoking setter: ", e);
} catch (InvocationTargetException e) {
logger.warn("Unable to inject resource. Exception while invoking setter: ", e.getCause());
}
} }


} }
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.axonframework.config;

import org.axonframework.commandhandling.CommandBus;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.junit.Before;
import org.junit.Test;

import javax.inject.Inject;

import static org.junit.Assert.*;

public class ConfigurationResourceInjectorTest {

private Configuration configuration;
private ConfigurationResourceInjector testSubject;

@Before
public void setUp() throws Exception {
configuration = DefaultConfigurer.defaultConfiguration().buildConfiguration();
testSubject = new ConfigurationResourceInjector(configuration);
}

@Test
public void testInjectorHasResource() throws Exception {
Saga saga = new Saga();
testSubject.injectResources(saga);

assertSame(configuration.commandBus(), saga.commandBus);
assertSame(configuration.commandGateway(), saga.commandGateway);
assertNull(saga.inexistent);
}

public static class Saga {

@Inject
private CommandBus commandBus;

@Inject
private String inexistent;

private CommandGateway commandGateway;

@Inject
public void setCommandGateway(CommandGateway commandGateway) {
this.commandGateway = commandGateway;
}
}
}
Loading

0 comments on commit 663c6f8

Please sign in to comment.