Merge pull request #1363 from mgeiss/command-provider

Command provider
This commit is contained in:
Vishwas Babu A J
2015-04-26 19:57:20 -07:00
9 changed files with 218 additions and 3 deletions
+3 -1
View File
@@ -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',
+3 -1
View File
@@ -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',
@@ -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.<br/>
* <br/>
* 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();
}
@@ -0,0 +1,85 @@
/**
* 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.ArrayUtils;
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.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
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.<br/>
* <br/>
* 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 implements ApplicationContextAware {
private ApplicationContext applicationContext;
private HashMap<String, String> registeredHandlers;
CommandHandlerProvider() {
super();
}
/**
* Returns a handler for the given entity and action.<br/>
* <br/>
* 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 (NewCommandSourceHandler)this.applicationContext.getBean(this.registeredHandlers.get(key));
}
private void initializeHandlerRegistry() {
if (this.registeredHandlers == null) {
this.registeredHandlers = new HashMap<>();
final String[] commandHandlerBeans = this.applicationContext.getBeanNamesForAnnotation(CommandType.class);
if (ArrayUtils.isNotEmpty(commandHandlerBeans)) {
for (final String commandHandlerName : commandHandlerBeans) {
final CommandType commandType = this.applicationContext.getType(commandHandlerName).getAnnotation(CommandType.class);
this.registeredHandlers.put(commandType.entity() + "|" + commandType.action(), commandHandlerName);
}
}
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
this.initializeHandlerRegistry();
}
}
@@ -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<CommandProcessingResult> toApiResultJsonSerializer;
private CommandSourceRepository commandSourceRepository;
private final ConfigurationDomainService configurationDomainService;
private final CommandHandlerProvider commandHandlerProvider;
@Autowired
public SynchronousCommandProcessingService(final PlatformSecurityContext context, final ApplicationContext applicationContext,
final ToApiJsonSerializer<Map<String, Object>> toApiJsonSerializer,
final ToApiJsonSerializer<CommandProcessingResult> toApiResultJsonSerializer,
final CommandSourceRepository commandSourceRepository, final ConfigurationDomainService configurationDomainService) {
final CommandSourceRepository commandSourceRepository, final ConfigurationDomainService configurationDomainService,
final CommandHandlerProvider commandHandlerProvider) {
this.context = context;
this.context = context;
this.applicationContext = applicationContext;
@@ -52,6 +55,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
this.commandSourceRepository = commandSourceRepository;
this.commandSourceRepository = commandSourceRepository;
this.configurationDomainService = configurationDomainService;
this.commandHandlerProvider = commandHandlerProvider;
}
@Transactional
@@ -62,6 +66,10 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
final boolean rollbackTransaction = this.configurationDomainService.isMakerCheckerEnabledForTask(wrapper.taskPermissionName());
final NewCommandSourceHandler handler = findCommandHandler(wrapper);
// TODO remove line 64 and uncomment following statement once all handlers are refactored
// final NewCommandSourceHandler handler = this.commandHandlerProvider.getHandler(wrapper.entityName(), wrapper.actionName());
final CommandProcessingResult result = handler.processCommand(command);
final AppUser maker = this.context.authenticatedUser(wrapper);
@@ -124,6 +132,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
.withEntityId(commandSourceResult.getResourceId()).build();
}
// TODO remove this method once all handlers are refactored
@Deprecated
private NewCommandSourceHandler findCommandHandler(final CommandWrapper wrapper) {
NewCommandSourceHandler handler = null;
@@ -5,7 +5,9 @@
*/
package org.mifosplatform.portfolio.client.handler;
import org.mifosplatform.commands.annotation.CommandType;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.commands.provider.CommandHandlerProvider;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.client.service.ClientWritePlatformService;
@@ -14,6 +16,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@CommandType(entity = "CLIENT", action = "CREATE")
public class CreateClientCommandHandler implements NewCommandSourceHandler {
private final ClientWritePlatformService clientWritePlatformService;
@@ -27,6 +27,7 @@
<context:component-scan
base-package="org.mifosplatform.accounting.*,
org.mifosplatform.commands.provider.*,
org.mifosplatform.commands.handler.*,
org.mifosplatform.commands.service.*,
org.mifosplatform.commands.*,
@@ -0,0 +1,53 @@
/**
* 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 org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mifosplatform.commands.exception.UnsupportedCommandException;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.configuration.spring.TestsWithoutDatabaseAndNoJobsConfiguration;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = TestsWithoutDatabaseAndNoJobsConfiguration.class)
public class CommandHandlerProviderTest {
@Autowired
private CommandHandlerProvider commandHandlerProvider;
public CommandHandlerProviderTest() {
super();
}
@Test
public void shouldRegisterHandler() {
try {
final Long testCommandId = 815L;
final NewCommandSourceHandler registeredHandler = this.commandHandlerProvider.getHandler("HUMAN", "UPDATE");
final CommandProcessingResult result =
registeredHandler.processCommand(
JsonCommand.fromExistingCommand(testCommandId, null, null, null, null, null, null, null, null));
Assert.assertEquals(testCommandId, result.commandId());
} catch (UnsupportedCommandException ucex) {
Assert.fail();
}
}
@Test(expected = UnsupportedCommandException.class)
public void shouldThrowUnsupportedCommandException() {
this.commandHandlerProvider.getHandler("WHATEVER", "DOSOMETHING");
}
}
@@ -0,0 +1,26 @@
/**
* 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 org.mifosplatform.commands.annotation.CommandType;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.springframework.stereotype.Component;
@Component
@CommandType(entity = "HUMAN", action = "UPDATE")
public class ValidCommandHandler implements NewCommandSourceHandler {
public ValidCommandHandler() {
super();
}
@Override
public CommandProcessingResult processCommand(JsonCommand command) {
return CommandProcessingResult.commandOnlyResult(command.commandId());
}
}