Permalink
Browse files

AggregateAnnotationCommandHandler now returns identifier on aggregate…

… creation command

Instead of returning null, the callback is invoked with the identifier
of the aggregate that was created. This can help in cases where
server-generated identifiers are being used.

Issue #AXON-238 Fixed
  • Loading branch information...
1 parent a5ad573 commit aaa1e3c9166b46b20c80e9f1e90a4fe78fb7597d @abuijze abuijze committed May 28, 2014
View
101 .../java/org/axonframework/commandhandling/annotation/AggregateAnnotationCommandHandler.java
@@ -59,47 +59,6 @@
private final Map<String, CommandHandler<Object>> handlers;
/**
- * Subscribe a handler for the given aggregate type to the given command bus.
- *
- * @param aggregateType The type of aggregate
- * @param repository The repository providing access to aggregate instances
- * @param commandBus The command bus to register command handlers to
- * @param <T> The type of aggregate this handler handles commands for
- * @return the Adapter created for the command handler target. Can be used to unsubscribe.
- */
- public static <T extends AggregateRoot> AggregateAnnotationCommandHandler subscribe(
- Class<T> aggregateType, Repository<T> repository, CommandBus commandBus) {
- AggregateAnnotationCommandHandler<T> adapter = new AggregateAnnotationCommandHandler<T>(aggregateType,
- repository);
- for (String supportedCommand : adapter.supportedCommands()) {
- commandBus.subscribe(supportedCommand, adapter);
- }
-
- return adapter;
- }
-
- /**
- * Subscribe a handler for the given aggregate type to the given command bus.
- *
- * @param aggregateType The type of aggregate
- * @param repository The repository providing access to aggregate instances
- * @param commandBus The command bus to register command handlers to
- * @param commandTargetResolver The target resolution strategy
- * @param <T> The type of aggregate this handler handles commands for
- * @return the Adapter created for the command handler target. Can be used to unsubscribe.
- */
- public static <T extends AggregateRoot> AggregateAnnotationCommandHandler subscribe(
- Class<T> aggregateType, Repository<T> repository, CommandBus commandBus,
- CommandTargetResolver commandTargetResolver) {
- AggregateAnnotationCommandHandler<T> adapter = new AggregateAnnotationCommandHandler<T>(
- aggregateType, repository, commandTargetResolver);
- for (String supportedCommand : adapter.supportedCommands()) {
- commandBus.subscribe(supportedCommand, adapter);
- }
- return adapter;
- }
-
- /**
* Initializes an AnnotationCommandHandler based on the annotations on given <code>aggregateType</code>, using the
* given <code>repository</code> to add and load aggregate instances.
*
@@ -194,6 +153,47 @@ public AggregateAnnotationCommandHandler(Class<T> aggregateType, Repository<T> r
aggregateType, ClasspathParameterResolverFactory.forClass(aggregateType)));
}
+ /**
+ * Subscribe a handler for the given aggregate type to the given command bus.
+ *
+ * @param aggregateType The type of aggregate
+ * @param repository The repository providing access to aggregate instances
+ * @param commandBus The command bus to register command handlers to
+ * @param <T> The type of aggregate this handler handles commands for
+ * @return the Adapter created for the command handler target. Can be used to unsubscribe.
+ */
+ public static <T extends AggregateRoot> AggregateAnnotationCommandHandler subscribe(
+ Class<T> aggregateType, Repository<T> repository, CommandBus commandBus) {
+ AggregateAnnotationCommandHandler<T> adapter = new AggregateAnnotationCommandHandler<T>(aggregateType,
+ repository);
+ for (String supportedCommand : adapter.supportedCommands()) {
+ commandBus.subscribe(supportedCommand, adapter);
+ }
+
+ return adapter;
+ }
+
+ /**
+ * Subscribe a handler for the given aggregate type to the given command bus.
+ *
+ * @param aggregateType The type of aggregate
+ * @param repository The repository providing access to aggregate instances
+ * @param commandBus The command bus to register command handlers to
+ * @param commandTargetResolver The target resolution strategy
+ * @param <T> The type of aggregate this handler handles commands for
+ * @return the Adapter created for the command handler target. Can be used to unsubscribe.
+ */
+ public static <T extends AggregateRoot> AggregateAnnotationCommandHandler subscribe(
+ Class<T> aggregateType, Repository<T> repository, CommandBus commandBus,
+ CommandTargetResolver commandTargetResolver) {
+ AggregateAnnotationCommandHandler<T> adapter = new AggregateAnnotationCommandHandler<T>(
+ aggregateType, repository, commandTargetResolver);
+ for (String supportedCommand : adapter.supportedCommands()) {
+ commandBus.subscribe(supportedCommand, adapter);
+ }
+ return adapter;
+ }
+
private Map<String, CommandHandler<Object>> initializeHandlers(AggregateCommandHandlerInspector<T> inspector) {
Map<String, CommandHandler<Object>> handlersFound = new HashMap<String, CommandHandler<Object>>();
for (final AbstractMessageHandler commandHandler : inspector.getHandlers()) {
@@ -263,6 +263,20 @@ private T loadAggregate(CommandMessage<?> command) {
return repository.load(iv.getIdentifier(), iv.getVersion());
}
+ /**
+ * Resolves the value to return when the given <code>command</code> has created the given <code>aggregate</code>.
+ * This implementation returns the identifier of the created aggregate.
+ * <p/>
+ * This method may be overridden to change the return value of this Command Handler
+ *
+ * @param command The command being executed
+ * @param createdAggregate The aggregate that has been created as a result of the command
+ * @return The value to report as result of the command
+ */
+ protected Object resolveReturnValue(CommandMessage<?> command, T createdAggregate) {
+ return createdAggregate.getIdentifier();
+ }
+
private class AggregateConstructorCommandHandler implements CommandHandler<Object> {
private final ConstructorCommandMessageHandler<T> handler;
@@ -274,11 +288,12 @@ public AggregateConstructorCommandHandler(ConstructorCommandMessageHandler<T> ha
@Override
public Object handle(CommandMessage<Object> command, UnitOfWork unitOfWork) throws Throwable {
try {
- repository.add(handler.invoke(null, command));
+ final T createdAggregate = handler.invoke(null, command);
+ repository.add(createdAggregate);
+ return resolveReturnValue(command, createdAggregate);
} catch (InvocationTargetException e) {
throw e.getCause();
}
- return null;
}
}
View
23 ...a/org/axonframework/commandhandling/annotation/AggregateAnnotationCommandHandlerTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010-2012. Axon Framework
+ * 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.
@@ -58,7 +58,7 @@ public void setUp() throws Exception {
@Test
public void testAggregateConstructorThrowsException() {
- commandBus.dispatch(asCommandMessage(new FailingCreateCommand("parameter")), new VoidCallback() {
+ commandBus.dispatch(asCommandMessage(new FailingCreateCommand("id", "parameter")), new VoidCallback() {
@Override
protected void onSuccess() {
fail("Expected exception");
@@ -121,8 +121,11 @@ public void testCommandHandlerSubscribesToCommands() {
@Test
public void testCommandHandlerCreatesAggregateInstance() {
- commandBus.dispatch(GenericCommandMessage.asCommandMessage(new CreateCommand("Hi")));
+ final CommandCallback callback = mock(CommandCallback.class);
+ commandBus.dispatch(GenericCommandMessage.asCommandMessage(new CreateCommand("id", "Hi")), callback);
verify(mockRepository).add(isA(StubCommandAnnotatedAggregate.class));
+ // make sure the identifier was invoked in the callback
+ verify(callback).onSuccess("id");
}
@Test
@@ -369,7 +372,7 @@ public Object getIdentifier() {
@CommandHandler
public StubCommandAnnotatedAggregate(CreateCommand createCommand, MetaData metaData, UnitOfWork unitOfWork,
@org.axonframework.common.annotation.MetaData("notExist") String value) {
- super(IdentifierFactory.getInstance().generateIdentifier());
+ super(createCommand.getId());
Assert.assertNotNull(unitOfWork);
Assert.assertNull(value);
apply(new StubDomainEvent());
@@ -459,21 +462,27 @@ private UpdateNestedEntityStateCommand(String aggregateId) {
private static class CreateCommand {
+ private final String id;
private String parameter;
- private CreateCommand(String parameter) {
+ private CreateCommand(String id, String parameter) {
+ this.id = id;
this.parameter = parameter;
}
public String getParameter() {
return parameter;
}
+
+ public String getId() {
+ return id;
+ }
}
private static class FailingCreateCommand extends CreateCommand {
- private FailingCreateCommand(String parameter) {
- super(parameter);
+ private FailingCreateCommand(String id, String parameter) {
+ super(id, parameter);
}
}

0 comments on commit aaa1e3c

Please sign in to comment.