FINERACT-1744: Tiny refactorings as a preparation for idempotency implementation
This commit is contained in:
committed by
Arnold Gálovics
parent
622e32e737
commit
b5b189d610
+5
-29
@@ -18,6 +18,11 @@
|
||||
*/
|
||||
package org.apache.fineract.commands.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum CommandProcessingResultType {
|
||||
|
||||
INVALID(0, "commandProcessingResultType.invalid"), //
|
||||
@@ -27,33 +32,4 @@ public enum CommandProcessingResultType {
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
CommandProcessingResultType(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static CommandProcessingResultType fromInt(final Integer typeValue) {
|
||||
CommandProcessingResultType type = CommandProcessingResultType.INVALID;
|
||||
switch (typeValue) {
|
||||
case 1:
|
||||
type = PROCESSED;
|
||||
break;
|
||||
case 2:
|
||||
type = AWAITING_APPROVAL;
|
||||
break;
|
||||
case 3:
|
||||
type = REJECTED;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
+25
-24
@@ -28,6 +28,7 @@ import org.apache.fineract.commands.annotation.CommandType;
|
||||
import org.apache.fineract.commands.exception.UnsupportedCommandException;
|
||||
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -47,10 +48,30 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
@NoArgsConstructor
|
||||
@Slf4j
|
||||
public class CommandHandlerProvider implements ApplicationContextAware {
|
||||
public class CommandHandlerProvider implements ApplicationContextAware, InitializingBean {
|
||||
|
||||
private final HashMap<String, String> registeredHandlers = new HashMap<>();
|
||||
private ApplicationContext applicationContext;
|
||||
private HashMap<String, String> registeredHandlers;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
initializeHandlerRegistry();
|
||||
}
|
||||
|
||||
private void initializeHandlerRegistry() {
|
||||
final String[] commandHandlerBeans = applicationContext.getBeanNamesForAnnotation(CommandType.class);
|
||||
if (ArrayUtils.isNotEmpty(commandHandlerBeans)) {
|
||||
for (final String commandHandlerName : commandHandlerBeans) {
|
||||
log.debug("Register command handler '{}' ...", commandHandlerName);
|
||||
final CommandType commandType = applicationContext.findAnnotationOnBean(commandHandlerName, CommandType.class);
|
||||
try {
|
||||
registeredHandlers.put(commandType.entity() + "|" + commandType.action(), commandHandlerName);
|
||||
} catch (final Throwable th) {
|
||||
log.error("Unable to register command handler '{}'!", commandHandlerName, th);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a handler for the given entity and action.<br>
|
||||
@@ -68,34 +89,14 @@ public class CommandHandlerProvider implements ApplicationContextAware {
|
||||
Preconditions.checkArgument(StringUtils.isNoneEmpty(action), "An action must be given!");
|
||||
|
||||
final String key = entity + "|" + action;
|
||||
if (!this.registeredHandlers.containsKey(key)) {
|
||||
if (!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) {
|
||||
log.debug("Register command handler '{}' ...", commandHandlerName);
|
||||
final CommandType commandType = this.applicationContext.findAnnotationOnBean(commandHandlerName, CommandType.class);
|
||||
try {
|
||||
this.registeredHandlers.put(commandType.entity() + "|" + commandType.action(), commandHandlerName);
|
||||
} catch (final Throwable th) {
|
||||
log.error("Unable to register command handler '{}'!", commandHandlerName, th);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (NewCommandSourceHandler) applicationContext.getBean(registeredHandlers.get(key));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
this.initializeHandlerRegistry();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ import org.apache.fineract.useradministration.domain.AppUser;
|
||||
|
||||
public interface CommandProcessingService {
|
||||
|
||||
CommandProcessingResult processAndLogCommand(CommandWrapper wrapper, JsonCommand command, boolean isApprovedByChecker);
|
||||
CommandProcessingResult executeCommand(CommandWrapper wrapper, JsonCommand command, boolean isApprovedByChecker);
|
||||
|
||||
CommandProcessingResult logCommand(CommandSource commandSourceResult);
|
||||
|
||||
|
||||
+3
-3
@@ -77,7 +77,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
|
||||
final String json = wrapper.getJson();
|
||||
CommandProcessingResult result = null;
|
||||
JsonCommand command = null;
|
||||
JsonCommand command;
|
||||
int numberOfRetries = 0;
|
||||
int maxNumberOfRetries = ThreadLocalContextUtil.getTenant().getConnection().getMaxRetriesOnDeadlock();
|
||||
int maxIntervalBetweenRetries = ThreadLocalContextUtil.getTenant().getConnection().getMaxIntervalBetweenRetries();
|
||||
@@ -88,7 +88,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
wrapper.getOrganisationCreditBureauId());
|
||||
while (numberOfRetries <= maxNumberOfRetries) {
|
||||
try {
|
||||
result = this.processAndLogCommandService.processAndLogCommand(wrapper, command, isApprovedByChecker);
|
||||
result = this.processAndLogCommandService.executeCommand(wrapper, command, isApprovedByChecker);
|
||||
numberOfRetries = maxNumberOfRetries + 1;
|
||||
} catch (CannotAcquireLockException | ObjectOptimisticLockingFailureException exception) {
|
||||
log.info("The following command {} has been retried {} time(s)", command.json(), numberOfRetries);
|
||||
@@ -140,7 +140,7 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
|
||||
commandSourceInput.getOrganisationCreditBureauId());
|
||||
|
||||
final boolean makerCheckerApproval = true;
|
||||
return this.processAndLogCommandService.processAndLogCommand(wrapper, command, makerCheckerApproval);
|
||||
return this.processAndLogCommandService.executeCommand(wrapper, command, makerCheckerApproval);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
||||
+32
-33
@@ -65,10 +65,10 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processAndLogCommand(final CommandWrapper wrapper, final JsonCommand command,
|
||||
public CommandProcessingResult executeCommand(final CommandWrapper wrapper, final JsonCommand command,
|
||||
final boolean isApprovedByChecker) {
|
||||
|
||||
final boolean rollbackTransaction = this.configurationDomainService.isMakerCheckerEnabledForTask(wrapper.taskPermissionName());
|
||||
final boolean rollbackTransaction = configurationDomainService.isMakerCheckerEnabledForTask(wrapper.taskPermissionName());
|
||||
|
||||
final NewCommandSourceHandler handler = findCommandHandler(wrapper);
|
||||
|
||||
@@ -76,16 +76,15 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
try {
|
||||
result = handler.processCommand(command);
|
||||
} catch (Throwable t) {
|
||||
// publish error event
|
||||
publishErrorEvent(wrapper, command, t);
|
||||
publishHookErrorEvent(wrapper, command, t);
|
||||
throw t;
|
||||
}
|
||||
|
||||
final AppUser maker = this.context.authenticatedUser(wrapper);
|
||||
final AppUser maker = context.authenticatedUser(wrapper);
|
||||
|
||||
CommandSource commandSourceResult;
|
||||
if (command.commandId() != null) {
|
||||
commandSourceResult = this.commandSourceRepository.findById(command.commandId())
|
||||
commandSourceResult = commandSourceRepository.findById(command.commandId())
|
||||
.orElseThrow(() -> new CommandNotFoundException(command.commandId()));
|
||||
commandSourceResult.markAsChecked(maker);
|
||||
} else {
|
||||
@@ -98,7 +97,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
String changesOnlyJson;
|
||||
boolean rollBack = (rollbackTransaction || result.isRollbackTransaction()) && !isApprovedByChecker;
|
||||
if (result.hasChanges() && !rollBack) {
|
||||
changesOnlyJson = this.toApiJsonSerializer.serializeResult(result.getChanges());
|
||||
changesOnlyJson = toApiJsonSerializer.serializeResult(result.getChanges());
|
||||
commandSourceResult.updateJsonTo(changesOnlyJson);
|
||||
}
|
||||
|
||||
@@ -107,7 +106,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
}
|
||||
|
||||
if (commandSourceResult.hasJson()) {
|
||||
this.commandSourceRepository.save(commandSourceResult);
|
||||
commandSourceRepository.save(commandSourceResult);
|
||||
}
|
||||
|
||||
if ((rollbackTransaction || result.isRollbackTransaction()) && !isApprovedByChecker) {
|
||||
@@ -125,7 +124,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
}
|
||||
result.setRollbackTransaction(null);
|
||||
|
||||
publishEvent(wrapper.entityName(), wrapper.actionName(), command, result);
|
||||
publishHookEvent(wrapper.entityName(), wrapper.actionName(), command, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -135,7 +134,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
public CommandProcessingResult logCommand(CommandSource commandSourceResult) {
|
||||
|
||||
commandSourceResult.markAsAwaitingApproval();
|
||||
commandSourceResult = this.commandSourceRepository.saveAndFlush(commandSourceResult);
|
||||
commandSourceResult = commandSourceRepository.saveAndFlush(commandSourceResult);
|
||||
|
||||
return new CommandProcessingResultBuilder().withCommandId(commandSourceResult.getId())
|
||||
.withEntityId(commandSourceResult.getResourceId()).build();
|
||||
@@ -146,54 +145,54 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
|
||||
if (wrapper.isDatatableResource()) {
|
||||
if (wrapper.isCreateDatatable()) {
|
||||
handler = this.applicationContext.getBean("createDatatableCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("createDatatableCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDeleteDatatable()) {
|
||||
handler = this.applicationContext.getBean("deleteDatatableCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("deleteDatatableCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdateDatatable()) {
|
||||
handler = this.applicationContext.getBean("updateDatatableCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("updateDatatableCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isCreate()) {
|
||||
handler = this.applicationContext.getBean("createDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("createDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdateMultiple()) {
|
||||
handler = this.applicationContext.getBean("updateOneToManyDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("updateOneToManyDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdateOneToOne()) {
|
||||
handler = this.applicationContext.getBean("updateOneToOneDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("updateOneToOneDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDeleteMultiple()) {
|
||||
handler = this.applicationContext.getBean("deleteOneToManyDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("deleteOneToManyDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDeleteOneToOne()) {
|
||||
handler = this.applicationContext.getBean("deleteOneToOneDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("deleteOneToOneDatatableEntryCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isRegisterDatatable()) {
|
||||
handler = this.applicationContext.getBean("registerDatatableCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("registerDatatableCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else if (wrapper.isNoteResource()) {
|
||||
if (wrapper.isCreate()) {
|
||||
handler = this.applicationContext.getBean("createNoteCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("createNoteCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isUpdate()) {
|
||||
handler = this.applicationContext.getBean("updateNoteCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("updateNoteCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isDelete()) {
|
||||
handler = this.applicationContext.getBean("deleteNoteCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("deleteNoteCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else if (wrapper.isSurveyResource()) {
|
||||
if (wrapper.isRegisterSurvey()) {
|
||||
handler = this.applicationContext.getBean("registerSurveyCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("registerSurveyCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.isFullFilSurvey()) {
|
||||
handler = this.applicationContext.getBean("fullFilSurveyCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("fullFilSurveyCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else if (wrapper.isLoanDisburseDetailResource()) {
|
||||
if (wrapper.isUpdateDisbursementDate()) {
|
||||
handler = this.applicationContext.getBean("updateLoanDisbuseDateCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("updateLoanDisburseDateCommandHandler", NewCommandSourceHandler.class);
|
||||
} else if (wrapper.addAndDeleteDisbursementDetails()) {
|
||||
handler = this.applicationContext.getBean("addAndDeleteLoanDisburseDetailsCommandHandler", NewCommandSourceHandler.class);
|
||||
handler = applicationContext.getBean("addAndDeleteLoanDisburseDetailsCommandHandler", NewCommandSourceHandler.class);
|
||||
} else {
|
||||
throw new UnsupportedCommandException(wrapper.commandName());
|
||||
}
|
||||
} else {
|
||||
handler = this.commandHandlerProvider.getHandler(wrapper.entityName(), wrapper.actionName());
|
||||
handler = commandHandlerProvider.getHandler(wrapper.entityName(), wrapper.actionName());
|
||||
}
|
||||
|
||||
return handler;
|
||||
@@ -201,12 +200,12 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
|
||||
@Override
|
||||
public boolean validateCommand(final CommandWrapper commandWrapper, final AppUser user) {
|
||||
boolean rollbackTransaction = this.configurationDomainService.isMakerCheckerEnabledForTask(commandWrapper.taskPermissionName());
|
||||
boolean rollbackTransaction = configurationDomainService.isMakerCheckerEnabledForTask(commandWrapper.taskPermissionName());
|
||||
user.validateHasPermissionTo(commandWrapper.getTaskPermissionName());
|
||||
return rollbackTransaction;
|
||||
}
|
||||
|
||||
private void publishErrorEvent(CommandWrapper wrapper, JsonCommand command, Throwable t) {
|
||||
private void publishHookErrorEvent(CommandWrapper wrapper, JsonCommand command, Throwable t) {
|
||||
|
||||
ErrorInfo ex;
|
||||
if (t instanceof final RuntimeException e) {
|
||||
@@ -215,13 +214,13 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
ex = new ErrorInfo(500, 9999, "{\"Exception\": " + t.toString() + "}");
|
||||
}
|
||||
|
||||
publishEvent(wrapper.entityName(), wrapper.actionName(), command, ex);
|
||||
publishHookEvent(wrapper.entityName(), wrapper.actionName(), command, ex);
|
||||
}
|
||||
|
||||
private void publishEvent(final String entityName, final String actionName, JsonCommand command, final Object result) {
|
||||
private void publishHookEvent(final String entityName, final String actionName, JsonCommand command, final Object result) {
|
||||
Gson gson = new Gson();
|
||||
try {
|
||||
final AppUser appUser = this.context.authenticatedUser(CommandWrapper.wrap(actionName, entityName, null, null));
|
||||
final AppUser appUser = context.authenticatedUser(CommandWrapper.wrap(actionName, entityName, null, null));
|
||||
|
||||
final HookEventSource hookEventSource = new HookEventSource(entityName, actionName);
|
||||
|
||||
@@ -260,7 +259,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
|
||||
|
||||
reqmap.put("timestamp", Instant.now().toString());
|
||||
|
||||
final String serializedResult = this.toApiResultJsonSerializer.serialize(reqmap);
|
||||
final String serializedResult = toApiResultJsonSerializer.serialize(reqmap);
|
||||
|
||||
final HookEvent applicationEvent = new HookEvent(hookEventSource, serializedResult, appUser,
|
||||
ThreadLocalContextUtil.getContext());
|
||||
|
||||
+2
-2
@@ -52,11 +52,11 @@ public class FineractHookListener implements HookListener {
|
||||
final String actionName = hookEventSource.getActionName();
|
||||
final String payload = event.getPayload();
|
||||
|
||||
final List<Hook> hooks = this.hookReadPlatformService.retrieveHooksByEvent(hookEventSource.getEntityName(),
|
||||
final List<Hook> hooks = hookReadPlatformService.retrieveHooksByEvent(hookEventSource.getEntityName(),
|
||||
hookEventSource.getActionName());
|
||||
|
||||
for (final Hook hook : hooks) {
|
||||
final HookProcessor processor = this.hookProcessorProvider.getProcessor(hook);
|
||||
final HookProcessor processor = hookProcessorProvider.getProcessor(hook);
|
||||
try {
|
||||
processor.process(hook, payload, entityName, actionName, fineractContext);
|
||||
} catch (Throwable e) {
|
||||
|
||||
+1
-1
@@ -125,7 +125,7 @@ public class SchedulerJobRunnerReadServiceImpl implements SchedulerJobRunnerRead
|
||||
public boolean isUpdatesAllowed() {
|
||||
final String sql = "select job.display_name from job job where job.currently_running=true and job.updates_allowed=false";
|
||||
final List<String> names = this.jdbcTemplate.queryForList(sql, String.class);
|
||||
if (names != null && names.size() > 0) {
|
||||
if (names.size() > 0) {
|
||||
final String listVals = names.toString();
|
||||
final String jobNames = listVals.substring(listVals.indexOf("[") + 1, listVals.indexOf("]"));
|
||||
throw new OperationNotAllowedException(jobNames);
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class UpdateLoanDisbuseDateCommandHandler implements NewCommandSourceHandler {
|
||||
public class UpdateLoanDisburseDateCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final LoanWritePlatformService writePlatformService;
|
||||
|
||||
Reference in New Issue
Block a user