datatables: handle input containing just space(s)

This commit is contained in:
John Woodlock
2013-01-11 13:01:25 +00:00
parent fe7667b9ec
commit 0049d07cac
2 changed files with 821 additions and 629 deletions
@@ -81,8 +81,7 @@ public class GenericDataServiceImpl implements GenericDataService {
} }
// long elapsed = System.currentTimeMillis() - startTime; // long elapsed = System.currentTimeMillis() - startTime;
// logger.info("Elapsed Time FOR UPDATE: " + elapsed + " SQL: " + // logger.info("Elapsed Time: " + elapsed + " SQL: " + sql);
// sql);
} }
@Override @Override
@@ -1,6 +1,7 @@
package org.mifosplatform.infrastructure.dataqueries.service; package org.mifosplatform.infrastructure.dataqueries.service;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.sql.ResultSetMetaData; import java.sql.ResultSetMetaData;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -13,6 +14,7 @@ import java.util.Set;
import javax.sql.rowset.CachedRowSet; import javax.sql.rowset.CachedRowSet;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
@@ -35,15 +37,19 @@ import org.springframework.stereotype.Service;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
@Service @Service
public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataService { public class ReadWriteNonCoreDataServiceImpl implements
ReadWriteNonCoreDataService {
private final static Logger logger = LoggerFactory.getLogger(ReadWriteNonCoreDataServiceImpl.class); private final static Logger logger = LoggerFactory
.getLogger(ReadWriteNonCoreDataServiceImpl.class);
private final PlatformSecurityContext context; private final PlatformSecurityContext context;
private final FromJsonHelper fromJsonHelper; private final FromJsonHelper fromJsonHelper;
@Autowired @Autowired
public ReadWriteNonCoreDataServiceImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper) { public ReadWriteNonCoreDataServiceImpl(
final PlatformSecurityContext context,
final FromJsonHelper fromJsonHelper) {
this.context = context; this.context = context;
this.fromJsonHelper = fromJsonHelper; this.fromJsonHelper = fromJsonHelper;
} }
@@ -61,24 +67,36 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
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" String sql = "select application_table_name, registered_table_name"
+ " (select 'f'" + " from m_appuser_role ur " + " join m_role r on r.id = ur.role_id" + " from x_registered_table "
+ " left join m_role_permission rp on rp.role_id = r.id" + " left join m_permission p on p.id = rp.permission_id" + " where exists"
+ " where ur.appuser_id = " + context.authenticatedUser().getId() + " (select 'f'"
+ " from m_appuser_role ur "
+ " join m_role r on r.id = ur.role_id"
+ " left join m_role_permission rp on rp.role_id = r.id"
+ " left join m_permission p on p.id = rp.permission_id"
+ " where ur.appuser_id = "
+ context.authenticatedUser().getId()
+ " and (p.code in ('ALL_FUNCTIONS', 'ALL_FUNCTIONS_READ') or p.code = concat('READ_', registered_table_name))) " + " 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; String sqlErrorMsg = "Application Table Name: " + appTable + " sql: "
CachedRowSet rs = genericDataService.getCachedResultSet(sql, sqlErrorMsg); + sql;
CachedRowSet rs = genericDataService.getCachedResultSet(sql,
sqlErrorMsg);
List<DatatableData> datatables = new ArrayList<DatatableData>(); List<DatatableData> datatables = new ArrayList<DatatableData>();
try { try {
while (rs.next()) { while (rs.next()) {
datatables.add(new DatatableData(rs.getString("application_table_name"), rs.getString("registered_table_name"))); datatables.add(new DatatableData(rs
.getString("application_table_name"), rs
.getString("registered_table_name")));
} }
} catch (SQLException e) { } catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg); throw new PlatformDataIntegrityException("error.msg.sql.error",
e.getMessage(), sqlErrorMsg);
} }
return datatables; return datatables;
@@ -97,21 +115,49 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
String deletePermission = "'DELETE_" + datatable + "'"; String deletePermission = "'DELETE_" + datatable + "'";
String deletePermissionChecker = "'DELETE_" + datatable + "_CHECKER'"; String deletePermissionChecker = "'DELETE_" + datatable + "_CHECKER'";
// TODO - put in batch command later // TODO - put in batch command later
String sql = "insert into x_registered_table (registered_table_name, application_table_name) values ('" + datatable + "', '" String sql = "insert into x_registered_table (registered_table_name, application_table_name) values ('"
+ appTable + "')"; + datatable + "', '" + appTable + "')";
genericDataService.updateSQL(sql, "SQL: " + sql); genericDataService.updateSQL(sql, "SQL: " + sql);
/* /*
* add all permissions, including checker permissions for maintenance * add all permissions, including checker permissions for maintenance
* tasks * tasks
*/ */
sql = "insert into m_permission (grouping, code, action_name, entity_name, can_maker_checker) values " + "('datatable', " sql = "insert into m_permission (grouping, code, action_name, entity_name, can_maker_checker) values "
+ createPermission + ", 'CREATE', '" + datatable + "', true)," + "('datatable', " + createPermissionChecker + "('datatable', "
+ ", 'CREATE', '" + datatable + "', false)," + "('datatable', " + readPermission + ", 'READ', '" + datatable + "', false)," + createPermission
+ "('datatable', " + updatePermission + ", 'UPDATE', '" + datatable + "', true)," + "('datatable', " + ", 'CREATE', '"
+ updatePermissionChecker + ", 'UPDATE', '" + datatable + "', false)," + "('datatable', " + deletePermission + datatable
+ ", 'DELETE', '" + datatable + "', true)," + "('datatable', " + deletePermissionChecker + ", 'DELETE', '" + datatable + "', true),"
+ "', false)"; + "('datatable', "
+ createPermissionChecker
+ ", 'CREATE', '"
+ datatable
+ "', false),"
+ "('datatable', "
+ readPermission
+ ", 'READ', '"
+ datatable
+ "', false),"
+ "('datatable', "
+ updatePermission
+ ", 'UPDATE', '"
+ datatable
+ "', true),"
+ "('datatable', "
+ updatePermissionChecker
+ ", 'UPDATE', '"
+ datatable
+ "', false),"
+ "('datatable', "
+ deletePermission
+ ", 'DELETE', '"
+ datatable
+ "', true),"
+ "('datatable', "
+ deletePermissionChecker
+ ", 'DELETE', '"
+ datatable + "', false)";
genericDataService.updateSQL(sql, "SQL: " + sql); genericDataService.updateSQL(sql, "SQL: " + sql);
} }
@@ -120,8 +166,10 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
public void deregisterDatatable(final String datatable) { public void deregisterDatatable(final String datatable) {
// TODO - put in batch command later // TODO - put in batch command later
String permissionList = "('CREATE_" + datatable + "', 'CREATE_" + datatable + "_CHECKER', 'READ_" + datatable + "', 'UPDATE_" String permissionList = "('CREATE_" + datatable + "', 'CREATE_"
+ datatable + "', 'UPDATE_" + datatable + "_CHECKER', 'DELETE_" + datatable + "', 'DELETE_" + datatable + "_CHECKER')"; + datatable + "_CHECKER', 'READ_" + datatable + "', 'UPDATE_"
+ datatable + "', 'UPDATE_" + datatable + "_CHECKER', 'DELETE_"
+ datatable + "', 'DELETE_" + datatable + "_CHECKER')";
String sql = "delete from m_role_permission where m_role_permission.permission_id in (select id from m_permission where code in " String sql = "delete from m_role_permission where m_role_permission.permission_id in (select id from m_permission where code in "
+ permissionList + ")"; + permissionList + ")";
@@ -130,43 +178,59 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
sql = "delete from m_permission where code in " + permissionList; sql = "delete from m_permission where code in " + permissionList;
genericDataService.updateSQL(sql, "SQL: " + sql); genericDataService.updateSQL(sql, "SQL: " + 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); genericDataService.updateSQL(sql, "SQL: " + sql);
} }
@Override @Override
public void newDatatableEntry(final String datatable, final Long appTableId, final JsonCommand command) { public void newDatatableEntry(final String datatable,
String appTable = getWithinScopeApplicationTableName(datatable, appTableId); final Long appTableId, final JsonCommand command) {
String appTable = getWithinScopeApplicationTableName(datatable,
appTableId);
List<ResultsetColumnHeader> columnHeaders = getDatatableResultsetColumnHeaders(datatable); List<ResultsetColumnHeader> columnHeaders = getDatatableResultsetColumnHeaders(datatable);
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, String>>() {
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json()); }.getType();
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(
typeOfMap, command.json());
String sql = getAddSql(columnHeaders, datatable, getFKField(appTable), appTableId, dataParams); String sql = getAddSql(columnHeaders, datatable, getFKField(appTable),
appTableId, dataParams);
genericDataService.updateSQL(sql, "SQL: " + sql); genericDataService.updateSQL(sql, "SQL: " + sql);
} }
@Override @Override
public Map<String, Object> updateDatatableEntryOneToOne(final String datatable, final Long appTableId, final JsonCommand command) { public Map<String, Object> updateDatatableEntryOneToOne(
final String datatable, final Long appTableId,
final JsonCommand command) {
GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable, appTableId, null, null); GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable,
appTableId, null, null);
if (grs.getData().size() == 0) throw new DataTableNotFoundException(datatable, appTableId); if (grs.getData().size() == 0)
throw new DataTableNotFoundException(datatable, appTableId);
if (grs.getData().size() > 1) if (grs.getData().size() > 1)
throw new PlatformDataIntegrityException("error.msg.attempting.multiple.update", "Application Table: " + datatable throw new PlatformDataIntegrityException(
+ " Foreign Key Id: " + appTableId); "error.msg.attempting.multiple.update",
"Application Table: " + datatable + " Foreign Key Id: "
+ appTableId);
String fkName = getFKField(getApplicationTableName(datatable)); String fkName = getFKField(getApplicationTableName(datatable));
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType(); final Type typeOfMap = new TypeToken<Map<String, String>>() {
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json()); }.getType();
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(
typeOfMap, command.json());
final Map<String, Object> changes = getAffectedAndChangedColumns(grs, dataParams, fkName); final Map<String, Object> changes = getAffectedAndChangedColumns(grs,
dataParams, fkName);
if (changes.size() == 0) return changes; if (changes.size() == 0)
return changes;
String sql = getUpdateSql(datatable, fkName, appTableId, changes); String sql = getUpdateSql(datatable, fkName, appTableId, changes);
@@ -180,19 +244,26 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} }
@Override @Override
public Map<String, Object> updateDatatableEntryOneToMany(final String datatable, final Long appTableId, final Long datatableId, public Map<String, Object> updateDatatableEntryOneToMany(
final JsonCommand command) { final String datatable, final Long appTableId,
final Long datatableId, final JsonCommand command) {
GenericResultsetData grs = retrieveDataTableGenericResultSet(datatable, appTableId, null, datatableId); 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>>() {
Map<String, String> dataParams = this.fromJsonHelper.extractDataMap(typeOfMap, command.json()); }.getType();
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); String sql = getUpdateSql(datatable, "id", datatableId, changes);
@@ -206,17 +277,21 @@ 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); String appTable = getWithinScopeApplicationTableName(datatable,
appTableId);
String sql = getDeleteEntriesSql(datatable, getFKField(appTable), appTableId); String sql = getDeleteEntriesSql(datatable, getFKField(appTable),
appTableId);
genericDataService.updateSQL(sql, "SQL: " + sql); genericDataService.updateSQL(sql, "SQL: " + sql);
} }
@Override @Override
public void deleteDatatableEntry(final String datatable, final Long appTableId, final Long datatableId) { public void deleteDatatableEntry(final String datatable,
final Long appTableId, final Long datatableId) {
getWithinScopeApplicationTableName(datatable, appTableId); getWithinScopeApplicationTableName(datatable, appTableId);
@@ -226,10 +301,12 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
} }
@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); String appTable = getWithinScopeApplicationTableName(datatable,
appTableId);
List<ResultsetColumnHeader> columnHeaders = getDatatableResultsetColumnHeaders(datatable); List<ResultsetColumnHeader> columnHeaders = getDatatableResultsetColumnHeaders(datatable);
@@ -238,27 +315,33 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// id only used for reading a specific entry in a one to many datatable // id only used for reading a specific entry in a one to many datatable
// (when updating) // (when updating)
if (id == null) { if (id == null) {
sql = sql + "select * from `" + datatable + "` where " + getFKField(appTable) + " = " + appTableId; sql = sql + "select * from `" + datatable + "` where "
+ getFKField(appTable) + " = " + appTableId;
} else { } else {
sql = sql + "select * from `" + datatable + "` where id = " + id; sql = sql + "select * from `" + datatable + "` where id = " + id;
} }
if (order != null) sql = sql + " order by " + order; if (order != null)
sql = sql + " order by " + order;
List<ResultsetDataRow> result = fillDatatableResultSetDataRows(sql); List<ResultsetDataRow> 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; String unscopedSql = "select t.id from `" + appTable
+ "` t ${dataScopeCriteria} where t.id = " + appTableId;
String sql = dataScopedSQL(unscopedSql, appTable); String sql = dataScopedSQL(unscopedSql, appTable);
CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : " + sql); CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : "
+ sql);
if (rs.size() == 0) throw new DataTableNotFoundException(appTable, appTableId); if (rs.size() == 0)
throw new DataTableNotFoundException(appTable, appTableId);
} }
private String dataScopedSQL(final String unscopedSQL, final String appTable) { private String dataScopedSQL(final String unscopedSQL, final String appTable) {
@@ -273,33 +356,45 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
AppUser currentUser = context.authenticatedUser(); AppUser currentUser = context.authenticatedUser();
if (appTable.equalsIgnoreCase("m_client")) { if (appTable.equalsIgnoreCase("m_client")) {
dataScopeCriteria = " join m_office o on o.id = t.office_id and o.hierarchy like '" + currentUser.getOffice().getHierarchy() dataScopeCriteria = " join m_office o on o.id = t.office_id and o.hierarchy like '"
+ "%'"; + currentUser.getOffice().getHierarchy() + "%'";
} }
if (appTable.equalsIgnoreCase("m_loan")) { if (appTable.equalsIgnoreCase("m_loan")) {
dataScopeCriteria = " join m_client c on c.id = t.client_id " + " join m_office o on o.id = c.office_id and o.hierarchy like '" dataScopeCriteria = " join m_client c on c.id = t.client_id "
+ " join m_office o on o.id = c.office_id and o.hierarchy like '"
+ currentUser.getOffice().getHierarchy() + "%'"; + currentUser.getOffice().getHierarchy() + "%'";
} }
if (dataScopeCriteria == null) { throw new PlatformDataIntegrityException("error.msg.invalid.dataScopeCriteria", if (dataScopeCriteria == null) {
"Application Table: " + appTable + " not catered for in data Scoping"); } throw new PlatformDataIntegrityException(
"error.msg.invalid.dataScopeCriteria",
"Application Table: " + appTable
+ " not catered for in data Scoping");
}
return genericDataService.replace(unscopedSQL, "${dataScopeCriteria}", dataScopeCriteria); return genericDataService.replace(unscopedSQL, "${dataScopeCriteria}",
dataScopeCriteria);
} }
private void validateAppTable(final String appTable) { private void validateAppTable(final String appTable) {
if (appTable.equalsIgnoreCase("m_client")) return; if (appTable.equalsIgnoreCase("m_client"))
if (appTable.equalsIgnoreCase("m_loan")) return; return;
if (appTable.equalsIgnoreCase("m_loan"))
return;
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<ResultsetDataRow> fillDatatableResultSetDataRows(
final String sql) {
String sqlErrorMsg = "Sql: " + sql; String sqlErrorMsg = "Sql: " + sql;
CachedRowSet rs = genericDataService.getCachedResultSet(sql, sqlErrorMsg); CachedRowSet rs = genericDataService.getCachedResultSet(sql,
sqlErrorMsg);
List<ResultsetDataRow> resultsetDataRows = new ArrayList<ResultsetDataRow>(); List<ResultsetDataRow> resultsetDataRows = new ArrayList<ResultsetDataRow>();
@@ -325,16 +420,21 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return resultsetDataRows; return resultsetDataRows;
} catch (SQLException e) { } catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage(), sqlErrorMsg); 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,
String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '" + 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); CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : "
+ sql);
if (rs.size() == 0) throw new DataTableNotFoundException(datatable); if (rs.size() == 0)
throw new DataTableNotFoundException(datatable);
try { try {
rs.next(); rs.next();
@@ -344,24 +444,29 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return appTable; return appTable;
} catch (SQLException e) { } catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage()); throw new PlatformDataIntegrityException("error.msg.sql.error",
e.getMessage());
} }
} }
private String getApplicationTableName(final String datatable) { private String getApplicationTableName(final String datatable) {
// TODO - only used for update... can probably remove this after as its // TODO - only used for update... can probably remove this after as its
// a reread // a reread
String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '" + datatable + "'"; String sql = "SELECT application_table_name FROM x_registered_table where registered_table_name = '"
+ datatable + "'";
CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : " + sql); CachedRowSet rs = genericDataService.getCachedResultSet(sql, "SQL : "
+ sql);
if (rs.size() == 0) throw new DataTableNotFoundException(datatable); if (rs.size() == 0)
throw new DataTableNotFoundException(datatable);
try { try {
rs.next(); rs.next();
return rs.getString("application_table_name"); return rs.getString("application_table_name");
} catch (SQLException e) { } catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage()); throw new PlatformDataIntegrityException("error.msg.sql.error",
e.getMessage());
} }
} }
@@ -373,17 +478,21 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
private CachedRowSet getDatatableMetaData(final String datatable) { private CachedRowSet getDatatableMetaData(final String datatable) {
String sql = "select COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH, COLUMN_KEY" 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 + " from INFORMATION_SCHEMA.COLUMNS "
+ "'order by ORDINAL_POSITION"; + " where TABLE_SCHEMA = schema() and TABLE_NAME = '"
+ datatable + "'order by ORDINAL_POSITION";
CachedRowSet columnDefinitions = genericDataService.getCachedResultSet(sql, "SQL: " + sql); CachedRowSet columnDefinitions = genericDataService.getCachedResultSet(
sql, "SQL: " + sql);
if (columnDefinitions.size() > 0) return columnDefinitions; if (columnDefinitions.size() > 0)
return columnDefinitions;
throw new DataTableNotFoundException(datatable); throw new DataTableNotFoundException(datatable);
} }
private List<ResultsetColumnHeader> getDatatableResultsetColumnHeaders(final String datatable) { private List<ResultsetColumnHeader> getDatatableResultsetColumnHeaders(
final String datatable) {
CachedRowSet columnDefinitions = getDatatableMetaData(datatable); CachedRowSet columnDefinitions = getDatatableMetaData(datatable);
@@ -408,15 +517,20 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
else else
rsch.setColumnPrimaryKey(false); rsch.setColumnPrimaryKey(false);
Long columnLength = columnDefinitions.getLong("CHARACTER_MAXIMUM_LENGTH"); Long columnLength = columnDefinitions
if (columnLength > 0) rsch.setColumnLength(columnDefinitions.getLong("CHARACTER_MAXIMUM_LENGTH")); .getLong("CHARACTER_MAXIMUM_LENGTH");
if (columnLength > 0)
rsch.setColumnLength(columnDefinitions
.getLong("CHARACTER_MAXIMUM_LENGTH"));
rsch.setColumnType(columnDefinitions.getString("DATA_TYPE")); rsch.setColumnType(columnDefinitions.getString("DATA_TYPE"));
/* look for codes */ /* look for codes */
if (rsch.getColumnType().equalsIgnoreCase("varchar")) addCodesValueIfNecessary(rsch, "_cv"); if (rsch.getColumnType().equalsIgnoreCase("varchar"))
addCodesValueIfNecessary(rsch, "_cv");
if (rsch.getColumnType().equalsIgnoreCase("int")) addCodesValueIfNecessary(rsch, "_cd"); if (rsch.getColumnType().equalsIgnoreCase("int"))
addCodesValueIfNecessary(rsch, "_cd");
rsch.setColumnDisplayType(); rsch.setColumnDisplayType();
@@ -426,36 +540,46 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return columnHeaders; return columnHeaders;
} catch (SQLException e) { } catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage()); throw new PlatformDataIntegrityException("error.msg.sql.error",
e.getMessage());
} }
} }
private void addCodesValueIfNecessary(final ResultsetColumnHeader rsch, final String code_suffix) { private void addCodesValueIfNecessary(final ResultsetColumnHeader rsch,
final String code_suffix) {
int codePosition = rsch.getColumnName().indexOf(code_suffix); int codePosition = rsch.getColumnName().indexOf(code_suffix);
if (codePosition > 0) { if (codePosition > 0) {
String codeName = rsch.getColumnName().substring(0, codePosition); 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 " String sql = "select v.id, v.code_value from m_code m "
+ " where m.code_name = '" + codeName + "' order by v.order_position, v.id"; + " 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); CachedRowSet rsValues = genericDataService.getCachedResultSet(sql,
"SQL: " + sql);
try { try {
while (rsValues.next()) { while (rsValues.next()) {
rsch.getColumnValues().add(new ResultsetColumnValue(rsValues.getInt("id"), rsValues.getString("code_value"))); rsch.getColumnValues().add(
new ResultsetColumnValue(rsValues.getInt("id"),
rsValues.getString("code_value")));
} }
} catch (SQLException e) { } catch (SQLException e) {
throw new PlatformDataIntegrityException("error.msg.sql.error", e.getMessage()); throw new PlatformDataIntegrityException("error.msg.sql.error",
e.getMessage());
} }
} }
} }
private String getAddSql(final List<ResultsetColumnHeader> columnHeaders, final String datatable, final String fkName, private String getAddSql(final List<ResultsetColumnHeader> columnHeaders,
final Long appTableId, final Map<String, String> queryParams) { final String datatable, final String fkName, 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);
String pValueWrite = ""; String pValueWrite = "";
String addSql = ""; String addSql = "";
@@ -471,20 +595,24 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (StringUtils.isEmpty(pValue)) { if (StringUtils.isEmpty(pValue)) {
pValueWrite = "null"; pValueWrite = "null";
} else { } else {
pValueWrite = singleQuote + genericDataService.replace(pValue, singleQuote, singleQuote + singleQuote) + singleQuote; pValueWrite = singleQuote
+ genericDataService.replace(pValue, singleQuote,
singleQuote + singleQuote) + singleQuote;
} }
columnName = "`" + key + "`"; columnName = "`" + key + "`";
insertColumns += ", " + columnName; insertColumns += ", " + columnName;
selectColumns += "," + pValueWrite + " as " + columnName; selectColumns += "," + pValueWrite + " as " + columnName;
} }
addSql = "insert into `" + datatable + "` (`" + fkName + "` " + insertColumns + ")" + " select " + appTableId + " as id" addSql = "insert into `" + datatable + "` (`" + fkName + "` "
+ insertColumns + ")" + " select " + appTableId + " as id"
+ selectColumns; + selectColumns;
return addSql; return addSql;
} }
private String getUpdateSql(final String datatable, final String keyFieldName, final Long keyFieldValue, private String getUpdateSql(final String datatable,
final String keyFieldName, final Long keyFieldValue,
final Map<String, Object> changedColumns) { final Map<String, Object> changedColumns) {
// just updating fields that have changed since pre-update read - though // just updating fields that have changed since pre-update read - though
@@ -494,7 +622,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// completeness but its okay to take this risk with additional fields // completeness but its okay to take this risk with additional fields
// data // data
if (changedColumns.size() == 0) return null; if (changedColumns.size() == 0)
return null;
String pValue = null; String pValue = null;
String pValueWrite = ""; String pValueWrite = "";
@@ -514,7 +643,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
if (StringUtils.isEmpty(pValue)) { if (StringUtils.isEmpty(pValue)) {
pValueWrite = "null"; pValueWrite = "null";
} else { } else {
pValueWrite = singleQuote + genericDataService.replace(pValue, singleQuote, singleQuote + singleQuote) + singleQuote; pValueWrite = singleQuote
+ genericDataService.replace(pValue, singleQuote,
singleQuote + singleQuote) + singleQuote;
} }
sql += "`" + key + "` = " + pValueWrite; sql += "`" + key + "` = " + pValueWrite;
} }
@@ -524,10 +655,12 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return sql; return sql;
} }
private Map<String, Object> getAffectedAndChangedColumns(final GenericResultsetData grs, final Map<String, String> queryParams, private Map<String, Object> getAffectedAndChangedColumns(
final String fkName) { final GenericResultsetData grs,
final Map<String, String> queryParams, final String fkName) {
Map<String, String> affectedColumns = getAffectedColumns(grs.getColumnHeaders(), queryParams, fkName); Map<String, String> affectedColumns = getAffectedColumns(
grs.getColumnHeaders(), queryParams, fkName);
Map<String, Object> affectedAndChangedColumns = new HashMap<String, Object>(); Map<String, Object> affectedAndChangedColumns = new HashMap<String, Object>();
String columnValue; String columnValue;
@@ -541,7 +674,8 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
return affectedAndChangedColumns; return affectedAndChangedColumns;
} }
private boolean columnChanged(final String key, final String keyValue, final GenericResultsetData grs) { private boolean columnChanged(final String key, final String keyValue,
final GenericResultsetData grs) {
List<String> columnValues = grs.getData().get(0).getRow(); List<String> columnValues = grs.getData().get(0).getRow();
@@ -552,7 +686,9 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
columnValue = columnValues.get(i); columnValue = columnValues.get(i);
if (notTheSame(columnValue, keyValue)) { if (notTheSame(columnValue, keyValue)) {
logger.info("Difference - Column: " + key + "- Current Value: " + columnValue + " New Value: " + keyValue); // logger.info("Difference - Column: " + key +
// "- Current Value: " + columnValue + " New Value: " +
// keyValue);
return true; return true;
} }
@@ -560,16 +696,20 @@ 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 String keyFieldName) { final List<ResultsetColumnHeader> columnHeaders,
final Map<String, String> queryParams, final String keyFieldName) {
String dateFormat = queryParams.get("dateFormat"); String dateFormat = queryParams.get("dateFormat");
Locale clientApplicationLocale = null; Locale clientApplicationLocale = null;
String localeQueryParam = queryParams.get("locale"); String localeQueryParam = queryParams.get("locale");
if (!(StringUtils.isBlank(localeQueryParam))) clientApplicationLocale = new Locale(queryParams.get("locale")); if (!(StringUtils.isBlank(localeQueryParam)))
clientApplicationLocale = new Locale(queryParams.get("locale"));
String underscore = "_"; String underscore = "_";
String space = " "; String space = " ";
@@ -584,116 +724,169 @@ public class ReadWriteNonCoreDataServiceImpl implements ReadWriteNonCoreDataServ
// ignores id and foreign key fields // ignores id and foreign key fields
// also ignores locale and dateformat fields that are used for // also ignores locale and dateformat fields that are used for
// validating numeric and date data // validating numeric and date data
if (!((key.equalsIgnoreCase("id")) || (key.equalsIgnoreCase(keyFieldName)) || (key.equals("locale")) || (key if (!((key.equalsIgnoreCase("id"))
.equals("dateFormat")))) { || (key.equalsIgnoreCase(keyFieldName))
|| (key.equals("locale")) || (key.equals("dateFormat")))) {
notFound = true; notFound = true;
// 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 (ResultsetColumnHeader columnHeader : columnHeaders) {
if (notFound) { if (notFound) {
columnHeaderUnderscored = genericDataService.replace(columnHeader.getColumnName(), space, underscore); columnHeaderUnderscored = genericDataService
if (queryParamColumnUnderscored.equalsIgnoreCase(columnHeaderUnderscored)) { .replace(columnHeader.getColumnName(), space,
underscore);
if (queryParamColumnUnderscored
.equalsIgnoreCase(columnHeaderUnderscored)) {
pValue = queryParams.get(key); pValue = queryParams.get(key);
pValue = validateColumn(columnHeader, pValue, dateFormat, clientApplicationLocale); pValue = validateColumn(columnHeader, pValue,
affectedColumns.put(columnHeader.getColumnName(), pValue); dateFormat, clientApplicationLocale);
affectedColumns.put(columnHeader.getColumnName(),
pValue);
notFound = false; notFound = false;
} }
} }
} }
if (notFound) { throw new PlatformDataIntegrityException("error.msg.column.not.found", "Column: " + key + " Not Found"); } if (notFound) {
throw new PlatformDataIntegrityException(
"error.msg.column.not.found", "Column: " + key
+ " Not Found");
}
} }
} }
return affectedColumns; return affectedColumns;
} }
private String validateColumn(final ResultsetColumnHeader columnHeader, final String pValue, final String dateFormat, private String validateColumn(final ResultsetColumnHeader 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"))
|| (columnHeader.getColumnDisplayType().equals("DECIMAL")))
paramValue = paramValue.trim();
if ((StringUtils.isEmpty(paramValue)) && (!(columnHeader.isColumnNullable()))) { if ((StringUtils.isEmpty(paramValue))
&& (!(columnHeader.isColumnNullable()))) {
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("error.msg.column.mandatory", "Mandatory", 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(
dataValidationErrors); "validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
} }
if (!StringUtils.isEmpty(paramValue)) { if (!StringUtils.isEmpty(paramValue)) {
if (columnHeader.getColumnValues().size() > 0) { if (columnHeader.getColumnValues().size() > 0) {
// match code value or id // match code value or id
List<ResultsetColumnValue> allowedValues = columnHeader.getColumnValues(); List<ResultsetColumnValue> allowedValues = columnHeader
.getColumnValues();
if (columnHeader.getColumnDisplayType().equals("CODEVALUE")) { if (columnHeader.getColumnDisplayType().equals("CODEVALUE")) {
for (ResultsetColumnValue allowedValue : allowedValues) { for (ResultsetColumnValue allowedValue : allowedValues) {
if (paramValue.equalsIgnoreCase(allowedValue.getValue())) return paramValue; if (paramValue
.equalsIgnoreCase(allowedValue.getValue()))
return paramValue;
} }
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue", ApiParameterError error = ApiParameterError.parameterError(
"Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue); "error.msg.invalid.columnValue",
"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(
dataValidationErrors); "validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
} }
if (columnHeader.getColumnDisplayType().equals("CODELOOKUP")) { if (columnHeader.getColumnDisplayType().equals("CODELOOKUP")) {
for (ResultsetColumnValue allowedValue : allowedValues) { for (ResultsetColumnValue allowedValue : allowedValues) {
if (paramValue.equals(Integer.toString(allowedValue.getId()))) return paramValue; if (paramValue.equals(Integer.toString(allowedValue
.getId())))
return paramValue;
} }
List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>(); List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
ApiParameterError error = ApiParameterError.parameterError("error.msg.invalid.columnValue", ApiParameterError error = ApiParameterError.parameterError(
"Value not found in Allowed Value list", columnHeader.getColumnName(), paramValue); "error.msg.invalid.columnValue",
"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(
dataValidationErrors); "validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors);
} }
throw new PlatformDataIntegrityException("error.msg.invalid.columnType.", "Code: " + columnHeader.getColumnName() throw new PlatformDataIntegrityException(
+ " - Invalid Type " + columnHeader.getColumnType() + " (neither varchar nor int)"); "error.msg.invalid.columnType.", "Code: "
+ columnHeader.getColumnName()
+ " - Invalid Type "
+ columnHeader.getColumnType()
+ " (neither varchar nor int)");
} }
JsonParserHelper helper = new JsonParserHelper(); JsonParserHelper helper = new JsonParserHelper();
if (columnHeader.getColumnDisplayType().equals("DATE")) if (columnHeader.getColumnDisplayType().equals("DATE")) {
paramValue = helper.convertFrom(paramValue, columnHeader.getColumnName(), dateFormat, clientApplicationLocale).toString(); LocalDate tmpDate = helper.convertFrom(paramValue,
columnHeader.getColumnName(), dateFormat,
if (columnHeader.getColumnDisplayType().equals("INTEGER")) clientApplicationLocale);
paramValue = helper.convertToInteger(paramValue, columnHeader.getColumnName(), clientApplicationLocale).toString(); if (tmpDate == null)
return null;
if (columnHeader.getColumnDisplayType().equals("DECIMAL")) return tmpDate.toString();
paramValue = helper.convertFrom(paramValue, columnHeader.getColumnName(), clientApplicationLocale).toString(); }
// logger.info("Converted Value: " + paramValue + " - was: " + if (columnHeader.getColumnDisplayType().equals("INTEGER")) {
// pValue); Integer tmpInt = helper.convertToInteger(paramValue,
columnHeader.getColumnName(), clientApplicationLocale);
if (tmpInt == null)
return null;
return tmpInt.toString();
}
if (columnHeader.getColumnDisplayType().equals("DECIMAL")) {
BigDecimal tmpDecimal = helper.convertFrom(paramValue,
columnHeader.getColumnName(), clientApplicationLocale);
if (tmpDecimal == null)
return null;
return tmpDecimal.toString();
}
} }
return paramValue; return paramValue;
} }
private String getDeleteEntriesSql(final String datatable, final String FKField, final Long appTableId) { private String getDeleteEntriesSql(final String datatable,
final String FKField, final Long appTableId) {
return "delete from `" + datatable + "` where `" + FKField + "` = " + appTableId; return "delete from `" + datatable + "` where `" + FKField + "` = "
+ appTableId;
} }
private String getDeleteEntrySql(final String datatable, final Long datatableId) { private String getDeleteEntrySql(final String datatable,
final Long datatableId) {
return "delete from `" + datatable + "` where `id` = " + datatableId; return "delete from `" + datatable + "` where `id` = " + datatableId;
} }
private boolean notTheSame(final String currValue, final String pValue) { private boolean notTheSame(final String currValue, final String pValue) {
if (StringUtils.isEmpty(currValue) && StringUtils.isEmpty(pValue)) return false; if (StringUtils.isEmpty(currValue) && StringUtils.isEmpty(pValue))
return false;
if (StringUtils.isEmpty(currValue)) return true; if (StringUtils.isEmpty(currValue))
return true;
if (StringUtils.isEmpty(pValue)) return true; if (StringUtils.isEmpty(pValue))
return true;
if (currValue.equals(pValue)) return false; if (currValue.equals(pValue))
return false;
return true; return true;
} }