diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/GroupsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/GroupsApiResource.java index 636ab698b..3b51f7dff 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/GroupsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/GroupsApiResource.java @@ -1,15 +1,28 @@ package org.mifosng.platform.api; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + import javax.ws.rs.Consumes; +import javax.ws.rs.GET; import javax.ws.rs.POST; +import javax.ws.rs.PUT; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriInfo; import org.mifosng.platform.api.commands.GroupCommand; import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosng.platform.api.data.GroupData; import org.mifosng.platform.api.infrastructure.ApiDataConversionService; +import org.mifosng.platform.api.infrastructure.ApiParameterHelper; +import org.mifosng.platform.group.service.GroupReadPlatformService; import org.mifosng.platform.group.service.GroupWritePlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; @@ -20,21 +33,79 @@ import org.springframework.stereotype.Component; @Scope("singleton") public class GroupsApiResource { + @Autowired + private GroupReadPlatformService groupReadPlatformService; + @Autowired private GroupWritePlatformService groupWritePlatformService; @Autowired private ApiDataConversionService apiDataConversionService; + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAllGroups(@Context final UriInfo uriInfo){ + + Set typicalResponseParameters = new HashSet( + Arrays.asList("id", "name", "externalId") + ); + + Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + if (responseParameters.isEmpty()) { + responseParameters.addAll(typicalResponseParameters); + } + + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + Collection groups = this.groupReadPlatformService.retrieveAllGroups(); + + return this.apiDataConversionService.convertGroupDataToJson(prettyPrint, responseParameters, groups.toArray(new GroupData[groups.size()])); + } + + @GET + @Path("{groupId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveGroupData(@PathParam("groupId") final Long groupId, @Context final UriInfo uriInfo) { + + Set typicalResponseParameters = new HashSet(Arrays.asList("id", "name", "externalId")); + + Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo + .getQueryParameters()); + if (responseParameters.isEmpty()) { + responseParameters.addAll(typicalResponseParameters); + } + + boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + GroupData group = this.groupReadPlatformService.retrieveGroup(groupId); + + return this.apiDataConversionService.convertGroupDataToJson(prettyPrint, responseParameters, group); + } + @POST @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) public Response createGroup(final String jsonRequestBody) { - + final GroupCommand command = this.apiDataConversionService.convertJsonToGroupCommand(null, jsonRequestBody); - + EntityIdentifier entityIdentifier = this.groupWritePlatformService.createGroup(command); - + + return Response.ok().entity(entityIdentifier).build(); + } + + @PUT + @Path("{groupId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response updateGroup(@PathParam("groupId") final Long groupId, final String jsonRequestBody) { + + final GroupCommand command = this.apiDataConversionService.convertJsonToGroupCommand(groupId, jsonRequestBody); + + EntityIdentifier entityIdentifier = this.groupWritePlatformService.updateGroup(command); + return Response.ok().entity(entityIdentifier).build(); } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/GroupCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/GroupCommand.java index 9837812c9..10f0ee383 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/GroupCommand.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/GroupCommand.java @@ -4,12 +4,14 @@ import java.util.Set; public class GroupCommand { + private final Long id; private final String externalId; private final String name; private final Set modifiedParameters; - public GroupCommand(Set modifiedParameters, String externalId, String name) { + public GroupCommand(Set modifiedParameters, final Long id, String externalId, String name) { + this.id = id; this.externalId = externalId; this.name = name; this.modifiedParameters = modifiedParameters; @@ -23,4 +25,16 @@ public class GroupCommand { return name; } + public Long getId() { + return id; + } + + public boolean isNameChanged() { + return this.modifiedParameters.contains("name"); + } + + public boolean isExternalIdChanged() { + return this.modifiedParameters.contains("externalId"); + } + } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/GroupData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/GroupData.java new file mode 100644 index 000000000..27239cfa8 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/GroupData.java @@ -0,0 +1,28 @@ +package org.mifosng.platform.api.data; + +public class GroupData { + + private final Long id; + private final String name; + private final String externalId; + + public GroupData(Long id, String name, String externalId) { + super(); + this.id = id; + this.name = name; + this.externalId = externalId; + } + + public Long getId() { + return id; + } + + public String getName() { + return name; + } + + public String getExternalId() { + return externalId; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionService.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionService.java index 9ff5d75f7..4b0ec19d7 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionService.java @@ -25,6 +25,7 @@ import org.mifosng.platform.api.data.ClientLoanAccountSummaryCollectionData; import org.mifosng.platform.api.data.ConfigurationData; import org.mifosng.platform.api.data.FundData; import org.mifosng.platform.api.data.GenericResultsetData; +import org.mifosng.platform.api.data.GroupData; import org.mifosng.platform.api.data.LoanAccountData; import org.mifosng.platform.api.data.LoanProductData; import org.mifosng.platform.api.data.LoanTransactionData; @@ -54,6 +55,8 @@ public interface ApiDataConversionService { String convertClientLoanAccountSummaryCollectionDataToJson(boolean prettyPrint, Set responseParameters, ClientLoanAccountSummaryCollectionData clientAccountsData); + String convertGroupDataToJson(boolean prettyPrint, Set responseParameters, GroupData... groups); + String convertNoteDataToJson(boolean prettyPrint, Set responseParameters, NoteData... notes); String convertLoanProductDataToJson(boolean prettyPrint, Set responseParameters, LoanProductData... products); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java index 7e0842c98..ebccba698 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/infrastructure/ApiDataConversionServiceImpl.java @@ -42,6 +42,7 @@ import org.mifosng.platform.api.data.ClientLoanAccountSummaryCollectionData; import org.mifosng.platform.api.data.ConfigurationData; import org.mifosng.platform.api.data.FundData; import org.mifosng.platform.api.data.GenericResultsetData; +import org.mifosng.platform.api.data.GroupData; import org.mifosng.platform.api.data.LoanAccountData; import org.mifosng.platform.api.data.LoanProductData; import org.mifosng.platform.api.data.LoanTransactionData; @@ -373,6 +374,40 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { } @Override + public String convertGroupDataToJson(boolean prettyPrint, Set responseParameters, GroupData... groups) { + final Set supportedParameters = new HashSet( + Arrays.asList("id", "name", "externalId") + ); + + final Set parameterNamesToSkip = new HashSet(); + + if (!responseParameters.isEmpty()) { + if (!supportedParameters.containsAll(responseParameters)) { + throw new UnsupportedParameterException(new ArrayList(responseParameters)); + } + + parameterNamesToSkip.addAll(supportedParameters); + parameterNamesToSkip.removeAll(responseParameters); + } + + ExclusionStrategy strategy = new ParameterListExclusionStrategy(parameterNamesToSkip); + GsonBuilder builder = new GsonBuilder().addSerializationExclusionStrategy(strategy); + if (prettyPrint) { + builder.setPrettyPrinting(); + } + Gson gsonDeserializer = builder.create(); + String json = ""; + + if (groups != null && groups.length == 1) { + json = gsonDeserializer.toJson(groups[0]); + } else { + json = gsonDeserializer.toJson(groups); + } + + return json; + } + + @Override public String convertConfigurationDataToJson(final boolean prettyPrint, final Set responseParameters, final ConfigurationData... configuration) { final Set supportedParameters = new HashSet(Arrays.asList("selectedCurrencyOptions", "currencyOptions")); @@ -838,7 +873,7 @@ public class ApiDataConversionServiceImpl implements ApiDataConversionService { String externalId = extractStringParameter("externalId", requestMap, modifiedParameters); String name = extractStringParameter("name", requestMap, modifiedParameters); - return new GroupCommand(modifiedParameters, externalId, name); + return new GroupCommand(modifiedParameters, resourceIdentifier, externalId, name); } @Override diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/GroupNotFoundException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/GroupNotFoundException.java new file mode 100644 index 000000000..afed44d6f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/GroupNotFoundException.java @@ -0,0 +1,12 @@ +package org.mifosng.platform.exceptions; + +/** + * A {@link RuntimeException} thrown when group resources are not found. + */ +public class GroupNotFoundException extends AbstractPlatformResourceNotFoundException { + + public GroupNotFoundException(Long id){ + super("error.msg.group.id.invalid", "Group with identifier " + id + " does not exist", id); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/group/domain/Group.java b/mifosng-provider/src/main/java/org/mifosng/platform/group/domain/Group.java index 27aa0a591..2c5e63554 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/group/domain/Group.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/group/domain/Group.java @@ -5,6 +5,7 @@ import javax.persistence.Entity; import javax.persistence.Table; import org.apache.commons.lang.StringUtils; +import org.mifosng.platform.api.commands.GroupCommand; import org.mifosng.platform.infrastructure.AbstractAuditableCustom; import org.mifosng.platform.user.domain.AppUser; @@ -40,4 +41,14 @@ public class Group extends AbstractAuditableCustom { this.externalId = null; } } + + public void update(GroupCommand command) { + if (command.isExternalIdChanged()) { + this.externalId = command.getExternalId(); + } + + if (command.isNameChanged()) { + this.name = command.getName(); + } + } } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupCommandValidator.java index d3d14ad50..96f9c531b 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupCommandValidator.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupCommandValidator.java @@ -30,4 +30,19 @@ public class GroupCommandValidator { } } + public void validateForUpdate() { + + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("group"); + + baseDataValidator.reset().parameter("id").value(command.getId()).notNull(); + baseDataValidator.reset().parameter("name").value(command.getName()).ignoreIfNull().notBlank(); + baseDataValidator.reset().parameter("externalId").value(command.getExternalId()).ignoreIfNull().notExceedingLengthOf(100); + + 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/group/service/GroupReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupReadPlatformService.java new file mode 100644 index 000000000..069787c15 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupReadPlatformService.java @@ -0,0 +1,13 @@ +package org.mifosng.platform.group.service; + +import java.util.Collection; + +import org.mifosng.platform.api.data.GroupData; + +public interface GroupReadPlatformService { + + Collection retrieveAllGroups(); + + GroupData retrieveGroup(Long groupId); + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupReadPlatformServiceImpl.java new file mode 100644 index 000000000..448de8726 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupReadPlatformServiceImpl.java @@ -0,0 +1,76 @@ +package org.mifosng.platform.group.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +import org.mifosng.platform.api.data.GroupData; +import org.mifosng.platform.exceptions.GroupNotFoundException; +import org.mifosng.platform.infrastructure.TenantAwareRoutingDataSource; +import org.mifosng.platform.security.PlatformSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + private final PlatformSecurityContext context; + + @Autowired + public GroupReadPlatformServiceImpl(final PlatformSecurityContext context, + final TenantAwareRoutingDataSource dataSource) { + this.context = context; + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public Collection retrieveAllGroups() { + + this.context.authenticatedUser(); + + GroupMapper rm = new GroupMapper(); + + String sql = "select " + rm.groupSchema(); + + return this.jdbcTemplate.query(sql, rm, new Object[] {}); + } + + @Override + public GroupData retrieveGroup(Long groupId) { + + try{ + this.context.authenticatedUser(); + + GroupMapper rm = new GroupMapper(); + + String sql = "select " + rm.groupSchema() + " where g.id = ?"; + + return this.jdbcTemplate.queryForObject(sql, rm, new Object[] {groupId}); + } catch (EmptyResultDataAccessException e){ + throw new GroupNotFoundException(groupId); + } + } + + private static final class GroupMapper implements RowMapper { + + public String groupSchema() { + return "g.id as id, g.external_id as externalId, g.name as name from portfolio_group g"; + } + + @Override + public GroupData mapRow(ResultSet rs, int rowNum) throws SQLException { + + Long id = rs.getLong("id"); + String name = rs.getString("name"); + String externalId = rs.getString("externalId"); + + return new GroupData(id, name, externalId); + } + + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupWritePlatformService.java index f3054a6ef..b489af5b9 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupWritePlatformService.java @@ -9,4 +9,7 @@ public interface GroupWritePlatformService { @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") EntityIdentifier createGroup(GroupCommand command); + @PreAuthorize(value = "hasAnyRole('PORTFOLIO_MANAGEMENT_SUPER_USER_ROLE')") + EntityIdentifier updateGroup(GroupCommand command); + } diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java index 3f145f28c..9025052e4 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/group/service/GroupWritePlatformServiceJpaRepositoryImpl.java @@ -2,6 +2,7 @@ package org.mifosng.platform.group.service; import org.mifosng.platform.api.commands.GroupCommand; import org.mifosng.platform.api.data.EntityIdentifier; +import org.mifosng.platform.exceptions.GroupNotFoundException; import org.mifosng.platform.group.domain.Group; import org.mifosng.platform.group.domain.GroupRepository; import org.mifosng.platform.security.PlatformSecurityContext; @@ -38,4 +39,24 @@ public class GroupWritePlatformServiceJpaRepositoryImpl implements GroupWritePla return new EntityIdentifier(newGroup.getId()); } + @Transactional + @Override + public EntityIdentifier updateGroup(GroupCommand command) { + + context.authenticatedUser(); + + GroupCommandValidator validator = new GroupCommandValidator(command); + validator.validateForUpdate(); + + Group groupForUpdate = this.groupRepository.findOne(command.getId()); + if (groupForUpdate == null){ + throw new GroupNotFoundException(command.getId()); + } + groupForUpdate.update(command); + + groupRepository.save(groupForUpdate); + + return new EntityIdentifier(groupForUpdate.getId()); + } + }