MIFOSX-237: use of jdbcTemplate and SqlRowSet along with refactoring as a result of these changes.

This commit is contained in:
Keith Woodlock
2013-03-11 13:54:57 +00:00
parent d310d4df3c
commit be011529de
16 changed files with 1159 additions and 1220 deletions
@@ -17,12 +17,14 @@ import javax.xml.bind.annotation.XmlElementWrapper;
public class ApiGlobalErrorResponse { public class ApiGlobalErrorResponse {
/** /**
* A developer friendly plain English description of why the HTTP error response was returned from the API. * A developer friendly plain English description of why the HTTP error
* response was returned from the API.
*/ */
private String developerMessage; private String developerMessage;
/** /**
* A link to a URL which provides more information on the details of this type of error. * A link to a URL which provides more information on the details of this
* type of error.
*/ */
private String developerDocLink; private String developerDocLink;
@@ -32,17 +34,21 @@ public class ApiGlobalErrorResponse {
private String httpStatusCode; 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. * 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; private String defaultUserMessage;
/** /**
* A code that can be used for globalisation support by client applications of the API. * A code that can be used for globalisation support by client applications
* of the API.
*/ */
private String userMessageGlobalisationCode; 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. * 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>(); private List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
@@ -70,22 +76,24 @@ public class ApiGlobalErrorResponse {
return globalErrorResponse; return globalErrorResponse;
} }
public static ApiGlobalErrorResponse unAuthorized() { public static ApiGlobalErrorResponse unAuthorized(final String defaultUserMessage) {
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse(); ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
globalErrorResponse.setHttpStatusCode("403"); globalErrorResponse.setHttpStatusCode("403");
globalErrorResponse.setDeveloperMessage("The user associated with credentials passed on this request does not have sufficient privileges to perform this action."); 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.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authorized"); globalErrorResponse.setUserMessageGlobalisationCode("error.msg.not.authorized");
globalErrorResponse.setDefaultUserMessage("Insufficient privileges to perform this action."); globalErrorResponse.setDefaultUserMessage("Insufficient privileges to perform this action.");
List<ApiParameterError> errors = new ArrayList<ApiParameterError>(); List<ApiParameterError> errors = new ArrayList<ApiParameterError>();
errors.add(ApiParameterError.generalError("error.msg.not.authorized", "Insufficient privileges to perform this action.")); errors.add(ApiParameterError.generalError("error.msg.not.authorized", defaultUserMessage));
globalErrorResponse.setErrors(errors); globalErrorResponse.setErrors(errors);
return globalErrorResponse; return globalErrorResponse;
} }
public static ApiGlobalErrorResponse domainRuleViolation(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) { public static ApiGlobalErrorResponse domainRuleViolation(final String globalisationMessageCode, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse(); ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
globalErrorResponse.setHttpStatusCode("403"); globalErrorResponse.setHttpStatusCode("403");
globalErrorResponse.setDeveloperMessage("Request was understood but caused a domain rule violation."); globalErrorResponse.setDeveloperMessage("Request was understood but caused a domain rule violation.");
@@ -100,8 +108,8 @@ public class ApiGlobalErrorResponse {
return globalErrorResponse; return globalErrorResponse;
} }
public static ApiGlobalErrorResponse notFound(final String globalisationMessageCode, final String defaultUserMessage,
public static ApiGlobalErrorResponse notFound(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) { final Object... defaultUserMessageArgs) {
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse(); ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
globalErrorResponse.setHttpStatusCode("404"); globalErrorResponse.setHttpStatusCode("404");
@@ -117,7 +125,8 @@ public class ApiGlobalErrorResponse {
return globalErrorResponse; return globalErrorResponse;
} }
public static ApiGlobalErrorResponse dataIntegrityError(final String globalisationMessageCode, final String defaultUserMessage, final String parameterName, final Object... defaultUserMessageArgs) { public static ApiGlobalErrorResponse dataIntegrityError(final String globalisationMessageCode, final String defaultUserMessage,
final String parameterName, final Object... defaultUserMessageArgs) {
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse(); ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
globalErrorResponse.setHttpStatusCode("403"); globalErrorResponse.setHttpStatusCode("403");
@@ -134,11 +143,12 @@ public class ApiGlobalErrorResponse {
} }
public static ApiGlobalErrorResponse badClientRequest(final String globalisationMessageCode, final String defaultUserMessage, public static ApiGlobalErrorResponse badClientRequest(final String globalisationMessageCode, final String defaultUserMessage,
List<ApiParameterError> errors) { final List<ApiParameterError> errors) {
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse(); ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
globalErrorResponse.setHttpStatusCode("400"); globalErrorResponse.setHttpStatusCode("400");
globalErrorResponse.setDeveloperMessage("The request was invalid. This typically will happen due to validation errors which are provided."); 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.setDeveloperDocLink("https://github.com/keithwoodlock/mifosx/wiki/HTTP-API-Error-codes");
globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode); globalErrorResponse.setUserMessageGlobalisationCode(globalisationMessageCode);
globalErrorResponse.setDefaultUserMessage(defaultUserMessage); globalErrorResponse.setDefaultUserMessage(defaultUserMessage);
@@ -148,7 +158,8 @@ public class ApiGlobalErrorResponse {
return globalErrorResponse; return globalErrorResponse;
} }
public static ApiGlobalErrorResponse serverSideError(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) { public static ApiGlobalErrorResponse serverSideError(final String globalisationMessageCode, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse(); ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
globalErrorResponse.setHttpStatusCode("500"); globalErrorResponse.setHttpStatusCode("500");
@@ -178,7 +189,7 @@ public class ApiGlobalErrorResponse {
return errors; return errors;
} }
public void setErrors(List<ApiParameterError> errors) { public void setErrors(final List<ApiParameterError> errors) {
this.errors = errors; this.errors = errors;
} }
@@ -186,7 +197,7 @@ public class ApiGlobalErrorResponse {
return developerMessage; return developerMessage;
} }
public void setDeveloperMessage(String developerMessage) { public void setDeveloperMessage(final String developerMessage) {
this.developerMessage = developerMessage; this.developerMessage = developerMessage;
} }
@@ -194,7 +205,7 @@ public class ApiGlobalErrorResponse {
return httpStatusCode; return httpStatusCode;
} }
public void setHttpStatusCode(String httpStatusCode) { public void setHttpStatusCode(final String httpStatusCode) {
this.httpStatusCode = httpStatusCode; this.httpStatusCode = httpStatusCode;
} }
@@ -202,7 +213,7 @@ public class ApiGlobalErrorResponse {
return defaultUserMessage; return defaultUserMessage;
} }
public void setDefaultUserMessage(String defaultUserMessage) { public void setDefaultUserMessage(final String defaultUserMessage) {
this.defaultUserMessage = defaultUserMessage; this.defaultUserMessage = defaultUserMessage;
} }
@@ -210,7 +221,7 @@ public class ApiGlobalErrorResponse {
return userMessageGlobalisationCode; return userMessageGlobalisationCode;
} }
public void setUserMessageGlobalisationCode(String userMessageGlobalisationCode) { public void setUserMessageGlobalisationCode(final String userMessageGlobalisationCode) {
this.userMessageGlobalisationCode = userMessageGlobalisationCode; this.userMessageGlobalisationCode = userMessageGlobalisationCode;
} }
@@ -218,7 +229,7 @@ public class ApiGlobalErrorResponse {
return developerDocLink; return developerDocLink;
} }
public void setDeveloperDocLink(String developerDocLink) { public void setDeveloperDocLink(final String developerDocLink) {
this.developerDocLink = developerDocLink; this.developerDocLink = developerDocLink;
} }
} }
@@ -30,9 +30,11 @@ import org.springframework.stereotype.Component;
public class AccessDeniedExceptionMapper implements ExceptionMapper<AccessDeniedException> { public class AccessDeniedExceptionMapper implements ExceptionMapper<AccessDeniedException> {
@Override @Override
public Response toResponse(@SuppressWarnings("unused") AccessDeniedException exception) { public Response toResponse(final AccessDeniedException exception) {
// Status code 403 really reads as: // Status code 403 really reads as:
// "Authenticated - but not authorized": // "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();
} }
} }
@@ -29,9 +29,11 @@ import org.springframework.stereotype.Component;
public class NoAuthorizationExceptionMapper implements ExceptionMapper<NoAuthorizationException> { public class NoAuthorizationExceptionMapper implements ExceptionMapper<NoAuthorizationException> {
@Override @Override
public Response toResponse(@SuppressWarnings("unused") NoAuthorizationException exception) { public Response toResponse(final NoAuthorizationException exception) {
// Status code 403 really reads as: // Status code 403 really reads as:
// "Authenticated - but not authorized": // "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();
} }
} }
@@ -386,6 +386,7 @@ public class JsonParserHelper {
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer.format", "The parameter " ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer.format", "The parameter "
+ parameterName + " has value: " + numericalValueFormatted + " which is invalid integer value for provided locale of [" + parameterName + " has value: " + numericalValueFormatted + " which is invalid integer value for provided locale of ["
+ clientApplicationLocale.toString() + "].", parameterName, numericalValueFormatted, clientApplicationLocale); + clientApplicationLocale.toString() + "].", parameterName, numericalValueFormatted, clientApplicationLocale);
error.setValue(numericalValueFormatted);
dataValidationErrors.add(error); dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
@@ -408,6 +409,7 @@ public class JsonParserHelper {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer", "The parameter " + parameterName ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.integer", "The parameter " + parameterName
+ " has value: " + numericalValueFormatted + " which is invalid integer.", parameterName, numericalValueFormatted); + " has value: " + numericalValueFormatted + " which is invalid integer.", parameterName, numericalValueFormatted);
error.setValue(numericalValueFormatted);
dataValidationErrors.add(error); dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", 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 " ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.decimal.format", "The parameter "
+ parameterName + " has value: " + numericalValueFormatted + " which is invalid decimal value for provided locale of [" + parameterName + " has value: " + numericalValueFormatted + " which is invalid decimal value for provided locale of ["
+ clientApplicationLocale.toString() + "].", parameterName, numericalValueFormatted, clientApplicationLocale); + clientApplicationLocale.toString() + "].", parameterName, numericalValueFormatted, clientApplicationLocale);
error.setValue(numericalValueFormatted);
dataValidationErrors.add(error); dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
@@ -53,6 +53,7 @@ public class ReportsApiResource {
this.genericDataService = genericDataService; this.genericDataService = genericDataService;
this.toApiJsonSerializer = toApiJsonSerializer; this.toApiJsonSerializer = toApiJsonSerializer;
} }
@GET @GET
@Consumes({ MediaType.APPLICATION_JSON }) @Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON, "application/x-msdownload" }) @Produces({ MediaType.APPLICATION_JSON, "application/x-msdownload" })
@@ -160,15 +161,10 @@ public class ReportsApiResource {
// Anyone can run a 'report' that is simply getting possible parameter // Anyone can run a 'report' that is simply getting possible parameter
// (dropdown listbox) values. // (dropdown listbox) values.
if (!parameterType) { if (!parameterType) {
AppUser currentUser = context.authenticatedUser(); AppUser currentUser = context.authenticatedUser();
if (currentUser.hasNotPermissionForReport(reportName)) { if (currentUser.hasNotPermissionForReport(reportName)) { throw new NoAuthorizationException("Not authorised to run report: "
// FIXME - JW - message isnt passing back the message in the + reportName); }
// string in
// the json just a generalised not authorised message
throw new NoAuthorizationException("Not Authorised to Run Report: " + reportName);
}
} }
} }
@@ -15,7 +15,11 @@ public class DatatableData {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private final String registeredTableName; 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.applicationTableName = applicationTableName;
this.registeredTableName = registeredTableName; this.registeredTableName = registeredTableName;
} }
@@ -13,19 +13,19 @@ import java.util.List;
*/ */
public class GenericResultsetData { public class GenericResultsetData {
private final List<ResultsetColumnHeader> columnHeaders; private final List<ResultsetColumnHeaderData> columnHeaders;
private final List<ResultsetDataRow> data; 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.columnHeaders = columnHeaders;
this.data = resultsetDataRows; this.data = resultsetDataRows;
} }
public List<ResultsetColumnHeader> getColumnHeaders() { public List<ResultsetColumnHeaderData> getColumnHeaders() {
return columnHeaders; return columnHeaders;
} }
public List<ResultsetDataRow> getData() { public List<ResultsetRowData> getData() {
return data; return data;
} }
} }
@@ -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());
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -5,22 +5,21 @@
*/ */
package org.mifosplatform.infrastructure.dataqueries.data; package org.mifosplatform.infrastructure.dataqueries.data;
import java.util.ArrayList;
import java.util.List; 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() { public List<String> getRow() {
return row; return row;
} }
public void setRow(List<String> row) {
this.row = row;
}
} }
@@ -5,16 +5,13 @@
*/ */
package org.mifosplatform.infrastructure.dataqueries.service; 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.GenericResultsetData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
public interface GenericDataService { public interface GenericDataService {
CachedRowSet getCachedResultSet(String sql, String errorMsg);
void updateSQL(String sql, String sqlErrorMsg);
GenericResultsetData fillGenericResultSet(final String sql); GenericResultsetData fillGenericResultSet(final String sql);
String generateJsonFromGenericResultsetData(GenericResultsetData grs); String generateJsonFromGenericResultsetData(GenericResultsetData grs);
@@ -25,4 +22,5 @@ public interface GenericDataService {
String getDatabaseName(); String getDatabaseName();
List<ResultsetColumnHeaderData> fillResultsetColumnHeaders(String datatable);
} }
@@ -5,128 +5,70 @@
*/ */
package org.mifosplatform.infrastructure.dataqueries.service; 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.SQLException;
import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.sql.DataSource; import javax.sql.DataSource;
import javax.sql.rowset.CachedRowSet;
import org.joda.time.LocalDate; import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader; import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow; 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.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 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 @Service
public class GenericDataServiceImpl implements GenericDataService { public class GenericDataServiceImpl implements GenericDataService {
private final JdbcTemplate jdbcTemplate;
private final DataSource dataSource; private final DataSource dataSource;
@Autowired @Autowired
public GenericDataServiceImpl(final TenantAwareRoutingDataSource dataSource) { public GenericDataServiceImpl(final TenantAwareRoutingDataSource dataSource) {
this.dataSource = dataSource; this.dataSource = dataSource;
} this.jdbcTemplate = new JdbcTemplate(this.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);
} }
@Override @Override
public GenericResultsetData fillGenericResultSet(final String sql) { public GenericResultsetData fillGenericResultSet(final String sql) {
String sqlErrorMsg = "Sql: " + sql; final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
CachedRowSet rs = getCachedResultSet(sql, sqlErrorMsg);
List<ResultsetColumnHeader> columnHeaders = new ArrayList<ResultsetColumnHeader>(); final List<ResultsetColumnHeaderData> columnHeaders = new ArrayList<ResultsetColumnHeaderData>();
List<ResultsetDataRow> resultsetDataRows = new ArrayList<ResultsetDataRow>(); 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++) { for (int i = 0; i < rsmd.getColumnCount(); i++) {
ResultsetColumnHeader rsch = new ResultsetColumnHeader();
rsch.setColumnName(rsmd.getColumnName(i + 1)); final String columnName = rsmd.getColumnName(i + 1);
rsch.setColumnType(rsmd.getColumnTypeName(i + 1)); final String columnType = rsmd.getColumnTypeName(i + 1);
columnHeaders.add(rsch);
final ResultsetColumnHeaderData columnHeader = ResultsetColumnHeaderData.basic(columnName, columnType);
columnHeaders.add(columnHeader);
} }
ResultsetDataRow resultsetDataRow;
while (rs.next()) { while (rs.next()) {
resultsetDataRow = new ResultsetDataRow(); final List<String> columnValues = new ArrayList<String>();
List<String> columnValues = new ArrayList<String>();
for (int i = 0; i < rsmd.getColumnCount(); i++) { for (int i = 0; i < rsmd.getColumnCount(); i++) {
columnName = rsmd.getColumnName(i + 1); final String columnName = rsmd.getColumnName(i + 1);
columnValue = rs.getString(columnName); final String columnValue = rs.getString(columnName);
columnValues.add(columnValue); columnValues.add(columnValue);
} }
resultsetDataRow.setRow(columnValues);
final ResultsetRowData resultsetDataRow = ResultsetRowData.create(columnValues);
resultsetDataRows.add(resultsetDataRow); resultsetDataRows.add(resultsetDataRow);
} }
return new GenericResultsetData(columnHeaders, resultsetDataRows); return new GenericResultsetData(columnHeaders, resultsetDataRows);
} catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
}
} }
@Override @Override
@@ -165,17 +107,16 @@ public class GenericDataServiceImpl implements GenericDataService {
writer.append("["); writer.append("[");
List<ResultsetColumnHeader> columnHeaders = grs.getColumnHeaders(); final List<ResultsetColumnHeaderData> columnHeaders = grs.getColumnHeaders();
// logger.info("NO. of Columns: " + columnHeaders.size());
List<ResultsetDataRow> data = grs.getData(); List<ResultsetRowData> data = grs.getData();
List<String> row; List<String> row;
Integer rSize; Integer rSize;
String doubleQuote = "\""; String doubleQuote = "\"";
String slashDoubleQuote = "\\\""; String slashDoubleQuote = "\\\"";
String currColType; String currColType;
String currVal; String currVal;
// logger.info("NO. of Rows: " + data.size());
for (int i = 0; i < data.size(); i++) { for (int i = 0; i < data.size(); i++) {
writer.append("\n{"); writer.append("\n{");
@@ -217,8 +158,7 @@ public class GenericDataServiceImpl implements GenericDataService {
if (i < (data.size() - 1)) { if (i < (data.size() - 1)) {
writer.append("},"); writer.append("},");
} } else {
else {
writer.append("}"); writer.append("}");
} }
} }
@@ -228,24 +168,6 @@ public class GenericDataServiceImpl implements GenericDataService {
} }
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 @Override
public String getDatabaseName() { public String getDatabaseName() {
try { try {
@@ -254,4 +176,79 @@ public class GenericDataServiceImpl implements GenericDataService {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), "Error Accessing Database Name"); 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);
}
} }
@@ -13,13 +13,11 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.sql.Date; import java.sql.Date;
import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.sql.DataSource; import javax.sql.DataSource;
import javax.sql.rowset.CachedRowSet;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput; 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.FileUtils;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader; import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow; import org.mifosplatform.infrastructure.dataqueries.data.ResultsetRowData;
import org.mifosplatform.infrastructure.dataqueries.exception.ReportNotFoundException; import org.mifosplatform.infrastructure.dataqueries.exception.ReportNotFoundException;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
@@ -49,6 +47,8 @@ import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; 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 org.springframework.stereotype.Service;
import com.lowagie.text.Document; import com.lowagie.text.Document;
@@ -59,31 +59,29 @@ import com.lowagie.text.pdf.PdfWriter;
@Service @Service
public class ReadReportingServiceImpl implements ReadReportingService { public class ReadReportingServiceImpl implements ReadReportingService {
private final static Logger logger = LoggerFactory.getLogger(ReadReportingServiceImpl.class);
private final JdbcTemplate jdbcTemplate;
private final DataSource dataSource; private final DataSource dataSource;
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final GenericDataService genericDataService;
private final static Logger logger = LoggerFactory private boolean noPentaho = false;
.getLogger(ReadReportingServiceImpl.class);
private Boolean noPentaho = false;
@Autowired @Autowired
public ReadReportingServiceImpl(final PlatformSecurityContext context, public ReadReportingServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource,
final TenantAwareRoutingDataSource dataSource) { final GenericDataService genericDataService) {
// kick off pentaho reports server // kick off pentaho reports server
ClassicEngineBoot.getInstance().start(); ClassicEngineBoot.getInstance().start();
noPentaho = false; noPentaho = false;
this.context = context; this.context = context;
this.dataSource = dataSource; this.dataSource = dataSource;
this.jdbcTemplate = new JdbcTemplate(this.dataSource);
this.genericDataService = genericDataService;
} }
@Autowired
private GenericDataService genericDataService;
@Override @Override
public StreamingOutput retrieveReportCSV(final String name, public StreamingOutput retrieveReportCSV(final String name, final String type, final Map<String, String> queryParams) {
final String type, final Map<String, String> queryParams) {
return new StreamingOutput() { return new StreamingOutput() {
@@ -91,12 +89,10 @@ public class ReadReportingServiceImpl implements ReadReportingService {
public void write(final OutputStream out) { public void write(final OutputStream out) {
try { try {
GenericResultsetData result = retrieveGenericResultset( GenericResultsetData result = retrieveGenericResultset(name, type, queryParams);
name, type, queryParams);
StringBuffer sb = generateCsvFileBuffer(result); StringBuffer sb = generateCsvFileBuffer(result);
InputStream in = new ByteArrayInputStream(sb.toString() InputStream in = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
.getBytes("UTF-8"));
byte[] outputByte = new byte[4096]; byte[] outputByte = new byte[4096];
Integer readLen = in.read(outputByte, 0, 4096); Integer readLen = in.read(outputByte, 0, 4096);
@@ -109,8 +105,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
// out.flush(); // out.flush();
// out.close(); // out.close();
} catch (Exception e) { } catch (Exception e) {
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException("error.msg.exception.error", e.getMessage());
"error.msg.exception.error", e.getMessage());
} }
} }
}; };
@@ -120,17 +115,16 @@ public class ReadReportingServiceImpl implements ReadReportingService {
private StringBuffer generateCsvFileBuffer(final GenericResultsetData result) { private StringBuffer generateCsvFileBuffer(final GenericResultsetData result) {
StringBuffer writer = new StringBuffer(); StringBuffer writer = new StringBuffer();
List<ResultsetColumnHeader> columnHeaders = result.getColumnHeaders(); List<ResultsetColumnHeaderData> columnHeaders = result.getColumnHeaders();
logger.info("NO. of Columns: " + columnHeaders.size()); logger.info("NO. of Columns: " + columnHeaders.size());
Integer chSize = columnHeaders.size(); Integer chSize = columnHeaders.size();
for (int i = 0; i < chSize; i++) { for (int i = 0; i < chSize; i++) {
writer.append('"' + columnHeaders.get(i).getColumnName() + '"'); writer.append('"' + columnHeaders.get(i).getColumnName() + '"');
if (i < (chSize - 1)) if (i < (chSize - 1)) writer.append(",");
writer.append(",");
} }
writer.append('\n'); writer.append('\n');
List<ResultsetDataRow> data = result.getData(); List<ResultsetRowData> data = result.getData();
List<String> row; List<String> row;
Integer rSize; Integer rSize;
// String currCol; // String currCol;
@@ -147,19 +141,14 @@ public class ReadReportingServiceImpl implements ReadReportingService {
currColType = columnHeaders.get(j).getColumnType(); currColType = columnHeaders.get(j).getColumnType();
currVal = row.get(j); currVal = row.get(j);
if (currVal != null) { if (currVal != null) {
if (currColType.equals("DECIMAL") if (currColType.equals("DECIMAL") || currColType.equals("DOUBLE") || currColType.equals("BIGINT")
|| currColType.equals("DOUBLE") || currColType.equals("SMALLINT") || currColType.equals("INT"))
|| currColType.equals("BIGINT")
|| currColType.equals("SMALLINT")
|| currColType.equals("INT"))
writer.append(currVal); writer.append(currVal);
else else
writer.append('"' + genericDataService.replace(currVal, writer.append('"' + genericDataService.replace(currVal, doubleQuote, twoDoubleQuotes) + '"');
doubleQuote, twoDoubleQuotes) + '"');
} }
if (j < (rSize - 1)) if (j < (rSize - 1)) writer.append(",");
writer.append(",");
} }
writer.append('\n'); writer.append('\n');
} }
@@ -168,8 +157,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
} }
@Override @Override
public GenericResultsetData retrieveGenericResultset(final String name, public GenericResultsetData retrieveGenericResultset(final String name, final String type, final Map<String, String> queryParams) {
final String type, final Map<String, String> queryParams) {
long startTime = System.currentTimeMillis(); long startTime = System.currentTimeMillis();
logger.info("STARTING REPORT: " + name + " Type: " + type); logger.info("STARTING REPORT: " + name + " Type: " + type);
@@ -181,35 +169,26 @@ public class ReadReportingServiceImpl implements ReadReportingService {
// need to provide an api that does bring back 'permitted' reports // need to provide an api that does bring back 'permitted' reports
// PERMITTED REPORTS SQL // PERMITTED REPORTS SQL
sql = "select r.report_id, r.report_name, r.report_type, r.report_subtype, r.report_category," 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" + " rp.parameter_id, rp.report_parameter_name, p.parameter_name" + " from stretchy_report r"
+ " from stretchy_report r"
+ " left join stretchy_report_parameter rp on rp.report_id = r.report_id" + " 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" + " left join stretchy_parameter p on p.parameter_id = rp.parameter_id" + " where exists" + " (select 'f'"
+ " where exists" + " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id"
+ " (select 'f'" + " left join m_role_permission rp on rp.role_id = r.id" + " left join m_permission p on p.id = rp.permission_id"
+ " from m_appuser_role ur " + " where ur.appuser_id = " + context.authenticatedUser().getId()
+ " 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))) " + " 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"; + " order by r.report_name, rp.parameter_id";
} else { } else {
sql = getSQLtoRun(name, type, queryParams); sql = getSQLtoRun(name, type, queryParams);
} }
GenericResultsetData result = genericDataService GenericResultsetData result = genericDataService.fillGenericResultSet(sql);
.fillGenericResultSet(sql);
long elapsed = System.currentTimeMillis() - startTime; long elapsed = System.currentTimeMillis() - startTime;
logger.info("FINISHING Report/Request Name: " + name + " - " + type logger.info("FINISHING Report/Request Name: " + name + " - " + type + " Elapsed Time: " + elapsed);
+ " Elapsed Time: " + elapsed);
return result; return result;
} }
private String getSQLtoRun(final String name, final String type, private String getSQLtoRun(final String name, final String type, final Map<String, String> queryParams) {
final Map<String, String> queryParams) {
String sql = getSql(name, type); String sql = getSql(name, type);
@@ -222,13 +201,11 @@ public class ReadReportingServiceImpl implements ReadReportingService {
AppUser currentUser = context.authenticatedUser(); AppUser currentUser = context.authenticatedUser();
// Allows sql query to restrict data by office hierarchy if required // Allows sql query to restrict data by office hierarchy if required
sql = genericDataService.replace(sql, "${currentUserHierarchy}", sql = genericDataService.replace(sql, "${currentUserHierarchy}", currentUser.getOffice().getHierarchy());
currentUser.getOffice().getHierarchy());
// Allows sql query to restrict data by current user Id if required // Allows sql query to restrict data by current user Id if required
// (typically used to return report lists containing only reports // (typically used to return report lists containing only reports
// permitted to be run by the user // permitted to be run by the user
sql = genericDataService.replace(sql, "${currentUserId}", currentUser sql = genericDataService.replace(sql, "${currentUserId}", currentUser.getId().toString());
.getId().toString());
sql = genericDataService.wrapSQL(sql); sql = genericDataService.wrapSQL(sql);
@@ -238,85 +215,52 @@ public class ReadReportingServiceImpl implements ReadReportingService {
private String getSql(final String name, final String type) { private String getSql(final String name, final String type) {
String inputSql = "select " + type + "_sql as the_sql from stretchy_" final String inputSql = "select " + type + "_sql as the_sql from stretchy_" + type + " where " + type + "_name = '" + name + "'";
+ type + " where " + type + "_name = '" + name + "'"; final String inputSqlWrapped = genericDataService.wrapSQL(inputSql);
inputSql = genericDataService.wrapSQL(inputSql);
String sqlErrorMsg = "Sql: " + inputSql; final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(inputSqlWrapped);
CachedRowSet rs = genericDataService.getCachedResultSet(inputSql,
sqlErrorMsg);
try { if (rs.next()) { return rs.getString("the_sql"); }
if (rs.next()) {
return rs.getString("the_sql");
}
throw new ReportNotFoundException(inputSql); 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 @Override
public String getReportType(final String reportName) { 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); final String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '" + reportName + "'";
String sqlErrorMsg = "Report Name: " + reportName + " Sql: " + sql; final String sqlWrapped = genericDataService.wrapSQL(sql);
CachedRowSet rs = genericDataService.getCachedResultSet(sql,
sqlErrorMsg);
try { final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sqlWrapped);
if (rs.next()) { if (rs.next()) { return rs.getString("report_type"); }
return rs.getString("report_type");
}
throw new ReportNotFoundException(sql); throw new ReportNotFoundException(sql);
} catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error",
e.getMessage(), sqlErrorMsg);
}
} }
@Override @Override
public Response processPentahoRequest(final String reportName, public Response processPentahoRequest(final String reportName, final String outputTypeParam, final Map<String, String> queryParams) {
final String outputTypeParam, final Map<String, String> queryParams) {
String outputType = "HTML"; String outputType = "HTML";
if (StringUtils.isNotBlank(outputTypeParam)) if (StringUtils.isNotBlank(outputTypeParam)) outputType = outputTypeParam;
outputType = outputTypeParam;
if (!(outputType.equalsIgnoreCase("HTML") if (!(outputType.equalsIgnoreCase("HTML") || outputType.equalsIgnoreCase("PDF") || outputType.equalsIgnoreCase("XLS") || outputType
|| outputType.equalsIgnoreCase("PDF")
|| outputType.equalsIgnoreCase("XLS") || outputType
.equalsIgnoreCase("CSV"))) .equalsIgnoreCase("CSV")))
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType);
"error.msg.invalid.outputType", "No matching Output Type: "
+ outputType);
if (noPentaho) if (noPentaho) { throw new PlatformDataIntegrityException("error.msg.no.pentaho", "Pentaho is not enabled",
throw new PlatformDataIntegrityException("error.msg.no.pentaho", "Pentaho is not enabled"); }
"Pentaho is not enabled", "Pentaho is not enabled");
// TODO - JW - use pentaho location finder like Pawel does in Mifos // TODO - JW - use pentaho location finder like Pawel does in Mifos
// String reportPath = // String reportPath =
// "C:\\dev\\apache-tomcat-7.0.25\\webapps\\ROOT\\PentahoReports\\" // "C:\\dev\\apache-tomcat-7.0.25\\webapps\\ROOT\\PentahoReports\\"
// + reportName + ".prpt"; // + reportName + ".prpt";
/*String reportPath = FileUtils.MIFOSX_BASE_DIR /*
+ File.separator * String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator +
+ ThreadLocalContextUtil.getTenant().getName() * ThreadLocalContextUtil.getTenant().getName() .replaceAll(" ",
.replaceAll(" ", "").trim() + File.separator * "").trim() + File.separator + "reports" + File.separator + reportName
+ "reports" + File.separator + reportName + ".prpt";*/ * + ".prpt";
String reportPath = FileUtils.MIFOSX_BASE_DIR */
+ File.separator final String reportPath = FileUtils.MIFOSX_BASE_DIR + File.separator + "reports" + File.separator + reportName + ".prpt";
+ "reports" + File.separator + reportName + ".prpt";
logger.info("Report path: " + reportPath); logger.info("Report path: " + reportPath);
// load report definition // load report definition
@@ -334,58 +278,37 @@ public class ReadReportingServiceImpl implements ReadReportingService {
if ("PDF".equalsIgnoreCase(outputType)) { if ("PDF".equalsIgnoreCase(outputType)) {
PdfReportUtil.createPDF(masterReport, baos); PdfReportUtil.createPDF(masterReport, baos);
return Response.ok().entity(baos.toByteArray()) return Response.ok().entity(baos.toByteArray()).type("application/pdf").build();
.type("application/pdf").build();
} }
if ("XLS".equalsIgnoreCase(outputType)) { if ("XLS".equalsIgnoreCase(outputType)) {
ExcelReportUtil.createXLS(masterReport, baos); ExcelReportUtil.createXLS(masterReport, baos);
return Response return Response.ok().entity(baos.toByteArray()).type("application/vnd.ms-excel")
.ok() .header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".xls").build();
.entity(baos.toByteArray())
.type("application/vnd.ms-excel")
.header("Content-Disposition",
"attachment;filename="
+ reportName.replaceAll(" ", "")
+ ".xls").build();
} }
if ("CSV".equalsIgnoreCase(outputType)) { if ("CSV".equalsIgnoreCase(outputType)) {
CSVReportUtil.createCSV(masterReport, baos, "UTF-8"); CSVReportUtil.createCSV(masterReport, baos, "UTF-8");
return Response return Response.ok().entity(baos.toByteArray()).type("application/x-msdownload")
.ok() .header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".csv").build();
.entity(baos.toByteArray())
.type("application/x-msdownload")
.header("Content-Disposition",
"attachment;filename="
+ reportName.replaceAll(" ", "")
+ ".csv").build();
} }
if ("HTML".equalsIgnoreCase(outputType)) { if ("HTML".equalsIgnoreCase(outputType)) {
HtmlReportUtil.createStreamHTML(masterReport, baos); HtmlReportUtil.createStreamHTML(masterReport, baos);
return Response.ok().entity(baos.toByteArray()) return Response.ok().entity(baos.toByteArray()).type("text/html").build();
.type("text/html").build();
} }
} catch (ResourceException e) { } catch (ResourceException e) {
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
"error.msg.reporting.error", e.getMessage());
} catch (ReportProcessingException e) { } catch (ReportProcessingException e) {
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
"error.msg.reporting.error", e.getMessage());
} catch (IOException e) { } catch (IOException e) {
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
"error.msg.reporting.error", e.getMessage());
} }
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException("error.msg.invalid.outputType", "No matching Output Type: " + outputType);
"error.msg.invalid.outputType", "No matching Output Type: "
+ outputType);
} }
private void addParametersToReport(final MasterReport report, private void addParametersToReport(final MasterReport report, final Map<String, String> queryParams) {
final Map<String, String> queryParams) {
AppUser currentUser = context.authenticatedUser(); AppUser currentUser = context.authenticatedUser();
@@ -393,8 +316,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
logger.info("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); logger.info("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
ReportParameterValues rptParamValues = report.getParameterValues(); ReportParameterValues rptParamValues = report.getParameterValues();
ReportParameterDefinition paramsDefinition = report ReportParameterDefinition paramsDefinition = report.getParameterDefinition();
.getParameterDefinition();
/* /*
* only allow integer, long, date and string parameter types and * only allow integer, long, date and string parameter types and
@@ -403,36 +325,30 @@ public class ReadReportingServiceImpl implements ReadReportingService {
* better... currently assuming they come in ok... and if not an * better... currently assuming they come in ok... and if not an
* error * error
*/ */
for (ParameterDefinitionEntry paramDefEntry : paramsDefinition for (ParameterDefinitionEntry paramDefEntry : paramsDefinition.getParameterDefinitions()) {
.getParameterDefinitions()) {
String paramName = paramDefEntry.getName(); String paramName = paramDefEntry.getName();
if (!((paramName.equals("tenantdb")) || (paramName.equals("userhierarchy")))) { if (!((paramName.equals("tenantdb")) || (paramName.equals("userhierarchy")))) {
logger.info("paramName:" + paramName); logger.info("paramName:" + paramName);
String pValue = queryParams.get(paramName); String pValue = queryParams.get(paramName);
if (StringUtils.isBlank(pValue)) if (StringUtils.isBlank(pValue))
throw new PlatformDataIntegrityException( throw new PlatformDataIntegrityException("error.msg.reporting.error", "Pentaho Parameter: " + paramName
"error.msg.reporting.error",
"Pentaho Parameter: " + paramName
+ " - not Provided"); + " - not Provided");
Class<?> clazz = paramDefEntry.getValueType(); Class<?> clazz = paramDefEntry.getValueType();
logger.info("addParametersToReport(" + paramName + " : " logger.info("addParametersToReport(" + paramName + " : " + pValue + " : " + clazz.getCanonicalName() + ")");
+ pValue + " : " + clazz.getCanonicalName() + ")"); if (clazz.getCanonicalName().equalsIgnoreCase("java.lang.Integer"))
if (clazz.getCanonicalName().equalsIgnoreCase(
"java.lang.Integer"))
rptParamValues.put(paramName, Integer.parseInt(pValue)); rptParamValues.put(paramName, Integer.parseInt(pValue));
else if (clazz.getCanonicalName().equalsIgnoreCase( else if (clazz.getCanonicalName().equalsIgnoreCase("java.lang.Long"))
"java.lang.Long"))
rptParamValues.put(paramName, Long.parseLong(pValue)); rptParamValues.put(paramName, Long.parseLong(pValue));
else if (clazz.getCanonicalName().equalsIgnoreCase( else if (clazz.getCanonicalName().equalsIgnoreCase("java.sql.Date"))
"java.sql.Date"))
rptParamValues.put(paramName, Date.valueOf(pValue)); rptParamValues.put(paramName, Date.valueOf(pValue));
else else
rptParamValues.put(paramName, pValue); rptParamValues.put(paramName, pValue);
} }
// tenant database name and current user's office hierarchy // tenant database name and current user's office hierarchy
// passed as parameters to allow multitenant penaho reporting and // passed as parameters to allow multitenant penaho reporting
// and
// data scoping // data scoping
String tenantdb = dataSource.getConnection().getCatalog(); String tenantdb = dataSource.getConnection().getCatalog();
String userhierarchy = currentUser.getOffice().getHierarchy(); String userhierarchy = currentUser.getOffice().getHierarchy();
@@ -442,32 +358,26 @@ public class ReadReportingServiceImpl implements ReadReportingService {
} }
} catch (Exception e) { } catch (Exception e) {
logger.error("error.msg.reporting.error:" + e.getMessage());
logger.info("error.msg.reporting.error:" + e.getMessage()); throw new PlatformDataIntegrityException("error.msg.reporting.error", e.getMessage());
throw new PlatformDataIntegrityException(
"error.msg.reporting.error", e.getMessage());
} }
} }
@Override @Override
public String retrieveReportPDF(final String reportName, final String type, public String retrieveReportPDF(final String reportName, final String type, final Map<String, String> queryParams) {
final Map<String, String> queryParams) {
String fileLocation = FileUtils.MIFOSX_BASE_DIR + File.separator + ""; String fileLocation = FileUtils.MIFOSX_BASE_DIR + File.separator + "";
if (!new File(fileLocation).isDirectory()) { if (!new File(fileLocation).isDirectory()) {
new File(fileLocation).mkdirs(); new File(fileLocation).mkdirs();
} }
String genaratePdf = fileLocation + File.separator + reportName String genaratePdf = fileLocation + File.separator + reportName + ".pdf";
+ ".pdf";
try { try {
GenericResultsetData result = retrieveGenericResultset(reportName, GenericResultsetData result = retrieveGenericResultset(reportName, type, queryParams);
type, queryParams);
List<ResultsetColumnHeader> columnHeaders = result List<ResultsetColumnHeaderData> columnHeaders = result.getColumnHeaders();
.getColumnHeaders(); List<ResultsetRowData> data = result.getData();
List<ResultsetDataRow> data = result.getData();
List<String> row; List<String> row;
logger.info("NO. of Columns: " + columnHeaders.size()); logger.info("NO. of Columns: " + columnHeaders.size());
@@ -475,8 +385,7 @@ public class ReadReportingServiceImpl implements ReadReportingService {
Document document = new Document(PageSize.B0.rotate()); Document document = new Document(PageSize.B0.rotate());
PdfWriter.getInstance(document, new FileOutputStream(new File( PdfWriter.getInstance(document, new FileOutputStream(new File(fileLocation + reportName + ".pdf")));
fileLocation + reportName + ".pdf")));
document.open(); document.open();
PdfPTable table = new PdfPTable(chSize); PdfPTable table = new PdfPTable(chSize);
@@ -500,11 +409,8 @@ public class ReadReportingServiceImpl implements ReadReportingService {
currColType = columnHeaders.get(j).getColumnType(); currColType = columnHeaders.get(j).getColumnType();
currVal = row.get(j); currVal = row.get(j);
if (currVal != null) { if (currVal != null) {
if (currColType.equals("DECIMAL") if (currColType.equals("DECIMAL") || currColType.equals("DOUBLE") || currColType.equals("BIGINT")
|| currColType.equals("DOUBLE") || currColType.equals("SMALLINT") || currColType.equals("INT")) {
|| currColType.equals("BIGINT")
|| currColType.equals("SMALLINT")
|| currColType.equals("INT")) {
table.addCell(currVal.toString()); table.addCell(currVal.toString());
} else { } else {
@@ -518,8 +424,8 @@ public class ReadReportingServiceImpl implements ReadReportingService {
document.close(); document.close();
return genaratePdf; return genaratePdf;
} catch (Exception e) { } catch (Exception e) {
throw new PlatformDataIntegrityException( logger.error("error.msg.reporting.error:" + e.getMessage());
"error.msg.exception.error", e.getMessage()); throw new PlatformDataIntegrityException("error.msg.exception.error", e.getMessage());
} }
} }
} }
@@ -7,8 +7,6 @@ package org.mifosplatform.infrastructure.dataqueries.service;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -16,7 +14,7 @@ import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.sql.rowset.CachedRowSet; import javax.sql.DataSource;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate; 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.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.infrastructure.core.serialization.JsonParserHelper; 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.DatatableData;
import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeader; import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnHeaderData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetColumnValue; import org.mifosplatform.infrastructure.dataqueries.data.ResultsetRowData;
import org.mifosplatform.infrastructure.dataqueries.data.ResultsetDataRow;
import org.mifosplatform.infrastructure.dataqueries.exception.DataTableNotFoundException; import org.mifosplatform.infrastructure.dataqueries.exception.DataTableNotFoundException;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.useradministration.domain.AppUser; import org.mifosplatform.useradministration.domain.AppUser;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; 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 org.springframework.stereotype.Service;
import com.google.gson.reflect.TypeToken; 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 static Logger logger = LoggerFactory.getLogger(ReadWriteNonCoreDataServiceImpl.class);
private final JdbcTemplate jdbcTemplate;
private final DataSource dataSource;
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final FromJsonHelper fromJsonHelper; private final FromJsonHelper fromJsonHelper;
private final JsonParserHelper helper;
private final GenericDataService genericDataService;
@Autowired @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.context = context;
this.fromJsonHelper = fromJsonHelper; this.fromJsonHelper = fromJsonHelper;
this.helper = new JsonParserHelper();
this.genericDataService = genericDataService;
} }
@Autowired
private GenericDataService genericDataService;
@Override @Override
public List<DatatableData> retrieveDatatableNames(final String appTable) { public List<DatatableData> retrieveDatatableNames(final String appTable) {
@@ -67,25 +74,23 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} else { } else {
andClause = " and application_table_name = '" + appTable + "'"; andClause = " and application_table_name = '" + appTable + "'";
} }
// PERMITTED datatables // 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" + " (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" + " 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() + " where ur.appuser_id = " + context.authenticatedUser().getId()
+ " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', registered_table_name))) " + " 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"; + andClause + " order by application_table_name, registered_table_name";
String sqlErrorMsg = "Application Table Name: " + appTable + " sql: " + sql; final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
CachedRowSet rs = genericDataService.getCachedResultSet(sql, sqlErrorMsg);
List<DatatableData> datatables = new ArrayList<DatatableData>(); final List<DatatableData> datatables = new ArrayList<DatatableData>();
try {
while (rs.next()) { while (rs.next()) {
datatables.add(new DatatableData(rs.getString("application_table_name"), rs.getString("registered_table_name"))); final String appTableName = rs.getString("application_table_name");
} final String registeredDatatableName = rs.getString("registered_table_name");
} catch (SQLException e) { datatables.add(DatatableData.create(appTableName, registeredDatatableName));
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
} }
return datatables; return datatables;
@@ -96,63 +101,89 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
validateAppTable(appTable); validateAppTable(appTable);
String createPermission = "'CREATE_" + datatable + "'"; final String createPermission = "'CREATE_" + datatable + "'";
String createPermissionChecker = "'CREATE_" + datatable + "_CHECKER'"; final String createPermissionChecker = "'CREATE_" + datatable + "_CHECKER'";
String readPermission = "'READ_" + datatable + "'"; final String readPermission = "'READ_" + datatable + "'";
String updatePermission = "'UPDATE_" + datatable + "'"; final String updatePermission = "'UPDATE_" + datatable + "'";
String updatePermissionChecker = "'UPDATE_" + datatable + "_CHECKER'"; final String updatePermissionChecker = "'UPDATE_" + datatable + "_CHECKER'";
String deletePermission = "'DELETE_" + datatable + "'"; final String deletePermission = "'DELETE_" + datatable + "'";
String deletePermissionChecker = "'DELETE_" + datatable + "_CHECKER'"; final 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 + "')";
genericDataService.updateSQL(sql, "SQL: " + sql); // TODO - JW - put in batch command later
/* final String registerDatatableSql = "insert into x_registered_table (registered_table_name, application_table_name) values ('"
* add all permissions, including checker permissions for maintenance + datatable + "', '" + appTable + "')";
* tasks
*/ this.jdbcTemplate.update(registerDatatableSql);
sql = "insert into m_permission (grouping, code, action_name, entity_name, can_maker_checker) values " + "('datatable', "
+ createPermission + ", 'CREATE', '" + datatable + "', true)," + "('datatable', " + createPermissionChecker final String permissionsSql = "insert into m_permission (grouping, code, action_name, entity_name, can_maker_checker) values "
+ ", 'CREATE', '" + datatable + "', false)," + "('datatable', " + readPermission + ", 'READ', '" + datatable + "', false)," + "('datatable', "
+ "('datatable', " + updatePermission + ", 'UPDATE', '" + datatable + "', true)," + "('datatable', " + createPermission
+ updatePermissionChecker + ", 'UPDATE', '" + datatable + "', false)," + "('datatable', " + deletePermission + ", 'CREATE', '"
+ ", 'DELETE', '" + datatable + "', true)," + "('datatable', " + deletePermissionChecker + ", 'DELETE', '" + datatable + 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)"; + "', false)";
genericDataService.updateSQL(sql, "SQL: " + sql); this.jdbcTemplate.update(permissionsSql);
} }
@Override @Override
public void deregisterDatatable(final String datatable) { public void deregisterDatatable(final String datatable) {
// TODO - JW - put in batch command later // TODO - JW - put in batch command later
final String permissionList = "('CREATE_" + datatable + "', 'CREATE_" + datatable + "_CHECKER', 'READ_" + datatable + "', 'UPDATE_"
String permissionList = "('CREATE_" + datatable + "', 'CREATE_" + datatable + "_CHECKER', 'READ_" + datatable + "', 'UPDATE_"
+ datatable + "', 'UPDATE_" + datatable + "_CHECKER', 'DELETE_" + datatable + "', 'DELETE_" + datatable + "_CHECKER')"; + 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 " String sql = "delete from m_role_permission where m_role_permission.permission_id in (select id from m_permission where code in "
+ permissionList + ")"; + permissionList + ")";
genericDataService.updateSQL(sql, "SQL: " + sql); this.jdbcTemplate.update(sql);
sql = "delete from m_permission where code in " + permissionList; 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 + "'"; sql = "delete from x_registered_table where registered_table_name = '" + datatable + "'";
genericDataService.updateSQL(sql, "SQL: " + sql); this.jdbcTemplate.update(sql);
} }
@Override @Override
public void newDatatableEntry(final String datatable, final Long appTableId, final JsonCommand command) { public void newDatatableEntry(final String datatable, final Long appTableId, final JsonCommand command) {
String appTable = getWithinScopeApplicationTableName(datatable, appTableId); 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(); 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 @Override
@@ -166,7 +197,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
throw new PlatformDataIntegrityException("error.msg.attempting.multiple.update", "Application Table: " + datatable throw new PlatformDataIntegrityException("error.msg.attempting.multiple.update", "Application Table: " + datatable
+ " Foreign Key Id: " + appTableId); + " Foreign Key Id: " + appTableId);
String fkName = getFKField(getApplicationTableName(datatable)); String fkName = getFKField(queryForApplicationTableName(datatable));
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json()); 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; if (changes.size() == 0) return changes;
String sql = getUpdateSql(datatable, fkName, appTableId, changes); final String sql = getUpdateSql(datatable, fkName, appTableId, changes);
if (sql != null) { if (StringUtils.isNotBlank(sql)) {
genericDataService.updateSQL(sql, "SQL: " + sql); this.jdbcTemplate.update(sql);
} else { } else {
logger.info("No Changes"); 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, public Map<String, Object> updateDatatableEntryOneToMany(final String datatable, final Long appTableId, final Long datatableId,
final JsonCommand command) { 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); if (grs.getData().size() == 0) throw new DataTableNotFoundException(datatable, appTableId);
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType(); 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"); final Map<String, Object> changes = getAffectedAndChangedColumns(grs, dataParams, "id");
if (changes.size() == 0) return changes; if (changes.size() == 0) return changes;
String sql = getUpdateSql(datatable, "id", datatableId, changes); final String sql = getUpdateSql(datatable, "id", datatableId, changes);
if (sql != null) { if (StringUtils.isNotBlank(sql)) {
genericDataService.updateSQL(sql, "SQL: " + sql); this.jdbcTemplate.update(sql);
} else { } else {
logger.info("No Changes"); logger.info("No Changes");
} }
@@ -215,11 +246,11 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
@Override @Override
public void deleteDatatableEntries(final String datatable, final Long appTableId) { 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 @Override
@@ -227,18 +258,18 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
getWithinScopeApplicationTableName(datatable, appTableId); getWithinScopeApplicationTableName(datatable, appTableId);
String sql = getDeleteEntrySql(datatable, datatableId); final String sql = getDeleteEntrySql(datatable, datatableId);
genericDataService.updateSQL(sql, "SQL: " + sql); this.jdbcTemplate.update(sql);
} }
@Override @Override
public GenericResultsetData retrieveDataTableGenericResultSet(final String datatable, final Long appTableId, final String order, public GenericResultsetData retrieveDataTableGenericResultSet(final String datatable, final Long appTableId, final String order,
final Long id) { 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 = ""; String sql = "";
@@ -252,20 +283,20 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (order != null) sql = sql + " order by " + order; if (order != null) sql = sql + " order by " + order;
List<ResultsetDataRow> result = fillDatatableResultSetDataRows(sql); List<ResultsetRowData> result = fillDatatableResultSetDataRows(sql);
return new GenericResultsetData(columnHeaders, result); return new GenericResultsetData(columnHeaders, result);
} }
private void checkMainResourceExistsWithinScope(final String appTable, final Long appTableId) { 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) { 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); 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; final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sql);
CachedRowSet rs = genericDataService.getCachedResultSet(sql, sqlErrorMsg);
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()) { while (rs.next()) {
resultsetDataRow = new ResultsetDataRow(); final List<String> columnValues = new ArrayList<String>();
List<String> columnValues = new ArrayList<String>(); for (int i = 0; i < rsmd.getColumnCount(); i++) {
for (int i = 0; i < columnCount; i++) { final String columnName = rsmd.getColumnName(i + 1);
columnName = rsmd.getColumnName(i + 1); final String columnValue = rs.getString(columnName);
columnValue = rs.getString(columnName);
columnValues.add(columnValue); columnValues.add(columnValue);
} }
resultsetDataRow.setRow(columnValues);
final ResultsetRowData resultsetDataRow = ResultsetRowData.create(columnValues);
resultsetDataRows.add(resultsetDataRow); resultsetDataRows.add(resultsetDataRow);
} }
return resultsetDataRows; return resultsetDataRows;
} catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg);
}
} }
private String getWithinScopeApplicationTableName(final String datatable, final Long appTableId) { 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); return applicationTableName;
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());
}
} }
private String getApplicationTableName(final String datatable) { private String queryForApplicationTableName(final String datatable) {
// TODO - JW - only used for update... can probably remove this after as final String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '" + datatable + "'";
// its
// a reread
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); String applicationTableName = null;
if (rs.next()) {
try { applicationTableName = rs.getString("application_table_name");
rs.next(); } else {
return rs.getString("application_table_name"); throw new DataTableNotFoundException(datatable);
} catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage());
} }
return applicationTableName;
} }
private String getFKField(final String applicationTableName) { private String getFKField(final String applicationTableName) {
@@ -378,89 +385,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return applicationTableName.substring(2) + "_id"; return applicationTableName.substring(2) + "_id";
} }
private CachedRowSet getDatatableMetaData(final String datatable) { private String getAddSql(final List<ResultsetColumnHeaderData> columnHeaders, final String datatable, final String fkName,
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,
final Long appTableId, final Map<String, String> queryParams) { final Long appTableId, final Map<String, String> queryParams) {
final Map<String, String> affectedColumns = getAffectedColumns(columnHeaders, queryParams, fkName); 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"); 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, private Map<String, String> getAffectedColumns(final List<ResultsetColumnHeaderData> columnHeaders,
final String keyFieldName) { final Map<String, String> queryParams, final String keyFieldName) {
String dateFormat = queryParams.get("dateFormat"); String dateFormat = queryParams.get("dateFormat");
Locale clientApplicationLocale = null; Locale clientApplicationLocale = null;
@@ -600,7 +525,7 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// matches incoming fields with and without underscores (spaces // matches incoming fields with and without underscores (spaces
// and underscores considered the same) // and underscores considered the same)
queryParamColumnUnderscored = genericDataService.replace(key, space, underscore); queryParamColumnUnderscored = genericDataService.replace(key, space, underscore);
for (ResultsetColumnHeader columnHeader : columnHeaders) { for (ResultsetColumnHeaderData columnHeader : columnHeaders) {
if (notFound) { if (notFound) {
columnHeaderUnderscored = genericDataService.replace(columnHeader.getColumnName(), space, underscore); columnHeaderUnderscored = genericDataService.replace(columnHeader.getColumnName(), space, underscore);
if (queryParamColumnUnderscored.equalsIgnoreCase(columnHeaderUnderscored)) { if (queryParamColumnUnderscored.equalsIgnoreCase(columnHeaderUnderscored)) {
@@ -618,74 +543,84 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return affectedColumns; 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) { final Locale clientApplicationLocale) {
String paramValue = pValue; String paramValue = pValue;
if ((columnHeader.getColumnDisplayType().equals("DATE")) || (columnHeader.getColumnDisplayType().equals("INTEGER")) if (columnHeader.isDateDisplayType() || columnHeader.isIntegerDisplayType() || columnHeader.isDecimalDisplayType()) {
|| (columnHeader.getColumnDisplayType().equals("DECIMAL"))) paramValue = paramValue.trim(); paramValue = paramValue.trim();
}
if ((StringUtils.isEmpty(paramValue)) && (!(columnHeader.isColumnNullable()))) { if (StringUtils.isEmpty(paramValue) && columnHeader.isMandatory()) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("error.msg.column.mandatory", "Mandatory", final ApiParameterError error = ApiParameterError.parameterError("error.msg.column.mandatory", "Mandatory",
columnHeader.getColumnName()); columnHeader.getColumnName());
dataValidationErrors.add(error); dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors); dataValidationErrors);
} }
if (!StringUtils.isEmpty(paramValue)) { if (StringUtils.isNotEmpty(paramValue)) {
if (columnHeader.getColumnValues().size() > 0) { if (columnHeader.hasColumnValues()) {
// match code value or id if (columnHeader.isCodeValueDisplayType()) {
List<ResultsetColumnValue> allowedValues = columnHeader.getColumnValues();
if (columnHeader.getColumnDisplayType().equals("CODEVALUE")) { if (columnHeader.isColumnValueNotAllowed(paramValue)) {
for (ResultsetColumnValue allowedValue : allowedValues) { final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
if (paramValue.equalsIgnoreCase(allowedValue.getValue())) return paramValue; final ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue",
}
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue",
"Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue); "Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue);
dataValidationErrors.add(error); dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors); dataValidationErrors);
} }
if (columnHeader.getColumnDisplayType().equals("CODELOOKUP")) { return paramValue;
for (ResultsetColumnValue allowedValue : allowedValues) { } else if (columnHeader.isCodeLookupDisplayType()) {
if (paramValue.equals(Integer.toString(allowedValue.getId()))) return paramValue;
} final Integer codeLookup = Integer.valueOf(paramValue);
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); if (columnHeader.isColumnCodeNotAllowed(codeLookup)) {
ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue", 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); "Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue);
dataValidationErrors.add(error); dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors); dataValidationErrors);
} }
return paramValue;
} else {
throw new PlatformDataIntegrityException("error.msg.invalid.columnType.", "Code: " + columnHeader.getColumnName() throw new PlatformDataIntegrityException("error.msg.invalid.columnType.", "Code: " + columnHeader.getColumnName()
+ " - Invalid Type " + columnHeader.getColumnType() + " (neither varchar nor int)"); + " - 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.getColumnDisplayType().equals("INTEGER")) {
if (columnHeader.isDateDisplayType()) {
final LocalDate tmpDate = helper.convertFrom(paramValue, columnHeader.getColumnName(), dateFormat, clientApplicationLocale);
if (tmpDate == null) {
paramValue = null;
} else {
paramValue = tmpDate.toString();
}
}
if (columnHeader.isIntegerDisplayType()) {
Integer tmpInt = helper.convertToInteger(paramValue, columnHeader.getColumnName(), clientApplicationLocale); Integer tmpInt = helper.convertToInteger(paramValue, columnHeader.getColumnName(), clientApplicationLocale);
if (tmpInt == null) return null; if (tmpInt == null) {
return tmpInt.toString(); paramValue = null;
} else {
paramValue = tmpInt.toString();
} }
if (columnHeader.getColumnDisplayType().equals("DECIMAL")) {
BigDecimal tmpDecimal = helper.convertFrom(paramValue, columnHeader.getColumnName(), clientApplicationLocale);
if (tmpDecimal == null) return null;
return tmpDecimal.toString();
} }
if (columnHeader.isDecimalDisplayType()) {
BigDecimal tmpDecimal = helper.convertFrom(paramValue, columnHeader.getColumnName(), clientApplicationLocale);
if (tmpDecimal == null) {
paramValue = null;
} else {
paramValue = tmpDecimal.toString();
}
}
} }
return paramValue; return paramValue;