diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/CodesApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/CodesApiResource.java index b934565fa..8c9e1d62c 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/CodesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/CodesApiResource.java @@ -4,6 +4,7 @@ import java.util.Collection; import java.util.Set; import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; @@ -41,10 +42,11 @@ public class CodesApiResource { @Autowired private PortfolioApiDataConversionService apiDataConversionService; - + @Autowired private PortfolioApiJsonSerializerService apiJsonSerializerService; + private final String entityType = "CODE"; private final PlatformSecurityContext context; @@ -52,19 +54,20 @@ public class CodesApiResource { public CodesApiResource(final PlatformSecurityContext context) { this.context = context; } - + + @GET @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) public String retrieveCodes(@Context final UriInfo uriInfo) { context.authenticatedUser().validateHasReadPermission(entityType); - + Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); - + final Collection codes = this.readPlatformService.retrieveAllCodes(); - + return this.apiJsonSerializerService.serializeCodeDataToJson(prettyPrint, responseParameters, codes); } @@ -72,21 +75,50 @@ public class CodesApiResource { @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) public Response createCode(final String jsonRequestBody) { - + final CodeCommand command = this.apiDataConversionService.convertJsonToCodeCommand(null, jsonRequestBody); - + final Long id = this.writePlatformService.createCode(command); return Response.ok().entity(new EntityIdentifier(id)).build(); } + @GET + @Path("{codeId}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public String retreiveOffice(@PathParam("codeId") final Long codeId, @Context final UriInfo uriInfo) { + + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + final CodeData code = this.readPlatformService.retrieveCode(codeId); + + return this.apiJsonSerializerService.serializeCodeDataToJson(prettyPrint, responseParameters, code); + } + @PUT @Path("{Id}") @Consumes({MediaType.APPLICATION_JSON}) @Produces({MediaType.APPLICATION_JSON}) - public Response updateCode(@PathParam("Id") final Long Id, final String jsonRequestBody) { + public Response updateCode(@PathParam("Id") final Long codeId, final String jsonRequestBody) { + + final CodeCommand command = this.apiDataConversionService.convertJsonToCodeCommand(codeId, jsonRequestBody); + final Long entityId = this.writePlatformService.updateCode(command); + return Response.ok().entity(new EntityIdentifier(entityId)).build(); - return null; } + + @DELETE + @Path("{codeId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response deleteCodeApplication(@PathParam("codeId") final Long Id) { + + EntityIdentifier identifier = this.writePlatformService.deleteCode(Id); + + return Response.ok().entity(identifier).build(); + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/CodeCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/CodeCommand.java index ed9537a81..3c83a8c83 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/CodeCommand.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/CodeCommand.java @@ -25,9 +25,9 @@ public class CodeCommand { public String getCodeName() { return codeName; } - + public boolean isNameChanged() { - return this.modifiedParameters.contains("codename"); + return this.modifiedParameters.contains("name"); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/domain/Code.java b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/domain/Code.java index ece7f04cd..6fcd9ff2b 100755 --- a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/domain/Code.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/domain/Code.java @@ -5,8 +5,12 @@ import javax.persistence.Entity; import javax.persistence.Table; import javax.persistence.UniqueConstraint; +import org.apache.commons.lang.StringUtils; +import org.mifosng.platform.api.commands.CodeCommand; + import org.springframework.data.jpa.domain.AbstractPersistable; + @Entity @Table(name = "m_code", uniqueConstraints = { @UniqueConstraint(columnNames = { "code_name" }, name = "code_name") }) public class Code extends AbstractPersistable { @@ -27,4 +31,11 @@ public class Code extends AbstractPersistable { this.codeName = codeName; } + public void update(final CodeCommand command) + { + if (command.isNameChanged()) { + this.codeName = StringUtils.defaultIfEmpty(command.getCodeName(), null); + } + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeCommandValidator.java new file mode 100644 index 000000000..ed387aaa9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeCommandValidator.java @@ -0,0 +1,42 @@ +package org.mifosng.platform.organisation.service; + +import java.util.ArrayList; +import java.util.List; + +import org.mifosng.platform.DataValidatorBuilder; +import org.mifosng.platform.api.commands.CodeCommand; +import org.mifosng.platform.api.data.ApiParameterError; +import org.mifosng.platform.exceptions.PlatformApiDataValidationException; + + +public class CodeCommandValidator +{ + private final CodeCommand command; + + public CodeCommandValidator(CodeCommand command) + { + this.command = command; + } + + public void validateForCreate() + { + List dataValidationErrors = new ArrayList(); + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("code"); + baseDataValidator.reset().parameter("codeName").value(command.getCodeName()).notBlank(); + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); + } + } + + public void validateForUpdate() + { + List dataValidationErrors = new ArrayList(); + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("code"); + baseDataValidator.reset().parameter("id").value(command.getId()).notNull(); + baseDataValidator.reset().parameter("codeName").value(command.getCodeName()).ignoreIfNull().notBlank(); + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); + } + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeWritePlatformService.java index d36f52217..00f119204 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeWritePlatformService.java @@ -1,13 +1,19 @@ package org.mifosng.platform.organisation.service; import org.mifosng.platform.api.commands.CodeCommand; +import org.mifosng.platform.api.data.EntityIdentifier; import org.springframework.security.access.prepost.PreAuthorize; public interface CodeWritePlatformService { @PreAuthorize(value = "hasRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'CREATE_CODE')") Long createCode(final CodeCommand command); - + + @PreAuthorize(value = "hasRole('ALL_FUNCTIONS', 'ORGANISATION_ADMINISTRATION_SUPER_USER', 'UPDATE_CODE)") + Long updateCode(final CodeCommand command); + + @PreAuthorize(value = "hasRole('ORGANISATION_ADMINISTRATION_SUPER_USER_ROLE')") + EntityIdentifier deleteCode(Long codeId); } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeWritePlatformServiceJpaRepositoryImpl.java index 4e7692ca1..2fa737bff 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/organisation/service/CodeWritePlatformServiceJpaRepositoryImpl.java @@ -2,9 +2,17 @@ package org.mifosng.platform.organisation.service; import org.mifosng.platform.api.commands.CodeCommand; import org.mifosng.platform.api.commands.FundCommand; +import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosng.platform.exceptions.CodeValueNotFoundException; +import org.mifosng.platform.exceptions.FundNotFoundException; +import org.mifosng.platform.exceptions.PlatformDataIntegrityException; +import org.mifosng.platform.fund.domain.Fund; +import org.mifosng.platform.fund.service.FundWritePlatformServiceJpaRepositoryImpl; import org.mifosng.platform.organisation.domain.Code; import org.mifosng.platform.organisation.domain.CodeRepository; import org.mifosng.platform.security.PlatformSecurityContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.dao.DataIntegrityViolationException; import org.springframework.stereotype.Service; @@ -13,6 +21,7 @@ import org.springframework.transaction.annotation.Transactional; @Service public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatformService { + private final static Logger logger = LoggerFactory.getLogger(CodeWritePlatformServiceJpaRepositoryImpl.class); private final PlatformSecurityContext context; private final CodeRepository codeRepository; @@ -21,20 +30,22 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf this.context = context; this.codeRepository = codeRepository; } - + @Transactional @Override public Long createCode(final CodeCommand command) { - + try { context.authenticatedUser(); - + + CodeCommandValidator validator = new CodeCommandValidator(command); + validator.validateForCreate(); Code code = Code.createNew(command.getCodeName()); - + this.codeRepository.saveAndFlush(code); - + return code.getId(); } catch (DataIntegrityViolationException dve) { return Long.valueOf(-1); @@ -45,18 +56,65 @@ public class CodeWritePlatformServiceJpaRepositoryImpl implements CodeWritePlatf @Override public Long updateCode(final CodeCommand command) { - /** - * TODO - NATU - - **/ - - return null; + try + { + context.authenticatedUser(); + + CodeCommandValidator validator = new CodeCommandValidator(command); + validator.validateForUpdate(); + + final Long codeId = command.getId(); + Code code = this.codeRepository.findOne(codeId); + if (code == null) { + throw new CodeValueNotFoundException(codeId); + } + code.update(command); + + this.codeRepository.saveAndFlush(code); + + return code.getId(); + } + catch (DataIntegrityViolationException dve) { + handleCodeDataIntegrityIssues(command, dve); + return Long.valueOf(-1); + } + } /* * Guaranteed to throw an exception no matter what the data integrity issue is. */ - private void handleCodeDataIntegrityIssues(final FundCommand command, DataIntegrityViolationException dve) { - + + private void handleCodeDataIntegrityIssues(final CodeCommand command, 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.getCodeName() + "' 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 + @Override + public EntityIdentifier deleteCode(final Long codeId) { + + context.authenticatedUser(); + + final Code code = retrieveCodeBy(codeId); + + + this.codeRepository.delete(codeId); + + return new EntityIdentifier(codeId); + } + + private Code retrieveCodeBy(final Long codeId) { + final Code code = this.codeRepository.findOne(codeId); + if (code == null) { + throw new CodeValueNotFoundException(codeId); + } + return code; } - } \ No newline at end of file diff --git a/mifosng-provider/us.stackdump b/mifosng-provider/us.stackdump new file mode 100644 index 000000000..70e504d51 --- /dev/null +++ b/mifosng-provider/us.stackdump @@ -0,0 +1,16 @@ +MSYS-1.0.12 Build:2011-07-20 17:52 +Exception: STATUS_ACCESS_VIOLATION at eip=68085E34 +eax=68560000 ebx=00005D7C ecx=0000175F edx=00000000 esi=00000000 edi=68560000 +ebp=0023FE80 esp=0023FE74 program=us +cs=001B ds=0023 es=0023 fs=003B gs=0000 ss=0023 +Stack trace: +Frame Function Args +0023FE80 68085E34 (68560000, 00000000, 00005D7C, 00000004) +0023FED0 68001CB0 (00020C58, 00000001, 0023FF20, 680044EA) +0023FF20 680045C7 (8600D670, FFDFF538, 0023FF60, 00405F80) +0023FF40 68004C5F (00402318, 00000000, 804FA14C, 0000D670) +0023FF60 68004C98 (00000000, 00000000, A78A3C6C, 00000000) +0023FF90 00405E90 (00402318, 00000000, 00000001, 00000006) +0023FFC0 0040103D (00000000, 00000000, 7FFDE000, 8054A6ED) +0023FFF0 7C816FE7 (00401000, 00000000, 78746341, 00000020) +End of stack trace \ No newline at end of file