MIFOSX-97: update way of handling updates for client and codes.

This commit is contained in:
Keith Woodlock
2012-12-06 15:31:54 +00:00
parent cb6ea0ae63
commit 669503b34b
16 changed files with 163 additions and 178 deletions
@@ -93,6 +93,10 @@ public class CommandSource extends AbstractPersistable<Long> {
return this.resourceId; return this.resourceId;
} }
public boolean hasJson() {
return StringUtils.isNotBlank(this.commandAsJson);
}
public String json() { public String json() {
return this.commandAsJson; return this.commandAsJson;
} }
@@ -46,11 +46,9 @@ public class ClientCommandHandler implements CommandSourceHandler {
final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper); final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper);
CommandSource commandSourceResult = commandSource.copy(); CommandSource commandSourceResult = commandSource.copy();
Long newResourceId = null;
if (commandSource.isCreate()) { if (commandSource.isCreate()) {
try { try {
newResourceId = this.clientWritePlatformService.createClient(command); Long newResourceId = this.clientWritePlatformService.createClient(command);
commandSourceResult.markAsChecked(maker, asToday); commandSourceResult.markAsChecked(maker, asToday);
commandSourceResult.updateResourceId(newResourceId); commandSourceResult.updateResourceId(newResourceId);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
@@ -59,8 +57,6 @@ public class ClientCommandHandler implements CommandSourceHandler {
} else if (commandSource.isUpdate()) { } else if (commandSource.isUpdate()) {
try { try {
EntityIdentifier result = this.clientWritePlatformService.updateClientDetails(commandSource.resourceId(), command); EntityIdentifier result = this.clientWritePlatformService.updateClientDetails(commandSource.resourceId(), command);
newResourceId = result.getEntityId();
final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges()); final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges());
commandSourceResult.updateJsonTo(jsonOfChangesOnly); commandSourceResult.updateJsonTo(jsonOfChangesOnly);
@@ -70,8 +66,7 @@ public class ClientCommandHandler implements CommandSourceHandler {
} }
} else if (commandSource.isDelete()) { } else if (commandSource.isDelete()) {
try { try {
EntityIdentifier result = this.clientWritePlatformService.deleteClient(commandSource.resourceId(), command); this.clientWritePlatformService.deleteClient(commandSource.resourceId(), command);
newResourceId = result.getEntityId();
commandSourceResult.markAsChecked(maker, asToday); commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design // swallow this rollback transaction by design
@@ -102,7 +97,11 @@ public class ClientCommandHandler implements CommandSourceHandler {
"UPDATE_CLIENT_CHECKER"); "UPDATE_CLIENT_CHECKER");
context.authenticatedUser().validateHasPermissionTo("UPDATE_CLIENT_CHECKER", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("UPDATE_CLIENT_CHECKER", allowedPermissions);
this.clientWritePlatformService.updateClientDetails(commandSourceResult.resourceId(), command); EntityIdentifier result = this.clientWritePlatformService.updateClientDetails(commandSourceResult.resourceId(), command);
final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges());
commandSourceResult.updateJsonTo(jsonOfChangesOnly);
commandSourceResult.markAsChecked(checker, new LocalDate()); commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isDelete()) { } else if (commandSourceResult.isDelete()) {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER", final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "PORTFOLIO_MANAGEMENT_SUPER_USER",
@@ -5,27 +5,35 @@ import java.util.List;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.commands.domain.CommandSource; import org.mifosplatform.commands.domain.CommandSource;
import org.mifosplatform.infrastructure.codes.command.CodeCommand;
import org.mifosplatform.infrastructure.codes.serialization.CodeCommandFromCommandJsonDeserializer;
import org.mifosplatform.infrastructure.codes.service.CodeWritePlatformService; import org.mifosplatform.infrastructure.codes.service.CodeWritePlatformService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException; import org.mifosplatform.portfolio.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.google.gson.JsonElement;
@Service @Service
public class CodeCommandHandler implements CommandSourceHandler { public class CodeCommandHandler implements CommandSourceHandler {
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final CodeCommandFromCommandJsonDeserializer fromCommandJsonDeserializer; private final FromJsonHelper fromApiJsonHelper;
private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer;
private final CodeWritePlatformService writePlatformService; private final CodeWritePlatformService writePlatformService;
@Autowired @Autowired
public CodeCommandHandler(final PlatformSecurityContext context, public CodeCommandHandler(final PlatformSecurityContext context,
final CodeCommandFromCommandJsonDeserializer fromCommandJsonDeserializer, final CodeWritePlatformService writePlatformService) { final FromJsonHelper fromApiJsonHelper,
final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson toApiJsonSerializer,
final CodeWritePlatformService writePlatformService) {
this.context = context; this.context = context;
this.fromCommandJsonDeserializer = fromCommandJsonDeserializer; this.fromApiJsonHelper = fromApiJsonHelper;
this.toApiJsonSerializer = toApiJsonSerializer;
this.writePlatformService = writePlatformService; this.writePlatformService = writePlatformService;
} }
@@ -36,7 +44,8 @@ public class CodeCommandHandler implements CommandSourceHandler {
final LocalDate asToday = new LocalDate(); final LocalDate asToday = new LocalDate();
final Long resourceId = commandSource.resourceId(); final Long resourceId = commandSource.resourceId();
final CodeCommand command = this.fromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSource.json()); final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSource.json());
final JsonCommand command = JsonCommand.from(commandSource.json(), parsedCommand, this.fromApiJsonHelper);
CommandSource commandSourceResult = commandSource.copy(); CommandSource commandSourceResult = commandSource.copy();
@@ -50,7 +59,10 @@ public class CodeCommandHandler implements CommandSourceHandler {
} }
} else if (commandSource.isUpdate()) { } else if (commandSource.isUpdate()) {
try { try {
this.writePlatformService.updateCode(command); EntityIdentifier result = this.writePlatformService.updateCode(resourceId, command);
final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges());
commandSourceResult.updateJsonTo(jsonOfChangesOnly);
commandSourceResult.markAsChecked(maker, asToday); commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
@@ -58,7 +70,7 @@ public class CodeCommandHandler implements CommandSourceHandler {
} }
} else if (commandSource.isDelete()) { } else if (commandSource.isDelete()) {
try { try {
this.writePlatformService.deleteCode(command); this.writePlatformService.deleteCode(resourceId, command);
commandSourceResult.markAsChecked(maker, asToday); commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) { } catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design // swallow this rollback transaction by design
@@ -74,7 +86,8 @@ public class CodeCommandHandler implements CommandSourceHandler {
final AppUser checker = context.authenticatedUser(); final AppUser checker = context.authenticatedUser();
Long resourceId = commandSourceResult.resourceId(); Long resourceId = commandSourceResult.resourceId();
final CodeCommand command = this.fromCommandJsonDeserializer.commandFromCommandJson(resourceId, commandSourceResult.json(), true); final JsonElement parsedCommand = this.fromApiJsonHelper.parse(commandSourceResult.json());
final JsonCommand command = JsonCommand.withMakerCheckerApproval(commandSourceResult.json(), parsedCommand, this.fromApiJsonHelper);
if (commandSourceResult.isCreate()) { if (commandSourceResult.isCreate()) {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "CREATE_CODE_MAKER"); final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "CREATE_CODE_MAKER");
@@ -87,13 +100,17 @@ public class CodeCommandHandler implements CommandSourceHandler {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "UPDATE_CODE_MAKER"); final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "UPDATE_CODE_MAKER");
context.authenticatedUser().validateHasPermissionTo("UPDATE_CODE_MAKER", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("UPDATE_CODE_MAKER", allowedPermissions);
this.writePlatformService.updateCode(command); EntityIdentifier result = this.writePlatformService.updateCode(resourceId, command);
final String jsonOfChangesOnly = toApiJsonSerializer.serialize(result.getChanges());
commandSourceResult.updateJsonTo(jsonOfChangesOnly);
commandSourceResult.markAsChecked(checker, new LocalDate()); commandSourceResult.markAsChecked(checker, new LocalDate());
} else if (commandSourceResult.isDelete()) { } else if (commandSourceResult.isDelete()) {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "DELETE_CODE_MAKER"); final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "DELETE_CODE_MAKER");
context.authenticatedUser().validateHasPermissionTo("DELETE_CODE_MAKER", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("DELETE_CODE_MAKER", allowedPermissions);
this.writePlatformService.deleteCode(command); this.writePlatformService.deleteCode(resourceId, command);
commandSourceResult.markAsChecked(checker, new LocalDate()); commandSourceResult.markAsChecked(checker, new LocalDate());
} }
@@ -36,7 +36,10 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
final CommandSource commandSourceInput = CommandSource.createdBy(apiOperation, resource, resourceId, commandSerializedAsJson, maker, asToday); final CommandSource commandSourceInput = CommandSource.createdBy(apiOperation, resource, resourceId, commandSerializedAsJson, maker, asToday);
final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleCommandWithSupportForRollback(commandSourceInput); final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleCommandWithSupportForRollback(commandSourceInput);
commandSourceRepository.save(commandSourceResult);
if (commandSourceResult.hasJson()) {
commandSourceRepository.save(commandSourceResult);
}
return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId()); return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId());
} }
@@ -49,7 +52,9 @@ public class PortfolioCommandSourceWritePlatformServiceImpl implements Portfolio
final CommandSource commandSourceInput = this.commandSourceRepository.findOne(id); final CommandSource commandSourceInput = this.commandSourceRepository.findOne(id);
final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleCommandForCheckerApproval(commandSourceInput); final CommandSource commandSourceResult = this.commandSourceHandlerDelegator.handleCommandForCheckerApproval(commandSourceInput);
commandSourceRepository.save(commandSourceResult); if (commandSourceResult.hasJson()) {
commandSourceRepository.save(commandSourceResult);
}
return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId()); return EntityIdentifier.makerChecker(commandSourceResult.resourceId(), commandSourceResult.getId());
} }
@@ -20,7 +20,6 @@ import javax.ws.rs.core.UriInfo;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.codes.data.CodeData; import org.mifosplatform.infrastructure.codes.data.CodeData;
import org.mifosplatform.infrastructure.codes.serialization.CodeCommandFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.codes.service.CodeReadPlatformService; import org.mifosplatform.infrastructure.codes.service.CodeReadPlatformService;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
@@ -44,19 +43,16 @@ public class CodesApiResource {
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final CodeReadPlatformService readPlatformService; private final CodeReadPlatformService readPlatformService;
private final CodeCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final DefaultToApiJsonSerializer<CodeData> toApiJsonSerializer; private final DefaultToApiJsonSerializer<CodeData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper; private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired @Autowired
public CodesApiResource(final PlatformSecurityContext context, final CodeReadPlatformService readPlatformService, public CodesApiResource(final PlatformSecurityContext context, final CodeReadPlatformService readPlatformService,
final CodeCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final DefaultToApiJsonSerializer<CodeData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper, final DefaultToApiJsonSerializer<CodeData> toApiJsonSerializer, final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context; this.context = context;
this.readPlatformService = readPlatformService; this.readPlatformService = readPlatformService;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.toApiJsonSerializer = toApiJsonSerializer; this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper; this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
@@ -83,10 +79,8 @@ public class CodesApiResource {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "CREATE_CODE"); final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "CREATE_CODE");
context.authenticatedUser().validateHasPermissionTo("CREATE_CODE", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("CREATE_CODE", allowedPermissions);
final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(apiRequestBodyAsJson);
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "codes", null, final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "codes", null,
commandSerializedAsJson); apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(result); return this.toApiJsonSerializer.serialize(result);
} }
@@ -112,10 +106,8 @@ public class CodesApiResource {
final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "UPDATE_CODE"); final List<String> allowedPermissions = Arrays.asList("ALL_FUNCTIONS", "UPDATE_CODE");
context.authenticatedUser().validateHasPermissionTo("UPDATE_CODE", allowedPermissions); context.authenticatedUser().validateHasPermissionTo("UPDATE_CODE", allowedPermissions);
final String commandSerializedAsJson = this.fromApiJsonDeserializer.serializedCommandJsonFromApiJson(codeId, apiRequestBodyAsJson);
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "codes", codeId, final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "codes", codeId,
commandSerializedAsJson); apiRequestBodyAsJson);
return this.toApiJsonSerializer.serialize(result); return this.toApiJsonSerializer.serialize(result);
} }
@@ -2,7 +2,6 @@ package org.mifosplatform.infrastructure.codes.command;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set;
import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
@@ -10,21 +9,12 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
/** /**
* <p>Immutable command for creating or updating details of a code.</p> * <p>Immutable command for creating or updating details of a code.</p>
*
* <p>Transient fields are not intended for serialization.</p>
*/ */
public class CodeCommand { public class CodeCommand {
private final String name; private final String name;
private final transient Set<String> parametersPassedInRequest; public CodeCommand(final String name) {
private final transient boolean makerCheckerApproval;
private final transient Long id;
public CodeCommand(final Set<String> modifiedParameters, final boolean makerCheckerApproval, final Long id, final String name) {
this.parametersPassedInRequest = modifiedParameters;
this.makerCheckerApproval = makerCheckerApproval;
this.id = id;
this.name = name; this.name = name;
} }
@@ -42,26 +32,11 @@ public class CodeCommand {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("code"); DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("code");
baseDataValidator.reset().parameter("id").value(this.id).notNull(); baseDataValidator.reset().parameter("name").value(this.name).notBlank();
baseDataValidator.reset().parameter("name").value(this.name).ignoreIfNull().notBlank();
baseDataValidator.reset().anyOfNotNull(this.name);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); } "Validation errors exist.", dataValidationErrors); }
} }
public String getName() {
return this.name;
}
public Long getId() {
return this.id;
}
public boolean isNameChanged() {
return this.parametersPassedInRequest.contains("name");
}
public boolean isApprovedByChecker() {
return this.makerCheckerApproval;
}
} }
@@ -1,5 +1,7 @@
package org.mifosplatform.infrastructure.codes.domain; package org.mifosplatform.infrastructure.codes.domain;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.persistence.CascadeType; import javax.persistence.CascadeType;
@@ -12,8 +14,8 @@ import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.LazyCollection; import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption; import org.hibernate.annotations.LazyCollectionOption;
import org.mifosplatform.infrastructure.codes.command.CodeCommand;
import org.mifosplatform.infrastructure.codes.exception.SystemDefinedCodeCannotBeChangedException; import org.mifosplatform.infrastructure.codes.exception.SystemDefinedCodeCannotBeChangedException;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.springframework.data.jpa.domain.AbstractPersistable; import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity @Entity
@@ -31,8 +33,9 @@ public class Code extends AbstractPersistable<Long> {
@OneToMany(cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true) @OneToMany(cascade = CascadeType.ALL, mappedBy = "code", orphanRemoval = true)
private Set<CodeValue> values; private Set<CodeValue> values;
public static Code createNew(final String codeName) { public static Code fromJson(final JsonCommand command) {
return new Code(codeName); final String name = command.stringValueOfParameterNamed("name");
return new Code(name);
} }
protected Code() { protected Code() {
@@ -52,14 +55,19 @@ public class Code extends AbstractPersistable<Long> {
return this.systemDefined; return this.systemDefined;
} }
public void update(final CodeCommand command) { public Map<String, Object> update(final JsonCommand command) {
if (systemDefined) { if (systemDefined) { throw new SystemDefinedCodeCannotBeChangedException(); }
throw new SystemDefinedCodeCannotBeChangedException();
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(1);
final String firstnameParamName = "name";
if (command.isChangeInStringParameterNamed(firstnameParamName, this.name)) {
final String newValue = command.stringValueOfParameterNamed(firstnameParamName);
actualChanges.put(firstnameParamName, newValue);
this.name = StringUtils.defaultIfEmpty(newValue, null);
} }
if (command.isNameChanged()) { return actualChanges;
this.name = StringUtils.defaultIfEmpty(command.getName(), null);
}
} }
} }
@@ -14,6 +14,7 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
/** /**
@@ -26,25 +27,24 @@ public final class CodeCommandFromApiJsonDeserializer extends AbstractFromApiJso
* The parameters supported for this command. * The parameters supported for this command.
*/ */
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("name")); private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("name"));
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
private final CodeCommandFromCommandJsonDeserializer fromCommandJsonDeserializer;
@Autowired @Autowired
public CodeCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, public CodeCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper, final CommandSerializer commandSerializerService) {
final CodeCommandFromCommandJsonDeserializer fromCommandJsonDeserializer, final CommandSerializer commandSerializerService) {
super(commandSerializerService); super(commandSerializerService);
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
this.fromCommandJsonDeserializer = fromCommandJsonDeserializer;
} }
@Override @Override
public CodeCommand commandFromApiJson(final Long codeId, final String json) { public CodeCommand commandFromApiJson(@SuppressWarnings("unused") final Long codeId, final String json) {
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
return this.fromCommandJsonDeserializer.commandFromCommandJson(codeId, json); final JsonElement element = fromApiJsonHelper.parse(json);
final String name = fromApiJsonHelper.extractStringNamed("name", element);
return new CodeCommand(name);
} }
} }
@@ -1,40 +0,0 @@
package org.mifosplatform.infrastructure.codes.serialization;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.infrastructure.codes.command.CodeCommand;
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
import org.mifosplatform.infrastructure.core.serialization.AbstractFromCommandJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
/**
*
*/
@Component
public final class CodeCommandFromCommandJsonDeserializer extends AbstractFromCommandJsonDeserializer<CodeCommand> {
private final FromJsonHelper fromJsonHelper;
@Autowired
public CodeCommandFromCommandJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromJsonHelper = fromApiJsonHelper;
}
@Override
public CodeCommand commandFromCommandJson(Long codeId, String commandAsJson, boolean makerCheckerApproval) {
if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); }
final Set<String> parametersPassedInRequest = new HashSet<String>();
final JsonElement element = fromJsonHelper.parse(commandAsJson);
final String name = fromJsonHelper.extractStringNamed("name", element, parametersPassedInRequest);
return new CodeCommand(parametersPassedInRequest, makerCheckerApproval, codeId, name);
}
}
@@ -1,13 +1,13 @@
package org.mifosplatform.infrastructure.codes.service; package org.mifosplatform.infrastructure.codes.service;
import org.mifosplatform.infrastructure.codes.command.CodeCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
public interface CodeWritePlatformService { public interface CodeWritePlatformService {
Long createCode(CodeCommand command); Long createCode(JsonCommand command);
Long updateCode(CodeCommand command); EntityIdentifier updateCode(Long codeId, JsonCommand command);
EntityIdentifier deleteCode(CodeCommand command); EntityIdentifier deleteCode(Long codeId, JsonCommand command);
} }
@@ -1,10 +1,14 @@
package org.mifosplatform.infrastructure.codes.service; package org.mifosplatform.infrastructure.codes.service;
import java.util.Map;
import org.mifosplatform.infrastructure.codes.command.CodeCommand; import org.mifosplatform.infrastructure.codes.command.CodeCommand;
import org.mifosplatform.infrastructure.codes.domain.Code; import org.mifosplatform.infrastructure.codes.domain.Code;
import org.mifosplatform.infrastructure.codes.domain.CodeRepository; import org.mifosplatform.infrastructure.codes.domain.CodeRepository;
import org.mifosplatform.infrastructure.codes.exception.CodeNotFoundException; import org.mifosplatform.infrastructure.codes.exception.CodeNotFoundException;
import org.mifosplatform.infrastructure.codes.exception.SystemDefinedCodeCannotBeChangedException; import org.mifosplatform.infrastructure.codes.exception.SystemDefinedCodeCannotBeChangedException;
import org.mifosplatform.infrastructure.codes.serialization.CodeCommandFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.data.EntityIdentifier;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
@@ -24,27 +28,30 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final CodeRepository codeRepository; private final CodeRepository codeRepository;
private final ConfigurationDomainService configurationDomainService; private final ConfigurationDomainService configurationDomainService;
private final CodeCommandFromApiJsonDeserializer fromApiJsonDeserializer;
@Autowired @Autowired
public CodeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final CodeRepository codeRepository, public CodeWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final CodeRepository codeRepository,
final ConfigurationDomainService configurationDomainService) { final ConfigurationDomainService configurationDomainService,
final CodeCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
this.context = context; this.context = context;
this.codeRepository = codeRepository; this.codeRepository = codeRepository;
this.configurationDomainService = configurationDomainService; this.configurationDomainService = configurationDomainService;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
} }
@Transactional @Transactional
@Override @Override
public Long createCode(final CodeCommand command) { public Long createCode(final JsonCommand command) {
try { try {
context.authenticatedUser(); context.authenticatedUser();
command.validateForCreate();
final Code code = Code.createNew(command.getName()); final CodeCommand codeCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
codeCommand.validateForCreate();
final Code code = Code.fromJson(command);
this.codeRepository.save(code); this.codeRepository.save(code);
if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_CODE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } if (this.configurationDomainService.isMakerCheckerEnabledForTask("CREATE_CODE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
@@ -57,47 +64,36 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
@Transactional @Transactional
@Override @Override
public Long updateCode(final CodeCommand command) { public EntityIdentifier updateCode(final Long codeId, final JsonCommand command) {
try { try {
context.authenticatedUser(); context.authenticatedUser();
command.validateForUpdate(); final CodeCommand codeCommand = this.fromApiJsonDeserializer.commandFromApiJson(command.json());
codeCommand.validateForUpdate();
final Code code = retrieveCodeBy(command.getId()); final Code code = retrieveCodeBy(codeId);
code.update(command); Map<String, Object> changes = code.update(command);
this.codeRepository.save(code); if (!changes.isEmpty()) {
this.codeRepository.save(code);
}
if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_CODE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_CODE") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
return code.getId(); return EntityIdentifier.withChanges(codeId, changes);
} catch (DataIntegrityViolationException dve) { } catch (DataIntegrityViolationException dve) {
handleCodeDataIntegrityIssues(command, dve); handleCodeDataIntegrityIssues(command, dve);
return Long.valueOf(-1); return null;
} }
} }
/*
* Guaranteed to throw an exception no matter what the data integrity issue
* is.
*/
private void handleCodeDataIntegrityIssues(final CodeCommand command, final DataIntegrityViolationException dve) {
Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("code_name_org")) { throw new PlatformDataIntegrityException("error.msg.code.duplicate.name",
"A code with name '" + command.getName() + "' already exists"); }
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.cund.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + realCause.getMessage());
}
@Transactional @Transactional
@Override @Override
public EntityIdentifier deleteCode(final CodeCommand command) { public EntityIdentifier deleteCode(final Long codeId, final JsonCommand command) {
context.authenticatedUser(); context.authenticatedUser();
final Code code = retrieveCodeBy(command.getId()); final Code code = retrieveCodeBy(codeId);
if (code.isSystemDefined()) { if (code.isSystemDefined()) {
throw new SystemDefinedCodeCannotBeChangedException(); throw new SystemDefinedCodeCannotBeChangedException();
} }
@@ -114,4 +110,20 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf
if (code == null) { throw new CodeNotFoundException(codeId.toString()); } if (code == null) { throw new CodeNotFoundException(codeId.toString()); }
return code; return code;
} }
/*
* Guaranteed to throw an exception no matter what the data integrity issue
* is.
*/
private void handleCodeDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) {
Throwable realCause = dve.getMostSpecificCause();
if (realCause.getMessage().contains("code_name_org")) {
final String name = command.stringValueOfParameterNamed("name");
throw new PlatformDataIntegrityException("error.msg.code.duplicate.name",
"A code with name '" + name + "' already exists"); }
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.cund.unknown.data.integrity.issue",
"Unknown data integrity issue with resource: " + realCause.getMessage());
}
} }
@@ -7,7 +7,10 @@ import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
/** /**
* Represents JSON based command. * Immutable representation of a command.
*
* Wraps the provided JSON with convenience functions for extracting parameter
* values and checking for changes against an existing value.
*/ */
public final class JsonCommand { public final class JsonCommand {
@@ -20,11 +23,13 @@ public final class JsonCommand {
return new JsonCommand(jsonCommand, parsedCommand, fromApiJsonHelper, false); return new JsonCommand(jsonCommand, parsedCommand, fromApiJsonHelper, false);
} }
public static JsonCommand withMakerCheckerApproval(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper) { public static JsonCommand withMakerCheckerApproval(final String jsonCommand, final JsonElement parsedCommand,
final FromJsonHelper fromApiJsonHelper) {
return new JsonCommand(jsonCommand, parsedCommand, fromApiJsonHelper, true); return new JsonCommand(jsonCommand, parsedCommand, fromApiJsonHelper, true);
} }
public JsonCommand(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper, final boolean approvedByChecker) { public JsonCommand(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper,
final boolean approvedByChecker) {
this.jsonCommand = jsonCommand; this.jsonCommand = jsonCommand;
this.parsedCommand = parsedCommand; this.parsedCommand = parsedCommand;
this.fromApiJsonHelper = fromApiJsonHelper; this.fromApiJsonHelper = fromApiJsonHelper;
@@ -97,7 +102,7 @@ public final class JsonCommand {
} }
public Long longValueOfParameterNamed(final String parameterName) { public Long longValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractLongNamed(parameterName, parsedCommand); return this.fromApiJsonHelper.extractLongNamed(parameterName, parsedCommand);
} }
public boolean isChangeInLocalDateParameterNamed(final String parameterName, final LocalDate existingValue) { public boolean isChangeInLocalDateParameterNamed(final String parameterName, final LocalDate existingValue) {
@@ -51,6 +51,10 @@ public class EntityIdentifier {
} }
public Map<String, Object> getChanges() { public Map<String, Object> getChanges() {
return this.changes; Map<String, Object> checkIfEmpty = null;
if (!this.changes.isEmpty()) {
checkIfEmpty = this.changes;
}
return checkIfEmpty;
} }
} }
@@ -28,6 +28,11 @@ public final class ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson {
} }
public String serialize(final Object result) { public String serialize(final Object result) {
return this.gson.toJson(result); String returnedResult = null;
final String serializedResult = this.gson.toJson(result);
if (!"null".equalsIgnoreCase(serializedResult)) {
returnedResult = serializedResult;
}
return returnedResult;
} }
} }
@@ -46,16 +46,13 @@ public final class ClientCommandFromApiJsonDeserializer extends AbstractFromApiJ
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final Set<String> parametersPassedInRequest = new HashSet<String>();
final JsonElement element = fromApiJsonHelper.parse(json); final JsonElement element = fromApiJsonHelper.parse(json);
final Long officeId = fromApiJsonHelper.extractLongNamed("officeId", element, parametersPassedInRequest); final Long officeId = fromApiJsonHelper.extractLongNamed("officeId", element);
final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element, parametersPassedInRequest); final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element);
final String firstname = fromApiJsonHelper.extractStringNamed("firstname", element, parametersPassedInRequest); final String firstname = fromApiJsonHelper.extractStringNamed("firstname", element);
final String lastname = fromApiJsonHelper.extractStringNamed("lastname", element, parametersPassedInRequest); final String lastname = fromApiJsonHelper.extractStringNamed("lastname", element);
final String clientOrBusinessName = fromApiJsonHelper final String clientOrBusinessName = fromApiJsonHelper.extractStringNamed("clientOrBusinessName", element);
.extractStringNamed("clientOrBusinessName", element, parametersPassedInRequest); final LocalDate joiningDate = fromApiJsonHelper.extractLocalDateNamed("joiningDate", element);
final LocalDate joiningDate = fromApiJsonHelper.extractLocalDateNamed("joiningDate", element, parametersPassedInRequest);
return new ClientCommand(externalId, firstname, lastname, clientOrBusinessName, officeId, joiningDate); return new ClientCommand(externalId, firstname, lastname, clientOrBusinessName, officeId, joiningDate);
} }
@@ -155,7 +155,9 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
clientForUpdate.changeOffice(newOffice); clientForUpdate.changeOffice(newOffice);
} }
this.clientRepository.save(clientForUpdate); if (!changesOnly.isEmpty()) {
this.clientRepository.save(clientForUpdate);
}
if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_CLIENT") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); } if (this.configurationDomainService.isMakerCheckerEnabledForTask("UPDATE_CLIENT") && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }