MIFOSX-97: process role commands through command_source table.

This commit is contained in:
Keith Woodlock
2012-11-22 14:51:53 +00:00
parent 85de5e92c2
commit 79ff5a7511
17 changed files with 1162 additions and 1054 deletions
@@ -60,436 +60,402 @@ import com.sun.jersey.multipart.FormDataParam;
@Scope("singleton")
public class ClientsApiResource {
private final static Logger logger = LoggerFactory.getLogger(ClientsApiResource.class);
private final static Logger logger = LoggerFactory.getLogger(ClientsApiResource.class);
@Autowired
private ClientReadPlatformService clientReadPlatformService;
@Autowired
private ClientReadPlatformService clientReadPlatformService;
@Autowired
private ClientWritePlatformService clientWritePlatformService;
@Autowired
private PortfolioCommandsReadPlatformService commandSourceReadPlatformService;
@Autowired
private PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired
private ClientWritePlatformService clientWritePlatformService;
@Autowired
private OfficeReadPlatformService officeReadPlatformService;
@Autowired
private PortfolioCommandsReadPlatformService commandSourceReadPlatformService;
@Autowired
private PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired
private OfficeReadPlatformService officeReadPlatformService;
@Autowired
private PortfolioApiDataConversionService apiDataConversionService;
@Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService;
@Autowired
private PortfolioApiDataConversionService apiDataConversionService;
@Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService;
@Autowired
private PlatformSecurityContext context;
@GET
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveAllIndividualClients(@Context final UriInfo uriInfo,
@QueryParam("sqlSearch") final String sqlSearch,
@QueryParam("officeId") final Integer officeId,
@QueryParam("externalId") final String externalId,
@QueryParam("displayName") final String displayName,
@QueryParam("firstName") final String firstName,
@QueryParam("lastName") final String lastName,
@QueryParam("underHierarchy") final String hierarchy) {
context.authenticatedUser().validateHasReadPermission("CLIENT");
final String extraCriteria = getClientCriteria(sqlSearch, officeId, externalId, displayName, firstName, lastName, hierarchy);
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllIndividualClients(@Context final UriInfo uriInfo, @QueryParam("sqlSearch") final String sqlSearch,
@QueryParam("officeId") final Integer officeId, @QueryParam("externalId") final String externalId,
@QueryParam("displayName") final String displayName, @QueryParam("firstName") final String firstName,
@QueryParam("lastName") final String lastName, @QueryParam("underHierarchy") final String hierarchy) {
final Collection<ClientData> clients = this.clientReadPlatformService.retrieveAllIndividualClients(extraCriteria);
return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clients);
}
context.authenticatedUser().validateHasReadPermission("CLIENT");
private String getClientCriteria(String sqlSearch, Integer officeId,
String externalId, String displayName, String firstName,
String lastName, String hierarchy) {
final String extraCriteria = getClientCriteria(sqlSearch, officeId, externalId, displayName, firstName, lastName, hierarchy);
String extraCriteria = "";
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
if (sqlSearch != null) {
extraCriteria = " and (" + sqlSearch + ")";
}
final Collection<ClientData> clients = this.clientReadPlatformService.retrieveAllIndividualClients(extraCriteria);
if (officeId != null) {
extraCriteria += " and office_id = " + officeId;
}
if (externalId != null) {
extraCriteria += " and external_id like " + ApiParameterHelper.sqlEncodeString(externalId);
}
if (displayName != null) {
extraCriteria += " and concat(ifnull(firstname, ''), if(firstname > '',' ', '') , ifnull(lastname, '')) like "
+ ApiParameterHelper.sqlEncodeString(displayName);
}
if (firstName != null) {
extraCriteria += " and firstname like " + ApiParameterHelper.sqlEncodeString(firstName);
}
if (lastName != null) {
extraCriteria += " and lastname like " + ApiParameterHelper.sqlEncodeString(lastName);
}
if (hierarchy != null) {
extraCriteria += " and o.hierarchy like " + ApiParameterHelper.sqlEncodeString(hierarchy+"%");
}
return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clients);
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
private String getClientCriteria(String sqlSearch, Integer officeId, String externalId, String displayName, String firstName,
String lastName, String hierarchy) {
logger.info("extraCriteria; " + extraCriteria);
String extraCriteria = "";
return extraCriteria;
}
if (sqlSearch != null) {
extraCriteria = " and (" + sqlSearch + ")";
}
@GET
@Path("{clientId}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveClient(
@PathParam("clientId") final Long clientId,
@Context final UriInfo uriInfo) {
if (officeId != null) {
extraCriteria += " and office_id = " + officeId;
}
context.authenticatedUser().validateHasReadPermission("CLIENT");
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
final Long makerCheckerId = ApiParameterHelper.makerCheckerId(uriInfo.getQueryParameters());
ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
if (template) {
final List<OfficeLookup> allowedOffices = new ArrayList<OfficeLookup>(officeReadPlatformService.retrieveAllOfficesForLookup());
clientData = ClientData.templateOnTop(clientData, allowedOffices);
}
if (makerCheckerId != null) {
clientData = handleMakerCheckerRequest(clientId, makerCheckerId, clientData);
}
boolean retrieveChanges = true;
if (retrieveChanges) {
final Collection<ClientData> dataChanges = retrieveAllUnprocessedDataChanges(clientId);
clientData = ClientData.integrateChanges(clientData, clientData.currentChange(), dataChanges);
}
if (externalId != null) {
extraCriteria += " and external_id like " + ApiParameterHelper.sqlEncodeString(externalId);
}
return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clientData);
}
if (displayName != null) {
extraCriteria += " and concat(ifnull(firstname, ''), if(firstname > '',' ', '') , ifnull(lastname, '')) like "
+ ApiParameterHelper.sqlEncodeString(displayName);
}
private ClientData handleMakerCheckerRequest(final Long clientId, final Long makerCheckerId, ClientData clientData) {
final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(makerCheckerId);
final ClientData currentChange = this.apiDataConversionService.convertInternalJsonFormatToClientDataChange(clientId, entry.json());
final Collection<ClientData> dataChanges = retrieveAllUnprocessedDataChanges(clientId);
clientData = ClientData.integrateChanges(clientData, currentChange, dataChanges);
return clientData;
}
if (firstName != null) {
extraCriteria += " and firstname like " + ApiParameterHelper.sqlEncodeString(firstName);
}
private Collection<ClientData> retrieveAllUnprocessedDataChanges(final Long clientId) {
Collection<ClientData> dataChanges = new ArrayList<ClientData>();
boolean retrieveChanges = true;
if (retrieveChanges) {
Collection<CommandSourceData> unprocessedChanges = this.commandSourceReadPlatformService.retrieveUnprocessChangesByResourceId("clients", clientId);
for (CommandSourceData commandSourceData : unprocessedChanges) {
ClientData change = this.apiDataConversionService.convertInternalJsonFormatToClientDataChange(clientId, commandSourceData.json());
dataChanges.add(change);
}
}
if (dataChanges.isEmpty()) {
dataChanges = null;
}
return dataChanges;
}
if (lastName != null) {
extraCriteria += " and lastname like " + ApiParameterHelper.sqlEncodeString(lastName);
}
@GET
@Path("template")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String newClientDetails(@Context final UriInfo uriInfo) {
if (hierarchy != null) {
extraCriteria += " and o.hierarchy like " + ApiParameterHelper.sqlEncodeString(hierarchy + "%");
}
context.authenticatedUser().validateHasReadPermission("CLIENT");
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
final Long makerCheckerId = ApiParameterHelper.makerCheckerId(uriInfo.getQueryParameters());
ClientData clientData = this.clientReadPlatformService.retrieveNewClientDetails();
if (makerCheckerId != null) {
clientData = handleMakerCheckerRequest(null, makerCheckerId, clientData);
}
return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clientData);
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
@POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String createClient(final String jsonRequestBody) {
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "clients", null, jsonRequestBody);
return this.apiJsonSerializerService.serializeEntityIdentifier(result);
}
logger.info("extraCriteria; " + extraCriteria);
@PUT
@Path("{clientId}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String updateClient(@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
return extraCriteria;
}
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "clients", clientId, jsonRequestBody);
return this.apiJsonSerializerService.serializeEntityIdentifier(result);
}
@DELETE
@Path("{clientId}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String deleteClient(@PathParam("clientId") final Long clientId) {
@GET
@Path("{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveClient(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "clients", clientId, "{}");
return this.apiJsonSerializerService.serializeEntityIdentifier(result);
}
context.authenticatedUser().validateHasReadPermission("CLIENT");
@GET
@Path("{clientId}/loans")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveClientAccount(@PathParam("clientId") final Long clientId,
@Context final UriInfo uriInfo) {
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
final boolean template = ApiParameterHelper.template(uriInfo.getQueryParameters());
final Long makerCheckerId = ApiParameterHelper.makerCheckerId(uriInfo.getQueryParameters());
context.authenticatedUser().validateHasReadPermission("CLIENT");
Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("pendingApprovalLoans", "awaitingDisbursalLoans", "openLoans", "closedLoans",
"anyLoanCount", "pendingApprovalLoanCount", "awaitingDisbursalLoanCount", "activeLoanCount", "closedLoanCount",
"pendingApprovalDespositAccountsCount", "pendingApprovalDespositAccounts", "approvedDespositAccountsCount", "approvedDespositAccounts",
"withdrawnByClientDespositAccountsCount","withdrawnByClientDespositAccounts","closedDepositAccountsCount","closedDepositAccounts",
"rejectedDepositAccountsCount","rejectedDepositAccounts","preclosedDepositAccountsCount","preclosedDepositAccounts")
);
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
ClientAccountSummaryCollectionData clientAccount = this.clientReadPlatformService.retrieveClientAccountDetails(clientId);
return this.apiJsonSerializerService.serializeClientAccountSummaryCollectionDataToJson(prettyPrint, responseParameters, clientAccount);
}
ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
if (template) {
final List<OfficeLookup> allowedOffices = new ArrayList<OfficeLookup>(officeReadPlatformService.retrieveAllOfficesForLookup());
clientData = ClientData.templateOnTop(clientData, allowedOffices);
}
if (makerCheckerId != null) {
clientData = handleMakerCheckerRequest(clientId, makerCheckerId, clientData);
}
@GET
@Path("{clientId}/notes")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveAllClientNotes(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
boolean retrieveChanges = true;
if (retrieveChanges) {
final Collection<ClientData> dataChanges = retrieveAllUnprocessedDataChanges(clientId);
clientData = ClientData.integrateChanges(clientData, clientData.currentChange(), dataChanges);
}
context.authenticatedUser().validateHasReadPermission("CLIENTNOTE");
Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("id", "clientId", "loanId", "loanTransactionId", "noteType", "note", "createdById", "createdByUsername",
"createdOn", "updatedById", "updatedByUsername", "updatedOn")
);
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
Collection<NoteData> notes = this.clientReadPlatformService.retrieveAllClientNotes(clientId);
return this.apiJsonSerializerService.serializeNoteDataToJson(prettyPrint, responseParameters, notes);
}
return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clientData);
}
@POST
@Path("{clientId}/notes")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public Response addNewClientNote(@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
private ClientData handleMakerCheckerRequest(final Long clientId, final Long makerCheckerId, ClientData clientData) {
final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(makerCheckerId);
final ClientData currentChange = this.apiDataConversionService.convertInternalJsonFormatToClientDataChange(clientId, entry.json());
NoteCommand command = this.apiDataConversionService.convertJsonToNoteCommand(null, clientId, jsonRequestBody);
EntityIdentifier identifier = this.clientWritePlatformService.addClientNote(command);
final Collection<ClientData> dataChanges = retrieveAllUnprocessedDataChanges(clientId);
clientData = ClientData.integrateChanges(clientData, currentChange, dataChanges);
return clientData;
}
return Response.ok().entity(identifier).build();
}
private Collection<ClientData> retrieveAllUnprocessedDataChanges(final Long clientId) {
Collection<ClientData> dataChanges = new ArrayList<ClientData>();
@GET
@Path("{clientId}/notes/{noteId}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveClientNote(
@PathParam("clientId") final Long clientId,
@PathParam("noteId") final Long noteId,
@Context final UriInfo uriInfo) {
boolean retrieveChanges = true;
if (retrieveChanges) {
Collection<CommandSourceData> unprocessedChanges = this.commandSourceReadPlatformService.retrieveUnprocessChangesByResourceId(
"clients", clientId);
for (CommandSourceData commandSourceData : unprocessedChanges) {
ClientData change = this.apiDataConversionService.convertInternalJsonFormatToClientDataChange(clientId,
commandSourceData.json());
dataChanges.add(change);
}
}
context.authenticatedUser().validateHasReadPermission("CLIENTNOTE");
Set<String> typicalResponseParameters = new HashSet<String>(
Arrays.asList("id", "clientId", "loanId", "loanTransactionId", "noteType", "note", "createdById", "createdByUsername",
"createdOn", "updatedById", "updatedByUsername", "updatedOn")
);
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
NoteData note = this.clientReadPlatformService.retrieveClientNote(clientId, noteId);
return this.apiJsonSerializerService.serializeNoteDataToJson(prettyPrint, responseParameters, note);
}
if (dataChanges.isEmpty()) {
dataChanges = null;
}
@PUT
@Path("{clientId}/notes/{noteId}")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public Response updateClientNote(
@PathParam("clientId") final Long clientId,
@PathParam("noteId") final Long noteId, final String jsonRequestBody) {
return dataChanges;
}
NoteCommand command = this.apiDataConversionService.convertJsonToNoteCommand(noteId, clientId, jsonRequestBody);
EntityIdentifier identifier = this.clientWritePlatformService.updateNote(command);
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String newClientDetails(@Context final UriInfo uriInfo) {
return Response.ok().entity(identifier).build();
}
/**
* Upload images through multi-part form upload
*/
@POST
@Path("{clientId}/image")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Produces({ MediaType.APPLICATION_JSON })
public Response addNewClientImage(
@PathParam("clientId") final Long clientId,
@HeaderParam("Content-Length") Long fileSize,
@FormDataParam("file") InputStream inputStream,
@FormDataParam("file") FormDataContentDisposition fileDetails,
@FormDataParam("file") FormDataBodyPart bodyPart) {
context.authenticatedUser().validateHasReadPermission("CLIENT");
//TODO: vishwas might need more advances validation (like reading magic number) for handling malicious clients
//and clients not setting mime type
FileUtils.validateClientImageNotEmpty(fileDetails.getFileName());
FileUtils.validateImageMimeType(bodyPart.getMediaType().toString());
FileUtils.validateFileSizeWithinPermissibleRange(fileSize,
fileDetails.getFileName(),
ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB);
logger.debug(bodyPart.getMediaType().toString());
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
final Long makerCheckerId = ApiParameterHelper.makerCheckerId(uriInfo.getQueryParameters());
EntityIdentifier entityIdentifier = this.clientWritePlatformService
.saveOrUpdateClientImage(clientId, fileDetails.getFileName(),
inputStream);
ClientData clientData = this.clientReadPlatformService.retrieveNewClientDetails();
if (makerCheckerId != null) {
clientData = handleMakerCheckerRequest(null, makerCheckerId, clientData);
}
return Response.ok().entity(entityIdentifier).build();
}
return this.apiJsonSerializerService.serializeClientDataToJson(prettyPrint, responseParameters, clientData);
}
/**
* Upload image as a Data URL (essentially a base64 encoded stream)
*/
@POST
@Path("{clientId}/image")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addNewClientImage(
@PathParam("clientId") final Long clientId,
final String jsonRequestBody) {
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createClient(final String jsonRequestBody) {
Base64EncodedImage base64EncodedImage = FileUtils
.extractImageFromDataURL(jsonRequestBody);
final EntityIdentifier result = this.commandsSourceWritePlatformService
.logCommandSource("CREATE", "clients", null, jsonRequestBody);
EntityIdentifier entityIdentifier = this.clientWritePlatformService
.saveOrUpdateClientImage(clientId, base64EncodedImage);
return this.apiJsonSerializerService.serializeEntityIdentifier(result);
}
return Response.ok().entity(entityIdentifier).build();
}
@PUT
@Path("{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateClient(@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
/**
* Returns a base 64 encoded client image
*/
@GET
@Path("{clientId}/image")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public Response retrieveClientImage(
@PathParam("clientId") final Long clientId) {
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("UPDATE", "clients", clientId,
jsonRequestBody);
context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE");
final ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
return this.apiJsonSerializerService.serializeEntityIdentifier(result);
}
if (clientData.imageKeyDoesNotExist()) {
throw new ImageNotFoundException("clients", clientId);
}
return Response.ok().entity(Base64.encodeFromFile(clientData.imageKey())).build();
}
/**
* This method is added only for consistency with other URL patterns
* and for maintaining consistency of usage of the HTTP "verb"
* at the client side
*/
@PUT
@Path("{clientId}/image")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateClientImage(
@PathParam("clientId") final Long clientId,
@HeaderParam("Content-Length") Long fileSize,
@FormDataParam("file") InputStream inputStream,
@FormDataParam("file") FormDataContentDisposition fileDetails,
@FormDataParam("file") FormDataBodyPart bodyPart) {
return addNewClientImage(clientId, fileSize, inputStream, fileDetails,
bodyPart);
}
@DELETE
@Path("{clientId}/image")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public Response deleteClientImage(@PathParam("clientId") final Long clientId) {
this.clientWritePlatformService.deleteClientImage(clientId);
return Response.ok(new EntityIdentifier(clientId)).build();
}
/**
* This method is added only for consistency with other URL patterns
* and for maintaining consistency of usage of the HTTP "verb"
* at the client side
*
* Upload image as a Data URL (essentially a base64 encoded stream)
*/
@PUT
@Path("{clientId}/image")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateClientImage(
@PathParam("clientId") final Long clientId,
final String jsonRequestBody) {
return addNewClientImage(clientId, jsonRequestBody);
}
@DELETE
@Path("{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteClient(@PathParam("clientId") final Long clientId) {
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("DELETE", "clients", clientId, "{}");
return this.apiJsonSerializerService.serializeEntityIdentifier(result);
}
@GET
@Path("{clientId}/loans")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveClientAccount(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("CLIENT");
Set<String> typicalResponseParameters = new HashSet<String>(Arrays.asList("pendingApprovalLoans", "awaitingDisbursalLoans",
"openLoans", "closedLoans", "anyLoanCount", "pendingApprovalLoanCount", "awaitingDisbursalLoanCount", "activeLoanCount",
"closedLoanCount", "pendingApprovalDespositAccountsCount", "pendingApprovalDespositAccounts",
"approvedDespositAccountsCount", "approvedDespositAccounts", "withdrawnByClientDespositAccountsCount",
"withdrawnByClientDespositAccounts", "closedDepositAccountsCount", "closedDepositAccounts", "rejectedDepositAccountsCount",
"rejectedDepositAccounts", "preclosedDepositAccountsCount", "preclosedDepositAccounts"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
ClientAccountSummaryCollectionData clientAccount = this.clientReadPlatformService.retrieveClientAccountDetails(clientId);
return this.apiJsonSerializerService.serializeClientAccountSummaryCollectionDataToJson(prettyPrint, responseParameters,
clientAccount);
}
@GET
@Path("{clientId}/notes")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllClientNotes(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("CLIENTNOTE");
Set<String> typicalResponseParameters = new HashSet<String>(Arrays.asList("id", "clientId", "loanId", "loanTransactionId",
"noteType", "note", "createdById", "createdByUsername", "createdOn", "updatedById", "updatedByUsername", "updatedOn"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
Collection<NoteData> notes = this.clientReadPlatformService.retrieveAllClientNotes(clientId);
return this.apiJsonSerializerService.serializeNoteDataToJson(prettyPrint, responseParameters, notes);
}
@POST
@Path("{clientId}/notes")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addNewClientNote(@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
NoteCommand command = this.apiDataConversionService.convertJsonToNoteCommand(null, clientId, jsonRequestBody);
EntityIdentifier identifier = this.clientWritePlatformService.addClientNote(command);
return Response.ok().entity(identifier).build();
}
@GET
@Path("{clientId}/notes/{noteId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveClientNote(@PathParam("clientId") final Long clientId, @PathParam("noteId") final Long noteId,
@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("CLIENTNOTE");
Set<String> typicalResponseParameters = new HashSet<String>(Arrays.asList("id", "clientId", "loanId", "loanTransactionId",
"noteType", "note", "createdById", "createdByUsername", "createdOn", "updatedById", "updatedByUsername", "updatedOn"));
Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters());
if (responseParameters.isEmpty()) {
responseParameters.addAll(typicalResponseParameters);
}
boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
NoteData note = this.clientReadPlatformService.retrieveClientNote(clientId, noteId);
return this.apiJsonSerializerService.serializeNoteDataToJson(prettyPrint, responseParameters, note);
}
@PUT
@Path("{clientId}/notes/{noteId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateClientNote(@PathParam("clientId") final Long clientId, @PathParam("noteId") final Long noteId,
final String jsonRequestBody) {
NoteCommand command = this.apiDataConversionService.convertJsonToNoteCommand(noteId, clientId, jsonRequestBody);
EntityIdentifier identifier = this.clientWritePlatformService.updateNote(command);
return Response.ok().entity(identifier).build();
}
/**
* Upload images through multi-part form upload
*/
@POST
@Path("{clientId}/image")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Produces({ MediaType.APPLICATION_JSON })
public Response addNewClientImage(@PathParam("clientId") final Long clientId, @HeaderParam("Content-Length") Long fileSize,
@FormDataParam("file") InputStream inputStream, @FormDataParam("file") FormDataContentDisposition fileDetails,
@FormDataParam("file") FormDataBodyPart bodyPart) {
// TODO: vishwas might need more advances validation (like reading magic
// number) for handling malicious clients
// and clients not setting mime type
FileUtils.validateClientImageNotEmpty(fileDetails.getFileName());
FileUtils.validateImageMimeType(bodyPart.getMediaType().toString());
FileUtils.validateFileSizeWithinPermissibleRange(fileSize, fileDetails.getFileName(), ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB);
logger.debug(bodyPart.getMediaType().toString());
EntityIdentifier entityIdentifier = this.clientWritePlatformService.saveOrUpdateClientImage(clientId, fileDetails.getFileName(),
inputStream);
return Response.ok().entity(entityIdentifier).build();
}
/**
* Upload image as a Data URL (essentially a base64 encoded stream)
*/
@POST
@Path("{clientId}/image")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response addNewClientImage(@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
Base64EncodedImage base64EncodedImage = FileUtils.extractImageFromDataURL(jsonRequestBody);
EntityIdentifier entityIdentifier = this.clientWritePlatformService.saveOrUpdateClientImage(clientId, base64EncodedImage);
return Response.ok().entity(entityIdentifier).build();
}
/**
* Returns a base 64 encoded client image
*/
@GET
@Path("{clientId}/image")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response retrieveClientImage(@PathParam("clientId") final Long clientId) {
context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE");
final ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
if (clientData.imageKeyDoesNotExist()) { throw new ImageNotFoundException("clients", clientId); }
return Response.ok().entity(Base64.encodeFromFile(clientData.imageKey())).build();
}
/**
* This method is added only for consistency with other URL patterns and for
* maintaining consistency of usage of the HTTP "verb" at the client side
*/
@PUT
@Path("{clientId}/image")
@Consumes({ MediaType.MULTIPART_FORM_DATA })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateClientImage(@PathParam("clientId") final Long clientId, @HeaderParam("Content-Length") Long fileSize,
@FormDataParam("file") InputStream inputStream, @FormDataParam("file") FormDataContentDisposition fileDetails,
@FormDataParam("file") FormDataBodyPart bodyPart) {
return addNewClientImage(clientId, fileSize, inputStream, fileDetails, bodyPart);
}
@DELETE
@Path("{clientId}/image")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response deleteClientImage(@PathParam("clientId") final Long clientId) {
this.clientWritePlatformService.deleteClientImage(clientId);
return Response.ok(new EntityIdentifier(clientId)).build();
}
/**
* This method is added only for consistency with other URL patterns and for
* maintaining consistency of usage of the HTTP "verb" at the client side
*
* Upload image as a Data URL (essentially a base64 encoded stream)
*/
@PUT
@Path("{clientId}/image")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public Response updateClientImage(@PathParam("clientId") final Long clientId, final String jsonRequestBody) {
return addNewClientImage(clientId, jsonRequestBody);
}
}
@@ -25,6 +25,7 @@ import org.mifosng.platform.api.data.RolePermissionsData;
import org.mifosng.platform.api.infrastructure.PortfolioApiDataConversionService;
import org.mifosng.platform.api.infrastructure.PortfolioApiJsonSerializerService;
import org.mifosng.platform.infrastructure.api.ApiParameterHelper;
import org.mifosng.platform.makerchecker.service.PortfolioCommandSourceWritePlatformService;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.service.PermissionReadPlatformService;
import org.mifosng.platform.user.service.RoleReadPlatformService;
@@ -52,6 +53,9 @@ public class RolesApiResource {
@Autowired
private PortfolioApiJsonSerializerService apiJsonSerializerService;
@Autowired
private PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired
private PlatformSecurityContext context;
@@ -77,7 +81,7 @@ public class RolesApiResource {
@Path("template")
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String retrieveNewRoleDetails(@Context final UriInfo uriInfo) {
public String retrieveRoleTemplate(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
@@ -94,13 +98,11 @@ public class RolesApiResource {
@POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.APPLICATION_JSON})
public String createRole(final String jsonRequestBody) {
public String createRole(final String apiRequestBodyAsJson) {
final EntityIdentifier result = this.commandsSourceWritePlatformService.logCommandSource("CREATE", "roles", null, apiRequestBodyAsJson);
final RoleCommand command = this.apiDataConversionService.convertJsonToRoleCommand(null, jsonRequestBody);
final Long roleId = this.roleWritePlatformService.createRole(command);
return this.apiJsonSerializerService.serializeEntityIdentifier(new EntityIdentifier(roleId));
return this.apiJsonSerializerService.serializeEntityIdentifier(result);
}
// TODO - General thing to fix about REST API is if use partial response
@@ -140,7 +142,7 @@ public class RolesApiResource {
@Produces({MediaType.APPLICATION_JSON})
public String updateRole(@PathParam("roleId") final Long roleId, final String jsonRequestBody) {
final RoleCommand command = this.apiDataConversionService.convertJsonToRoleCommand(roleId, jsonRequestBody);
final RoleCommand command = this.apiDataConversionService.convertApiRequestJsonToRoleCommand(roleId, jsonRequestBody);
this.roleWritePlatformService.updateRole(command);
@@ -9,92 +9,85 @@ import org.joda.time.LocalDate;
*/
public class ClientCommand {
private final String externalId;
private final String firstname;
private final String lastname;
private final String clientOrBusinessName;
private final Long officeId;
private final LocalDate joiningDate;
private final String externalId;
private final String firstname;
private final String lastname;
private final String clientOrBusinessName;
private final Long officeId;
private final LocalDate joiningDate;
// made transient as dont want them to be serialized/converted to JSON
private final transient Long id;
private final transient boolean makerCheckerApproval;
private final transient Set<String> parametersPassedInRequest;
public ClientCommand(
final Set<String> modifiedParameters,
final Long id,
final String externalId,
final String firstname,
final String lastname,
final String clientOrBusinessName,
final Long officeId,
final LocalDate joiningDate,
final boolean makerCheckerApproval) {
this.parametersPassedInRequest = modifiedParameters;
this.id = id;
this.externalId = externalId;
this.firstname = firstname;
this.lastname = lastname;
this.clientOrBusinessName = clientOrBusinessName;
this.officeId = officeId;
this.joiningDate = joiningDate;
this.makerCheckerApproval = makerCheckerApproval;
}
// made transient as dont want them to be serialized/converted to JSON
private final transient Long id;
private final transient boolean makerCheckerApproval;
private final transient Set<String> parametersPassedInRequest;
public Long getId() {
return id;
}
public ClientCommand(final Set<String> modifiedParameters, final Long id, final String externalId, final String firstname,
final String lastname, final String clientOrBusinessName, final Long officeId, final LocalDate joiningDate,
final boolean makerCheckerApproval) {
this.parametersPassedInRequest = modifiedParameters;
this.id = id;
this.externalId = externalId;
this.firstname = firstname;
this.lastname = lastname;
this.clientOrBusinessName = clientOrBusinessName;
this.officeId = officeId;
this.joiningDate = joiningDate;
this.makerCheckerApproval = makerCheckerApproval;
}
public String getExternalId() {
return externalId;
}
public Long getId() {
return id;
}
public String getFirstname() {
return firstname;
}
public String getExternalId() {
return externalId;
}
public String getLastname() {
return lastname;
}
public String getFirstname() {
return firstname;
}
public String getClientOrBusinessName() {
return clientOrBusinessName;
}
public String getLastname() {
return lastname;
}
public Long getOfficeId() {
return officeId;
}
public String getClientOrBusinessName() {
return clientOrBusinessName;
}
public LocalDate getJoiningDate() {
return joiningDate;
}
public boolean isFirstnameChanged() {
return this.parametersPassedInRequest.contains("firstname");
}
public boolean isLastnameChanged() {
return this.parametersPassedInRequest.contains("lastname");
}
public boolean isClientOrBusinessNameChanged() {
return this.parametersPassedInRequest.contains("clientOrBusinessName");
}
public boolean isExternalIdChanged() {
return this.parametersPassedInRequest.contains("externalId");
}
public boolean isJoiningDateChanged() {
return this.parametersPassedInRequest.contains("joiningDate");
}
public boolean isOfficeChanged() {
return this.parametersPassedInRequest.contains("officeId");
}
public Long getOfficeId() {
return officeId;
}
public boolean isApprovedByChecker() {
return this.makerCheckerApproval;
}
public LocalDate getJoiningDate() {
return joiningDate;
}
public boolean isFirstnameChanged() {
return this.parametersPassedInRequest.contains("firstname");
}
public boolean isLastnameChanged() {
return this.parametersPassedInRequest.contains("lastname");
}
public boolean isClientOrBusinessNameChanged() {
return this.parametersPassedInRequest.contains("clientOrBusinessName");
}
public boolean isExternalIdChanged() {
return this.parametersPassedInRequest.contains("externalId");
}
public boolean isJoiningDateChanged() {
return this.parametersPassedInRequest.contains("joiningDate");
}
public boolean isOfficeChanged() {
return this.parametersPassedInRequest.contains("officeId");
}
public boolean isApprovedByChecker() {
return this.makerCheckerApproval;
}
}
@@ -4,17 +4,26 @@ import java.util.Set;
/**
* Immutable command for creating or updating details of a role.
*
* <p>Fields that are transient are intended not to be serialized into JSON.</p>
*/
public class RoleCommand {
private final Long id;
private final transient Long id;
private final String name;
private final String description;
private final Set<String> modifiedParameters;
private final transient boolean makerCheckerApproval;
private final transient Set<String> modifiedParameters;
public RoleCommand(Set<String> modifiedParameters, final Long id, final String name, final String description) {
public RoleCommand(
final Set<String> modifiedParameters,
final boolean makerCheckerApproval,
final Long id,
final String name,
final String description) {
this.modifiedParameters = modifiedParameters;
this.makerCheckerApproval = makerCheckerApproval;
this.id = id;
this.name = name;
this.description = description;
@@ -39,4 +48,8 @@ public class RoleCommand {
public boolean isDescriptionChanged() {
return this.modifiedParameters.contains("description");
}
public boolean isApprovedByChecker() {
return this.makerCheckerApproval;
}
}
@@ -40,7 +40,7 @@ public interface PortfolioApiDataConversionService {
OfficeCommand convertJsonToOfficeCommand(Long resourceIdentifier, String json);
RoleCommand convertJsonToRoleCommand(Long resourceIdentifier, String json);
RoleCommand convertApiRequestJsonToRoleCommand(Long resourceIdentifier, String json);
RolePermissionCommand convertJsonToRolePermissionCommand(Long roleId, String jsonRequestBody);
@@ -53,6 +53,7 @@ import org.mifosng.platform.exceptions.PlatformApiDataValidationException;
import org.mifosng.platform.infrastructure.api.JsonParserHelper;
import org.mifosng.platform.infrastructure.errorhandling.InvalidJsonException;
import org.mifosng.platform.infrastructure.errorhandling.UnsupportedParameterException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.number.NumberFormatter;
import org.springframework.stereotype.Service;
@@ -66,9 +67,20 @@ import com.google.gson.reflect.TypeToken;
@Service
public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataConversionService {
/**
* Used in places where the support json of the api request is not any
* different to that of the json of a serialized command object.
*/
private final PortfolioCommandDeserializerService portfolioCommandDeserializerService;
/**
* Google-gson class for converting to and from json.
*/
private final Gson gsonConverter;
public PortfolioApiDataConversionServiceImpl() {
@Autowired
public PortfolioApiDataConversionServiceImpl(final PortfolioCommandDeserializerService portfolioCommandDeserializerService) {
this.portfolioCommandDeserializerService = portfolioCommandDeserializerService;
gsonConverter = new Gson();
}
@@ -229,22 +241,20 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo
}
@Override
public RoleCommand convertJsonToRoleCommand(final Long resourceIdentifier, final String json) {
public RoleCommand convertApiRequestJsonToRoleCommand(final Long resourceIdentifier, final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap);
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
final Map<String, Object> requestMap = gsonConverter.fromJson(json, typeOfMap);
Set<String> supportedParams = new HashSet<String>(Arrays.asList("name", "description", "permissions"));
final Set<String> supportedParams = new HashSet<String>(Arrays.asList("id", "name", "description"));
checkForUnsupportedParameters(requestMap, supportedParams);
Set<String> modifiedParameters = new HashSet<String>();
String name = extractStringParameter("name", requestMap, modifiedParameters);
String description = extractStringParameter("description", requestMap, modifiedParameters);
return new RoleCommand(modifiedParameters, resourceIdentifier, name, description);
// no difference between the api json and internal command
// representation of json so reuse this code to de-serialize into
// command object
return this.portfolioCommandDeserializerService.deserializeRoleCommand(resourceIdentifier, json, false);
}
@Override
@@ -13,6 +13,7 @@ import org.mifosng.platform.api.data.ClientAccountSummaryCollectionData;
import org.mifosng.platform.api.data.ClientData;
import org.mifosng.platform.api.data.ClientIdentifierData;
import org.mifosng.platform.api.data.CodeData;
import org.mifosng.platform.api.data.CommandSourceData;
import org.mifosng.platform.api.data.ConfigurationData;
import org.mifosng.platform.api.data.DatatableData;
import org.mifosng.platform.api.data.DepositAccountData;
@@ -30,7 +31,6 @@ import org.mifosng.platform.api.data.LoanProductData;
import org.mifosng.platform.api.data.LoanReassignmentData;
import org.mifosng.platform.api.data.LoanScheduleData;
import org.mifosng.platform.api.data.LoanTransactionData;
import org.mifosng.platform.api.data.CommandSourceData;
import org.mifosng.platform.api.data.NoteData;
import org.mifosng.platform.api.data.OfficeData;
import org.mifosng.platform.api.data.OfficeTransactionData;
@@ -157,9 +157,9 @@ public interface PortfolioApiJsonSerializerService {
String serializeSavingAccountsDataToJson(boolean prettyPrint, Set<String> responseParameters, Collection<SavingAccountData> accounts);
// TODO - KW - might devide serialize up into portfolio and account to reduce interface
String serializeChartOfAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, ChartOfAccountsData chartOfAccounts);
String serializeGuarantorDataToJson(boolean prettyPrint,Set<String> responseParameters, GuarantorData guarantorData);
String serializeGuarantorDataToJson(boolean prettyPrint, Set<String> responseParameters, GuarantorData guarantorData);
// TODO - KW - might devide serialize up into portfolio and account to
// reduce interface
String serializeChartOfAccountDataToJson(boolean prettyPrint, Set<String> responseParameters, ChartOfAccountsData chartOfAccounts);
}
@@ -0,0 +1,42 @@
package org.mifosng.platform.api.infrastructure;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.mifosng.platform.api.commands.RoleCommand;
import org.mifosng.platform.infrastructure.api.JsonParserHelper;
import org.mifosng.platform.infrastructure.errorhandling.InvalidJsonException;
import org.springframework.stereotype.Service;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
/**
* Implementation of {@link PortfolioCommandDeserializerService} that de-serializes
* JSON of commands into Java object representation using google-gson.
*/
@Service
public class PortfolioCommandDeerializerServiceGoogleGson implements PortfolioCommandDeserializerService {
private final JsonParser parser;
public PortfolioCommandDeerializerServiceGoogleGson() {
parser = new JsonParser();
}
@Override
public RoleCommand deserializeRoleCommand(final Long roleId, final String commandAsJson, final boolean makerCheckerApproval) {
if (StringUtils.isBlank(commandAsJson)) { throw new InvalidJsonException(); }
final JsonParserHelper helper = new JsonParserHelper();
final JsonElement element = parser.parse(commandAsJson);
final Set<String> parametersPassedInRequest = new HashSet<String>();
final String name = helper.extractStringNamed("name", element, parametersPassedInRequest);
final String description = helper.extractStringNamed("description", element, parametersPassedInRequest);
return new RoleCommand(parametersPassedInRequest, makerCheckerApproval, roleId, name, description);
}
}
@@ -0,0 +1,18 @@
package org.mifosng.platform.api.infrastructure;
import org.mifosng.platform.api.commands.RoleCommand;
/**
* Service for de-serializing JSON for a command into the platforms internal
* Java object representation of the command.
*
* <p>
* Known implementations:
* </p>
*
* @see PortfolioCommandDeerializerServiceGoogleGson
*/
public interface PortfolioCommandDeserializerService {
RoleCommand deserializeRoleCommand(Long roleId, String commandAsJson, boolean makerCheckerApproval);
}
@@ -0,0 +1,14 @@
package org.mifosng.platform.api.infrastructure;
import org.mifosng.platform.api.commands.RoleCommand;
/**
* Service for serializing commands into another format.
*
* <p>Known implementations:</p>
* @see PortfolioCommandSerializerServiceJson
*/
public interface PortfolioCommandSerializerService {
String serializeRoleCommandToJson(RoleCommand command);
}
@@ -0,0 +1,32 @@
package org.mifosng.platform.api.infrastructure;
import java.util.HashSet;
import org.mifosng.platform.api.commands.RoleCommand;
import org.mifosng.platform.infrastructure.api.GoogleGsonSerializerHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.google.gson.Gson;
/**
* Implementation of {@link PortfolioCommandSerializerService} that serializes
* the commands into JSON using google-gson.
*/
@Service
public class PortfolioCommandSerializerServiceJson implements PortfolioCommandSerializerService {
private final GoogleGsonSerializerHelper helper;
@Autowired
public PortfolioCommandSerializerServiceJson(final GoogleGsonSerializerHelper helper) {
this.helper = helper;
}
@Override
public String serializeRoleCommandToJson(final RoleCommand command) {
final Gson gsonDeserializer = helper.createGsonBuilderWithParameterExclusionSerializationStrategy(new HashSet<String>(), false,
new HashSet<String>());
return helper.serializedJsonFrom(gsonDeserializer, command);
}
}
@@ -27,522 +27,424 @@ import com.google.gson.JsonPrimitive;
* Helper class to extract values of json named attributes.
*/
public class JsonParserHelper {
public Boolean extractBooleanNamed(final String parameterName, final JsonElement element, final Set<String> requestParamatersDetected) {
Boolean value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
requestParamatersDetected.add(parameterName);
JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
value = primitive.getAsBoolean();
}
}
return value;
}
public Long extractLongNamed(final String parameterName,
final JsonElement element, final Set<String> parametersPassedInRequest) {
Long longValue = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName)
&& object.get(parameterName).isJsonPrimitive()) {
parametersPassedInRequest.add(parameterName);
JsonPrimitive primitive = object.get(parameterName)
.getAsJsonPrimitive();
final String stringValue = primitive.getAsString();
if (StringUtils.isNotBlank(stringValue)) {
longValue = Long.valueOf(stringValue);
}
}
}
return longValue;
}
public Boolean extractBooleanNamed(final String parameterName, final JsonElement element, final Set<String> requestParamatersDetected) {
Boolean value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
requestParamatersDetected.add(parameterName);
public String extractStringNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
String stringValue = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInRequest.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
stringValue = valueAsString;
}
}
}
return stringValue;
}
JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
value = primitive.getAsBoolean();
}
}
return value;
}
public BigDecimal extractBigDecimalNamed(
final String parameterName,
final JsonElement element,
final Set<String> modifiedParameters) {
BigDecimal value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final Locale locale = extractLocaleValue(object);
value = extractBigDecimalNamed(parameterName, object, locale, modifiedParameters);
}
return value;
}
public BigDecimal extractBigDecimalNamed(
final String parameterName,
final JsonObject element,
final Locale locale,
final Set<String> modifiedParameters) {
BigDecimal value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName)
&& object.get(parameterName).isJsonPrimitive()) {
modifiedParameters.add(parameterName);
JsonPrimitive primitive = object.get(parameterName)
.getAsJsonPrimitive();
String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertFrom(valueAsString, parameterName, locale);
}
}
}
return value;
}
public Long extractLongNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
Long longValue = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInRequest.add(parameterName);
JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String stringValue = primitive.getAsString();
if (StringUtils.isNotBlank(stringValue)) {
longValue = Long.valueOf(stringValue);
}
}
}
return longValue;
}
public Integer extractIntegerNamed(
final String parameterName,
final JsonElement element,
final Set<String> modifiedParameters) {
Integer value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final Locale locale = extractLocaleValue(object);
value = extractIntegerNamed(parameterName, object, locale, modifiedParameters);
}
return value;
}
public Integer extractIntegerNamed(
final String parameterName,
final JsonElement element,
final Locale locale,
final Set<String> modifiedParameters) {
Integer value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
modifiedParameters.add(parameterName);
JsonPrimitive primitive = object.get(parameterName)
.getAsJsonPrimitive();
String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertToInteger(valueAsString, parameterName, locale);
}
}
}
return value;
}
public String extractDateFormatParameter(final JsonObject element) {
String value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
public String extractStringNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
String stringValue = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInRequest.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
stringValue = valueAsString;
}
}
}
return stringValue;
}
final String dateFormatParameter = "dateFormat";
if (object.has(dateFormatParameter)
&& object.get(dateFormatParameter).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(dateFormatParameter).getAsJsonPrimitive();
value = primitive.getAsString();
}
}
return value;
}
public Locale extractLocaleParameter(final JsonObject element) {
Locale clientApplicationLocale = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
String locale = null;
final String localeParameter = "locale";
if (object.has(localeParameter)
&& object.get(localeParameter).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(localeParameter).getAsJsonPrimitive();
locale = primitive.getAsString();
clientApplicationLocale = localeFromString(locale);
}
}
return clientApplicationLocale;
}
/**
* Used with the local date is in array format
*/
public LocalDate extractLocalDateAsArrayNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInCommand) {
LocalDate value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
public BigDecimal extractBigDecimalNamed(final String parameterName, final JsonElement element, final Set<String> modifiedParameters) {
BigDecimal value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final Locale locale = extractLocaleValue(object);
value = extractBigDecimalNamed(parameterName, object, locale, modifiedParameters);
}
return value;
}
if (object.has(parameterName) && object.get(parameterName).isJsonArray()) {
parametersPassedInCommand.add(parameterName);
public BigDecimal extractBigDecimalNamed(final String parameterName, final JsonObject element, final Locale locale,
final Set<String> modifiedParameters) {
BigDecimal value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
modifiedParameters.add(parameterName);
JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertFrom(valueAsString, parameterName, locale);
}
}
}
return value;
}
final JsonArray dateArray = object.get(parameterName).getAsJsonArray();
Integer year = dateArray.get(0).getAsInt();
Integer month = dateArray.get(1).getAsInt();
Integer day = dateArray.get(2).getAsInt();
value = new LocalDate().withYearOfEra(year).withMonthOfYear(month).withDayOfMonth(day);
}
public Integer extractIntegerNamed(final String parameterName, final JsonElement element, final Set<String> modifiedParameters) {
Integer value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final Locale locale = extractLocaleValue(object);
value = extractIntegerNamed(parameterName, object, locale, modifiedParameters);
}
return value;
}
}
return value;
}
public Integer extractIntegerNamed(final String parameterName, final JsonElement element, final Locale locale,
final Set<String> modifiedParameters) {
Integer value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
modifiedParameters.add(parameterName);
JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertToInteger(valueAsString, parameterName, locale);
}
}
}
return value;
}
public LocalDate extractLocalDateNamed(
final String parameterName,
final JsonElement element,
final Set<String> parametersPassedInCommand) {
public String extractDateFormatParameter(final JsonObject element) {
String value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
LocalDate value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
final String dateFormatParameter = "dateFormat";
if (object.has(dateFormatParameter) && object.get(dateFormatParameter).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(dateFormatParameter).getAsJsonPrimitive();
value = primitive.getAsString();
}
}
return value;
}
final String dateFormat = extractDateFormatParameter(object);
final Locale clientApplicationLocale = extractLocaleParameter(object);
value = extractLocalDateNamed(parameterName, object, dateFormat, clientApplicationLocale, parametersPassedInCommand);
}
return value;
}
public LocalDate extractLocalDateNamed(
final String parameterName,
final JsonObject element,
final String dateFormat,
final Locale clientApplicationLocale,
final Set<String> parametersPassedInCommand) {
LocalDate value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
public Locale extractLocaleParameter(final JsonObject element) {
Locale clientApplicationLocale = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (object.has(parameterName)
&& object.get(parameterName).isJsonPrimitive()) {
parametersPassedInCommand.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertFrom(valueAsString, parameterName, dateFormat, clientApplicationLocale);
}
}
String locale = null;
final String localeParameter = "locale";
if (object.has(localeParameter) && object.get(localeParameter).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(localeParameter).getAsJsonPrimitive();
locale = primitive.getAsString();
clientApplicationLocale = localeFromString(locale);
}
}
return clientApplicationLocale;
}
}
return value;
}
/**
* Used with the local date is in array format
*/
public LocalDate extractLocalDateAsArrayNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInCommand) {
LocalDate value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
public LocalDate convertFrom(final String dateAsString,
final String parameterName, final String dateFormat,
final Locale clientApplicationLocale) {
if (object.has(parameterName) && object.get(parameterName).isJsonArray()) {
if (StringUtils.isBlank(dateFormat) || clientApplicationLocale == null) {
parametersPassedInCommand.add(parameterName);
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
if (StringUtils.isBlank(dateFormat)) {
String defaultMessage = new StringBuilder(
"The parameter '"
+ parameterName
+ "' requires a 'dateFormat' parameter to be passed with it.")
.toString();
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.missing.dateFormat.parameter",
defaultMessage, parameterName);
dataValidationErrors.add(error);
}
if (clientApplicationLocale == null) {
String defaultMessage = new StringBuilder(
"The parameter '"
+ parameterName
+ "' requires a 'locale' parameter to be passed with it.")
.toString();
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.missing.locale.parameter",
defaultMessage, parameterName);
dataValidationErrors.add(error);
}
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
final JsonArray dateArray = object.get(parameterName).getAsJsonArray();
LocalDate eventLocalDate = null;
if (StringUtils.isNotBlank(dateAsString)) {
try {
// Locale locale = LocaleContextHolder.getLocale();
eventLocalDate = DateTimeFormat
.forPattern(dateFormat)
.withLocale(clientApplicationLocale)
.parseLocalDate(
dateAsString
.toLowerCase(clientApplicationLocale));
} catch (IllegalArgumentException e) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.invalid.date.format", "The parameter "
+ parameterName
+ " is invalid based on the dateFormat: '"
+ dateFormat + "' and locale: '"
+ clientApplicationLocale + "' provided:",
parameterName, dateAsString, dateFormat);
dataValidationErrors.add(error);
Integer year = dateArray.get(0).getAsInt();
Integer month = dateArray.get(1).getAsInt();
Integer day = dateArray.get(2).getAsInt();
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
}
value = new LocalDate().withYearOfEra(year).withMonthOfYear(month).withDayOfMonth(day);
}
return eventLocalDate;
}
}
return value;
}
public Integer convertToInteger(final String numericalValueFormatted,
final String parameterName, final Locale clientApplicationLocale) {
public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInCommand) {
if (clientApplicationLocale == null) {
LocalDate value = null;
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
String defaultMessage = new StringBuilder("The parameter '"
+ parameterName
+ "' requires a 'locale' parameter to be passed with it.")
.toString();
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
final String dateFormat = extractDateFormatParameter(object);
final Locale clientApplicationLocale = extractLocaleParameter(object);
value = extractLocalDateNamed(parameterName, object, dateFormat, clientApplicationLocale, parametersPassedInCommand);
}
return value;
}
try {
Integer number = null;
public LocalDate extractLocalDateNamed(final String parameterName, final JsonObject element, final String dateFormat,
final Locale clientApplicationLocale, final Set<String> parametersPassedInCommand) {
LocalDate value = null;
if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
if (StringUtils.isNotBlank(numericalValueFormatted)) {
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
String source = numericalValueFormatted.trim();
parametersPassedInCommand.add(parameterName);
NumberFormat format = NumberFormat
.getInstance(clientApplicationLocale);
DecimalFormat df = (DecimalFormat) format;
DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
df.setParseBigDecimal(true);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertFrom(valueAsString, parameterName, dateFormat, clientApplicationLocale);
}
}
// http://bugs.sun.com/view_bug.do?bug_id=4510618
char groupingSeparator = symbols.getGroupingSeparator();
if (groupingSeparator == '\u00a0') {
source = source.replaceAll(" ",
Character.toString('\u00a0'));
}
}
return value;
}
Number parsedNumber = df.parse(source);
public LocalDate convertFrom(final String dateAsString, final String parameterName, final String dateFormat,
final Locale clientApplicationLocale) {
double parsedNumberDouble = parsedNumber.doubleValue();
int parsedNumberInteger = parsedNumber.intValue();
if (StringUtils.isBlank(dateFormat) || clientApplicationLocale == null) {
if (source.contains(Character.toString(symbols
.getDecimalSeparator()))) {
throw new ParseException(source, 0);
}
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
if (StringUtils.isBlank(dateFormat)) {
String defaultMessage = new StringBuilder("The parameter '" + parameterName
+ "' requires a 'dateFormat' parameter to be passed with it.").toString();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.dateFormat.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
}
if (clientApplicationLocale == null) {
String defaultMessage = new StringBuilder("The parameter '" + parameterName
+ "' requires a 'locale' parameter to be passed with it.").toString();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
}
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
if (!Double.valueOf(parsedNumberDouble).equals(
Double.valueOf(Integer.valueOf(parsedNumberInteger)))) {
throw new ParseException(source, 0);
}
LocalDate eventLocalDate = null;
if (StringUtils.isNotBlank(dateAsString)) {
try {
// Locale locale = LocaleContextHolder.getLocale();
eventLocalDate = DateTimeFormat.forPattern(dateFormat).withLocale(clientApplicationLocale)
.parseLocalDate(dateAsString.toLowerCase(clientApplicationLocale));
} catch (IllegalArgumentException e) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.date.format", "The parameter "
+ parameterName + " is invalid based on the dateFormat: '" + dateFormat + "' and locale: '"
+ clientApplicationLocale + "' provided:", parameterName, dateAsString, dateFormat);
dataValidationErrors.add(error);
number = parsedNumber.intValue();
}
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
return number;
} catch (ParseException e) {
return eventLocalDate;
}
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError
.parameterError(
"validation.msg.invalid.integer.format",
"The parameter "
+ parameterName
+ " has value: "
+ numericalValueFormatted
+ " which is invalid integer value for provided locale of ["
+ clientApplicationLocale.toString() + "].",
parameterName, numericalValueFormatted,
clientApplicationLocale);
dataValidationErrors.add(error);
public Integer convertToInteger(final String numericalValueFormatted, final String parameterName, final Locale clientApplicationLocale) {
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
}
if (clientApplicationLocale == null) {
public BigDecimal convertFrom(final String numericalValueFormatted,
final String parameterName, final Locale clientApplicationLocale) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
String defaultMessage = new StringBuilder("The parameter '" + parameterName
+ "' requires a 'locale' parameter to be passed with it.").toString();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
if (clientApplicationLocale == null) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
String defaultMessage = new StringBuilder("The parameter '"
+ parameterName
+ "' requires a 'locale' parameter to be passed with it.")
.toString();
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
try {
Integer number = null;
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
if (StringUtils.isNotBlank(numericalValueFormatted)) {
try {
BigDecimal number = null;
String source = numericalValueFormatted.trim();
if (StringUtils.isNotBlank(numericalValueFormatted)) {
NumberFormat format = NumberFormat.getInstance(clientApplicationLocale);
DecimalFormat df = (DecimalFormat) format;
DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
df.setParseBigDecimal(true);
String source = numericalValueFormatted.trim();
// http://bugs.sun.com/view_bug.do?bug_id=4510618
char groupingSeparator = symbols.getGroupingSeparator();
if (groupingSeparator == '\u00a0') {
source = source.replaceAll(" ", Character.toString('\u00a0'));
}
NumberFormat format = NumberFormat
.getNumberInstance(clientApplicationLocale);
DecimalFormat df = (DecimalFormat) format;
DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
// http://bugs.sun.com/view_bug.do?bug_id=4510618
char groupingSeparator = symbols.getGroupingSeparator();
if (groupingSeparator == '\u00a0') {
source = source.replaceAll(" ",
Character.toString('\u00a0'));
}
Number parsedNumber = df.parse(source);
NumberFormatter numberFormatter = new NumberFormatter();
Number parsedNumber = numberFormatter.parse(source,
clientApplicationLocale);
number = BigDecimal.valueOf(Double.valueOf(parsedNumber
.doubleValue()));
}
double parsedNumberDouble = parsedNumber.doubleValue();
int parsedNumberInteger = parsedNumber.intValue();
return number;
} catch (ParseException e) {
if (source.contains(Character.toString(symbols.getDecimalSeparator()))) { throw new ParseException(source, 0); }
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError
.parameterError(
"validation.msg.invalid.decimal.format",
"The parameter "
+ parameterName
+ " has value: "
+ numericalValueFormatted
+ " which is invalid decimal value for provided locale of ["
+ clientApplicationLocale.toString() + "].",
parameterName, numericalValueFormatted,
clientApplicationLocale);
dataValidationErrors.add(error);
if (!Double.valueOf(parsedNumberDouble).equals(Double.valueOf(Integer.valueOf(parsedNumberInteger)))) { throw new ParseException(
source, 0); }
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
}
number = parsedNumber.intValue();
}
private Locale localeFromString(final String localeAsString) {
return number;
} catch (ParseException e) {
if (StringUtils.isBlank(localeAsString)) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.invalid.locale.format",
"The parameter locale is invalid. It cannot be blank.",
"locale");
dataValidationErrors.add(error);
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer.format", "The parameter "
+ parameterName + " has value: " + numericalValueFormatted + " which is invalid integer value for provided locale of ["
+ clientApplicationLocale.toString() + "].", parameterName, numericalValueFormatted, clientApplicationLocale);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
String languageCode = "";
String courntryCode = "";
String variantCode = "";
public BigDecimal convertFrom(final String numericalValueFormatted, final String parameterName, final Locale clientApplicationLocale) {
String[] localeParts = localeAsString.split("_");
if (clientApplicationLocale == null) {
if (localeParts != null && localeParts.length == 1) {
languageCode = localeParts[0];
}
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
String defaultMessage = new StringBuilder("The parameter '" + parameterName
+ "' requires a 'locale' parameter to be passed with it.").toString();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
if (localeParts != null && localeParts.length == 2) {
languageCode = localeParts[0];
courntryCode = localeParts[1];
}
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
if (localeParts != null && localeParts.length == 3) {
languageCode = localeParts[0];
courntryCode = localeParts[1];
variantCode = localeParts[2];
}
try {
BigDecimal number = null;
return localeFrom(languageCode, courntryCode, variantCode);
}
if (StringUtils.isNotBlank(numericalValueFormatted)) {
private Locale localeFrom(final String languageCode,
final String courntryCode, final String variantCode) {
String source = numericalValueFormatted.trim();
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
NumberFormat format = NumberFormat.getNumberInstance(clientApplicationLocale);
DecimalFormat df = (DecimalFormat) format;
DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
// http://bugs.sun.com/view_bug.do?bug_id=4510618
char groupingSeparator = symbols.getGroupingSeparator();
if (groupingSeparator == '\u00a0') {
source = source.replaceAll(" ", Character.toString('\u00a0'));
}
List<String> allowedLanguages = Arrays.asList(Locale.getISOLanguages());
if (!allowedLanguages.contains(languageCode.toLowerCase())) {
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.invalid.locale.format",
"The parameter locale has an invalid language value "
+ languageCode + " .", "locale", languageCode);
dataValidationErrors.add(error);
}
NumberFormatter numberFormatter = new NumberFormatter();
Number parsedNumber = numberFormatter.parse(source, clientApplicationLocale);
number = BigDecimal.valueOf(Double.valueOf(parsedNumber.doubleValue()));
}
if (StringUtils.isNotBlank(courntryCode.toUpperCase())) {
List<String> allowedCountries = Arrays.asList(Locale
.getISOCountries());
if (!allowedCountries.contains(courntryCode)) {
ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.invalid.locale.format",
"The parameter locale has an invalid country value "
+ courntryCode + " .", "locale", courntryCode);
dataValidationErrors.add(error);
}
}
return number;
} catch (ParseException e) {
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException(
"validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
}
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.decimal.format", "The parameter "
+ parameterName + " has value: " + numericalValueFormatted + " which is invalid decimal value for provided locale of ["
+ clientApplicationLocale.toString() + "].", parameterName, numericalValueFormatted, clientApplicationLocale);
dataValidationErrors.add(error);
return new Locale(languageCode.toLowerCase(),
courntryCode.toUpperCase(), variantCode);
}
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
private Locale extractLocaleValue(final JsonObject object) {
Locale clientApplicationLocale = null;
String locale = null;
if (object.has("locale") && object.get("locale").isJsonPrimitive()) {
JsonPrimitive primitive = object.get("locale").getAsJsonPrimitive();
locale = primitive.getAsString();
clientApplicationLocale = localeFromString(locale);
}
return clientApplicationLocale;
}
private Locale localeFromString(final String localeAsString) {
if (StringUtils.isBlank(localeAsString)) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter locale is invalid. It cannot be blank.", "locale");
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
String languageCode = "";
String courntryCode = "";
String variantCode = "";
String[] localeParts = localeAsString.split("_");
if (localeParts != null && localeParts.length == 1) {
languageCode = localeParts[0];
}
if (localeParts != null && localeParts.length == 2) {
languageCode = localeParts[0];
courntryCode = localeParts[1];
}
if (localeParts != null && localeParts.length == 3) {
languageCode = localeParts[0];
courntryCode = localeParts[1];
variantCode = localeParts[2];
}
return localeFrom(languageCode, courntryCode, variantCode);
}
private Locale localeFrom(final String languageCode, final String courntryCode, final String variantCode) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
List<String> allowedLanguages = Arrays.asList(Locale.getISOLanguages());
if (!allowedLanguages.contains(languageCode.toLowerCase())) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter locale has an invalid language value " + languageCode + " .", "locale", languageCode);
dataValidationErrors.add(error);
}
if (StringUtils.isNotBlank(courntryCode.toUpperCase())) {
List<String> allowedCountries = Arrays.asList(Locale.getISOCountries());
if (!allowedCountries.contains(courntryCode)) {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter locale has an invalid country value " + courntryCode + " .", "locale", courntryCode);
dataValidationErrors.add(error);
}
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
return new Locale(languageCode.toLowerCase(), courntryCode.toUpperCase(), variantCode);
}
private Locale extractLocaleValue(final JsonObject object) {
Locale clientApplicationLocale = null;
String locale = null;
if (object.has("locale") && object.get("locale").isJsonPrimitive()) {
JsonPrimitive primitive = object.get("locale").getAsJsonPrimitive();
locale = primitive.getAsString();
clientApplicationLocale = localeFromString(locale);
}
return clientApplicationLocale;
}
}
@@ -108,10 +108,6 @@ public class CommandSource extends AbstractPersistable<Long> {
return this.apiOperation;
}
public boolean isClientResource() {
return this.resource.equalsIgnoreCase("CLIENTS");
}
public boolean isCreate() {
return this.apiOperation.equalsIgnoreCase("CREATE");
}
@@ -123,4 +119,12 @@ public class CommandSource extends AbstractPersistable<Long> {
public boolean isDelete() {
return this.apiOperation.equalsIgnoreCase("DELETE") && this.resourceId != null;
}
public boolean isClientResource() {
return this.resource.equalsIgnoreCase("CLIENTS");
}
public boolean isRoleResource() {
return this.resource.equalsIgnoreCase("ROLES");
}
}
@@ -14,11 +14,15 @@ public class CommandSourceHandlerDelegator {
private final PlatformSecurityContext context;
private final ClientCommandHandler clientCommandHandler;
private final RoleCommandHandler roleCommandHandler;
@Autowired
public CommandSourceHandlerDelegator(final PlatformSecurityContext context, final ClientCommandHandler clientCommandHandler) {
public CommandSourceHandlerDelegator(final PlatformSecurityContext context,
final ClientCommandHandler clientCommandHandler,
final RoleCommandHandler roleCommandHandler) {
this.context = context;
this.clientCommandHandler = clientCommandHandler;
this.roleCommandHandler = roleCommandHandler;
}
public CommandSource handle(final CommandSource commandSource, final String apiRequestBodyInJson) {
@@ -27,6 +31,8 @@ public class CommandSourceHandlerDelegator {
CommandSource commandSourceResult = null;
if (commandSource.isClientResource()) {
commandSourceResult = clientCommandHandler.handle(commandSource, apiRequestBodyInJson);
} else if (commandSource.isRoleResource()) {
commandSourceResult = roleCommandHandler.handle(commandSource, apiRequestBodyInJson);
} else {
throw new UnsupportedCommandException(commandSource.commandName());
}
@@ -39,6 +45,8 @@ public class CommandSourceHandlerDelegator {
CommandSource commandSourceResult = null;
if (commandSource.isClientResource()) {
commandSourceResult = clientCommandHandler.handle(commandSource);
} else if (commandSource.isRoleResource()) {
commandSourceResult = roleCommandHandler.handle(commandSource);
} else {
throw new UnsupportedCommandException(commandSource.commandName());
}
@@ -0,0 +1,110 @@
package org.mifosng.platform.makerchecker.service;
import org.joda.time.LocalDate;
import org.mifosng.platform.api.commands.RoleCommand;
import org.mifosng.platform.api.infrastructure.PortfolioApiDataConversionService;
import org.mifosng.platform.api.infrastructure.PortfolioCommandDeserializerService;
import org.mifosng.platform.api.infrastructure.PortfolioCommandSerializerService;
import org.mifosng.platform.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.mifosng.platform.infrastructure.errorhandling.UnsupportedCommandException;
import org.mifosng.platform.makerchecker.domain.CommandSource;
import org.mifosng.platform.security.PlatformSecurityContext;
import org.mifosng.platform.user.domain.AppUser;
import org.mifosng.platform.user.service.RoleWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class RoleCommandHandler implements CommandSourceHandler {
private final PlatformSecurityContext context;
private final ChangeDetectionService changeDetectionService;
private final PortfolioApiDataConversionService apiDataConversionService;
private final PortfolioCommandSerializerService commandSerializerService;
private final PortfolioCommandDeserializerService commandDeserializerService;
private final RoleWritePlatformService writePlatformService;
@Autowired
public RoleCommandHandler(final PlatformSecurityContext context, final ChangeDetectionService changeDetectionService,
final PortfolioApiDataConversionService apiDataConversionService,
final PortfolioCommandSerializerService commandSerializerService,
final PortfolioCommandDeserializerService commandDeserializerService,
final RoleWritePlatformService writePlatformService) {
this.context = context;
this.changeDetectionService = changeDetectionService;
this.apiDataConversionService = apiDataConversionService;
this.commandSerializerService = commandSerializerService;
this.commandDeserializerService = commandDeserializerService;
this.writePlatformService = writePlatformService;
}
/*
* Used when users with 'create' capability create a command. If 'maker-checker' is not
* enabled for this specific command then the 'creator' is also marked 'as the checker' and command
* automatically is processed and changes state of system.
*/
public CommandSource handle(final CommandSource commandSource, final String apiRequestBodyInJson) {
final AppUser maker = context.authenticatedUser();
final LocalDate asToday = new LocalDate();
CommandSource commandSourceResult = commandSource.copy();
final Long resourceId = commandSource.resourceId();
Long newResourceId = null;
final RoleCommand command = this.apiDataConversionService.convertApiRequestJsonToRoleCommand(resourceId, apiRequestBodyInJson);
final String commandSerializedAsJson = this.commandSerializerService.serializeRoleCommandToJson(command);
commandSourceResult.updateJsonTo(commandSerializedAsJson);
if (commandSource.isCreate()) {
try {
newResourceId = this.writePlatformService.createRole(command);
commandSourceResult.markAsChecked(maker, asToday);
commandSourceResult.updateResourceId(newResourceId);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design
}
} else if (commandSource.isUpdate()) {
try {
final String jsonOfChangesOnly = this.changeDetectionService.detectChangesOnUpdate(commandSource.resourceName(), commandSource.resourceId(), commandSerializedAsJson);
commandSourceResult.updateJsonTo(jsonOfChangesOnly);
final RoleCommand changesOnly = this.commandDeserializerService.deserializeRoleCommand(resourceId, jsonOfChangesOnly, false);
newResourceId = this.writePlatformService.updateRole(changesOnly);
commandSourceResult.markAsChecked(maker, asToday);
} catch (RollbackTransactionAsCommandIsNotApprovedByCheckerException e) {
// swallow this rollback transaction by design
}
} else if (commandSource.isDelete()) {
throw new UnsupportedCommandException(commandSource.commandName());
}
return commandSourceResult;
}
/*
* Used when users with 'checker' capability approve a command.
*/
public CommandSource handle(final CommandSource commandSourceResult) {
Long resourceId = null;
if (commandSourceResult.isRoleResource()) {
final RoleCommand command = this.commandDeserializerService.deserializeRoleCommand(resourceId, commandSourceResult.json(), true);
if (commandSourceResult.isCreate()) {
resourceId = this.writePlatformService.createRole(command);
} else if (commandSourceResult.isUpdate()) {
resourceId = this.writePlatformService.updateRole(command);
} else if (commandSourceResult.isDelete()) {
throw new UnsupportedCommandException(commandSourceResult.commandName());
}
}
commandSourceResult.updateResourceId(resourceId);
return commandSourceResult;
}
}
@@ -12,27 +12,26 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
public class Permission extends AbstractPersistable<Long> {
@SuppressWarnings("unused")
@Column(name = "grouping", nullable = false, length=45)
private final String grouping;
@Column(name = "code", nullable = false, length=100)
private final String code;
@Column(name = "grouping", nullable = false, length = 45)
private final String grouping;
@Column(name = "default_name", nullable = false, length=100)
private final String defaultName;
@Column(name = "code", nullable = false, length = 100)
private final String code;
@Column(name = "default_description", nullable = false, length=500)
private final String defaultDescription;
@Column(name = "default_name", nullable = false, length = 100)
private final String defaultName;
@Column(name = "default_description", nullable = false, length = 500)
private final String defaultDescription;
@SuppressWarnings("unused")
@Column(name = "entity_name", nullable = true, length=100)
private final String entityName;
@Column(name = "entity_name", nullable = true, length = 100)
private final String entityName;
@SuppressWarnings("unused")
@Column(name = "action_name", nullable = true, length=100)
private final String actionName;
@Column(name = "action_name", nullable = true, length = 100)
private final String actionName;
protected Permission() {
this.grouping = null;
this.code = null;
@@ -42,15 +41,15 @@ public class Permission extends AbstractPersistable<Long> {
this.actionName = null;
}
public boolean hasCode(String checkCode) {
return this.code.equalsIgnoreCase(checkCode);
}
public boolean hasCode(final String checkCode) {
return this.code.equalsIgnoreCase(checkCode);
}
public String code() {
return this.code;
}
public String code() {
return this.code;
}
public PermissionData toData() {
return new PermissionData(this.getId(), this.defaultName, this.defaultDescription, this.code);
}
public PermissionData toData() {
return new PermissionData(this.getId(), this.defaultName, this.defaultDescription, this.code);
}
}
@@ -5,6 +5,7 @@ import java.util.Map;
import org.mifosng.platform.accounting.api.commands.RolePermissionCommand;
import org.mifosng.platform.api.commands.RoleCommand;
import org.mifosng.platform.client.service.RollbackTransactionAsCommandIsNotApprovedByCheckerException;
import org.mifosng.platform.exceptions.PermissionNotFoundException;
import org.mifosng.platform.exceptions.RoleNotFoundException;
import org.mifosng.platform.security.PlatformSecurityContext;
@@ -17,108 +18,102 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class RoleWritePlatformServiceJpaRepositoryImpl implements
RoleWritePlatformService {
public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatformService {
private final PlatformSecurityContext context;
private final RoleRepository roleRepository;
private final PlatformSecurityContext context;
private final RoleRepository roleRepository;
private final PermissionRepository permissionRepository;
private final PermissionRepository permissionRepository;
// FIXME - kw - this value is hardcoded for now but will be retrieved from
// configuration
private boolean makerCheckerEnabledForTask = false;
@Autowired
public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository,
final PermissionRepository permissionRepository) {
this.context = context;
this.roleRepository = roleRepository;
this.permissionRepository = permissionRepository;
}
@Autowired
public RoleWritePlatformServiceJpaRepositoryImpl(
final PlatformSecurityContext context,
final RoleRepository roleRepository,
final PermissionRepository permissionRepository) {
this.context = context;
this.roleRepository = roleRepository;
this.permissionRepository = permissionRepository;
}
@Transactional
@Override
public Long createRole(final RoleCommand command) {
@Transactional
@Override
public Long createRole(final RoleCommand command) {
context.authenticatedUser();
context.authenticatedUser();
RoleCommandValidator validator = new RoleCommandValidator(command);
validator.validateForCreate();
RoleCommandValidator validator = new RoleCommandValidator(command);
validator.validateForCreate();
Role entity = new Role(command.getName(), command.getDescription());
Role entity = new Role(command.getName(), command.getDescription());
this.roleRepository.save(entity);
if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
this.roleRepository.save(entity);
return entity.getId();
}
return entity.getId();
}
@Transactional
@Override
public Long updateRole(RoleCommand command) {
@Transactional
@Override
public Long updateRole(RoleCommand command) {
context.authenticatedUser();
context.authenticatedUser();
RoleCommandValidator validator = new RoleCommandValidator(command);
validator.validateForUpdate();
RoleCommandValidator validator = new RoleCommandValidator(command);
validator.validateForUpdate();
Role role = this.roleRepository.findOne(command.getId());
if (role == null) { throw new RoleNotFoundException(command.getId()); }
role.update(command);
Role role = this.roleRepository.findOne(command.getId());
if (role == null) {
throw new RoleNotFoundException(command.getId());
}
role.update(command);
this.roleRepository.save(role);
if (this.makerCheckerEnabledForTask && !command.isApprovedByChecker()) { throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(); }
this.roleRepository.save(role);
return role.getId();
}
return role.getId();
}
@Transactional
@Override
public Long updateRolePermissions(final RolePermissionCommand command) {
context.authenticatedUser();
@Transactional
@Override
public Long updateRolePermissions(final RolePermissionCommand command) {
context.authenticatedUser();
final Role role = this.roleRepository.findOne(command.getRoleId());
if (role == null) { throw new RoleNotFoundException(command.getRoleId()); }
final Role role = this.roleRepository.findOne(command.getRoleId());
if (role == null) {
throw new RoleNotFoundException(command.getRoleId());
}
Collection<Permission> allPermissions = this.permissionRepository.findAll();
Collection<Permission> allPermissions = this.permissionRepository
.findAll();
Map<String, Boolean> commandPermissions = command.getPermissions();
for (String permissionCode : commandPermissions.keySet()) {
Boolean selected = commandPermissions.get(permissionCode);
Map<String, Boolean> commandPermissions = command.getPermissions();
for (String permissionCode : commandPermissions.keySet()) {
Boolean selected = commandPermissions.get(permissionCode);
final Permission permission = findPermissionByCode(allPermissions, permissionCode);
Permission permission = getPermissionByCode(allPermissions,
permissionCode);
if (role.getPermissions().contains(permission)) {
if (!(selected)) {
role.getPermissions().remove(permission);
}
} else {
if (selected) {
role.getPermissions().add(permission);
}
}
}
if (role.getPermissions().contains(permission)) {
if (!(selected)) {
role.getPermissions().remove(permission);
}
this.roleRepository.save(role);
} else {
if (selected) {
role.getPermissions().add(permission);
}
return role.getId();
}
}
}
private Permission findPermissionByCode(Collection<Permission> allPermissions, String permissionCode) {
this.roleRepository.save(role);
if (allPermissions != null) {
for (Permission permission : allPermissions) {
if (permission.hasCode(permissionCode)) {return permission;}
}
}
return role.getId();
}
private Permission getPermissionByCode(
Collection<Permission> allPermissions, String permissionCode) {
if (allPermissions != null) {
for (Permission permission : allPermissions) {
if (permission.code().equals(permissionCode)) return permission;
}
}
throw new PermissionNotFoundException(permissionCode);
}
throw new PermissionNotFoundException(permissionCode);
}
}