MIFOSX-237: use of jdbcTemplate and SqlRowSet along with refactoring as a result of these changes.
This commit is contained in:
+200
-189
@@ -16,209 +16,220 @@ import javax.xml.bind.annotation.XmlElementWrapper;
|
||||
*/
|
||||
public class ApiGlobalErrorResponse {
|
||||
|
||||
/**
|
||||
* A developer friendly plain English description of why the HTTP error response was returned from the API.
|
||||
*/
|
||||
private String developerMessage;
|
||||
|
||||
/**
|
||||
* A link to a URL which provides more information on the details of this type of error.
|
||||
*/
|
||||
private String developerDocLink;
|
||||
|
||||
/**
|
||||
* The HTTP status code of the response.
|
||||
*/
|
||||
private String httpStatusCode;
|
||||
|
||||
/**
|
||||
* A user friendly plain English description of why the HTTP error response was returned from the API that can be presented to end users.
|
||||
*/
|
||||
private String defaultUserMessage;
|
||||
|
||||
/**
|
||||
* A code that can be used for globalisation support by client applications of the API.
|
||||
*/
|
||||
private String userMessageGlobalisationCode;
|
||||
|
||||
/**
|
||||
* A list of zero or more of the actual reasons for the HTTP error should they be needed. Typically used to express data validation errors with parameters passed to API.
|
||||
*/
|
||||
private List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
/**
|
||||
* A developer friendly plain English description of why the HTTP error
|
||||
* response was returned from the API.
|
||||
*/
|
||||
private String developerMessage;
|
||||
|
||||
public static ApiGlobalErrorResponse unAuthenticated() {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("401");
|
||||
globalErrorResponse.setDeveloperMessage("Invalid authentication details were passed in api request.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authenticated");
|
||||
globalErrorResponse.setDefaultUserMessage("Unauthenticated. Please login.");
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse invalidTenantIdentifier() {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("401");
|
||||
globalErrorResponse.setDeveloperMessage("Invalid tenant details were passed in api request.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.invalid.tenant.identifier");
|
||||
globalErrorResponse.setDefaultUserMessage("Invalide tenant identifier provided with request.");
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
/**
|
||||
* A link to a URL which provides more information on the details of this
|
||||
* type of error.
|
||||
*/
|
||||
private String developerDocLink;
|
||||
|
||||
public static ApiGlobalErrorResponse unAuthorized() {
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("403");
|
||||
globalErrorResponse.setDeveloperMessage("The user associated with credentials passed on this request does not have sufficient privileges to perform this action.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authorized");
|
||||
globalErrorResponse.setDefaultUserMessage("Insufficient privileges to perform this action.");
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.generalError("error.msg.not.authorized", "Insufficient privileges to perform this action."));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse domainRuleViolation(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("403");
|
||||
globalErrorResponse.setDeveloperMessage("Request was understood but caused a domain rule violation.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("validation.msg.domain.rule.violation");
|
||||
globalErrorResponse.setDefaultUserMessage("Errors contain reason for domain rule violation.");
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.generalError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* The HTTP status code of the response.
|
||||
*/
|
||||
private String httpStatusCode;
|
||||
|
||||
public static ApiGlobalErrorResponse notFound(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("404");
|
||||
globalErrorResponse.setDeveloperMessage("The requested resource is not available.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.resource.not.found");
|
||||
globalErrorResponse.setDefaultUserMessage("The requested resource is not available.");
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.resourceIdentifierNotFound(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse dataIntegrityError(final String globalisationMessageCode, final String defaultUserMessage, final String parameterName, final Object... defaultUserMessageArgs) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("403");
|
||||
globalErrorResponse.setDeveloperMessage("The request caused a data integrity issue to be fired by the database.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
||||
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.parameterError(globalisationMessageCode, defaultUserMessage, parameterName, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse badClientRequest(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
List<ApiParameterError> errors) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("400");
|
||||
globalErrorResponse.setDeveloperMessage("The request was invalid. This typically will happen due to validation errors which are provided.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
||||
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
||||
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse serverSideError(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("500");
|
||||
globalErrorResponse.setDeveloperMessage("An unexpected error occured on the platform server.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.platform.server.side.error");
|
||||
globalErrorResponse.setDefaultUserMessage("An unexpected error occured on the platform server.");
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.generalError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
protected ApiGlobalErrorResponse() {
|
||||
//
|
||||
}
|
||||
/**
|
||||
* A user friendly plain English description of why the HTTP error response
|
||||
* was returned from the API that can be presented to end users.
|
||||
*/
|
||||
private String defaultUserMessage;
|
||||
|
||||
public ApiGlobalErrorResponse(final List<ApiParameterError> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
/**
|
||||
* A code that can be used for globalisation support by client applications
|
||||
* of the API.
|
||||
*/
|
||||
private String userMessageGlobalisationCode;
|
||||
|
||||
@XmlElementWrapper(name="errors")
|
||||
@XmlElement(name="errorResponse")
|
||||
public List<ApiParameterError> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
/**
|
||||
* A list of zero or more of the actual reasons for the HTTP error should
|
||||
* they be needed. Typically used to express data validation errors with
|
||||
* parameters passed to API.
|
||||
*/
|
||||
private List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
|
||||
public void setErrors(List<ApiParameterError> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
public static ApiGlobalErrorResponse unAuthenticated() {
|
||||
|
||||
public String getDeveloperMessage() {
|
||||
return developerMessage;
|
||||
}
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("401");
|
||||
globalErrorResponse.setDeveloperMessage("Invalid authentication details were passed in api request.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authenticated");
|
||||
globalErrorResponse.setDefaultUserMessage("Unauthenticated. Please login.");
|
||||
|
||||
public void setDeveloperMessage(String developerMessage) {
|
||||
this.developerMessage = developerMessage;
|
||||
}
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public String getHttpStatusCode() {
|
||||
return httpStatusCode;
|
||||
}
|
||||
public static ApiGlobalErrorResponse invalidTenantIdentifier() {
|
||||
|
||||
public void setHttpStatusCode(String httpStatusCode) {
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
}
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("401");
|
||||
globalErrorResponse.setDeveloperMessage("Invalid tenant details were passed in api request.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.invalid.tenant.identifier");
|
||||
globalErrorResponse.setDefaultUserMessage("Invalide tenant identifier provided with request.");
|
||||
|
||||
public String getDefaultUserMessage() {
|
||||
return defaultUserMessage;
|
||||
}
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public void setDefaultUserMessage(String defaultUserMessage) {
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
}
|
||||
public static ApiGlobalErrorResponse unAuthorized(final String defaultUserMessage) {
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("403");
|
||||
globalErrorResponse
|
||||
.setDeveloperMessage("The user associated with credentials passed on this request does not have sufficient privileges to perform this action.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authorized");
|
||||
globalErrorResponse.setDefaultUserMessage("Insufficient privileges to perform this action.");
|
||||
|
||||
public String getUserMessageGlobalisationCode() {
|
||||
return userMessageGlobalisationCode;
|
||||
}
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.generalError("error.msg.not.authorized", defaultUserMessage));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
public void setUserMessageGlobalisationCode(String userMessageGlobalisationCode) {
|
||||
this.userMessageGlobalisationCode = userMessageGlobalisationCode;
|
||||
}
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public String getDeveloperDocLink() {
|
||||
return developerDocLink;
|
||||
}
|
||||
public static ApiGlobalErrorResponse domainRuleViolation(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("403");
|
||||
globalErrorResponse.setDeveloperMessage("Request was understood but caused a domain rule violation.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("validation.msg.domain.rule.violation");
|
||||
globalErrorResponse.setDefaultUserMessage("Errors contain reason for domain rule violation.");
|
||||
|
||||
public void setDeveloperDocLink(String developerDocLink) {
|
||||
this.developerDocLink = developerDocLink;
|
||||
}
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.generalError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse notFound(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("404");
|
||||
globalErrorResponse.setDeveloperMessage("The requested resource is not available.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.resource.not.found");
|
||||
globalErrorResponse.setDefaultUserMessage("The requested resource is not available.");
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.resourceIdentifierNotFound(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse dataIntegrityError(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
final String parameterName, final Object... defaultUserMessageArgs) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("403");
|
||||
globalErrorResponse.setDeveloperMessage("The request caused a data integrity issue to be fired by the database.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
||||
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.parameterError(globalisationMessageCode, defaultUserMessage, parameterName, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse badClientRequest(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
final List<ApiParameterError> errors) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("400");
|
||||
globalErrorResponse
|
||||
.setDeveloperMessage("The request was invalid. This typically will happen due to validation errors which are provided.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
|
||||
globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
|
||||
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse serverSideError(final String globalisationMessageCode, final String defaultUserMessage,
|
||||
final Object... defaultUserMessageArgs) {
|
||||
|
||||
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode("500");
|
||||
globalErrorResponse.setDeveloperMessage("An unexpected error occured on the platform server.");
|
||||
globalErrorResponse.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.platform.server.side.error");
|
||||
globalErrorResponse.setDefaultUserMessage("An unexpected error occured on the platform server.");
|
||||
|
||||
List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
|
||||
errors.add(ApiParameterError.generalError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs));
|
||||
globalErrorResponse.setErrors(errors);
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
protected ApiGlobalErrorResponse() {
|
||||
//
|
||||
}
|
||||
|
||||
public ApiGlobalErrorResponse(final List<ApiParameterError> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
@XmlElementWrapper(name = "errors")
|
||||
@XmlElement(name = "errorResponse")
|
||||
public List<ApiParameterError> getErrors() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
public void setErrors(final List<ApiParameterError> errors) {
|
||||
this.errors = errors;
|
||||
}
|
||||
|
||||
public String getDeveloperMessage() {
|
||||
return developerMessage;
|
||||
}
|
||||
|
||||
public void setDeveloperMessage(final String developerMessage) {
|
||||
this.developerMessage = developerMessage;
|
||||
}
|
||||
|
||||
public String getHttpStatusCode() {
|
||||
return httpStatusCode;
|
||||
}
|
||||
|
||||
public void setHttpStatusCode(final String httpStatusCode) {
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
}
|
||||
|
||||
public String getDefaultUserMessage() {
|
||||
return defaultUserMessage;
|
||||
}
|
||||
|
||||
public void setDefaultUserMessage(final String defaultUserMessage) {
|
||||
this.defaultUserMessage = defaultUserMessage;
|
||||
}
|
||||
|
||||
public String getUserMessageGlobalisationCode() {
|
||||
return userMessageGlobalisationCode;
|
||||
}
|
||||
|
||||
public void setUserMessageGlobalisationCode(final String userMessageGlobalisationCode) {
|
||||
this.userMessageGlobalisationCode = userMessageGlobalisationCode;
|
||||
}
|
||||
|
||||
public String getDeveloperDocLink() {
|
||||
return developerDocLink;
|
||||
}
|
||||
|
||||
public void setDeveloperDocLink(final String developerDocLink) {
|
||||
this.developerDocLink = developerDocLink;
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -30,9 +30,11 @@ import org.springframework.stereotype.Component;
|
||||
public class AccessDeniedExceptionMapper implements ExceptionMapper<AccessDeniedException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(@SuppressWarnings("unused") AccessDeniedException exception) {
|
||||
public Response toResponse(final AccessDeniedException exception) {
|
||||
// Status code 403 really reads as:
|
||||
// "Authenticated - but not authorized":
|
||||
return Response.status(Status.FORBIDDEN).entity(ApiGlobalErrorResponse.unAuthorized()).type(MediaType.APPLICATION_JSON).build();
|
||||
final String defaultUserMessage = exception.getMessage();
|
||||
return Response.status(Status.FORBIDDEN).entity(ApiGlobalErrorResponse.unAuthorized(defaultUserMessage))
|
||||
.type(MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
}
|
||||
+4
-2
@@ -29,9 +29,11 @@ import org.springframework.stereotype.Component;
|
||||
public class NoAuthorizationExceptionMapper implements ExceptionMapper<NoAuthorizationException> {
|
||||
|
||||
@Override
|
||||
public Response toResponse(@SuppressWarnings("unused") NoAuthorizationException exception) {
|
||||
public Response toResponse(final NoAuthorizationException exception) {
|
||||
// Status code 403 really reads as:
|
||||
// "Authenticated - but not authorized":
|
||||
return Response.status(Status.FORBIDDEN).entity(ApiGlobalErrorResponse.unAuthorized()).type(MediaType.APPLICATION_JSON).build();
|
||||
final String defaultUserMessage = exception.getMessage();
|
||||
return Response.status(Status.FORBIDDEN).entity(ApiGlobalErrorResponse.unAuthorized(defaultUserMessage))
|
||||
.type(MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
}
|
||||
+3
@@ -386,6 +386,7 @@ public class JsonParserHelper {
|
||||
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);
|
||||
error.setValue(numericalValueFormatted);
|
||||
dataValidationErrors.add(error);
|
||||
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
@@ -408,6 +409,7 @@ public class JsonParserHelper {
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer", "The parameter " + parameterName
|
||||
+ " has value: " + numericalValueFormatted + " which is invalid integer.", parameterName, numericalValueFormatted);
|
||||
error.setValue(numericalValueFormatted);
|
||||
dataValidationErrors.add(error);
|
||||
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
@@ -458,6 +460,7 @@ public class JsonParserHelper {
|
||||
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);
|
||||
error.setValue(numericalValueFormatted);
|
||||
dataValidationErrors.add(error);
|
||||
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
|
||||
+5
-9
@@ -53,6 +53,7 @@ public class ReportsApiResource {
|
||||
this.genericDataService = genericDataService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
}
|
||||
|
||||
@GET
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON, "application/x-msdownload" })
|
||||
@@ -144,10 +145,10 @@ public class ReportsApiResource {
|
||||
} else {
|
||||
json = this.toApiJsonSerializer.serializePretty(prettyPrint, result);
|
||||
}
|
||||
|
||||
|
||||
return Response.ok().entity(json).type(MediaType.APPLICATION_JSON).build();
|
||||
}
|
||||
|
||||
|
||||
// CSV Export
|
||||
Map<String, String> reportParams = getReportParams(queryParams, false);
|
||||
StreamingOutput result = this.readExtraDataAndReportingService.retrieveReportCSV(reportName, parameterTypeValue, reportParams);
|
||||
@@ -160,15 +161,10 @@ public class ReportsApiResource {
|
||||
|
||||
// Anyone can run a 'report' that is simply getting possible parameter
|
||||
// (dropdown listbox) values.
|
||||
|
||||
if (!parameterType) {
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
if (currentUser.hasNotPermissionForReport(reportName)) {
|
||||
// FIXME - JW - message isnt passing back the message in the
|
||||
// string in
|
||||
// the json just a generalised not authorised message
|
||||
throw new NoAuthorizationException("Not Authorised to Run Report: " + reportName);
|
||||
}
|
||||
if (currentUser.hasNotPermissionForReport(reportName)) { throw new NoAuthorizationException("Not authorised to run report: "
|
||||
+ reportName); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -15,7 +15,11 @@ public class DatatableData {
|
||||
@SuppressWarnings("unused")
|
||||
private final String registeredTableName;
|
||||
|
||||
public DatatableData(final String applicationTableName, final String registeredTableName) {
|
||||
public static DatatableData create(final String applicationTableName, final String registeredTableName) {
|
||||
return new DatatableData(applicationTableName, registeredTableName);
|
||||
}
|
||||
|
||||
private DatatableData(final String applicationTableName, final String registeredTableName) {
|
||||
this.applicationTableName = applicationTableName;
|
||||
this.registeredTableName = registeredTableName;
|
||||
}
|
||||
|
||||
+5
-5
@@ -13,19 +13,19 @@ import java.util.List;
|
||||
*/
|
||||
public class GenericResultsetData {
|
||||
|
||||
private final List<ResultsetColumnHeader> columnHeaders;
|
||||
private final List<ResultsetDataRow> data;
|
||||
private final List<ResultsetColumnHeaderData> columnHeaders;
|
||||
private final List<ResultsetRowData> data;
|
||||
|
||||
public GenericResultsetData(final List<ResultsetColumnHeader> columnHeaders, final List<ResultsetDataRow> resultsetDataRows) {
|
||||
public GenericResultsetData(final List<ResultsetColumnHeaderData> columnHeaders, final List<ResultsetRowData> resultsetDataRows) {
|
||||
this.columnHeaders = columnHeaders;
|
||||
this.data = resultsetDataRows;
|
||||
}
|
||||
|
||||
public List<ResultsetColumnHeader> getColumnHeaders() {
|
||||
public List<ResultsetColumnHeaderData> getColumnHeaders() {
|
||||
return columnHeaders;
|
||||
}
|
||||
|
||||
public List<ResultsetDataRow> getData() {
|
||||
public List<ResultsetRowData> getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
-128
@@ -1,128 +0,0 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
|
||||
public class ResultsetColumnHeader {
|
||||
|
||||
private String columnName;
|
||||
private String columnType;
|
||||
private Long columnLength;
|
||||
private String columnDisplayType;
|
||||
private boolean isColumnNullable;
|
||||
private boolean isColumnPrimaryKey;
|
||||
private List<ResultsetColumnValue> columnValues = new ArrayList<ResultsetColumnValue>();
|
||||
|
||||
public ResultsetColumnHeader() {
|
||||
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
return columnName;
|
||||
}
|
||||
|
||||
public void setColumnName(String columnName) {
|
||||
this.columnName = columnName;
|
||||
}
|
||||
|
||||
public String getColumnType() {
|
||||
return columnType;
|
||||
}
|
||||
|
||||
public void setColumnType(String columnType) {
|
||||
this.columnType = columnType;
|
||||
}
|
||||
|
||||
public Long getColumnLength() {
|
||||
return columnLength;
|
||||
}
|
||||
|
||||
public void setColumnLength(Long columnLength) {
|
||||
this.columnLength = columnLength;
|
||||
}
|
||||
|
||||
public List<ResultsetColumnValue> getColumnValues() {
|
||||
return columnValues;
|
||||
}
|
||||
|
||||
public void setColumnValues(List<ResultsetColumnValue> columnValues) {
|
||||
this.columnValues = columnValues;
|
||||
}
|
||||
|
||||
public boolean isColumnNullable() {
|
||||
return isColumnNullable;
|
||||
}
|
||||
|
||||
public void setColumnNullable(boolean isColumnNullable) {
|
||||
this.isColumnNullable = isColumnNullable;
|
||||
}
|
||||
|
||||
public boolean isColumnPrimaryKey() {
|
||||
return isColumnPrimaryKey;
|
||||
}
|
||||
|
||||
public void setColumnPrimaryKey(boolean isColumnPrimaryKey) {
|
||||
this.isColumnPrimaryKey = isColumnPrimaryKey;
|
||||
}
|
||||
|
||||
public String getColumnDisplayType() {
|
||||
return columnDisplayType;
|
||||
}
|
||||
|
||||
public void setColumnDisplayType() {
|
||||
|
||||
if (this.getColumnValues().size() > 0) {
|
||||
|
||||
if (this.getColumnType().equalsIgnoreCase("int")) {
|
||||
this.columnDisplayType = "CODELOOKUP";
|
||||
return;
|
||||
}
|
||||
if (this.getColumnType().equalsIgnoreCase("varchar")) {
|
||||
this.columnDisplayType = "CODEVALUE";
|
||||
return;
|
||||
}
|
||||
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.lookup.type", "Invalid Lookup Type:" + this.getColumnType()
|
||||
+ " - Column Name: " + this.getColumnName());
|
||||
}
|
||||
|
||||
if (this.getColumnType().equalsIgnoreCase("varchar") || this.getColumnType().equalsIgnoreCase("char")) {
|
||||
this.columnDisplayType = "STRING";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.getColumnType().equalsIgnoreCase("int") || this.getColumnType().equalsIgnoreCase("bigint")
|
||||
|| this.getColumnType().equalsIgnoreCase("smallint") || this.getColumnType().equalsIgnoreCase("mediumint")
|
||||
|| this.getColumnType().equalsIgnoreCase("tinyint")) {
|
||||
this.columnDisplayType = "INTEGER";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.getColumnType().equalsIgnoreCase("date")) {
|
||||
this.columnDisplayType = "DATE";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.getColumnType().equalsIgnoreCase("decimal")) {
|
||||
this.columnDisplayType = "DECIMAL";
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.getColumnType().equalsIgnoreCase("text") || this.getColumnType().equalsIgnoreCase("mediumtext")
|
||||
|| this.getColumnType().equalsIgnoreCase("longtext") || this.getColumnType().equalsIgnoreCase("tinytext")) {
|
||||
this.columnDisplayType = "TEXT";
|
||||
return;
|
||||
}
|
||||
|
||||
throw new PlatformDataIntegrityException("error.msg.unsupported.column.type", "Unsupported Column Type:" + this.getColumnType()
|
||||
+ " - Column Name: " + this.getColumnName());
|
||||
}
|
||||
|
||||
}
|
||||
+218
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a resultset column.
|
||||
*/
|
||||
public final class ResultsetColumnHeaderData {
|
||||
|
||||
private final String columnName;
|
||||
private final String columnType;
|
||||
@SuppressWarnings("unused")
|
||||
private final Long columnLength;
|
||||
private final String columnDisplayType;
|
||||
private final boolean isColumnNullable;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean isColumnPrimaryKey;
|
||||
|
||||
private final List<ResultsetColumnValueData> columnValues;
|
||||
|
||||
public static ResultsetColumnHeaderData basic(final String columnName, final String columnType) {
|
||||
|
||||
final Long columnLength = null;
|
||||
final boolean columnNullable = false;
|
||||
final boolean columnIsPrimaryKey = false;
|
||||
final List<ResultsetColumnValueData> columnValues = new ArrayList<ResultsetColumnValueData>();
|
||||
return new ResultsetColumnHeaderData(columnName, columnType, columnLength, columnNullable, columnIsPrimaryKey, columnValues);
|
||||
}
|
||||
|
||||
public static ResultsetColumnHeaderData detailed(final String columnName, final String columnType, final Long columnLength,
|
||||
final boolean columnNullable, final boolean columnIsPrimaryKey, final List<ResultsetColumnValueData> columnValues) {
|
||||
return new ResultsetColumnHeaderData(columnName, columnType, columnLength, columnNullable, columnIsPrimaryKey, columnValues);
|
||||
}
|
||||
|
||||
private ResultsetColumnHeaderData(final String columnName, final String columnType, final Long columnLength,
|
||||
final boolean columnNullable, final boolean columnIsPrimaryKey, final List<ResultsetColumnValueData> columnValues) {
|
||||
this.columnName = columnName;
|
||||
this.columnType = columnType;
|
||||
this.columnLength = columnLength;
|
||||
this.isColumnNullable = columnNullable;
|
||||
this.isColumnPrimaryKey = columnIsPrimaryKey;
|
||||
this.columnValues = columnValues;
|
||||
|
||||
String displayType = null;
|
||||
if (this.columnValues.isEmpty()) {
|
||||
if (isString()) {
|
||||
displayType = "STRING";
|
||||
} else if (isAnyInteger()) {
|
||||
displayType = "INTEGER";
|
||||
} else if (isDate()) {
|
||||
displayType = "DATE";
|
||||
} else if (isDecimal()) {
|
||||
displayType = "DECIMAL";
|
||||
} else if (isAnyText()) {
|
||||
displayType = "TEXT";
|
||||
} else {
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.lookup.type", "Invalid Lookup Type:" + this.columnType
|
||||
+ " - Column Name: " + this.columnName);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (isInt()) {
|
||||
displayType = "CODELOOKUP";
|
||||
} else if (isVarchar()) {
|
||||
displayType = "CODEVALUE";
|
||||
} else {
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.lookup.type", "Invalid Lookup Type:" + this.columnType
|
||||
+ " - Column Name: " + this.columnName);
|
||||
}
|
||||
}
|
||||
|
||||
this.columnDisplayType = displayType;
|
||||
}
|
||||
|
||||
private boolean isAnyText() {
|
||||
return isText() || isTinyText() || isMediumText() || isLongText();
|
||||
}
|
||||
|
||||
private boolean isText() {
|
||||
return "text".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isTinyText() {
|
||||
return "tinytext".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isMediumText() {
|
||||
return "mediumtext".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isLongText() {
|
||||
return "longtext".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isDecimal() {
|
||||
return "decimal".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isDate() {
|
||||
return "date".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isString() {
|
||||
return isVarchar() || isChar();
|
||||
}
|
||||
|
||||
private boolean isChar() {
|
||||
return "char".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isVarchar() {
|
||||
return "varchar".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isAnyInteger() {
|
||||
return isInt() || isSmallInt() || isTinyInt() || isMediumInt() || isBigInt();
|
||||
}
|
||||
|
||||
private boolean isInt() {
|
||||
return "int".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isSmallInt() {
|
||||
return "smallint".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isTinyInt() {
|
||||
return "tinyint".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isMediumInt() {
|
||||
return "mediumint".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
private boolean isBigInt() {
|
||||
return "bigint".equalsIgnoreCase(this.columnType);
|
||||
}
|
||||
|
||||
public String getColumnName() {
|
||||
return this.columnName;
|
||||
}
|
||||
|
||||
public String getColumnType() {
|
||||
return this.columnType;
|
||||
}
|
||||
|
||||
public String getColumnDisplayType() {
|
||||
return this.columnDisplayType;
|
||||
}
|
||||
|
||||
public boolean isDateDisplayType() {
|
||||
return "DATE".equalsIgnoreCase(this.columnDisplayType);
|
||||
}
|
||||
|
||||
public boolean isIntegerDisplayType() {
|
||||
return "INTEGER".equalsIgnoreCase(this.columnDisplayType);
|
||||
}
|
||||
|
||||
public boolean isDecimalDisplayType() {
|
||||
return "DECIMAL".equalsIgnoreCase(this.columnDisplayType);
|
||||
}
|
||||
|
||||
public boolean isCodeValueDisplayType() {
|
||||
return "CODEVALUE".equalsIgnoreCase(this.columnDisplayType);
|
||||
}
|
||||
|
||||
public boolean isCodeLookupDisplayType() {
|
||||
return "CODELOOKUP".equalsIgnoreCase(this.columnDisplayType);
|
||||
}
|
||||
|
||||
public boolean isMandatory() {
|
||||
return !isOptional();
|
||||
}
|
||||
|
||||
public boolean isOptional() {
|
||||
return this.isColumnNullable;
|
||||
}
|
||||
|
||||
public boolean hasColumnValues() {
|
||||
return !this.columnValues.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isColumnValueAllowed(final String match) {
|
||||
boolean allowed = false;
|
||||
for (ResultsetColumnValueData allowedValue : this.columnValues) {
|
||||
if (allowedValue.matches(match)) {
|
||||
allowed = true;
|
||||
}
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
|
||||
public boolean isColumnValueNotAllowed(final String match) {
|
||||
return !isColumnValueAllowed(match);
|
||||
}
|
||||
|
||||
public boolean isColumnCodeNotAllowed(final Integer match) {
|
||||
return !isColumnCodeAllowed(match);
|
||||
}
|
||||
|
||||
public boolean isColumnCodeAllowed(final Integer match) {
|
||||
boolean allowed = false;
|
||||
for (ResultsetColumnValueData allowedValue : this.columnValues) {
|
||||
if (allowedValue.codeMatches(match)) {
|
||||
allowed = true;
|
||||
}
|
||||
}
|
||||
return allowed;
|
||||
}
|
||||
}
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.data;
|
||||
|
||||
public class ResultsetColumnValue {
|
||||
|
||||
private int id;
|
||||
private String value;
|
||||
|
||||
public ResultsetColumnValue(int id, String value) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.data;
|
||||
|
||||
/**
|
||||
* Immutable data object representing a possible value for a given resultset
|
||||
* column.
|
||||
*/
|
||||
public class ResultsetColumnValueData {
|
||||
|
||||
private final int id;
|
||||
private final String value;
|
||||
|
||||
public ResultsetColumnValueData(final int id, final String value) {
|
||||
this.id = id;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean matches(final String match) {
|
||||
return match.equalsIgnoreCase(this.value);
|
||||
}
|
||||
|
||||
public boolean codeMatches(final Integer match) {
|
||||
return match.intValue() == this.id;
|
||||
}
|
||||
}
|
||||
+7
-8
@@ -5,22 +5,21 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ResultsetDataRow {
|
||||
public class ResultsetRowData {
|
||||
|
||||
private List<String> row = new ArrayList<String>();
|
||||
private final List<String> row;
|
||||
|
||||
public ResultsetDataRow() {
|
||||
public static ResultsetRowData create(final List<String> rowValues) {
|
||||
return new ResultsetRowData(rowValues);
|
||||
}
|
||||
|
||||
private ResultsetRowData(final List<String> rowValues) {
|
||||
this.row = rowValues;
|
||||
}
|
||||
|
||||
public List<String> getRow() {
|
||||
return row;
|
||||
}
|
||||
|
||||
public void setRow(List<String> row) {
|
||||
this.row = row;
|
||||
}
|
||||
}
|
||||
+3
-5
@@ -5,16 +5,13 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.service;
|
||||
|
||||
import javax.sql.rowset.CachedRowSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
|
||||
|
||||
public interface GenericDataService {
|
||||
|
||||
CachedRowSet getCachedResultSet(String sql, String errorMsg);
|
||||
|
||||
void updateSQL(String sql, String sqlErrorMsg);
|
||||
|
||||
GenericResultsetData fillGenericResultSet(final String sql);
|
||||
|
||||
String generateJsonFromGenericResultsetData(GenericResultsetData grs);
|
||||
@@ -25,4 +22,5 @@ public interface GenericDataService {
|
||||
|
||||
String getDatabaseName();
|
||||
|
||||
List<ResultsetColumnHeaderData> fillResultsetColumnHeaders(String datatable);
|
||||
}
|
||||
+113
-116
@@ -5,128 +5,70 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.dataqueries.service;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import javax.sql.rowset.CachedRowSet;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnValueData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetRowData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.exception.DataTableNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.sun.rowset.CachedRowSetImpl;
|
||||
|
||||
//TODO - JW - Performance Item - most items (code values etc) can be cached but not doing that yet
|
||||
@Service
|
||||
public class GenericDataServiceImpl implements GenericDataService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final DataSource dataSource;
|
||||
|
||||
@Autowired
|
||||
public GenericDataServiceImpl(final TenantAwareRoutingDataSource dataSource) {
|
||||
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CachedRowSet getCachedResultSet(final String sql, final String sqlErrorMsg) {
|
||||
// FIXME - KW - Need to reimplement this away from Sun library - could
|
||||
// be mixture of Lists and jdbcTemplate.query
|
||||
|
||||
// long startTime = System.currentTimeMillis();
|
||||
Connection db_connection = null;
|
||||
Statement db_statement = null;
|
||||
CachedRowSet crs = null;
|
||||
try {
|
||||
db_connection = dataSource.getConnection();
|
||||
db_statement = db_connection.createStatement();
|
||||
ResultSet rs = db_statement.executeQuery(sql);
|
||||
crs = new CachedRowSetImpl();
|
||||
|
||||
crs.populate(rs);
|
||||
// logger.info("RS Size: " + crs.size() +
|
||||
// " getCachedResultSet sql: " + sql);
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
|
||||
} finally {
|
||||
dbClose(db_statement, db_connection);
|
||||
|
||||
}
|
||||
|
||||
// long elapsed = System.currentTimeMillis() - startTime;
|
||||
// logger.info("Elapsed Time: " + elapsed + " SQL: " + sql);
|
||||
return crs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSQL(final String sql, final String sqlErrorMsg) {
|
||||
|
||||
// long startTime = System.currentTimeMillis();
|
||||
Connection db_connection = null;
|
||||
Statement db_statement = null;
|
||||
try {
|
||||
db_connection = dataSource.getConnection();
|
||||
db_statement = db_connection.createStatement();
|
||||
db_statement.executeUpdate(sql);
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
|
||||
} finally {
|
||||
dbClose(db_statement, db_connection);
|
||||
}
|
||||
|
||||
// long elapsed = System.currentTimeMillis() - startTime;
|
||||
// logger.info("Elapsed Time: " + elapsed + " SQL: " + sql);
|
||||
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericResultsetData fillGenericResultSet(final String sql) {
|
||||
|
||||
String sqlErrorMsg = "Sql: " + sql;
|
||||
CachedRowSet rs = getCachedResultSet(sql, sqlErrorMsg);
|
||||
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
|
||||
|
||||
List<ResultsetColumnHeader> columnHeaders = new ArrayList<ResultsetColumnHeader>();
|
||||
List<ResultsetDataRow> resultsetDataRows = new ArrayList<ResultsetDataRow>();
|
||||
final List<ResultsetColumnHeaderData> columnHeaders = new ArrayList<ResultsetColumnHeaderData>();
|
||||
final List<ResultsetRowData> resultsetDataRows = new ArrayList<ResultsetRowData>();
|
||||
|
||||
try {
|
||||
final SqlRowSetMetaData rsmd = rs.getMetaData();
|
||||
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
String columnName = null;
|
||||
String columnValue = null;
|
||||
for (int i = 0; i < rsmd.getColumnCount(); i++) {
|
||||
ResultsetColumnHeader rsch = new ResultsetColumnHeader();
|
||||
rsch.setColumnName(rsmd.getColumnName(i + 1));
|
||||
rsch.setColumnType(rsmd.getColumnTypeName(i + 1));
|
||||
columnHeaders.add(rsch);
|
||||
}
|
||||
for (int i = 0; i < rsmd.getColumnCount(); i++) {
|
||||
|
||||
ResultsetDataRow resultsetDataRow;
|
||||
while (rs.next()) {
|
||||
resultsetDataRow = new ResultsetDataRow();
|
||||
List<String> columnValues = new ArrayList<String>();
|
||||
for (int i = 0; i < rsmd.getColumnCount(); i++) {
|
||||
columnName = rsmd.getColumnName(i + 1);
|
||||
columnValue = rs.getString(columnName);
|
||||
columnValues.add(columnValue);
|
||||
}
|
||||
resultsetDataRow.setRow(columnValues);
|
||||
resultsetDataRows.add(resultsetDataRow);
|
||||
}
|
||||
final String columnName = rsmd.getColumnName(i + 1);
|
||||
final String columnType = rsmd.getColumnTypeName(i + 1);
|
||||
|
||||
return new GenericResultsetData(columnHeaders, resultsetDataRows);
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
|
||||
final ResultsetColumnHeaderData columnHeader = ResultsetColumnHeaderData.basic(columnName, columnType);
|
||||
columnHeaders.add(columnHeader);
|
||||
}
|
||||
|
||||
while (rs.next()) {
|
||||
final List<String> columnValues = new ArrayList<String>();
|
||||
for (int i = 0; i < rsmd.getColumnCount(); i++) {
|
||||
final String columnName = rsmd.getColumnName(i + 1);
|
||||
final String columnValue = rs.getString(columnName);
|
||||
columnValues.add(columnValue);
|
||||
}
|
||||
|
||||
final ResultsetRowData resultsetDataRow = ResultsetRowData.create(columnValues);
|
||||
resultsetDataRows.add(resultsetDataRow);
|
||||
}
|
||||
|
||||
return new GenericResultsetData(columnHeaders, resultsetDataRows);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -165,17 +107,16 @@ public class GenericDataServiceImpl implements GenericDataService {
|
||||
|
||||
writer.append("[");
|
||||
|
||||
List<ResultsetColumnHeader> columnHeaders = grs.getColumnHeaders();
|
||||
// logger.info("NO. of Columns: " + columnHeaders.size());
|
||||
final List<ResultsetColumnHeaderData> columnHeaders = grs.getColumnHeaders();
|
||||
|
||||
List<ResultsetDataRow> data = grs.getData();
|
||||
List<ResultsetRowData> data = grs.getData();
|
||||
List<String> row;
|
||||
Integer rSize;
|
||||
String doubleQuote = "\"";
|
||||
String slashDoubleQuote = "\\\"";
|
||||
String currColType;
|
||||
String currVal;
|
||||
// logger.info("NO. of Rows: " + data.size());
|
||||
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
writer.append("\n{");
|
||||
|
||||
@@ -205,8 +146,8 @@ public class GenericDataServiceImpl implements GenericDataService {
|
||||
writer.append("[" + localDate.getYear() + ", " + localDate.getMonthOfYear() + ", " + localDate.getDayOfMonth()
|
||||
+ "]");
|
||||
} else {
|
||||
|
||||
writer.append(doubleQuote + replace(currVal, doubleQuote,slashDoubleQuote) + doubleQuote);
|
||||
|
||||
writer.append(doubleQuote + replace(currVal, doubleQuote, slashDoubleQuote) + doubleQuote);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -217,8 +158,7 @@ public class GenericDataServiceImpl implements GenericDataService {
|
||||
|
||||
if (i < (data.size() - 1)) {
|
||||
writer.append("},");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
writer.append("}");
|
||||
}
|
||||
}
|
||||
@@ -227,24 +167,6 @@ public class GenericDataServiceImpl implements GenericDataService {
|
||||
return writer.toString();
|
||||
|
||||
}
|
||||
|
||||
private void dbClose(Statement db_statement, Connection db_connection) {
|
||||
// logger.debug("dbClose");
|
||||
try {
|
||||
if (db_statement != null) {
|
||||
db_statement.close();
|
||||
// parameter assignment in this case is ok.
|
||||
db_statement = null;
|
||||
}
|
||||
if (db_connection != null) {
|
||||
db_connection.close();
|
||||
// parameter assignment in this case is ok.
|
||||
db_connection = null;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), "Error closing database connection");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDatabaseName() {
|
||||
@@ -254,4 +176,79 @@ public class GenericDataServiceImpl implements GenericDataService {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), "Error Accessing Database Name");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ResultsetColumnHeaderData> fillResultsetColumnHeaders(final String datatable) {
|
||||
|
||||
final SqlRowSet columnDefinitions = getDatatableMetaData(datatable);
|
||||
|
||||
final List<ResultsetColumnHeaderData> columnHeaders = new ArrayList<ResultsetColumnHeaderData>();
|
||||
|
||||
columnDefinitions.beforeFirst();
|
||||
while (columnDefinitions.next()) {
|
||||
final String columnName = columnDefinitions.getString("COLUMN_NAME");
|
||||
final String isNullable = columnDefinitions.getString("IS_NULLABLE");
|
||||
final String isPrimaryKey = columnDefinitions.getString("COLUMN_KEY");
|
||||
final String columnType = columnDefinitions.getString("DATA_TYPE");
|
||||
final Long columnLength = columnDefinitions.getLong("CHARACTER_MAXIMUM_LENGTH");
|
||||
|
||||
boolean columnNullable = "YES".equalsIgnoreCase(isNullable);
|
||||
boolean columnIsPrimaryKey = "PRI".equalsIgnoreCase(isPrimaryKey);
|
||||
|
||||
List<ResultsetColumnValueData> columnValues = new ArrayList<ResultsetColumnValueData>();
|
||||
if ("varchar".equalsIgnoreCase(columnType)) {
|
||||
columnValues = retreiveColumnValues(columnName, "_cv");
|
||||
} else if ("int".equalsIgnoreCase(columnType)) {
|
||||
columnValues = retreiveColumnValues(columnName, "_cd");
|
||||
}
|
||||
|
||||
final ResultsetColumnHeaderData rsch = ResultsetColumnHeaderData.detailed(columnName, columnType, columnLength, columnNullable,
|
||||
columnIsPrimaryKey, columnValues);
|
||||
|
||||
columnHeaders.add(rsch);
|
||||
}
|
||||
|
||||
return columnHeaders;
|
||||
}
|
||||
|
||||
/*
|
||||
* Candidate for using caching there to get allowed 'column values' from
|
||||
* code/codevalue tables
|
||||
*/
|
||||
private List<ResultsetColumnValueData> retreiveColumnValues(final String columnName, final String code_suffix) {
|
||||
|
||||
final List<ResultsetColumnValueData> columnValues = new ArrayList<ResultsetColumnValueData>();
|
||||
|
||||
int codePosition = columnName.indexOf(code_suffix);
|
||||
if (codePosition > 0) {
|
||||
final String codeName = columnName.substring(0, codePosition);
|
||||
|
||||
final String sql = "select v.id, v.code_value from m_code m " + " join m_code_value v on v.code_id = m.id "
|
||||
+ " where m.code_name = '" + codeName + "' order by v.order_position, v.id";
|
||||
|
||||
final SqlRowSet rsValues = this.jdbcTemplate.queryForRowSet(sql);
|
||||
|
||||
rsValues.beforeFirst();
|
||||
while (rsValues.next()) {
|
||||
final Integer id = rsValues.getInt("id");
|
||||
final String codeValue = rsValues.getString("code_value");
|
||||
|
||||
columnValues.add(new ResultsetColumnValueData(id, codeValue));
|
||||
}
|
||||
}
|
||||
|
||||
return columnValues;
|
||||
}
|
||||
|
||||
private SqlRowSet getDatatableMetaData(final String datatable) {
|
||||
|
||||
final String sql = "select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMN_KEY"
|
||||
+ " from INFORMATION_SCHEMA.COLUMNS " + " where TABLE_SCHEMA = schema() and TABLE_NAME = '" + datatable
|
||||
+ "'order by ORDINAL_POSITION";
|
||||
|
||||
final SqlRowSet columnDefinitions = this.jdbcTemplate.queryForRowSet(sql);
|
||||
if (columnDefinitions.next()) { return columnDefinitions; }
|
||||
|
||||
throw new DataTableNotFoundException(datatable);
|
||||
}
|
||||
}
|
||||
+373
-467
@@ -13,13 +13,11 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.sql.Date;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import javax.sql.rowset.CachedRowSet;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.StreamingOutput;
|
||||
|
||||
@@ -28,8 +26,8 @@ import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityExce
|
||||
import org.mifosplatform.infrastructure.core.service.FileUtils;
|
||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetRowData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.exception.ReportNotFoundException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
@@ -49,6 +47,8 @@ import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.lowagie.text.Document;
|
||||
@@ -59,467 +59,373 @@ import com.lowagie.text.pdf.PdfWriter;
|
||||
@Service
|
||||
public class ReadReportingServiceImpl implements ReadReportingService {
|
||||
|
||||
private final DataSource dataSource;
|
||||
private final PlatformSecurityContext context;
|
||||
|
||||
private final static Logger logger = LoggerFactory
|
||||
.getLogger(ReadReportingServiceImpl.class);
|
||||
|
||||
private Boolean noPentaho = false;
|
||||
|
||||
@Autowired
|
||||
public ReadReportingServiceImpl(final PlatformSecurityContext context,
|
||||
final TenantAwareRoutingDataSource dataSource) {
|
||||
// kick off pentaho reports server
|
||||
ClassicEngineBoot.getInstance().start();
|
||||
noPentaho = false;
|
||||
|
||||
this.context = context;
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private GenericDataService genericDataService;
|
||||
|
||||
@Override
|
||||
public StreamingOutput retrieveReportCSV(final String name,
|
||||
final String type, final Map<String, String> queryParams) {
|
||||
|
||||
return new StreamingOutput() {
|
||||
|
||||
@Override
|
||||
public void write(final OutputStream out) {
|
||||
try {
|
||||
|
||||
GenericResultsetData result = retrieveGenericResultset(
|
||||
name, type, queryParams);
|
||||
StringBuffer sb = generateCsvFileBuffer(result);
|
||||
|
||||
InputStream in = new ByteArrayInputStream(sb.toString()
|
||||
.getBytes("UTF-8"));
|
||||
|
||||
byte[] outputByte = new byte[4096];
|
||||
Integer readLen = in.read(outputByte, 0, 4096);
|
||||
|
||||
while (readLen != -1) {
|
||||
out.write(outputByte, 0, readLen);
|
||||
readLen = in.read(outputByte, 0, 4096);
|
||||
}
|
||||
// in.close();
|
||||
// out.flush();
|
||||
// out.close();
|
||||
} catch (Exception e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.exception.error", e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private StringBuffer generateCsvFileBuffer(final GenericResultsetData result) {
|
||||
StringBuffer writer = new StringBuffer();
|
||||
|
||||
List<ResultsetColumnHeader> columnHeaders = result.getColumnHeaders();
|
||||
logger.info("NO. of Columns: " + columnHeaders.size());
|
||||
Integer chSize = columnHeaders.size();
|
||||
for (int i = 0; i < chSize; i++) {
|
||||
writer.append('"' + columnHeaders.get(i).getColumnName() + '"');
|
||||
if (i < (chSize - 1))
|
||||
writer.append(",");
|
||||
}
|
||||
writer.append('\n');
|
||||
|
||||
List<ResultsetDataRow> data = result.getData();
|
||||
List<String> row;
|
||||
Integer rSize;
|
||||
// String currCol;
|
||||
String currColType;
|
||||
String currVal;
|
||||
String doubleQuote = "\"";
|
||||
String twoDoubleQuotes = doubleQuote + doubleQuote;
|
||||
logger.info("NO. of Rows: " + data.size());
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
row = data.get(i).getRow();
|
||||
rSize = row.size();
|
||||
for (int j = 0; j < rSize; j++) {
|
||||
// currCol = columnHeaders.get(j).getColumnName();
|
||||
currColType = columnHeaders.get(j).getColumnType();
|
||||
currVal = row.get(j);
|
||||
if (currVal != null) {
|
||||
if (currColType.equals("DECIMAL")
|
||||
|| currColType.equals("DOUBLE")
|
||||
|| currColType.equals("BIGINT")
|
||||
|| currColType.equals("SMALLINT")
|
||||
|| currColType.equals("INT"))
|
||||
writer.append(currVal);
|
||||
else
|
||||
writer.append('"' + genericDataService.replace(currVal,
|
||||
doubleQuote, twoDoubleQuotes) + '"');
|
||||
|
||||
}
|
||||
if (j < (rSize - 1))
|
||||
writer.append(",");
|
||||
}
|
||||
writer.append('\n');
|
||||
}
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericResultsetData retrieveGenericResultset(final String name,
|
||||
final String type, final Map<String, String> queryParams) {
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
logger.info("STARTING REPORT: " + name + " Type: " + type);
|
||||
|
||||
String sql;
|
||||
if (name.equals(".")) {
|
||||
// this is to support api /reports - which isn't an important
|
||||
// call. It isn't used in the default reporting UI. But there is a
|
||||
// need to provide an api that does bring back 'permitted' reports
|
||||
// PERMITTED REPORTS SQL
|
||||
sql = "select r.report_id, r.report_name, r.report_type, r.report_subtype, r.report_category,"
|
||||
+ " rp.parameter_id, rp.report_parameter_name, p.parameter_name"
|
||||
+ " from stretchy_report r"
|
||||
+ " left join stretchy_report_parameter rp on rp.report_id = r.report_id"
|
||||
+ " left join stretchy_parameter p on p.parameter_id = rp.parameter_id"
|
||||
+ " where exists"
|
||||
+ " (select 'f'"
|
||||
+ " from m_appuser_role ur "
|
||||
+ " join m_role r on r.id = ur.role_id"
|
||||
+ " left join m_role_permission rp on rp.role_id = r.id"
|
||||
+ " left join m_permission p on p.id = rp.permission_id"
|
||||
+ " where ur.appuser_id = "
|
||||
+ context.authenticatedUser().getId()
|
||||
+ " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', r.report_name))) "
|
||||
+ " order by r.report_name, rp.parameter_id";
|
||||
} else {
|
||||
sql = getSQLtoRun(name, type, queryParams);
|
||||
}
|
||||
|
||||
GenericResultsetData result = genericDataService
|
||||
.fillGenericResultSet(sql);
|
||||
|
||||
long elapsed = System.currentTimeMillis() - startTime;
|
||||
logger.info("FINISHING Report/Request Name: " + name + " - " + type
|
||||
+ " Elapsed Time: " + elapsed);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getSQLtoRun(final String name, final String type,
|
||||
final Map<String, String> queryParams) {
|
||||
|
||||
String sql = getSql(name, type);
|
||||
|
||||
Set<String> keys = queryParams.keySet();
|
||||
for (String key : keys) {
|
||||
String pValue = queryParams.get(key);
|
||||
// logger.info("(" + key + " : " + pValue + ")");
|
||||
sql = genericDataService.replace(sql, key, pValue);
|
||||
}
|
||||
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
// Allows sql query to restrict data by office hierarchy if required
|
||||
sql = genericDataService.replace(sql, "${currentUserHierarchy}",
|
||||
currentUser.getOffice().getHierarchy());
|
||||
// Allows sql query to restrict data by current user Id if required
|
||||
// (typically used to return report lists containing only reports
|
||||
// permitted to be run by the user
|
||||
sql = genericDataService.replace(sql, "${currentUserId}", currentUser
|
||||
.getId().toString());
|
||||
|
||||
sql = genericDataService.wrapSQL(sql);
|
||||
|
||||
return sql;
|
||||
|
||||
}
|
||||
|
||||
private String getSql(final String name, final String type) {
|
||||
|
||||
String inputSql = "select " + type + "_sql as the_sql from stretchy_"
|
||||
+ type + " where " + type + "_name = '" + name + "'";
|
||||
inputSql = genericDataService.wrapSQL(inputSql);
|
||||
|
||||
String sqlErrorMsg = "Sql: " + inputSql;
|
||||
CachedRowSet rs = genericDataService.getCachedResultSet(inputSql,
|
||||
sqlErrorMsg);
|
||||
|
||||
try {
|
||||
if (rs.next()) {
|
||||
return rs.getString("the_sql");
|
||||
}
|
||||
throw new ReportNotFoundException(inputSql);
|
||||
|
||||
} catch (SQLException e) {
|
||||
logger.info("msg: " + e.getMessage() + " sql: " + inputSql);
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error",
|
||||
e.getMessage(), sqlErrorMsg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReportType(final String reportName) {
|
||||
String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '"
|
||||
+ reportName + "'";
|
||||
|
||||
sql = genericDataService.wrapSQL(sql);
|
||||
|
||||
String sqlErrorMsg = "Report Name: " + reportName + " Sql: " + sql;
|
||||
CachedRowSet rs = genericDataService.getCachedResultSet(sql,
|
||||
sqlErrorMsg);
|
||||
|
||||
try {
|
||||
|
||||
if (rs.next()) {
|
||||
return rs.getString("report_type");
|
||||
}
|
||||
throw new ReportNotFoundException(sql);
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error",
|
||||
e.getMessage(), sqlErrorMsg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response processPentahoRequest(final String reportName,
|
||||
final String outputTypeParam, final Map<String, String> queryParams) {
|
||||
|
||||
String outputType = "HTML";
|
||||
if (StringUtils.isNotBlank(outputTypeParam))
|
||||
outputType = outputTypeParam;
|
||||
|
||||
if (!(outputType.equalsIgnoreCase("HTML")
|
||||
|| outputType.equalsIgnoreCase("PDF")
|
||||
|| outputType.equalsIgnoreCase("XLS") || outputType
|
||||
.equalsIgnoreCase("CSV")))
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.invalid.outputType", "No matching Output Type: "
|
||||
+ outputType);
|
||||
|
||||
if (noPentaho)
|
||||
throw new PlatformDataIntegrityException("error.msg.no.pentaho",
|
||||
"Pentaho is not enabled", "Pentaho is not enabled");
|
||||
|
||||
// TODO - JW - use pentaho location finder like Pawel does in Mifos
|
||||
// String reportPath =
|
||||
// "C:\\dev\\apache-tomcat-7.0.25\\webapps\\ROOT\\PentahoReports\\"
|
||||
// + reportName + ".prpt";
|
||||
/*String reportPath = FileUtils.MIFOSX_BASE_DIR
|
||||
+ File.separator
|
||||
+ ThreadLocalContextUtil.getTenant().getName()
|
||||
.replaceAll(" ", "").trim() + File.separator
|
||||
+ "reports" + File.separator + reportName + ".prpt";*/
|
||||
String reportPath = FileUtils.MIFOSX_BASE_DIR
|
||||
+ File.separator
|
||||
+ "reports" + File.separator + reportName + ".prpt";
|
||||
logger.info("Report path: " + reportPath);
|
||||
|
||||
// load report definition
|
||||
ResourceManager manager = new ResourceManager();
|
||||
manager.registerDefaults();
|
||||
Resource res;
|
||||
|
||||
try {
|
||||
res = manager.createDirectly(reportPath, MasterReport.class);
|
||||
MasterReport masterReport = (MasterReport) res.getResource();
|
||||
|
||||
addParametersToReport(masterReport, queryParams);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
if ("PDF".equalsIgnoreCase(outputType)) {
|
||||
PdfReportUtil.createPDF(masterReport, baos);
|
||||
return Response.ok().entity(baos.toByteArray())
|
||||
.type("application/pdf").build();
|
||||
}
|
||||
|
||||
if ("XLS".equalsIgnoreCase(outputType)) {
|
||||
ExcelReportUtil.createXLS(masterReport, baos);
|
||||
return Response
|
||||
.ok()
|
||||
.entity(baos.toByteArray())
|
||||
.type("application/vnd.ms-excel")
|
||||
.header("Content-Disposition",
|
||||
"attachment;filename="
|
||||
+ reportName.replaceAll(" ", "")
|
||||
+ ".xls").build();
|
||||
}
|
||||
|
||||
if ("CSV".equalsIgnoreCase(outputType)) {
|
||||
CSVReportUtil.createCSV(masterReport, baos, "UTF-8");
|
||||
return Response
|
||||
.ok()
|
||||
.entity(baos.toByteArray())
|
||||
.type("application/x-msdownload")
|
||||
.header("Content-Disposition",
|
||||
"attachment;filename="
|
||||
+ reportName.replaceAll(" ", "")
|
||||
+ ".csv").build();
|
||||
}
|
||||
|
||||
if ("HTML".equalsIgnoreCase(outputType)) {
|
||||
HtmlReportUtil.createStreamHTML(masterReport, baos);
|
||||
return Response.ok().entity(baos.toByteArray())
|
||||
.type("text/html").build();
|
||||
}
|
||||
} catch (ResourceException e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.reporting.error", e.getMessage());
|
||||
} catch (ReportProcessingException e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.reporting.error", e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.reporting.error", e.getMessage());
|
||||
}
|
||||
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.invalid.outputType", "No matching Output Type: "
|
||||
+ outputType);
|
||||
|
||||
}
|
||||
|
||||
private void addParametersToReport(final MasterReport report,
|
||||
final Map<String, String> queryParams) {
|
||||
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
try {
|
||||
|
||||
logger.info("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
||||
ReportParameterValues rptParamValues = report.getParameterValues();
|
||||
ReportParameterDefinition paramsDefinition = report
|
||||
.getParameterDefinition();
|
||||
|
||||
/*
|
||||
* only allow integer, long, date and string parameter types and
|
||||
* assume all mandatory - could go more detailed like Pawel did in
|
||||
* Mifos later and could match incoming and pentaho parameters
|
||||
* better... currently assuming they come in ok... and if not an
|
||||
* error
|
||||
*/
|
||||
for (ParameterDefinitionEntry paramDefEntry : paramsDefinition
|
||||
.getParameterDefinitions()) {
|
||||
String paramName = paramDefEntry.getName();
|
||||
if (!((paramName.equals("tenantdb")) || (paramName.equals("userhierarchy")))) {
|
||||
logger.info("paramName:" + paramName);
|
||||
String pValue = queryParams.get(paramName);
|
||||
if (StringUtils.isBlank(pValue))
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.reporting.error",
|
||||
"Pentaho Parameter: " + paramName
|
||||
+ " - not Provided");
|
||||
|
||||
Class<?> clazz = paramDefEntry.getValueType();
|
||||
logger.info("addParametersToReport(" + paramName + " : "
|
||||
+ pValue + " : " + clazz.getCanonicalName() + ")");
|
||||
if (clazz.getCanonicalName().equalsIgnoreCase(
|
||||
"java.lang.Integer"))
|
||||
rptParamValues.put(paramName, Integer.parseInt(pValue));
|
||||
else if (clazz.getCanonicalName().equalsIgnoreCase(
|
||||
"java.lang.Long"))
|
||||
rptParamValues.put(paramName, Long.parseLong(pValue));
|
||||
else if (clazz.getCanonicalName().equalsIgnoreCase(
|
||||
"java.sql.Date"))
|
||||
rptParamValues.put(paramName, Date.valueOf(pValue));
|
||||
else
|
||||
rptParamValues.put(paramName, pValue);
|
||||
}
|
||||
|
||||
// tenant database name and current user's office hierarchy
|
||||
// passed as parameters to allow multitenant penaho reporting and
|
||||
// data scoping
|
||||
String tenantdb = dataSource.getConnection().getCatalog();
|
||||
String userhierarchy = currentUser.getOffice().getHierarchy();
|
||||
logger.info("db name:" + tenantdb + " userhierarchy:" + userhierarchy);
|
||||
rptParamValues.put("tenantdb", tenantdb);
|
||||
rptParamValues.put("userhierarchy", userhierarchy);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
logger.info("error.msg.reporting.error:" + e.getMessage());
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.reporting.error", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String retrieveReportPDF(final String reportName, final String type,
|
||||
final Map<String, String> queryParams) {
|
||||
|
||||
String fileLocation = FileUtils.MIFOSX_BASE_DIR + File.separator + "";
|
||||
if (!new File(fileLocation).isDirectory()) {
|
||||
new File(fileLocation).mkdirs();
|
||||
}
|
||||
|
||||
String genaratePdf = fileLocation + File.separator + reportName
|
||||
+ ".pdf";
|
||||
|
||||
try {
|
||||
GenericResultsetData result = retrieveGenericResultset(reportName,
|
||||
type, queryParams);
|
||||
|
||||
List<ResultsetColumnHeader> columnHeaders = result
|
||||
.getColumnHeaders();
|
||||
List<ResultsetDataRow> data = result.getData();
|
||||
List<String> row;
|
||||
|
||||
logger.info("NO. of Columns: " + columnHeaders.size());
|
||||
Integer chSize = columnHeaders.size();
|
||||
|
||||
Document document = new Document(PageSize.B0.rotate());
|
||||
|
||||
PdfWriter.getInstance(document, new FileOutputStream(new File(
|
||||
fileLocation + reportName + ".pdf")));
|
||||
document.open();
|
||||
|
||||
PdfPTable table = new PdfPTable(chSize);
|
||||
table.setWidthPercentage(100);
|
||||
|
||||
for (int i = 0; i < chSize; i++) {
|
||||
|
||||
table.addCell(columnHeaders.get(i).getColumnName());
|
||||
|
||||
}
|
||||
table.completeRow();
|
||||
|
||||
Integer rSize;
|
||||
String currColType;
|
||||
String currVal;
|
||||
logger.info("NO. of Rows: " + data.size());
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
row = data.get(i).getRow();
|
||||
rSize = row.size();
|
||||
for (int j = 0; j < rSize; j++) {
|
||||
currColType = columnHeaders.get(j).getColumnType();
|
||||
currVal = row.get(j);
|
||||
if (currVal != null) {
|
||||
if (currColType.equals("DECIMAL")
|
||||
|| currColType.equals("DOUBLE")
|
||||
|| currColType.equals("BIGINT")
|
||||
|| currColType.equals("SMALLINT")
|
||||
|| currColType.equals("INT")) {
|
||||
|
||||
table.addCell(currVal.toString());
|
||||
} else {
|
||||
table.addCell(currVal.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
table.completeRow();
|
||||
document.add(table);
|
||||
document.close();
|
||||
return genaratePdf;
|
||||
} catch (Exception e) {
|
||||
throw new PlatformDataIntegrityException(
|
||||
"error.msg.exception.error", e.getMessage());
|
||||
}
|
||||
}
|
||||
private final static Logger logger = LoggerFactory.getLogger(ReadReportingServiceImpl.class);
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final DataSource dataSource;
|
||||
private final PlatformSecurityContext context;
|
||||
private final GenericDataService genericDataService;
|
||||
private boolean noPentaho = false;
|
||||
|
||||
@Autowired
|
||||
public ReadReportingServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource,
|
||||
final GenericDataService genericDataService) {
|
||||
// kick off pentaho reports server
|
||||
ClassicEngineBoot.getInstance().start();
|
||||
noPentaho = false;
|
||||
|
||||
this.context = context;
|
||||
this.dataSource = dataSource;
|
||||
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
|
||||
this.genericDataService = genericDataService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StreamingOutput retrieveReportCSV(final String name, final String type, final Map<String, String> queryParams) {
|
||||
|
||||
return new StreamingOutput() {
|
||||
|
||||
@Override
|
||||
public void write(final OutputStream out) {
|
||||
try {
|
||||
|
||||
GenericResultsetData result = retrieveGenericResultset(name, type, queryParams);
|
||||
StringBuffer sb = generateCsvFileBuffer(result);
|
||||
|
||||
InputStream in = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
|
||||
|
||||
byte[] outputByte = new byte[4096];
|
||||
Integer readLen = in.read(outputByte, 0, 4096);
|
||||
|
||||
while (readLen != -1) {
|
||||
out.write(outputByte, 0, readLen);
|
||||
readLen = in.read(outputByte, 0, 4096);
|
||||
}
|
||||
// in.close();
|
||||
// out.flush();
|
||||
// out.close();
|
||||
} catch (Exception e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.exception.error", e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
private StringBuffer generateCsvFileBuffer(final GenericResultsetData result) {
|
||||
StringBuffer writer = new StringBuffer();
|
||||
|
||||
List<ResultsetColumnHeaderData> columnHeaders = result.getColumnHeaders();
|
||||
logger.info("NO. of Columns: " + columnHeaders.size());
|
||||
Integer chSize = columnHeaders.size();
|
||||
for (int i = 0; i < chSize; i++) {
|
||||
writer.append('"' + columnHeaders.get(i).getColumnName() + '"');
|
||||
if (i < (chSize - 1)) writer.append(",");
|
||||
}
|
||||
writer.append('\n');
|
||||
|
||||
List<ResultsetRowData> data = result.getData();
|
||||
List<String> row;
|
||||
Integer rSize;
|
||||
// String currCol;
|
||||
String currColType;
|
||||
String currVal;
|
||||
String doubleQuote = "\"";
|
||||
String twoDoubleQuotes = doubleQuote + doubleQuote;
|
||||
logger.info("NO. of Rows: " + data.size());
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
row = data.get(i).getRow();
|
||||
rSize = row.size();
|
||||
for (int j = 0; j < rSize; j++) {
|
||||
// currCol = columnHeaders.get(j).getColumnName();
|
||||
currColType = columnHeaders.get(j).getColumnType();
|
||||
currVal = row.get(j);
|
||||
if (currVal != null) {
|
||||
if (currColType.equals("DECIMAL") || currColType.equals("DOUBLE") || currColType.equals("BIGINT")
|
||||
|| currColType.equals("SMALLINT") || currColType.equals("INT"))
|
||||
writer.append(currVal);
|
||||
else
|
||||
writer.append('"' + genericDataService.replace(currVal, doubleQuote, twoDoubleQuotes) + '"');
|
||||
|
||||
}
|
||||
if (j < (rSize - 1)) writer.append(",");
|
||||
}
|
||||
writer.append('\n');
|
||||
}
|
||||
|
||||
return writer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericResultsetData retrieveGenericResultset(final String name, final String type, final Map<String, String> queryParams) {
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
logger.info("STARTING REPORT: " + name + " Type: " + type);
|
||||
|
||||
String sql;
|
||||
if (name.equals(".")) {
|
||||
// this is to support api /reports - which isn't an important
|
||||
// call. It isn't used in the default reporting UI. But there is a
|
||||
// need to provide an api that does bring back 'permitted' reports
|
||||
// PERMITTED REPORTS SQL
|
||||
sql = "select r.report_id, r.report_name, r.report_type, r.report_subtype, r.report_category,"
|
||||
+ " rp.parameter_id, rp.report_parameter_name, p.parameter_name" + " from stretchy_report r"
|
||||
+ " left join stretchy_report_parameter rp on rp.report_id = r.report_id"
|
||||
+ " left join stretchy_parameter p on p.parameter_id = rp.parameter_id" + " where exists" + " (select 'f'"
|
||||
+ " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id"
|
||||
+ " left join m_role_permission rp on rp.role_id = r.id" + " left join m_permission p on p.id = rp.permission_id"
|
||||
+ " where ur.appuser_id = " + context.authenticatedUser().getId()
|
||||
+ " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', r.report_name))) "
|
||||
+ " order by r.report_name, rp.parameter_id";
|
||||
} else {
|
||||
sql = getSQLtoRun(name, type, queryParams);
|
||||
}
|
||||
|
||||
GenericResultsetData result = genericDataService.fillGenericResultSet(sql);
|
||||
|
||||
long elapsed = System.currentTimeMillis() - startTime;
|
||||
logger.info("FINISHING Report/Request Name: " + name + " - " + type + " Elapsed Time: " + elapsed);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getSQLtoRun(final String name, final String type, final Map<String, String> queryParams) {
|
||||
|
||||
String sql = getSql(name, type);
|
||||
|
||||
Set<String> keys = queryParams.keySet();
|
||||
for (String key : keys) {
|
||||
String pValue = queryParams.get(key);
|
||||
// logger.info("(" + key + " : " + pValue + ")");
|
||||
sql = genericDataService.replace(sql, key, pValue);
|
||||
}
|
||||
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
// Allows sql query to restrict data by office hierarchy if required
|
||||
sql = genericDataService.replace(sql, "${currentUserHierarchy}", currentUser.getOffice().getHierarchy());
|
||||
// Allows sql query to restrict data by current user Id if required
|
||||
// (typically used to return report lists containing only reports
|
||||
// permitted to be run by the user
|
||||
sql = genericDataService.replace(sql, "${currentUserId}", currentUser.getId().toString());
|
||||
|
||||
sql = genericDataService.wrapSQL(sql);
|
||||
|
||||
return sql;
|
||||
|
||||
}
|
||||
|
||||
private String getSql(final String name, final String type) {
|
||||
|
||||
final String inputSql = "select " + type + "_sql as the_sql from stretchy_" + type + " where " + type + "_name = '" + name + "'";
|
||||
final String inputSqlWrapped = genericDataService.wrapSQL(inputSql);
|
||||
|
||||
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(inputSqlWrapped);
|
||||
|
||||
if (rs.next()) { return rs.getString("the_sql"); }
|
||||
throw new ReportNotFoundException(inputSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReportType(final String reportName) {
|
||||
|
||||
final String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '" + reportName + "'";
|
||||
|
||||
final String sqlWrapped = genericDataService.wrapSQL(sql);
|
||||
|
||||
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sqlWrapped);
|
||||
|
||||
if (rs.next()) { return rs.getString("report_type"); }
|
||||
throw new ReportNotFoundException(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response processPentahoRequest(final String reportName, final String outputTypeParam, final Map<String, String> queryParams) {
|
||||
|
||||
String outputType = "HTML";
|
||||
if (StringUtils.isNotBlank(outputTypeParam)) outputType = outputTypeParam;
|
||||
|
||||
if (!(outputType.equalsIgnoreCase("HTML") || outputType.equalsIgnoreCase("PDF") || outputType.equalsIgnoreCase("XLS") || outputType
|
||||
.equalsIgnoreCase("CSV")))
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType);
|
||||
|
||||
if (noPentaho) { throw new PlatformDataIntegrityException("error.msg.no.pentaho", "Pentaho is not enabled",
|
||||
"Pentaho is not enabled"); }
|
||||
|
||||
// TODO - JW - use pentaho location finder like Pawel does in Mifos
|
||||
// String reportPath =
|
||||
// "C:\\dev\\apache-tomcat-7.0.25\\webapps\\ROOT\\PentahoReports\\"
|
||||
// + reportName + ".prpt";
|
||||
/*
|
||||
* String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator +
|
||||
* ThreadLocalContextUtil.getTenant().getName() .replaceAll(" ",
|
||||
* "").trim() + File.separator + "reports" + File.separator + reportName
|
||||
* + ".prpt";
|
||||
*/
|
||||
final String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator + "reports" + File.separator + reportName + ".prpt";
|
||||
logger.info("Report path: " + reportPath);
|
||||
|
||||
// load report definition
|
||||
ResourceManager manager = new ResourceManager();
|
||||
manager.registerDefaults();
|
||||
Resource res;
|
||||
|
||||
try {
|
||||
res = manager.createDirectly(reportPath, MasterReport.class);
|
||||
MasterReport masterReport = (MasterReport) res.getResource();
|
||||
|
||||
addParametersToReport(masterReport, queryParams);
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
if ("PDF".equalsIgnoreCase(outputType)) {
|
||||
PdfReportUtil.createPDF(masterReport, baos);
|
||||
return Response.ok().entity(baos.toByteArray()).type("application/pdf").build();
|
||||
}
|
||||
|
||||
if ("XLS".equalsIgnoreCase(outputType)) {
|
||||
ExcelReportUtil.createXLS(masterReport, baos);
|
||||
return Response.ok().entity(baos.toByteArray()).type("application/vnd.ms-excel")
|
||||
.header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".xls").build();
|
||||
}
|
||||
|
||||
if ("CSV".equalsIgnoreCase(outputType)) {
|
||||
CSVReportUtil.createCSV(masterReport, baos, "UTF-8");
|
||||
return Response.ok().entity(baos.toByteArray()).type("application/x-msdownload")
|
||||
.header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".csv").build();
|
||||
}
|
||||
|
||||
if ("HTML".equalsIgnoreCase(outputType)) {
|
||||
HtmlReportUtil.createStreamHTML(masterReport, baos);
|
||||
return Response.ok().entity(baos.toByteArray()).type("text/html").build();
|
||||
}
|
||||
} catch (ResourceException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
|
||||
} catch (ReportProcessingException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
|
||||
}
|
||||
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType);
|
||||
}
|
||||
|
||||
private void addParametersToReport(final MasterReport report, final Map<String, String> queryParams) {
|
||||
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
|
||||
try {
|
||||
|
||||
logger.info("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
|
||||
ReportParameterValues rptParamValues = report.getParameterValues();
|
||||
ReportParameterDefinition paramsDefinition = report.getParameterDefinition();
|
||||
|
||||
/*
|
||||
* only allow integer, long, date and string parameter types and
|
||||
* assume all mandatory - could go more detailed like Pawel did in
|
||||
* Mifos later and could match incoming and pentaho parameters
|
||||
* better... currently assuming they come in ok... and if not an
|
||||
* error
|
||||
*/
|
||||
for (ParameterDefinitionEntry paramDefEntry : paramsDefinition.getParameterDefinitions()) {
|
||||
String paramName = paramDefEntry.getName();
|
||||
if (!((paramName.equals("tenantdb")) || (paramName.equals("userhierarchy")))) {
|
||||
logger.info("paramName:" + paramName);
|
||||
String pValue = queryParams.get(paramName);
|
||||
if (StringUtils.isBlank(pValue))
|
||||
throw new PlatformDataIntegrityException("error.msg.reporting.error", "Pentaho Parameter: " + paramName
|
||||
+ " - not Provided");
|
||||
|
||||
Class<?> clazz = paramDefEntry.getValueType();
|
||||
logger.info("addParametersToReport(" + paramName + " : " + pValue + " : " + clazz.getCanonicalName() + ")");
|
||||
if (clazz.getCanonicalName().equalsIgnoreCase("java.lang.Integer"))
|
||||
rptParamValues.put(paramName, Integer.parseInt(pValue));
|
||||
else if (clazz.getCanonicalName().equalsIgnoreCase("java.lang.Long"))
|
||||
rptParamValues.put(paramName, Long.parseLong(pValue));
|
||||
else if (clazz.getCanonicalName().equalsIgnoreCase("java.sql.Date"))
|
||||
rptParamValues.put(paramName, Date.valueOf(pValue));
|
||||
else
|
||||
rptParamValues.put(paramName, pValue);
|
||||
}
|
||||
|
||||
// tenant database name and current user's office hierarchy
|
||||
// passed as parameters to allow multitenant penaho reporting
|
||||
// and
|
||||
// data scoping
|
||||
String tenantdb = dataSource.getConnection().getCatalog();
|
||||
String userhierarchy = currentUser.getOffice().getHierarchy();
|
||||
logger.info("db name:" + tenantdb + " userhierarchy:" + userhierarchy);
|
||||
rptParamValues.put("tenantdb", tenantdb);
|
||||
rptParamValues.put("userhierarchy", userhierarchy);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("error.msg.reporting.error:" + e.getMessage());
|
||||
throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String retrieveReportPDF(final String reportName, final String type, final Map<String, String> queryParams) {
|
||||
|
||||
String fileLocation = FileUtils.MIFOSX_BASE_DIR + File.separator + "";
|
||||
if (!new File(fileLocation).isDirectory()) {
|
||||
new File(fileLocation).mkdirs();
|
||||
}
|
||||
|
||||
String genaratePdf = fileLocation + File.separator + reportName + ".pdf";
|
||||
|
||||
try {
|
||||
GenericResultsetData result = retrieveGenericResultset(reportName, type, queryParams);
|
||||
|
||||
List<ResultsetColumnHeaderData> columnHeaders = result.getColumnHeaders();
|
||||
List<ResultsetRowData> data = result.getData();
|
||||
List<String> row;
|
||||
|
||||
logger.info("NO. of Columns: " + columnHeaders.size());
|
||||
Integer chSize = columnHeaders.size();
|
||||
|
||||
Document document = new Document(PageSize.B0.rotate());
|
||||
|
||||
PdfWriter.getInstance(document, new FileOutputStream(new File(fileLocation + reportName + ".pdf")));
|
||||
document.open();
|
||||
|
||||
PdfPTable table = new PdfPTable(chSize);
|
||||
table.setWidthPercentage(100);
|
||||
|
||||
for (int i = 0; i < chSize; i++) {
|
||||
|
||||
table.addCell(columnHeaders.get(i).getColumnName());
|
||||
|
||||
}
|
||||
table.completeRow();
|
||||
|
||||
Integer rSize;
|
||||
String currColType;
|
||||
String currVal;
|
||||
logger.info("NO. of Rows: " + data.size());
|
||||
for (int i = 0; i < data.size(); i++) {
|
||||
row = data.get(i).getRow();
|
||||
rSize = row.size();
|
||||
for (int j = 0; j < rSize; j++) {
|
||||
currColType = columnHeaders.get(j).getColumnType();
|
||||
currVal = row.get(j);
|
||||
if (currVal != null) {
|
||||
if (currColType.equals("DECIMAL") || currColType.equals("DOUBLE") || currColType.equals("BIGINT")
|
||||
|| currColType.equals("SMALLINT") || currColType.equals("INT")) {
|
||||
|
||||
table.addCell(currVal.toString());
|
||||
} else {
|
||||
table.addCell(currVal.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
table.completeRow();
|
||||
document.add(table);
|
||||
document.close();
|
||||
return genaratePdf;
|
||||
} catch (Exception e) {
|
||||
logger.error("error.msg.reporting.error:" + e.getMessage());
|
||||
throw new PlatformDataIntegrityException("error.msg.exception.error", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
+190
-255
@@ -7,8 +7,6 @@ package org.mifosplatform.infrastructure.dataqueries.service;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -16,7 +14,7 @@ import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.sql.rowset.CachedRowSet;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -26,17 +24,20 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.infrastructure.core.serialization.JsonParserHelper;
|
||||
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.DatatableData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnValue;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetRowData;
|
||||
import org.mifosplatform.infrastructure.dataqueries.exception.DataTableNotFoundException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSet;
|
||||
import org.springframework.jdbc.support.rowset.SqlRowSetMetaData;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
@@ -46,18 +47,24 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(ReadWriteNonCoreDataServiceImpl.class);
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final DataSource dataSource;
|
||||
private final PlatformSecurityContext context;
|
||||
private final FromJsonHelper fromJsonHelper;
|
||||
private final JsonParserHelper helper;
|
||||
private final GenericDataService genericDataService;
|
||||
|
||||
@Autowired
|
||||
public ReadWriteNonCoreDataServiceImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper) {
|
||||
public ReadWriteNonCoreDataServiceImpl(final TenantAwareRoutingDataSource dataSource, final PlatformSecurityContext context,
|
||||
final FromJsonHelper fromJsonHelper, final GenericDataService genericDataService) {
|
||||
this.dataSource = dataSource;
|
||||
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
|
||||
this.context = context;
|
||||
this.fromJsonHelper = fromJsonHelper;
|
||||
this.helper = new JsonParserHelper();
|
||||
this.genericDataService = genericDataService;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private GenericDataService genericDataService;
|
||||
|
||||
@Override
|
||||
public List<DatatableData> retrieveDatatableNames(final String appTable) {
|
||||
|
||||
@@ -67,25 +74,23 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
} else {
|
||||
andClause = " and application_table_name = '" + appTable + "'";
|
||||
}
|
||||
|
||||
// PERMITTED datatables
|
||||
String sql = "select application_table_name, registered_table_name" + " from x_registered_table " + " where exists"
|
||||
final String sql = "select application_table_name, registered_table_name" + " from x_registered_table " + " where exists"
|
||||
+ " (select 'f'" + " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id"
|
||||
+ " left join m_role_permission rp on rp.role_id = r.id" + " left join m_permission p on p.id = rp.permission_id"
|
||||
+ " where ur.appuser_id = " + context.authenticatedUser().getId()
|
||||
+ " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', registered_table_name))) "
|
||||
+ andClause + " order by application_table_name, registered_table_name";
|
||||
|
||||
String sqlErrorMsg = "Application Table Name: " + appTable + " sql: " + sql;
|
||||
CachedRowSet rs = genericDataService.getCachedResultSet(sql, sqlErrorMsg);
|
||||
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
|
||||
|
||||
List<DatatableData> datatables = new ArrayList<DatatableData>();
|
||||
try {
|
||||
while (rs.next()) {
|
||||
datatables.add(new DatatableData(rs.getString("application_table_name"), rs.getString("registered_table_name")));
|
||||
}
|
||||
final List<DatatableData> datatables = new ArrayList<DatatableData>();
|
||||
while (rs.next()) {
|
||||
final String appTableName = rs.getString("application_table_name");
|
||||
final String registeredDatatableName = rs.getString("registered_table_name");
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
|
||||
datatables.add(DatatableData.create(appTableName, registeredDatatableName));
|
||||
}
|
||||
|
||||
return datatables;
|
||||
@@ -96,63 +101,89 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
|
||||
validateAppTable(appTable);
|
||||
|
||||
String createPermission = "'CREATE_" + datatable + "'";
|
||||
String createPermissionChecker = "'CREATE_" + datatable + "_CHECKER'";
|
||||
String readPermission = "'READ_" + datatable + "'";
|
||||
String updatePermission = "'UPDATE_" + datatable + "'";
|
||||
String updatePermissionChecker = "'UPDATE_" + datatable + "_CHECKER'";
|
||||
String deletePermission = "'DELETE_" + datatable + "'";
|
||||
String deletePermissionChecker = "'DELETE_" + datatable + "_CHECKER'";
|
||||
// TODO - JW - put in batch command later
|
||||
String sql = "insert into x_registered_table (registered_table_name, application_table_name) values ('" + datatable + "', '"
|
||||
+ appTable + "')";
|
||||
final String createPermission = "'CREATE_" + datatable + "'";
|
||||
final String createPermissionChecker = "'CREATE_" + datatable + "_CHECKER'";
|
||||
final String readPermission = "'READ_" + datatable + "'";
|
||||
final String updatePermission = "'UPDATE_" + datatable + "'";
|
||||
final String updatePermissionChecker = "'UPDATE_" + datatable + "_CHECKER'";
|
||||
final String deletePermission = "'DELETE_" + datatable + "'";
|
||||
final String deletePermissionChecker = "'DELETE_" + datatable + "_CHECKER'";
|
||||
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
/*
|
||||
* add all permissions, including checker permissions for maintenance
|
||||
* tasks
|
||||
*/
|
||||
sql = "insert into m_permission (grouping, code, action_name, entity_name, can_maker_checker) values " + "('datatable', "
|
||||
+ createPermission + ", 'CREATE', '" + datatable + "', true)," + "('datatable', " + createPermissionChecker
|
||||
+ ", 'CREATE', '" + datatable + "', false)," + "('datatable', " + readPermission + ", 'READ', '" + datatable + "', false),"
|
||||
+ "('datatable', " + updatePermission + ", 'UPDATE', '" + datatable + "', true)," + "('datatable', "
|
||||
+ updatePermissionChecker + ", 'UPDATE', '" + datatable + "', false)," + "('datatable', " + deletePermission
|
||||
+ ", 'DELETE', '" + datatable + "', true)," + "('datatable', " + deletePermissionChecker + ", 'DELETE', '" + datatable
|
||||
// TODO - JW - put in batch command later
|
||||
final String registerDatatableSql = "insert into x_registered_table (registered_table_name, application_table_name) values ('"
|
||||
+ datatable + "', '" + appTable + "')";
|
||||
|
||||
this.jdbcTemplate.update(registerDatatableSql);
|
||||
|
||||
final String permissionsSql = "insert into m_permission (grouping, code, action_name, entity_name, can_maker_checker) values "
|
||||
+ "('datatable', "
|
||||
+ createPermission
|
||||
+ ", 'CREATE', '"
|
||||
+ datatable
|
||||
+ "', true),"
|
||||
+ "('datatable', "
|
||||
+ createPermissionChecker
|
||||
+ ", 'CREATE', '"
|
||||
+ datatable
|
||||
+ "', false),"
|
||||
+ "('datatable', "
|
||||
+ readPermission
|
||||
+ ", 'READ', '"
|
||||
+ datatable
|
||||
+ "', false),"
|
||||
+ "('datatable', "
|
||||
+ updatePermission
|
||||
+ ", 'UPDATE', '"
|
||||
+ datatable
|
||||
+ "', true),"
|
||||
+ "('datatable', "
|
||||
+ updatePermissionChecker
|
||||
+ ", 'UPDATE', '"
|
||||
+ datatable
|
||||
+ "', false),"
|
||||
+ "('datatable', "
|
||||
+ deletePermission
|
||||
+ ", 'DELETE', '"
|
||||
+ datatable
|
||||
+ "', true),"
|
||||
+ "('datatable', "
|
||||
+ deletePermissionChecker
|
||||
+ ", 'DELETE', '"
|
||||
+ datatable
|
||||
+ "', false)";
|
||||
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
this.jdbcTemplate.update(permissionsSql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deregisterDatatable(final String datatable) {
|
||||
// TODO - JW - put in batch command later
|
||||
|
||||
String permissionList = "('CREATE_" + datatable + "', 'CREATE_" + datatable + "_CHECKER', 'READ_" + datatable + "', 'UPDATE_"
|
||||
final String permissionList = "('CREATE_" + datatable + "', 'CREATE_" + datatable + "_CHECKER', 'READ_" + datatable + "', 'UPDATE_"
|
||||
+ datatable + "', 'UPDATE_" + datatable + "_CHECKER', 'DELETE_" + datatable + "', 'DELETE_" + datatable + "_CHECKER')";
|
||||
|
||||
String sql = "delete from m_role_permission where m_role_permission.permission_id in (select id from m_permission where code in "
|
||||
+ permissionList + ")";
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
this.jdbcTemplate.update(sql);
|
||||
|
||||
sql = "delete from m_permission where code in " + permissionList;
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
this.jdbcTemplate.update(sql);
|
||||
|
||||
sql = "delete from x_registered_table where registered_table_name = '" + datatable + "'";
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
this.jdbcTemplate.update(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void newDatatableEntry(final String datatable, final Long appTableId, final JsonCommand command) {
|
||||
String appTable = getWithinScopeApplicationTableName(datatable, appTableId);
|
||||
|
||||
List<ResultsetColumnHeader> columnHeaders = getDatatableResultsetColumnHeaders(datatable);
|
||||
final List<ResultsetColumnHeaderData> columnHeaders = this.genericDataService.fillResultsetColumnHeaders(datatable);
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
|
||||
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
|
||||
final Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
|
||||
|
||||
String sql = getAddSql(columnHeaders, datatable, getFKField(appTable), appTableId, dataParams);
|
||||
final String sql = getAddSql(columnHeaders, datatable, getFKField(appTable), appTableId, dataParams);
|
||||
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
this.jdbcTemplate.update(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -166,7 +197,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
throw new PlatformDataIntegrityException("error.msg.attempting.multiple.update", "Application Table: " + datatable
|
||||
+ " Foreign Key Id: " + appTableId);
|
||||
|
||||
String fkName = getFKField(getApplicationTableName(datatable));
|
||||
String fkName = getFKField(queryForApplicationTableName(datatable));
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
|
||||
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
|
||||
@@ -175,10 +206,10 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
|
||||
if (changes.size() == 0) return changes;
|
||||
|
||||
String sql = getUpdateSql(datatable, fkName, appTableId, changes);
|
||||
final String sql = getUpdateSql(datatable, fkName, appTableId, changes);
|
||||
|
||||
if (sql != null) {
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
if (StringUtils.isNotBlank(sql)) {
|
||||
this.jdbcTemplate.update(sql);
|
||||
} else {
|
||||
logger.info("No Changes");
|
||||
}
|
||||
@@ -190,21 +221,21 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
public Map<String, Object> updateDatatableEntryOneToMany(final String datatable, final Long appTableId, final Long datatableId,
|
||||
final JsonCommand command) {
|
||||
|
||||
GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable, appTableId, null, datatableId);
|
||||
final GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable, appTableId, null, datatableId);
|
||||
|
||||
if (grs.getData().size() == 0) throw new DataTableNotFoundException(datatable, appTableId);
|
||||
|
||||
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
|
||||
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
|
||||
final Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json());
|
||||
|
||||
final Map<String, Object> changes = getAffectedAndChangedColumns(grs, dataParams, "id");
|
||||
|
||||
if (changes.size() == 0) return changes;
|
||||
|
||||
String sql = getUpdateSql(datatable, "id", datatableId, changes);
|
||||
final String sql = getUpdateSql(datatable, "id", datatableId, changes);
|
||||
|
||||
if (sql != null) {
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
if (StringUtils.isNotBlank(sql)) {
|
||||
this.jdbcTemplate.update(sql);
|
||||
} else {
|
||||
logger.info("No Changes");
|
||||
}
|
||||
@@ -215,11 +246,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
@Override
|
||||
public void deleteDatatableEntries(final String datatable, final Long appTableId) {
|
||||
|
||||
String appTable = getWithinScopeApplicationTableName(datatable, appTableId);
|
||||
final String appTable = getWithinScopeApplicationTableName(datatable, appTableId);
|
||||
|
||||
String sql = getDeleteEntriesSql(datatable, getFKField(appTable), appTableId);
|
||||
final String sql = getDeleteEntriesSql(datatable, getFKField(appTable), appTableId);
|
||||
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
this.jdbcTemplate.update(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,18 +258,18 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
|
||||
getWithinScopeApplicationTableName(datatable, appTableId);
|
||||
|
||||
String sql = getDeleteEntrySql(datatable, datatableId);
|
||||
final String sql = getDeleteEntrySql(datatable, datatableId);
|
||||
|
||||
genericDataService.updateSQL(sql, "SQL: " + sql);
|
||||
this.jdbcTemplate.update(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenericResultsetData retrieveDataTableGenericResultSet(final String datatable, final Long appTableId, final String order,
|
||||
final Long id) {
|
||||
|
||||
String appTable = getWithinScopeApplicationTableName(datatable, appTableId);
|
||||
final String appTable = getWithinScopeApplicationTableName(datatable, appTableId);
|
||||
|
||||
List<ResultsetColumnHeader> columnHeaders = getDatatableResultsetColumnHeaders(datatable);
|
||||
final List<ResultsetColumnHeaderData> columnHeaders = this.genericDataService.fillResultsetColumnHeaders(datatable);
|
||||
|
||||
String sql = "";
|
||||
|
||||
@@ -252,20 +283,20 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
|
||||
if (order != null) sql = sql + " order by " + order;
|
||||
|
||||
List<ResultsetDataRow> result = fillDatatableResultSetDataRows(sql);
|
||||
List<ResultsetRowData> result = fillDatatableResultSetDataRows(sql);
|
||||
|
||||
return new GenericResultsetData(columnHeaders, result);
|
||||
}
|
||||
|
||||
private void checkMainResourceExistsWithinScope(final String appTable, final Long appTableId) {
|
||||
|
||||
String unscopedSql = "select t.id from `" + appTable + "` t ${dataScopeCriteria} where t.id = " + appTableId;
|
||||
final String unscopedSql = "select t.id from `" + appTable + "` t ${dataScopeCriteria} where t.id = " + appTableId;
|
||||
|
||||
String sql = dataScopedSQL(unscopedSql, appTable);
|
||||
final String sql = dataScopedSQL(unscopedSql, appTable);
|
||||
|
||||
CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : " + sql);
|
||||
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
|
||||
|
||||
if (rs.size() == 0) throw new DataTableNotFoundException(appTable, appTableId);
|
||||
if (!rs.next()) { throw new DataTableNotFoundException(appTable, appTableId); }
|
||||
}
|
||||
|
||||
private String dataScopedSQL(final String unscopedSQL, final String appTable) {
|
||||
@@ -303,74 +334,50 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.application.table", "Invalid Application Table: " + appTable);
|
||||
}
|
||||
|
||||
private List<ResultsetDataRow> fillDatatableResultSetDataRows(final String sql) {
|
||||
private List<ResultsetRowData> fillDatatableResultSetDataRows(final String sql) {
|
||||
|
||||
String sqlErrorMsg = "Sql: " + sql;
|
||||
CachedRowSet rs = genericDataService.getCachedResultSet(sql, sqlErrorMsg);
|
||||
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
|
||||
|
||||
List<ResultsetDataRow> resultsetDataRows = new ArrayList<ResultsetDataRow>();
|
||||
final List<ResultsetRowData> resultsetDataRows = new ArrayList<ResultsetRowData>();
|
||||
|
||||
try {
|
||||
final SqlRowSetMetaData rsmd = rs.getMetaData();
|
||||
|
||||
ResultSetMetaData rsmd = rs.getMetaData();
|
||||
int columnCount = rsmd.getColumnCount();
|
||||
|
||||
ResultsetDataRow resultsetDataRow;
|
||||
String columnName = null;
|
||||
String columnValue = null;
|
||||
while (rs.next()) {
|
||||
resultsetDataRow = new ResultsetDataRow();
|
||||
List<String> columnValues = new ArrayList<String>();
|
||||
for (int i = 0; i < columnCount; i++) {
|
||||
columnName = rsmd.getColumnName(i + 1);
|
||||
columnValue = rs.getString(columnName);
|
||||
columnValues.add(columnValue);
|
||||
}
|
||||
resultsetDataRow.setRow(columnValues);
|
||||
resultsetDataRows.add(resultsetDataRow);
|
||||
while (rs.next()) {
|
||||
final List<String> columnValues = new ArrayList<String>();
|
||||
for (int i = 0; i < rsmd.getColumnCount(); i++) {
|
||||
final String columnName = rsmd.getColumnName(i + 1);
|
||||
final String columnValue = rs.getString(columnName);
|
||||
columnValues.add(columnValue);
|
||||
}
|
||||
|
||||
return resultsetDataRows;
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
|
||||
final ResultsetRowData resultsetDataRow = ResultsetRowData.create(columnValues);
|
||||
resultsetDataRows.add(resultsetDataRow);
|
||||
}
|
||||
|
||||
return resultsetDataRows;
|
||||
}
|
||||
|
||||
private String getWithinScopeApplicationTableName(final String datatable, final Long appTableId) {
|
||||
String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '" + datatable + "'";
|
||||
|
||||
CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : " + sql);
|
||||
final String applicationTableName = queryForApplicationTableName(datatable);
|
||||
checkMainResourceExistsWithinScope(applicationTableName, appTableId);
|
||||
|
||||
if (rs.size() == 0) throw new DataTableNotFoundException(datatable);
|
||||
|
||||
try {
|
||||
rs.next();
|
||||
String appTable = rs.getString("application_table_name");
|
||||
|
||||
checkMainResourceExistsWithinScope(appTable, appTableId);
|
||||
|
||||
return appTable;
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage());
|
||||
}
|
||||
return applicationTableName;
|
||||
}
|
||||
|
||||
private String getApplicationTableName(final String datatable) {
|
||||
// TODO - JW - only used for update... can probably remove this after as
|
||||
// its
|
||||
// a reread
|
||||
String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '" + datatable + "'";
|
||||
private String queryForApplicationTableName(final String datatable) {
|
||||
final String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '" + datatable + "'";
|
||||
|
||||
CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : " + sql);
|
||||
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
|
||||
|
||||
if (rs.size() == 0) throw new DataTableNotFoundException(datatable);
|
||||
|
||||
try {
|
||||
rs.next();
|
||||
return rs.getString("application_table_name");
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage());
|
||||
String applicationTableName = null;
|
||||
if (rs.next()) {
|
||||
applicationTableName = rs.getString("application_table_name");
|
||||
} else {
|
||||
throw new DataTableNotFoundException(datatable);
|
||||
}
|
||||
|
||||
return applicationTableName;
|
||||
}
|
||||
|
||||
private String getFKField(final String applicationTableName) {
|
||||
@@ -378,89 +385,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
return applicationTableName.substring(2) + "_id";
|
||||
}
|
||||
|
||||
private CachedRowSet getDatatableMetaData(final String datatable) {
|
||||
|
||||
String sql = "select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMN_KEY"
|
||||
+ " from INFORMATION_SCHEMA.COLUMNS " + " where TABLE_SCHEMA = schema() and TABLE_NAME = '" + datatable
|
||||
+ "'order by ORDINAL_POSITION";
|
||||
|
||||
CachedRowSet columnDefinitions = genericDataService.getCachedResultSet(sql, "SQL: " + sql);
|
||||
|
||||
if (columnDefinitions.size() > 0) return columnDefinitions;
|
||||
|
||||
throw new DataTableNotFoundException(datatable);
|
||||
}
|
||||
|
||||
private List<ResultsetColumnHeader> getDatatableResultsetColumnHeaders(final String datatable) {
|
||||
|
||||
CachedRowSet columnDefinitions = getDatatableMetaData(datatable);
|
||||
|
||||
List<ResultsetColumnHeader> columnHeaders = new ArrayList<ResultsetColumnHeader>();
|
||||
|
||||
try {
|
||||
|
||||
while (columnDefinitions.next()) {
|
||||
ResultsetColumnHeader rsch = new ResultsetColumnHeader();
|
||||
|
||||
rsch.setColumnName(columnDefinitions.getString("COLUMN_NAME"));
|
||||
|
||||
String isNullable = columnDefinitions.getString("IS_NULLABLE");
|
||||
if (isNullable.equalsIgnoreCase("YES"))
|
||||
rsch.setColumnNullable(true);
|
||||
else
|
||||
rsch.setColumnNullable(false);
|
||||
|
||||
String isPrimaryKey = columnDefinitions.getString("COLUMN_KEY");
|
||||
if (isPrimaryKey.equalsIgnoreCase("PRI"))
|
||||
rsch.setColumnPrimaryKey(true);
|
||||
else
|
||||
rsch.setColumnPrimaryKey(false);
|
||||
|
||||
Long columnLength = columnDefinitions.getLong("CHARACTER_MAXIMUM_LENGTH");
|
||||
if (columnLength > 0) rsch.setColumnLength(columnDefinitions.getLong("CHARACTER_MAXIMUM_LENGTH"));
|
||||
|
||||
rsch.setColumnType(columnDefinitions.getString("DATA_TYPE"));
|
||||
|
||||
/* look for codes */
|
||||
if (rsch.getColumnType().equalsIgnoreCase("varchar")) addCodesValueIfNecessary(rsch, "_cv");
|
||||
|
||||
if (rsch.getColumnType().equalsIgnoreCase("int")) addCodesValueIfNecessary(rsch, "_cd");
|
||||
|
||||
rsch.setColumnDisplayType();
|
||||
|
||||
columnHeaders.add(rsch);
|
||||
}
|
||||
;
|
||||
return columnHeaders;
|
||||
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addCodesValueIfNecessary(final ResultsetColumnHeader rsch, final String code_suffix) {
|
||||
int codePosition = rsch.getColumnName().indexOf(code_suffix);
|
||||
if (codePosition > 0) {
|
||||
String codeName = rsch.getColumnName().substring(0, codePosition);
|
||||
|
||||
String sql = "select v.id, v.code_value from m_code m " + " join m_code_value v on v.code_id = m.id "
|
||||
+ " where m.code_name = '" + codeName + "' order by v.order_position, v.id";
|
||||
|
||||
CachedRowSet rsValues = genericDataService.getCachedResultSet(sql, "SQL: " + sql);
|
||||
|
||||
try {
|
||||
while (rsValues.next()) {
|
||||
rsch.getColumnValues().add(new ResultsetColumnValue(rsValues.getInt("id"), rsValues.getString("code_value")));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String getAddSql(final List<ResultsetColumnHeader> columnHeaders, final String datatable, final String fkName,
|
||||
private String getAddSql(final List<ResultsetColumnHeaderData> columnHeaders, final String datatable, final String fkName,
|
||||
final Long appTableId, final Map<String, String> queryParams) {
|
||||
|
||||
final Map<String, String> affectedColumns = getAffectedColumns(columnHeaders, queryParams, fkName);
|
||||
@@ -573,8 +498,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.columnName", "Parameter Column Name: " + key + " not found");
|
||||
}
|
||||
|
||||
private Map<String, String> getAffectedColumns(final List<ResultsetColumnHeader> columnHeaders, final Map<String, String> queryParams,
|
||||
final String keyFieldName) {
|
||||
private Map<String, String> getAffectedColumns(final List<ResultsetColumnHeaderData> columnHeaders,
|
||||
final Map<String, String> queryParams, final String keyFieldName) {
|
||||
|
||||
String dateFormat = queryParams.get("dateFormat");
|
||||
Locale clientApplicationLocale = null;
|
||||
@@ -600,7 +525,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
// matches incoming fields with and without underscores (spaces
|
||||
// and underscores considered the same)
|
||||
queryParamColumnUnderscored = genericDataService.replace(key, space, underscore);
|
||||
for (ResultsetColumnHeader columnHeader : columnHeaders) {
|
||||
for (ResultsetColumnHeaderData columnHeader : columnHeaders) {
|
||||
if (notFound) {
|
||||
columnHeaderUnderscored = genericDataService.replace(columnHeader.getColumnName(), space, underscore);
|
||||
if (queryParamColumnUnderscored.equalsIgnoreCase(columnHeaderUnderscored)) {
|
||||
@@ -618,74 +543,84 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
|
||||
return affectedColumns;
|
||||
}
|
||||
|
||||
private String validateColumn(final ResultsetColumnHeader columnHeader, final String pValue, final String dateFormat,
|
||||
private String validateColumn(final ResultsetColumnHeaderData columnHeader, final String pValue, final String dateFormat,
|
||||
final Locale clientApplicationLocale) {
|
||||
|
||||
String paramValue = pValue;
|
||||
if ((columnHeader.getColumnDisplayType().equals("DATE")) || (columnHeader.getColumnDisplayType().equals("INTEGER"))
|
||||
|| (columnHeader.getColumnDisplayType().equals("DECIMAL"))) paramValue = paramValue.trim();
|
||||
if (columnHeader.isDateDisplayType() || columnHeader.isIntegerDisplayType() || columnHeader.isDecimalDisplayType()) {
|
||||
paramValue = paramValue.trim();
|
||||
}
|
||||
|
||||
if ((StringUtils.isEmpty(paramValue)) && (!(columnHeader.isColumnNullable()))) {
|
||||
if (StringUtils.isEmpty(paramValue) && columnHeader.isMandatory()) {
|
||||
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
ApiParameterError error = ApiParameterError.parameterError("error.msg.column.mandatory", "Mandatory",
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.column.mandatory", "Mandatory",
|
||||
columnHeader.getColumnName());
|
||||
dataValidationErrors.add(error);
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
|
||||
if (!StringUtils.isEmpty(paramValue)) {
|
||||
if (StringUtils.isNotEmpty(paramValue)) {
|
||||
|
||||
if (columnHeader.getColumnValues().size() > 0) {
|
||||
// match code value or id
|
||||
List<ResultsetColumnValue> allowedValues = columnHeader.getColumnValues();
|
||||
if (columnHeader.getColumnDisplayType().equals("CODEVALUE")) {
|
||||
for (ResultsetColumnValue allowedValue : allowedValues) {
|
||||
if (paramValue.equalsIgnoreCase(allowedValue.getValue())) return paramValue;
|
||||
if (columnHeader.hasColumnValues()) {
|
||||
if (columnHeader.isCodeValueDisplayType()) {
|
||||
|
||||
if (columnHeader.isColumnValueNotAllowed(paramValue)) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue",
|
||||
"Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue);
|
||||
dataValidationErrors.add(error);
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue",
|
||||
"Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue);
|
||||
dataValidationErrors.add(error);
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
|
||||
if (columnHeader.getColumnDisplayType().equals("CODELOOKUP")) {
|
||||
for (ResultsetColumnValue allowedValue : allowedValues) {
|
||||
if (paramValue.equals(Integer.toString(allowedValue.getId()))) return paramValue;
|
||||
return paramValue;
|
||||
} else if (columnHeader.isCodeLookupDisplayType()) {
|
||||
|
||||
final Integer codeLookup = Integer.valueOf(paramValue);
|
||||
if (columnHeader.isColumnCodeNotAllowed(codeLookup)) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
final ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue",
|
||||
"Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue);
|
||||
dataValidationErrors.add(error);
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
|
||||
ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue",
|
||||
"Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue);
|
||||
dataValidationErrors.add(error);
|
||||
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
|
||||
dataValidationErrors);
|
||||
}
|
||||
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.columnType.", "Code: " + columnHeader.getColumnName()
|
||||
+ " - Invalid Type " + columnHeader.getColumnType() + " (neither varchar nor int)");
|
||||
return paramValue;
|
||||
} else {
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.columnType.", "Code: " + columnHeader.getColumnName()
|
||||
+ " - Invalid Type " + columnHeader.getColumnType() + " (neither varchar nor int)");
|
||||
}
|
||||
}
|
||||
|
||||
JsonParserHelper helper = new JsonParserHelper();
|
||||
|
||||
if (columnHeader.getColumnDisplayType().equals("DATE")) {
|
||||
LocalDate tmpDate = helper.convertFrom(paramValue, columnHeader.getColumnName(), dateFormat, clientApplicationLocale);
|
||||
if (tmpDate == null) return null;
|
||||
return tmpDate.toString();
|
||||
if (columnHeader.isDateDisplayType()) {
|
||||
final LocalDate tmpDate = helper.convertFrom(paramValue, columnHeader.getColumnName(), dateFormat, clientApplicationLocale);
|
||||
if (tmpDate == null) {
|
||||
paramValue = null;
|
||||
} else {
|
||||
paramValue = tmpDate.toString();
|
||||
}
|
||||
}
|
||||
if (columnHeader.getColumnDisplayType().equals("INTEGER")) {
|
||||
|
||||
if (columnHeader.isIntegerDisplayType()) {
|
||||
Integer tmpInt = helper.convertToInteger(paramValue, columnHeader.getColumnName(), clientApplicationLocale);
|
||||
if (tmpInt == null) return null;
|
||||
return tmpInt.toString();
|
||||
}
|
||||
if (columnHeader.getColumnDisplayType().equals("DECIMAL")) {
|
||||
BigDecimal tmpDecimal = helper.convertFrom(paramValue, columnHeader.getColumnName(), clientApplicationLocale);
|
||||
if (tmpDecimal == null) return null;
|
||||
return tmpDecimal.toString();
|
||||
if (tmpInt == null) {
|
||||
paramValue = null;
|
||||
} else {
|
||||
paramValue = tmpInt.toString();
|
||||
}
|
||||
}
|
||||
|
||||
if (columnHeader.isDecimalDisplayType()) {
|
||||
BigDecimal tmpDecimal = helper.convertFrom(paramValue, columnHeader.getColumnName(), clientApplicationLocale);
|
||||
if (tmpDecimal == null) {
|
||||
paramValue = null;
|
||||
} else {
|
||||
paramValue = tmpDecimal.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return paramValue;
|
||||
|
||||
Reference in New Issue
Block a user