diff --git a/mifosng-provider/dependencies.gradle b/mifosng-provider/dependencies.gradle
index 092847df2..19bf90bdd 100644
--- a/mifosng-provider/dependencies.gradle
+++ b/mifosng-provider/dependencies.gradle
@@ -81,7 +81,9 @@ dependencies {
// Although Mifos (at the time of writing) doesn't have any compile time dep. on this,
// it's useful to have this for the Spring Boot TestRestTemplate http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rest-templates-test-utility
- [group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.5']
+ [group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.5'],
+ // Once we've switched to Java 8 this dep can be removed.
+ [group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.0']
)
testCompile 'junit:junit:4.11',
'junit:junit-dep:4.11',
diff --git a/mifosng-provider/dev-dependencies.gradle b/mifosng-provider/dev-dependencies.gradle
index 573f262d3..aa3aa9a7e 100644
--- a/mifosng-provider/dev-dependencies.gradle
+++ b/mifosng-provider/dev-dependencies.gradle
@@ -81,7 +81,9 @@ dependencies {
// Although Mifos (at the time of writing) doesn't have any compile time dep. on this,
// it's useful to have this for the Spring Boot TestRestTemplate http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-rest-templates-test-utility
- [group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.5']
+ [group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.3.5'],
+ // Once we've switched to Java 8 this dep can be removed.
+ [group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.0']
)
testCompile 'junit:junit:4.11',
'junit:junit-dep:4.11',
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/annotation/CommandType.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/annotation/CommandType.java
new file mode 100644
index 000000000..23764bc97
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/annotation/CommandType.java
@@ -0,0 +1,33 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.commands.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * Specifies the command type for the annotated class.
+ *
+ * The entity name (e.g. CLIENT, SAVINGSACCOUNT, LOANPRODUCT) and the action (e.g. CREATE, DELETE) must be given.
+ *
+ * @author Markus Geiss
+ * @version 1.0
+ * @since 15.06
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+public @interface CommandType {
+
+ /**
+ * Returns the name of the entity for this {@link CommandType}.
+ */
+ String entity();
+
+ /**
+ * Return the name of the action for this {@link CommandType}.
+ */
+ String action();
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/provider/CommandHandlerProvider.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/provider/CommandHandlerProvider.java
new file mode 100644
index 000000000..ce6375248
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/provider/CommandHandlerProvider.java
@@ -0,0 +1,72 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.commands.provider;
+
+import com.google.common.base.Preconditions;
+import org.apache.commons.lang3.StringUtils;
+import org.mifosplatform.commands.annotation.CommandType;
+import org.mifosplatform.commands.exception.UnsupportedCommandException;
+import org.mifosplatform.commands.handler.NewCommandSourceHandler;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Nonnull;
+import java.util.HashMap;
+
+/**
+ * {@link CommandHandlerProvider} provides {@link NewCommandSourceHandler}s for a given entity and action.
+ *
+ * A {@link NewCommandSourceHandler} can be registered and the annotation {@link CommandType} is used to determine
+ * the entity and the action the handler is capable to process.
+ *
+ * @author Markus Geiss
+ * @version 1.0
+ * @since 15.06
+ * @see NewCommandSourceHandler
+ * @see CommandType
+ */
+@Component
+@Scope("singleton")
+public class CommandHandlerProvider {
+
+ private final HashMap registeredHandlers = new HashMap<>();
+
+ CommandHandlerProvider() {
+ super();
+ }
+
+ /**
+ * Registers a {@link NewCommandSourceHandler} using the annotation {@link CommandType} to register the handler.
+ *
+ * @param handler the {@link NewCommandSourceHandler} to be added, must be given
+ */
+ public void registerHandler(@Nonnull final C handler) {
+ Preconditions.checkArgument(handler != null, "A handler must be given!");
+
+ final CommandType commandType = handler.getClass().getAnnotation(CommandType.class);
+ this.registeredHandlers.put(commandType.entity() + "|" + commandType.action(), handler);
+ }
+
+ /**
+ * Returns a handler gor the given entity and action.
+ *
+ * Throws an {@link UnsupportedCommandException} if no handler
+ * for the given entity, action combination can be found.
+ * @param entity the entity to lookup the handler, must be given.
+ * @param action the action to lookup the handler, must be given.
+ */
+ @Nonnull
+ public NewCommandSourceHandler getHandler (@Nonnull final String entity, @Nonnull final String action) {
+ Preconditions.checkArgument(StringUtils.isNoneEmpty(entity), "An entity must be given!");
+ Preconditions.checkArgument(StringUtils.isNoneEmpty(action), "An action must be given!");
+
+ final String key = entity + "|" + action;
+ if (!this.registeredHandlers.containsKey(key)) {
+ throw new UnsupportedCommandException(key);
+ }
+ return this.registeredHandlers.get(entity + "|" + action);
+ }
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
index 9bb20affc..6072e0bd4 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
@@ -14,6 +14,7 @@ import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.exception.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.mifosplatform.commands.exception.UnsupportedCommandException;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
+import org.mifosplatform.commands.provider.CommandHandlerProvider;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
@@ -38,12 +39,14 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
private final ToApiJsonSerializer toApiResultJsonSerializer;
private CommandSourceRepository commandSourceRepository;
private final ConfigurationDomainService configurationDomainService;
+ private final CommandHandlerProvider commandHandlerProvider;
@Autowired
public SynchronousCommandProcessingService(final PlatformSecurityContext context, final ApplicationContext applicationContext,
final ToApiJsonSerializer