diff --git a/pom.xml b/pom.xml index 70859837..8733a6ca 100644 --- a/pom.xml +++ b/pom.xml @@ -47,12 +47,22 @@ org.springframework.boot spring-boot-starter - + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-simple + ${slf4j.version} co.elastic.logging diff --git a/src/main/java/com/iemr/mmu/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java b/src/main/java/com/iemr/mmu/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java index dedad0eb..eeb54e9f 100644 --- a/src/main/java/com/iemr/mmu/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java +++ b/src/main/java/com/iemr/mmu/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java @@ -36,9 +36,11 @@ import com.iemr.mmu.service.dataSyncLayerCentral.FetchDownloadDataImpl; import com.iemr.mmu.service.dataSyncLayerCentral.GetDataFromVanAndSyncToDBImpl; import com.iemr.mmu.service.dataSyncLayerCentral.GetMasterDataFromCentralForVanImpl; +import com.iemr.mmu.utils.CookieUtil; import com.iemr.mmu.utils.response.OutputResponse; import io.swagger.v3.oas.annotations.Operation; +import jakarta.servlet.http.HttpServletRequest; /*** * @operation Class used for data sync from van-to-server & server-to-van @@ -58,10 +60,15 @@ public class MMUDataSyncVanToServer { @Operation(summary = "Sync data from van-to-server") @PostMapping(value = { "/van-to-server" }, consumes = "application/json", produces = "application/json") public String dataSyncToServer(@RequestBody String requestOBJ, - @RequestHeader(value = "Authorization") String Authorization) { + @RequestHeader(value = "Authorization") String Authorization, HttpServletRequest request) { OutputResponse response = new OutputResponse(); + + logger.info("test: vanto server auth="+Authorization); try { - String s = getDataFromVanAndSyncToDBImpl.syncDataToServer(requestOBJ, Authorization); + String jwtToken = CookieUtil.getJwtTokenFromCookie(request); + logger.info("test: vanto server token="+jwtToken); + + String s = getDataFromVanAndSyncToDBImpl.syncDataToServer(requestOBJ, Authorization, jwtToken); if (s != null) response.setResponse(s); else diff --git a/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/DataSyncRepositoryCentral.java b/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/DataSyncRepositoryCentral.java index 6b62af69..175de980 100644 --- a/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/DataSyncRepositoryCentral.java +++ b/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/DataSyncRepositoryCentral.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.Set; import javax.sql.DataSource; @@ -34,175 +35,186 @@ import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; -/*** - * - * @author NE298657 - * - */ +import com.iemr.mmu.data.syncActivity_syncLayer.SyncUploadDataDigester; @Service public class DataSyncRepositoryCentral { - @Autowired - private DataSource dataSource; - - private JdbcTemplate jdbcTemplate; - - private JdbcTemplate getJdbcTemplate() { - return new JdbcTemplate(dataSource); - - } - - private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); - - // Data Upload Repository - public int checkRecordIsAlreadyPresentOrNot(String schemaName, String tableName, String vanSerialNo, String vanID, - String vanAutoIncColumnName, int syncFacilityID) { - jdbcTemplate = getJdbcTemplate(); - - List params = new ArrayList<>(); - - StringBuilder queryBuilder = new StringBuilder("SELECT "); - queryBuilder.append(vanAutoIncColumnName); - queryBuilder.append(" FROM "); - queryBuilder.append(schemaName+"."+tableName); - - //params.add(vanAutoIncColumnName); - //params.add(schemaName); - //params.add(tableName); - - StringBuilder whereClause = new StringBuilder(); - whereClause.append(" WHERE "); - whereClause.append("VanSerialNo = ?"); - params.add(vanSerialNo); - - if ((tableName.equalsIgnoreCase("t_patientissue") || tableName.equalsIgnoreCase("t_physicalstockentry") - || tableName.equalsIgnoreCase("t_stockadjustment") || tableName.equalsIgnoreCase("t_saitemmapping") - || tableName.equalsIgnoreCase("t_stocktransfer") || tableName.equalsIgnoreCase("t_patientreturn") - || tableName.equalsIgnoreCase("t_facilityconsumption") || tableName.equalsIgnoreCase("t_indent") - || tableName.equalsIgnoreCase("t_indentorder") || tableName.equalsIgnoreCase("t_indentissue") - || tableName.equalsIgnoreCase("t_itemstockentry") || tableName.equalsIgnoreCase("t_itemstockexit")) - && syncFacilityID > 0) { - - whereClause.append(" AND "); - whereClause.append("SyncFacilityID = ?"); - params.add(syncFacilityID); - - } - - else { - - whereClause.append(" AND "); - whereClause.append("VanID = ?"); - params.add(vanID); - - } - - queryBuilder.append(whereClause); - String query = queryBuilder.toString(); - Object[] queryParams = params.toArray(); - List> resultSet = jdbcTemplate.queryForList(query, queryParams); - if (resultSet != null && resultSet.size() > 0) - return 1; - else - return 0; - } - - // Method for synchronization of data to central DB - public int[] syncDataToCentralDB(String schema, String tableName, String serverColumns, String query, - List syncDataList) { - jdbcTemplate = getJdbcTemplate(); - if (query.startsWith("INSERT")) { - for (int i = 0; i < syncDataList.size(); i++) { - Object[] array = syncDataList.get(i);// Arrey 1 - - if (query.startsWith("INSERT")) { -// array = new Object[] {serverColumns, array }; - syncDataList.set(i, array); - } - } - } else { - for (int i = 0; i < syncDataList.size(); i++) { - - Object[] array = syncDataList.get(i);// Arrey 1 - String[] columnsArray = null; - if(null != serverColumns) - columnsArray = serverColumns.split(","); // arrey 2 - - List Newarray = new ArrayList<>(); - - int arrayIndex = 0; - int columnsArrayIndex = 0; - //Newarray.add(schema); - //Newarray.add(tableName); - //while (columnsArrayIndex < columnsArray.length || arrayIndex < array.length) { - if (null != columnsArray && columnsArrayIndex < columnsArray.length) { - Newarray.add(columnsArray[columnsArrayIndex]); - columnsArrayIndex++; - } - - /* - * if (arrayIndex < array.length) { Newarray.add(array); arrayIndex++; } - */ - //} - - // Convert Newarray back to an array - //Object[] resultArray = Newarray.toArray(new Object[0]); - syncDataList.set(i, array); - - } - } - // start batch insert/update - int[] i = jdbcTemplate.batchUpdate(query, syncDataList); - return i; - - } - - // End of Data Upload Repository - - public List> getMasterDataFromTable(String schema, String table, String columnNames, - String masterType, Timestamp lastDownloadDate, Integer vanID, Integer psmID) throws Exception { - jdbcTemplate = getJdbcTemplate(); - List> resultSetList =new ArrayList<>(); - String baseQuery = ""; - if (masterType != null) { - if (lastDownloadDate != null) { - if (masterType.equalsIgnoreCase("A")) { - baseQuery += " SELECT " + columnNames + " FROM " + schema + "." + table - + " WHERE LastModDate >= ? "; - resultSetList = jdbcTemplate.queryForList(baseQuery,lastDownloadDate); - - } - else if (masterType.equalsIgnoreCase("V")) { - baseQuery += " SELECT " + columnNames + " FROM " + schema + "." + table - + " WHERE LastModDate >= ? AND VanID = ? "; - resultSetList = jdbcTemplate.queryForList(baseQuery,lastDownloadDate,vanID); - } - else if (masterType.equalsIgnoreCase("P")) { - baseQuery += " SELECT " + columnNames + " FROM " + schema + "." + table - + " WHERE LastModDate >= ? AND ProviderServiceMapID = ? "; - resultSetList = jdbcTemplate.queryForList(baseQuery,lastDownloadDate,psmID); - } - } else { - if (masterType.equalsIgnoreCase("A")) { - baseQuery += " SELECT " + columnNames + " FROM " + schema + "." + table; - resultSetList = jdbcTemplate.queryForList(baseQuery); - } - else if (masterType.equalsIgnoreCase("V")) { - baseQuery += " SELECT " + columnNames + " FROM " + schema + "." + table + " WHERE VanID = ? "; - resultSetList = jdbcTemplate.queryForList(baseQuery,vanID); - } - else if (masterType.equalsIgnoreCase("P")) { - baseQuery += " SELECT " + columnNames + " FROM " + schema + "." + table - + " WHERE ProviderServiceMapID = ? "; - resultSetList = jdbcTemplate.queryForList(baseQuery,psmID); - } - } - } - logger.info("Select query central: " + baseQuery); - logger.info("Last Downloaded Date " + lastDownloadDate); - logger.info("Result set Details: " + resultSetList); - return resultSetList; - } - - // End of Data Download Repository + @Autowired + private DataSource dataSource; + + private JdbcTemplate jdbcTemplate; + + private JdbcTemplate getJdbcTemplate() { + if (this.jdbcTemplate == null) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + return this.jdbcTemplate; + } + + private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + + private static final Set VALID_SCHEMAS = Set.of("public", "db_iemr"); + + private static final Set VALID_TABLES = Set.of( + "m_beneficiaryregidmapping", "i_beneficiaryaccount", "i_beneficiaryaddress", "i_beneficiarycontacts", + "i_beneficiarydetails", "i_beneficiaryfamilymapping", "i_beneficiaryidentity", "i_beneficiarymapping", + "t_benvisitdetail", "t_phy_anthropometry", "t_phy_vitals", "t_benadherence", "t_anccare", "t_pnccare", + "t_ncdscreening", "t_ncdcare", "i_ben_flow_outreach", "t_covid19", "t_idrsdetails", "t_physicalactivity", + "t_phy_generalexam", "t_phy_headtotoe", "t_sys_obstetric", "t_sys_gastrointestinal", "t_sys_cardiovascular", + "t_sys_respiratory", "t_sys_centralnervous", "t_sys_musculoskeletalsystem", "t_sys_genitourinarysystem", + "t_ancdiagnosis", "t_ncddiagnosis", "t_pncdiagnosis", "t_benchefcomplaint", "t_benclinicalobservation", + "t_prescription", "t_prescribeddrug", "t_lab_testorder", "t_benreferdetails", + "t_lab_testresult", "t_physicalstockentry", "t_patientissue", "t_facilityconsumption", "t_itemstockentry", + "t_itemstockexit", "t_benmedhistory", "t_femaleobstetrichistory", "t_benmenstrualdetails", + "t_benpersonalhabit", "t_childvaccinedetail1", "t_childvaccinedetail2", "t_childoptionalvaccinedetail", + "t_ancwomenvaccinedetail", "t_childfeedinghistory", "t_benallergyhistory", "t_bencomorbiditycondition", + "t_benmedicationhistory", "t_benfamilyhistory", "t_perinatalhistory", "t_developmenthistory", + "t_cancerfamilyhistory", "t_cancerpersonalhistory", "t_cancerdiethistory", "t_cancerobstetrichistory", + "t_cancervitals", "t_cancersignandsymptoms", "t_cancerlymphnode", "t_canceroralexamination", + "t_cancerbreastexamination", "t_cancerabdominalexamination", "t_cancergynecologicalexamination", + "t_cancerdiagnosis", "t_cancerimageannotation", "i_beneficiaryimage", "t_stockadjustment", + "t_stocktransfer", "t_patientreturn", "t_indent", "t_indentissue", "t_indentorder", "t_saitemmapping" + ); + + private boolean isValidDatabaseIdentifierCharacter(String identifier) { + return identifier != null && identifier.matches("^[a-zA-Z_][a-zA-Z0-9_]*$"); + } + + private boolean isValidSchemaName(String schemaName) { + return VALID_SCHEMAS.contains(schemaName.toLowerCase()); + } + + private boolean isValidTableName(String tableName) { + return VALID_TABLES.contains(tableName.toLowerCase()); + } + + private boolean isValidColumnNamesList(String columnNames) { + if (columnNames == null || columnNames.trim().isEmpty()) { + return false; + } + for (String col : columnNames.split(",")) { + if (!isValidDatabaseIdentifierCharacter(col.trim())) { + return false; + } + } + return true; + } + + public int checkRecordIsAlreadyPresentOrNot(String schemaName, String tableName, String vanSerialNo, String vanID, + String vanAutoIncColumnName, int syncFacilityID) { + jdbcTemplate = getJdbcTemplate(); + List params = new ArrayList<>(); + + if (!isValidSchemaName(schemaName) || !isValidTableName(tableName) || + !isValidDatabaseIdentifierCharacter(vanAutoIncColumnName)) { + logger.error("Invalid identifiers: schema={}, table={}, column={}", schemaName, tableName, vanAutoIncColumnName); + throw new IllegalArgumentException("Invalid identifiers provided."); + } + + StringBuilder queryBuilder = new StringBuilder("SELECT ") + .append(vanAutoIncColumnName).append(" FROM ") + .append(schemaName).append(".").append(tableName).append(" WHERE VanSerialNo = ?"); + + params.add(vanSerialNo); + + if (List.of("t_patientissue", "t_physicalstockentry", "t_stockadjustment", "t_saitemmapping", + "t_stocktransfer", "t_patientreturn", "t_facilityconsumption", "t_indent", + "t_indentorder", "t_indentissue", "t_itemstockentry", "t_itemstockexit").contains(tableName.toLowerCase()) && syncFacilityID > 0) { + queryBuilder.append(" AND SyncFacilityID = ?"); + params.add(syncFacilityID); + } else { + queryBuilder.append(" AND VanID = ?"); + params.add(vanID); + } + + try { + List> resultSet = jdbcTemplate.queryForList(queryBuilder.toString(), params.toArray()); + return (resultSet != null && !resultSet.isEmpty()) ? 1 : 0; + } catch (Exception e) { + logger.error("Error checking record presence: {}", e.getMessage(), e); + throw new RuntimeException("Failed to check record existence: " + e.getMessage(), e); + } + } + + public int[] syncDataToCentralDB(String schema, String tableName, String serverColumns, String query, + List syncDataList) { + jdbcTemplate = getJdbcTemplate(); + try { + return jdbcTemplate.batchUpdate(query, syncDataList); + } catch (Exception e) { + logger.error("Batch sync failed for table {}: {}", tableName, e.getMessage(), e); + throw new RuntimeException("Batch sync failed: " + e.getMessage(), e); + } + } + + public List> getMasterDataFromTable(String schema, String table, String columnNames, + String masterType, Timestamp lastDownloadDate, Integer vanID, Integer psmID) { + jdbcTemplate = getJdbcTemplate(); + List params = new ArrayList<>(); + + if (!isValidSchemaName(schema) || !isValidTableName(table) || !isValidColumnNamesList(columnNames)) { + throw new IllegalArgumentException("Invalid schema, table, or column names."); + } + + StringBuilder queryBuilder = new StringBuilder("SELECT ").append(columnNames) + .append(" FROM ").append(schema).append(".").append(table); + + if (masterType != null) { + if (lastDownloadDate != null) { + queryBuilder.append(" WHERE LastModDate >= ?"); + params.add(lastDownloadDate); + + if ("V".equalsIgnoreCase(masterType)) { + queryBuilder.append(" AND VanID = ?"); + params.add(vanID); + } else if ("P".equalsIgnoreCase(masterType)) { + queryBuilder.append(" AND ProviderServiceMapID = ?"); + params.add(psmID); + } + } else { + queryBuilder.append(" WHERE "); + if ("V".equalsIgnoreCase(masterType)) { + queryBuilder.append("VanID = ?"); + params.add(vanID); + } else if ("P".equalsIgnoreCase(masterType)) { + queryBuilder.append("ProviderServiceMapID = ?"); + params.add(psmID); + } + } + } + + try { + // Safe dynamic SQL: All dynamic parts (table names, columns, etc.) are validated or hardcoded. + // Parameter values are bound safely using prepared statement placeholders (?). + return jdbcTemplate.queryForList(queryBuilder.toString(), params.toArray()); + } catch (Exception e) { + logger.error("Error fetching master data: {}", e.getMessage(), e); + throw new RuntimeException("Failed to fetch master data: " + e.getMessage(), e); + } + } + + public List> getBatchForBenDetails(SyncUploadDataDigester digester, + String whereClause, int limit, int offset) { + jdbcTemplate = getJdbcTemplate(); + +String schema = digester.getSchemaName(); + String table = digester.getTableName(); + String columnNames = digester.getServerColumns(); + + + if (!isValidSchemaName(schema) || !isValidTableName(table) || !isValidColumnNamesList(columnNames)) { + throw new IllegalArgumentException("Invalid schema, table, or column names."); + } + // Safe dynamic SQL: Schema, table, and column names are validated against predefined whitelists. + // Only trusted values are used in the query string. + // limit and offset are passed as parameters to prevent SQL injection. + String query = String.format("SELECT %s FROM %s.%s %s LIMIT ? OFFSET ?", columnNames, schema, table, whereClause); //NOSONAR + + try { + return jdbcTemplate.queryForList(query, limit, offset); + } catch (Exception e) { + logger.error("Error fetching batch details: {}", e.getMessage(), e); + throw new RuntimeException("Failed to fetch batch data: " + e.getMessage(), e); + } + } } diff --git a/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/GetDataFromVanAndSyncToDBImpl.java b/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/GetDataFromVanAndSyncToDBImpl.java index d70404bb..2d88e6f6 100644 --- a/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/GetDataFromVanAndSyncToDBImpl.java +++ b/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/GetDataFromVanAndSyncToDBImpl.java @@ -21,365 +21,625 @@ */ package com.iemr.mmu.service.dataSyncLayerCentral; -import java.sql.Timestamp; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.HashMap; +import java.util.Set; +import java.util.HashSet; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.fasterxml.jackson.databind.ObjectMapper; import com.iemr.mmu.data.syncActivity_syncLayer.SyncUploadDataDigester; -import com.iemr.mmu.utils.mapper.InputMapper; -/*** - * - * @author NE298657 - * - */ @Service public class GetDataFromVanAndSyncToDBImpl implements GetDataFromVanAndSyncToDB { - private static final String ServerColumnsNotRequired = null; - @Autowired - private DataSyncRepositoryCentral dataSyncRepositoryCentral; - - public String syncDataToServer(String requestOBJ, String Authorization) throws Exception { - - // feed sync request - ObjectMapper mapper = new ObjectMapper(); - SyncUploadDataDigester syncUploadDataDigester = mapper.readValue(requestOBJ, SyncUploadDataDigester.class); - /* - * SyncUploadDataDigester syncUploadDataDigester = - * InputMapper.gson().fromJson(requestOBJ, SyncUploadDataDigester.class); - */ - String syncTableName = syncUploadDataDigester.getTableName(); - if (syncUploadDataDigester != null && syncTableName != null - && syncTableName.equalsIgnoreCase("m_beneficiaryregidmapping")) { - String s = update_M_BeneficiaryRegIdMapping_for_provisioned_benID(syncUploadDataDigester); - return s; - } else { - - List> dataToBesync = syncUploadDataDigester.getSyncData(); - - Object[] objArr; - - // sync data 'list of object array' - List syncDataListInsert = new ArrayList<>(); - List syncDataListUpdate = new ArrayList<>(); - - int pointer; - String vanSerialNo; - String vanID; - int recordCheck; - int syncFacilityID = 0; - - for (Map map : dataToBesync) { - pointer = 0; - recordCheck = 0; - vanSerialNo = ""; - vanID = ""; - - vanSerialNo = String.valueOf(map.get(syncUploadDataDigester.getVanAutoIncColumnName())); - vanID = String.valueOf(map.get("VanID")); - - map.replace("SyncedBy", syncUploadDataDigester.getSyncedBy()); - - map.replace("date_format(SyncedDate,'%Y-%m-%d %H:%i:%s')", String.valueOf(LocalDateTime.now())); - - if (syncUploadDataDigester.getFacilityID() != null) { - Double changeDoubleToIntegerID = 0.0; - switch (syncTableName) { - case "t_indent": { - if (map.containsKey("FromFacilityID") && map.get("FromFacilityID") != null) { - changeDoubleToIntegerID = (Double) map.get("FromFacilityID"); - if (changeDoubleToIntegerID.intValue() == syncUploadDataDigester.getFacilityID()) - map.replace("Processed", "P"); - } - - } - case "t_indentorder": { - if (map.containsKey("FromFacilityID") && map.get("FromFacilityID") != null) - changeDoubleToIntegerID = (Double) map.get("FromFacilityID"); - if (changeDoubleToIntegerID.intValue() == syncUploadDataDigester.getFacilityID()) - map.replace("Processed", "P"); - } - case "t_indentissue": { - if (map.containsKey("ToFacilityID") && map.get("ToFacilityID") != null) { - changeDoubleToIntegerID = (Double) map.get("ToFacilityID"); - if (changeDoubleToIntegerID.intValue() == syncUploadDataDigester.getFacilityID()) - map.replace("Processed", "P"); - } - - } - // here a change in rule, will compare with toFacilityID - case "t_stocktransfer": { - if (map.containsKey("TransferToFacilityID") && map.get("TransferToFacilityID") != null) { - changeDoubleToIntegerID = (Double) map.get("TransferToFacilityID"); - if (changeDoubleToIntegerID.intValue() == syncUploadDataDigester.getFacilityID()) - map.replace("Processed", "P"); - } - - } - case "t_itemstockentry": { - - if (map.containsKey("FacilityID") && map.get("FacilityID") != null) { - changeDoubleToIntegerID = (Double) map.get("FacilityID"); - if (changeDoubleToIntegerID.intValue() == syncUploadDataDigester.getFacilityID()) - map.replace("Processed", "P"); - } - - } - default: - - } - - } - - if (map.containsKey("SyncFacilityID")) { - //double syncFaciltyID = (double) map.get("SyncFacilityID"); - syncFacilityID = (int) map.get("SyncFacilityID"); - } - - recordCheck = dataSyncRepositoryCentral.checkRecordIsAlreadyPresentOrNot( - syncUploadDataDigester.getSchemaName(), syncUploadDataDigester.getTableName(), vanSerialNo, - vanID, syncUploadDataDigester.getVanAutoIncColumnName(), syncFacilityID); - - if (recordCheck == 0) { - objArr = new Object[map.size()]; - } else { - objArr = new Object[map.size() + 2]; - } - - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() != null) { - if (String.valueOf(entry.getValue()).equalsIgnoreCase("false") - || String.valueOf(entry.getValue()).equalsIgnoreCase("true")) - objArr[pointer] = entry.getValue(); - else - objArr[pointer] = String.valueOf(entry.getValue()); - } else - objArr[pointer] = entry.getValue(); - - pointer++; - } - - if (recordCheck == 0) { - syncDataListInsert.add(objArr); - } else { - - - objArr[pointer] = String.valueOf(vanSerialNo); - - if ((syncTableName.equalsIgnoreCase("t_patientissue") - || syncTableName.equalsIgnoreCase("t_physicalstockentry") - || syncTableName.equalsIgnoreCase("t_stockadjustment") - || syncTableName.equalsIgnoreCase("t_saitemmapping") - || syncTableName.equalsIgnoreCase("t_stocktransfer") - || syncTableName.equalsIgnoreCase("t_patientreturn") - || syncTableName.equalsIgnoreCase("t_facilityconsumption") - || syncTableName.equalsIgnoreCase("t_indent") - || syncTableName.equalsIgnoreCase("t_indentorder") - || syncTableName.equalsIgnoreCase("t_indentissue") - || syncTableName.equalsIgnoreCase("t_itemstockentry") - || syncTableName.equalsIgnoreCase("t_itemstockexit")) - && map.containsKey("SyncFacilityID")) { - - objArr[pointer + 1] = String.valueOf(map.get("SyncFacilityID")); - } else - objArr[pointer + 1] = String.valueOf(vanID); - - syncDataListUpdate.add(objArr); - } - - } - - int[] i = null; - if (syncDataListInsert != null && syncDataListInsert.size() > 0) { - // schema name hard coded(Insert query builder) - String queryInsert = getQueryToInsertDataToServerDB(syncUploadDataDigester.getSchemaName(), - syncUploadDataDigester.getTableName(),syncUploadDataDigester.getServerColumns()); - - // call repository to execute the query with given data list(Insert) - i = dataSyncRepositoryCentral.syncDataToCentralDB( - syncUploadDataDigester.getSchemaName(), - syncUploadDataDigester.getTableName(), syncUploadDataDigester.getServerColumns(), queryInsert, - syncDataListInsert); - } - - int[] j = null; - if (syncDataListUpdate != null && syncDataListUpdate.size() > 0) { - // schema name hard coded(Update query builder) - String queryUpdate = getQueryToUpdateDataToServerDB(syncUploadDataDigester.getSchemaName(), syncUploadDataDigester.getServerColumns(), - syncUploadDataDigester.getTableName()); - - // call repository to execute the query with given data list(Update) - j = dataSyncRepositoryCentral.syncDataToCentralDB(syncUploadDataDigester.getSchemaName(), - syncUploadDataDigester.getTableName(), ServerColumnsNotRequired, queryUpdate, - syncDataListUpdate); - } - - // validating if data sync successfully - if ((i != null && syncDataListInsert.size() != i.length) - || (j != null && syncDataListUpdate.size() != j.length)) - return null; - else - return "data sync passed"; - - } - - } - - public String update_M_BeneficiaryRegIdMapping_for_provisioned_benID( - SyncUploadDataDigester syncUploadDataDigester) { - String returnOBJ = null; - List> dataToBesync = syncUploadDataDigester.getSyncData(); - - Object[] objArr; - // sync data 'list of object array' - List syncData = new ArrayList<>(); - - String query = getqueryFor_M_BeneficiaryRegIdMapping(syncUploadDataDigester.getSchemaName(), - syncUploadDataDigester.getTableName()); - - for (Map map : dataToBesync) { - if (map.get("BenRegId") != null && map.get("BeneficiaryID") != null && map.get("VanID") != null) { - objArr = new Object[4]; - objArr[0] = String.valueOf(syncUploadDataDigester.getSyncedBy()); - objArr[1] = String.valueOf(map.get("BenRegId")); - objArr[2] = String.valueOf(map.get("BeneficiaryID")); - objArr[3] = String.valueOf(map.get("VanID")); - - syncData.add(objArr); - } - } - int[] i = null; - - if (syncData != null && syncData.size() > 0) { - i = dataSyncRepositoryCentral.syncDataToCentralDB(syncUploadDataDigester.getSchemaName(), - syncUploadDataDigester.getTableName(), ServerColumnsNotRequired, query, syncData); - - if (i.length == syncData.size()) { - returnOBJ = "data sync passed"; - } - } else { - returnOBJ = "data sync passed"; - } - - return returnOBJ; - - } - - private String getqueryFor_M_BeneficiaryRegIdMapping(String schemaName, String tableName) { - - StringBuilder queryBuilder = new StringBuilder(" UPDATE "); - queryBuilder.append(schemaName+"."+tableName); - queryBuilder.append(" SET "); - queryBuilder.append("Provisioned = true, SyncedDate = now(), syncedBy = ?"); - queryBuilder.append(" WHERE "); - queryBuilder.append(" BenRegId = ? "); - queryBuilder.append(" AND "); - queryBuilder.append(" BeneficiaryID = ? "); - queryBuilder.append(" AND "); - queryBuilder.append(" VanID = ? "); - String query = queryBuilder.toString(); - return query; - } - - public String getQueryToInsertDataToServerDB(String schemaName, String tableName, String serverColumns) { - String[] columnsArr = null; - if (serverColumns != null) - columnsArr = serverColumns.split(","); - - StringBuilder preparedStatementSetter = new StringBuilder(); - /// StringBuilder updateStatement = new StringBuilder(); - - if (columnsArr != null && columnsArr.length > 0) { - int index = 0; - for (String column : columnsArr) { - if (index == columnsArr.length - 1) { - preparedStatementSetter.append(" ? "); - - } else { - preparedStatementSetter.append(" ?, "); - - } - index++; - } - } - /* - * String query = "INSERT INTO " + schemaName + "." + tableName + "( " + - * serverColumns + ") VALUES ( " + preparedStatementSetter + " ) "; - */ - - StringBuilder queryBuilder = new StringBuilder("INSERT INTO "); - queryBuilder.append(schemaName + "." + tableName); - queryBuilder.append("("); -// queryBuilder.append("?"); - queryBuilder.append(serverColumns); - queryBuilder.append(") VALUES ("); - queryBuilder.append(preparedStatementSetter); - queryBuilder.append(") "); - String query = queryBuilder.toString(); - - return query; - } - - public String getQueryToUpdateDataToServerDB(String schemaName, String serverColumns, String tableName) { - String[] columnsArr = null; - if (serverColumns != null) - columnsArr = serverColumns.split(","); - - StringBuilder preparedStatementSetter = new StringBuilder(); - - if (columnsArr != null && columnsArr.length > 0) { - int index = 0; - for (String column : columnsArr) { - if (index == columnsArr.length - 1) { - preparedStatementSetter.append(column); - preparedStatementSetter.append("= ?"); - } else { - preparedStatementSetter.append(column); - preparedStatementSetter.append("= ?, "); - } - index++; - } - } - - if (tableName.equalsIgnoreCase("t_patientissue") || tableName.equalsIgnoreCase("t_physicalstockentry") - || tableName.equalsIgnoreCase("t_stockadjustment") || tableName.equalsIgnoreCase("t_saitemmapping") - || tableName.equalsIgnoreCase("t_stocktransfer") || tableName.equalsIgnoreCase("t_patientreturn") - || tableName.equalsIgnoreCase("t_facilityconsumption") || tableName.equalsIgnoreCase("t_indent") - || tableName.equalsIgnoreCase("t_indentorder") || tableName.equalsIgnoreCase("t_indentissue") - || tableName.equalsIgnoreCase("t_itemstockentry") || tableName.equalsIgnoreCase("t_itemstockexit")) { - - StringBuilder queryBuilder = new StringBuilder(" UPDATE "); - queryBuilder.append(schemaName+"."+tableName); - queryBuilder.append(" SET "); - queryBuilder.append(preparedStatementSetter); - queryBuilder.append(" WHERE "); - queryBuilder.append(" VanSerialNo =? "); - queryBuilder.append(" AND "); - queryBuilder.append(" SyncFacilityID = ? "); - String query = queryBuilder.toString(); - return query; - } else { - StringBuilder queryBuilder = new StringBuilder(" UPDATE "); - queryBuilder.append(schemaName+"."+tableName); - queryBuilder.append(" SET "); - queryBuilder.append(preparedStatementSetter); - queryBuilder.append(" WHERE "); - queryBuilder.append(" VanSerialNo =? "); - queryBuilder.append(" AND "); - queryBuilder.append(" VanID = ? "); - String query = queryBuilder.toString(); - return query; - } - - } + private static final String SERVER_COLUMNS_NOT_REQUIRED = null; // Renamed for clarity + private static final Logger logger = LoggerFactory.getLogger(GetDataFromVanAndSyncToDBImpl.class); + + @Autowired + private DataSyncRepositoryCentral dataSyncRepositoryCentral; + + private static final Map> TABLE_GROUPS = new HashMap<>(); + private static final Set VALID_SCHEMAS = new HashSet<>(Arrays.asList("public", "db_iemr")); // Add your actual schema names + private static final Set VALID_TABLES = new HashSet<>(Arrays.asList( + "m_beneficiaryregidmapping", "i_beneficiaryaccount","i_beneficiaryaddress","i_beneficiarycontacts","i_beneficiarydetails","i_beneficiaryfamilymapping","i_beneficiaryidentity","i_beneficiarymapping", + "t_benvisitdetail","t_phy_anthropometry","t_phy_vitals","t_benadherence","t_anccare","t_pnccare","t_ncdscreening","t_ncdcare","i_ben_flow_outreach","t_covid19","t_idrsdetails","t_physicalactivity", + "t_phy_generalexam","t_phy_headtotoe","t_sys_obstetric","t_sys_gastrointestinal","t_sys_cardiovascular","t_sys_respiratory","t_sys_centralnervous","t_sys_musculoskeletalsystem","t_sys_genitourinarysystem", + "t_ancdiagnosis","t_ncddiagnosis","t_pncdiagnosis","t_benchefcomplaint","t_benclinicalobservation","t_prescription","t_prescribeddrug","t_lab_testorder","t_benreferdetails", + "t_lab_testresult","t_physicalstockentry","t_patientissue","t_facilityconsumption","t_itemstockentry","t_itemstockexit", + "t_benmedhistory","t_femaleobstetrichistory","t_benmenstrualdetails","t_benpersonalhabit","t_childvaccinedetail1","t_childvaccinedetail2","t_childoptionalvaccinedetail","t_ancwomenvaccinedetail","t_childfeedinghistory","t_benallergyhistory","t_bencomorbiditycondition","t_benmedicationhistory","t_benfamilyhistory","t_perinatalhistory","t_developmenthistory", + "t_cancerfamilyhistory","t_cancerpersonalhistory","t_cancerdiethistory","t_cancerobstetrichistory","t_cancervitals","t_cancersignandsymptoms","t_cancerlymphnode","t_canceroralexamination","t_cancerbreastexamination","t_cancerabdominalexamination","t_cancergynecologicalexamination","t_cancerdiagnosis","t_cancerimageannotation", + "i_beneficiaryimage", + "t_stockadjustment","t_stocktransfer","t_patientreturn","t_indent","t_indentissue","t_indentorder","t_saitemmapping" + )); + + static { + + TABLE_GROUPS.put(1, Arrays.asList("m_beneficiaryregidmapping", "i_beneficiaryaccount","i_beneficiaryaddress","i_beneficiarycontacts","i_beneficiarydetails","i_beneficiaryfamilymapping","i_beneficiaryidentity","i_beneficiarymapping")); + + TABLE_GROUPS.put(2, Arrays.asList("t_benvisitdetail","t_phy_anthropometry","t_phy_vitals","t_benadherence","t_anccare","t_pnccare","t_ncdscreening","t_ncdcare","i_ben_flow_outreach","t_covid19","t_idrsdetails","t_physicalactivity")); + + TABLE_GROUPS.put(3, Arrays.asList("t_phy_generalexam","t_phy_headtotoe","t_sys_obstetric","t_sys_gastrointestinal","t_sys_cardiovascular","t_sys_respiratory","t_sys_centralnervous","t_sys_musculoskeletalsystem","t_sys_genitourinarysystem")); + + TABLE_GROUPS.put(4, Arrays.asList("t_ancdiagnosis","t_ncddiagnosis","t_pncdiagnosis","t_benchefcomplaint","t_benclinicalobservation","t_prescription","t_prescribeddrug","t_lab_testorder","t_benreferdetails")); + + TABLE_GROUPS.put(5, Arrays.asList("t_lab_testresult","t_physicalstockentry","t_patientissue","t_facilityconsumption","t_itemstockentry","t_itemstockexit")); + + TABLE_GROUPS.put(6, Arrays.asList("t_benmedhistory","t_femaleobstetrichistory","t_benmenstrualdetails","t_benpersonalhabit","t_childvaccinedetail1","t_childvaccinedetail2","t_childoptionalvaccinedetail","t_ancwomenvaccinedetail","t_childfeedinghistory","t_benallergyhistory","t_bencomorbiditycondition","t_benmedicationhistory","t_benfamilyhistory","t_perinatalhistory","t_developmenthistory")); + + TABLE_GROUPS.put(7, Arrays.asList("t_cancerfamilyhistory","t_cancerpersonalhistory","t_cancerdiethistory","t_cancerobstetrichistory","t_cancervitals","t_cancersignandsymptoms","t_cancerlymphnode","t_canceroralexamination","t_cancerbreastexamination","t_cancerabdominalexamination","t_cancergynecologicalexamination","t_cancerdiagnosis","t_cancerimageannotation")); + + TABLE_GROUPS.put(8, Arrays.asList("i_beneficiaryimage")); + + TABLE_GROUPS.put(9, Arrays.asList("t_itemstockentry","t_itemstockexit","t_patientissue","t_physicalstockentry","t_stockadjustment","t_stocktransfer","t_patientreturn","t_facilityconsumption","t_indent","t_indentissue","t_indentorder","t_saitemmapping")); + + } + + public String syncDataToServer(String requestOBJ, String Authorization, String token) throws Exception { + logger.info("Starting syncDataToServer. Token: {}", token); + ObjectMapper mapper = new ObjectMapper(); + SyncUploadDataDigester syncUploadDataDigester = mapper.readValue(requestOBJ, SyncUploadDataDigester.class); + + if (syncUploadDataDigester == null || syncUploadDataDigester.getTableName() == null) { + logger.error("Invalid SyncUploadDataDigester object or tableName is null."); + return "Error: Invalid sync request."; + } + + String syncTableName = syncUploadDataDigester.getTableName(); + String schemaName = syncUploadDataDigester.getSchemaName(); + + if (!isValidSchemaName(schemaName) || !isValidTableName(syncTableName)) { + logger.error("Invalid schema or table name provided: Schema='{}', Table='{}'.", schemaName, syncTableName); + return "Error: Invalid schema or table name."; + } + + + // Handle specific tables first, if their logic is distinct + if ("m_beneficiaryregidmapping".equalsIgnoreCase(syncTableName)) { + String result = update_M_BeneficiaryRegIdMapping_for_provisioned_benID(syncUploadDataDigester); + if ("data sync passed".equals(result)) { + return "Sync successful for m_beneficiaryregidmapping."; + } else { + logger.error("Sync failed for m_beneficiaryregidmapping: {}", result); + return "Sync failed for m_beneficiaryregidmapping."; + } + } + if ("i_beneficiarydetails".equalsIgnoreCase(syncTableName)) { + String result = update_I_BeneficiaryDetails_for_processed_in_batches(syncUploadDataDigester); + if ("data sync passed".equals(result)) { + return "Sync successful for i_beneficiarydetails."; + } else { + logger.error("Sync failed for i_beneficiarydetails: {}", result); + return "Sync failed for i_beneficiarydetails."; + } + } else { + // Determine the group for the current table or iterate through all if no specific table is given + boolean syncSuccess = true; + String errorMessage = ""; + + // If a specific table is provided in the request, try to find its group and sync only that table. + // Otherwise, iterate through all defined groups. + if (syncTableName != null && !syncTableName.isEmpty()) { + boolean foundInGroup = false; + for (Map.Entry> entry : TABLE_GROUPS.entrySet()) { + if (entry.getValue().contains(syncTableName.toLowerCase())) { + logger.info("Attempting to sync table '{}' from Group {}", syncTableName, entry.getKey()); + syncSuccess = syncTablesInGroup(syncUploadDataDigester.getSchemaName(), syncTableName, syncUploadDataDigester); + foundInGroup = true; + break; + } + } + if (!foundInGroup) { + logger.warn("Table '{}' not found in any predefined groups. Proceeding with generic sync logic.", syncTableName); + syncSuccess = performGenericTableSync(syncUploadDataDigester); + } + } else { + // If no specific table is in the request (e.g., a general sync trigger), iterate through groups + logger.info("No specific table provided. Attempting to sync all tables group by group."); + for (Map.Entry> entry : TABLE_GROUPS.entrySet()) { + Integer groupId = entry.getKey(); + List tablesInGroup = entry.getValue(); + logger.info("Starting sync for Group {}", groupId); + for (String table : tablesInGroup) { + if (!isValidTableName(table)) { + logger.error("Invalid table name '{}' encountered in group {}. Skipping.", table, groupId); + syncSuccess = false; + errorMessage += "Invalid table name: " + table + " in Group " + groupId + ". "; + continue; // Skip this table + } + + try { + + boolean currentTableSyncResult = syncTablesInGroup(syncUploadDataDigester.getSchemaName(), table, syncUploadDataDigester); + if (!currentTableSyncResult) { + syncSuccess = false; + errorMessage += "Failed to sync table: " + table + " in Group " + groupId + ". "; + logger.error("Sync failed for table '{}' in Group {}. Error: {}", table, groupId, errorMessage); + } else { + logger.info("Successfully synced table: {} in Group {}", table, groupId); + } + } catch (Exception e) { + syncSuccess = false; + errorMessage += "Exception during sync for table: " + table + " in Group " + groupId + ": " + e.getMessage() + ". "; + logger.error("Exception during sync for table '{}' in Group {}: {}", table, groupId, e.getMessage(), e); + } + } + } + } + + if (syncSuccess) { + logger.info("Overall data sync passed."); + return "Overall data sync passed."; + } else { + logger.info("Overall data sync failed. Details: " + errorMessage); + return "Overall data sync failed. Details: " + errorMessage; + } + } + } + + + private boolean syncTablesInGroup(String schemaName, String currentTableName, SyncUploadDataDigester originalDigester) { + logger.info("Attempting generic sync for table: {}", currentTableName); + + // Validate schemaName and currentTableName for safety before proceeding + if (!isValidSchemaName(schemaName) || !isValidTableName(currentTableName)) { + logger.error("Invalid schema or table name for group sync: Schema='{}', Table='{}'.", schemaName, currentTableName); + return false; // Fail fast if identifiers are invalid + } + + SyncUploadDataDigester tableSpecificDigester = new SyncUploadDataDigester(); + tableSpecificDigester.setSchemaName(schemaName); + tableSpecificDigester.setTableName(currentTableName); + tableSpecificDigester.setSyncedBy(originalDigester.getSyncedBy()); + tableSpecificDigester.setFacilityID(originalDigester.getFacilityID()); + tableSpecificDigester.setVanAutoIncColumnName(originalDigester.getVanAutoIncColumnName()); + tableSpecificDigester.setServerColumns(originalDigester.getServerColumns()); // Assuming serverColumns is generic or set per table + + tableSpecificDigester.setSyncData(originalDigester.getSyncData()); // Placeholder: Replace with actual data fetching + + return performGenericTableSync(tableSpecificDigester); + } + + + private String update_M_BeneficiaryRegIdMapping_for_provisioned_benID(SyncUploadDataDigester syncUploadDataDigester) { + logger.info("Processing update_M_BeneficiaryRegIdMapping_for_provisioned_benID for table: {}", syncUploadDataDigester.getTableName()); + + String schemaName = syncUploadDataDigester.getSchemaName(); + String tableName = syncUploadDataDigester.getTableName(); + + if (!isValidSchemaName(schemaName) || !isValidTableName(tableName)) { + logger.error("Invalid schema or table name provided for m_beneficiaryregidmapping update: Schema='{}', Table='{}'.", schemaName, tableName); + return "Error: Invalid schema or table name."; + } + + List> dataToBesync = syncUploadDataDigester.getSyncData(); + List syncData = new ArrayList<>(); + + String query = String.format("UPDATE %s.%s SET Provisioned = true, SyncedDate = now(), SyncedBy = ? WHERE BenRegId = ? AND BeneficiaryID = ? AND VanID = ?", schemaName, tableName); + + for (Map map : dataToBesync) { + if (map.get("BenRegId") != null && map.get("BeneficiaryID") != null && map.get("VanID") != null) { + Object[] objArr = new Object[4]; + objArr[0] = syncUploadDataDigester.getSyncedBy(); // SyncedBy + objArr[1] = String.valueOf(map.get("BenRegId")); + objArr[2] = String.valueOf(map.get("BeneficiaryID")); + objArr[3] = String.valueOf(map.get("VanID")); + syncData.add(objArr); + } else { + logger.warn("Skipping record in m_beneficiaryregidmapping due to missing BenRegId, BeneficiaryID, or VanID: {}", map); + } + } + + if (!syncData.isEmpty()) { + try { + int[] i = dataSyncRepositoryCentral.syncDataToCentralDB(schemaName, + tableName, SERVER_COLUMNS_NOT_REQUIRED, query, syncData); + + if (i.length == syncData.size()) { + logger.info("Successfully updated {} records for m_beneficiaryregidmapping.", i.length); + return "data sync passed"; + } else { + logger.error("Partial update for m_beneficiaryregidmapping. Expected {} updates, got {}. Failed records: {}", syncData.size(), i.length, getFailedRecords(i, syncData)); + return "Partial data sync for m_beneficiaryregidmapping."; + } + } catch (Exception e) { + logger.error("Exception during update for m_beneficiaryregidmapping: {}", e.getMessage(), e); + return "Error during sync for m_beneficiaryregidmapping: " + e.getMessage(); + } + } else { + logger.info("No data to sync for m_beneficiaryregidmapping."); + return "data sync passed"; + } + } + + + public String update_I_BeneficiaryDetails_for_processed_in_batches(SyncUploadDataDigester syncUploadDataDigester) { + logger.info("Processing update_I_BeneficiaryDetails_for_processed_in_batches for table: {}", syncUploadDataDigester.getTableName()); + String schemaName = syncUploadDataDigester.getSchemaName(); + String tableName = syncUploadDataDigester.getTableName(); + + if (!isValidSchemaName(schemaName) || !isValidTableName(tableName)) { + logger.error("Invalid schema or table name provided for i_beneficiarydetails update: Schema='{}', Table='{}'.", schemaName, tableName); + return "Error: Invalid schema or table name."; + } + + List syncData = new ArrayList<>(); // This list will hold data for batch updates to 'Processed' + + String updateQuery = getQueryFor_I_BeneficiaryDetails(schemaName, tableName); + + int limit = 1000; + int offset = 0; + int totalProcessed = 0; + + String whereClauseForBatchFetch = " WHERE Processed <> 'P' AND VanID IS NOT NULL "; // This is for fetching, not for update + + while (true) { + List> batchToFetch; + try { + batchToFetch = dataSyncRepositoryCentral.getBatchForBenDetails( + syncUploadDataDigester, + whereClauseForBatchFetch, + limit, + offset); + } catch (Exception e) { + logger.error("Error fetching batch for i_beneficiarydetails: {}", e.getMessage(), e); + return "Error fetching data for i_beneficiarydetails: " + e.getMessage(); + } + + if (batchToFetch.isEmpty()) { + break; + } + + for (Map map : batchToFetch) { + if (map.get("BeneficiaryDetailsId") != null && map.get("VanID") != null) { + Object[] params = new Object[3]; + params[0] = syncUploadDataDigester.getSyncedBy(); + params[1] = String.valueOf(map.get("BeneficiaryDetailsId")); + params[2] = String.valueOf(map.get("VanID")); + syncData.add(params); + } else { + logger.warn("Skipping record in i_beneficiarydetails due to missing BeneficiaryDetailsId or VanID: {}", map); + } + } + + if (!syncData.isEmpty()) { + try { + int[] batchUpdateResults = dataSyncRepositoryCentral.syncDataToCentralDB( + schemaName, + tableName, + SERVER_COLUMNS_NOT_REQUIRED, + updateQuery, + syncData); + + int successfulUpdates = 0; + for (int result : batchUpdateResults) { + if (result >= 1) { + successfulUpdates++; + } + } + totalProcessed += successfulUpdates; + logger.info("Batch update for i_beneficiarydetails: {} records processed, {} successfully updated.", syncData.size(), successfulUpdates); + + syncData.clear(); + offset += limit; + + } catch (Exception e) { + logger.error("Exception during batch update for i_beneficiarydetails: {}", e.getMessage(), e); + return "Error during sync for i_beneficiarydetails: " + e.getMessage(); + } + } else { + logger.info("No valid records in the current batch for i_beneficiarydetails to update."); + offset += limit; + } + } + + if (totalProcessed > 0) { + logger.info("Finished processing i_beneficiarydetails. Total records processed: {}", totalProcessed); + return "data sync passed"; + } else { + logger.info("No records were processed for i_beneficiarydetails."); + return "No data processed for i_beneficiarydetails."; + } + } + + private String getQueryFor_I_BeneficiaryDetails(String schemaName, String tableName) { + if (!isValidSchemaName(schemaName) || !isValidTableName(tableName)) { + logger.error("Invalid schema or table name for getQueryFor_I_BeneficiaryDetails: Schema='{}', Table='{}'.", schemaName, tableName); + throw new IllegalArgumentException("Invalid schema or table name provided."); + } + return String.format("UPDATE %s.%s SET Processed = 'P', SyncedDate = now(), SyncedBy = ? WHERE BeneficiaryDetailsId = ? AND VanID = ?", schemaName, tableName); + } + + + + private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDigester) { + logger.info("Performing generic sync for table: {}", syncUploadDataDigester.getTableName()); + + String schemaName = syncUploadDataDigester.getSchemaName(); + String syncTableName = syncUploadDataDigester.getTableName(); + String vanAutoIncColumnName = syncUploadDataDigester.getVanAutoIncColumnName(); + String serverColumns = syncUploadDataDigester.getServerColumns(); + + if (!isValidSchemaName(schemaName) || !isValidTableName(syncTableName)) { + logger.error("Invalid schema or table name for generic sync: Schema='{}', Table='{}'.", schemaName, syncTableName); + return false; + } + + if (!isValidColumnNames(serverColumns)) { + logger.error("Invalid server columns provided for generic sync: {}", serverColumns); + return false; + } + + + List> dataToBesync = syncUploadDataDigester.getSyncData(); + List syncDataListInsert = new ArrayList<>(); + List syncDataListUpdate = new ArrayList<>(); + + if (dataToBesync == null || dataToBesync.isEmpty()) { + logger.info("No data to sync for table: {}", syncUploadDataDigester.getTableName()); + return true; // Nothing to sync, consider it a success + } + + Integer facilityIDFromDigester = syncUploadDataDigester.getFacilityID(); + + for (Map map : dataToBesync) { + String vanSerialNo = String.valueOf(map.get(vanAutoIncColumnName)); + String vanID = String.valueOf(map.get("VanID")); + int syncFacilityID = 0; + + map.put("SyncedBy", syncUploadDataDigester.getSyncedBy()); + map.put("SyncedDate", String.valueOf(LocalDateTime.now())); // Ensure column name matches DB + + if (facilityIDFromDigester != null) { + switch (syncTableName.toLowerCase()) { + case "t_indent": + case "t_indentorder": { + if (map.containsKey("FromFacilityID") && map.get("FromFacilityID") instanceof Double) { + Double fromFacilityID = (Double) map.get("FromFacilityID"); + if (fromFacilityID.intValue() == facilityIDFromDigester) { + map.put("Processed", "P"); + } + } + break; + } + case "t_indentissue": { + if (map.containsKey("ToFacilityID") && map.get("ToFacilityID") instanceof Double) { + Double toFacilityID = (Double) map.get("ToFacilityID"); + if (toFacilityID.intValue() == facilityIDFromDigester) { + map.put("Processed", "P"); + } + } + break; + } + case "t_stocktransfer": { + if (map.containsKey("TransferToFacilityID") && map.get("TransferToFacilityID") instanceof Double) { + Double transferToFacilityID = (Double) map.get("TransferToFacilityID"); + if (transferToFacilityID.intValue() == facilityIDFromDigester) { + map.put("Processed", "P"); + } + } + break; + } + case "t_itemstockentry": { + if (map.containsKey("FacilityID") && map.get("FacilityID") instanceof Double) { + Double mapFacilityID = (Double) map.get("FacilityID"); + if (mapFacilityID.intValue() == facilityIDFromDigester) { + map.put("Processed", "P"); + } + } + break; + } + default: + // No specific facility ID logic for other tables, maintain existing 'Processed' status or default + break; + } + } + + // Extract SyncFacilityID for checkRecordIsAlreadyPresentOrNot + if (map.containsKey("SyncFacilityID") && map.get("SyncFacilityID") instanceof Integer) { + syncFacilityID = (Integer) map.get("SyncFacilityID"); + } else if (map.containsKey("SyncFacilityID") && map.get("SyncFacilityID") instanceof Double) { + syncFacilityID = ((Double) map.get("SyncFacilityID")).intValue(); + } + + + int recordCheck; + try { + recordCheck = dataSyncRepositoryCentral.checkRecordIsAlreadyPresentOrNot( + schemaName, syncTableName, vanSerialNo, vanID, vanAutoIncColumnName, syncFacilityID); + } catch (Exception e) { + logger.error("Error checking record existence for table {}: VanSerialNo={}, VanID={}. Error: {}", syncTableName, vanSerialNo, vanID, e.getMessage(), e); + return false; // Critical error, stop sync for this table + } + + // Prepare Object array for insert/update + Object[] objArr; + List serverColumnsList = Arrays.asList(serverColumns.split(",")); + List currentRecordValues = new ArrayList<>(); + + for (String column : serverColumnsList) { + Object value = map.get(column.trim()); + // Handle boolean conversion if necessary, though String.valueOf should generally work for prepared statements + if (value instanceof Boolean) { + currentRecordValues.add(value); + } else if (value != null) { + currentRecordValues.add(String.valueOf(value)); + } else { + currentRecordValues.add(null); + } + } + + objArr = currentRecordValues.toArray(); + + if (recordCheck == 0) { + syncDataListInsert.add(objArr); + } else { + // For update, append the WHERE clause parameters at the end of the array + List updateParams = new ArrayList<>(Arrays.asList(objArr)); + updateParams.add(String.valueOf(vanSerialNo)); + + if (Arrays.asList("t_patientissue", "t_physicalstockentry", "t_stockadjustment", "t_saitemmapping", + "t_stocktransfer", "t_patientreturn", "t_facilityconsumption", "t_indent", + "t_indentorder", "t_indentissue", "t_itemstockentry", "t_itemstockexit") + .contains(syncTableName.toLowerCase()) && map.containsKey("SyncFacilityID")) { + updateParams.add(String.valueOf(map.get("SyncFacilityID"))); + } else { + updateParams.add(String.valueOf(vanID)); + } + syncDataListUpdate.add(updateParams.toArray()); + } + } + + boolean insertSuccess = true; + boolean updateSuccess = true; + + if (!syncDataListInsert.isEmpty()) { + String queryInsert = getQueryToInsertDataToServerDB(schemaName, syncTableName, serverColumns); + try { + int[] i = dataSyncRepositoryCentral.syncDataToCentralDB(schemaName, syncTableName, serverColumns, queryInsert, syncDataListInsert); + if (i.length != syncDataListInsert.size()) { + insertSuccess = false; + logger.error("Partial insert for table {}. Expected {} inserts, got {}. Failed records: {}", syncTableName, syncDataListInsert.size(), i.length, getFailedRecords(i, syncDataListInsert)); + } else { + logger.info("Successfully inserted {} records into table {}.", i.length, syncTableName); + } + } catch (Exception e) { + insertSuccess = false; + logger.error("Exception during insert for table {}: {}", syncTableName, e.getMessage(), e); + } + } + + if (!syncDataListUpdate.isEmpty()) { + String queryUpdate = getQueryToUpdateDataToServerDB(schemaName, serverColumns, syncTableName); + try { + int[] j = dataSyncRepositoryCentral.syncDataToCentralDB(schemaName, syncTableName, SERVER_COLUMNS_NOT_REQUIRED, queryUpdate, syncDataListUpdate); + if (j.length != syncDataListUpdate.size()) { + updateSuccess = false; + logger.error("Partial update for table {}. Expected {} updates, got {}. Failed records: {}", syncTableName, syncDataListUpdate.size(), j.length, getFailedRecords(j, syncDataListUpdate)); + } else { + logger.info("Successfully updated {} records in table {}.", j.length, syncTableName); + } + } catch (Exception e) { + updateSuccess = false; + logger.error("Exception during update for table {}: {}", syncTableName, e.getMessage(), e); + } + } + return insertSuccess && updateSuccess; + } + + private String getQueryToInsertDataToServerDB(String schemaName, String tableName, String serverColumns) { + if (!isValidSchemaName(schemaName) || !isValidTableName(tableName)) { + logger.error("Invalid schema or table name for getQueryToInsertDataToServerDB: Schema='{}', Table='{}'.", schemaName, tableName); + throw new IllegalArgumentException("Invalid schema or table name provided."); + } + if (!isValidColumnNames(serverColumns)) { + logger.error("Invalid server columns provided for getQueryToInsertDataToServerDB: {}", serverColumns); + throw new IllegalArgumentException("Invalid column names provided."); + } + + + String[] columnsArr = serverColumns.split(","); + StringBuilder preparedStatementSetter = new StringBuilder(); + + for (int i = 0; i < columnsArr.length; i++) { + preparedStatementSetter.append("?"); + if (i < columnsArr.length - 1) { + preparedStatementSetter.append(", "); + } + } + + return String.format("INSERT INTO %s.%s(%s) VALUES (%s)", schemaName, tableName, serverColumns, preparedStatementSetter.toString()); + } + + public String getQueryToUpdateDataToServerDB(String schemaName, String serverColumns, String tableName) { + if (!isValidSchemaName(schemaName) || !isValidTableName(tableName)) { + logger.error("Invalid schema or table name for getQueryToUpdateDataToServerDB: Schema='{}', Table='{}'.", schemaName, tableName); + throw new IllegalArgumentException("Invalid schema or table name provided."); + } + if (!isValidColumnNames(serverColumns)) { + logger.error("Invalid server columns provided for getQueryToUpdateDataToServerDB: {}", serverColumns); + throw new IllegalArgumentException("Invalid column names provided."); + } + + String[] columnsArr = serverColumns.split(","); + StringBuilder preparedStatementSetter = new StringBuilder(); + + for (int i = 0; i < columnsArr.length; i++) { + String column = columnsArr[i].trim(); + if (!isValidColumnName(column)) { + logger.error("Invalid individual column name encountered: {}", column); + throw new IllegalArgumentException("Invalid individual column name provided: " + column); + } + + preparedStatementSetter.append(column); + preparedStatementSetter.append(" = ?"); + if (i < columnsArr.length - 1) { + preparedStatementSetter.append(", "); + } + } + + StringBuilder queryBuilder = new StringBuilder(); + queryBuilder.append(String.format("UPDATE %s.%s SET %s WHERE VanSerialNo = ?", schemaName, tableName, preparedStatementSetter.toString())); + + + if (Arrays.asList("t_patientissue", "t_physicalstockentry", "t_stockadjustment", "t_saitemmapping", + "t_stocktransfer", "t_patientreturn", "t_facilityconsumption", "t_indent", + "t_indentorder", "t_indentissue", "t_itemstockentry", "t_itemstockexit") + .contains(tableName.toLowerCase())) { + queryBuilder.append(" AND SyncFacilityID = ? "); + } else { + queryBuilder.append(" AND VanID = ? "); + } + return queryBuilder.toString(); + } + + private boolean isValidSchemaName(String schemaName) { + return VALID_SCHEMAS.contains(schemaName.toLowerCase()); + } + + private boolean isValidTableName(String tableName) { + return VALID_TABLES.contains(tableName.toLowerCase()); + } + + private boolean isValidColumnName(String columnName) { + return columnName != null && columnName.matches("^[a-zA-Z_][a-zA-Z0-9_]*$"); + } + + private boolean isValidColumnNames(String columnNames) { + if (columnNames == null || columnNames.trim().isEmpty()) { + return false; + } + String[] cols = columnNames.split(","); + for (String col : cols) { + if (!isValidColumnName(col.trim())) { + return false; + } + } + return true; + } + + + private String getFailedRecords(int[] results, List data) { + List failedRecordsInfo = new ArrayList<>(); + for (int k = 0; k < results.length; k++) { + if (results[k] < 1) { + String idInfo = "N/A"; + if (data.get(k) != null && data.get(k).length > 0) { + idInfo = "Record data size: " + data.get(k).length; + } + failedRecordsInfo.add("Record at index " + k + " (Info: " + idInfo + ")"); + } + } + return String.join("; ", failedRecordsInfo); + } } \ No newline at end of file diff --git a/src/main/java/com/iemr/mmu/utils/RestTemplateUtil.java b/src/main/java/com/iemr/mmu/utils/RestTemplateUtil.java index cf07391c..2cbab41d 100644 --- a/src/main/java/com/iemr/mmu/utils/RestTemplateUtil.java +++ b/src/main/java/com/iemr/mmu/utils/RestTemplateUtil.java @@ -1,3 +1,24 @@ +/* +* AMRIT – Accessible Medical Records via Integrated Technology +* Integrated EHR (Electronic Health Records) Solution +* +* Copyright (C) "Piramal Swasthya Management and Research Institute" +* +* This file is part of AMRIT. +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see https://www.gnu.org/licenses/. +*/ package com.iemr.mmu.utils; import org.slf4j.Logger; @@ -23,16 +44,19 @@ public static HttpEntity createRequestEntity(Object body, String authori headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + authorization); } - if (jwtToken == null || jwtToken.isEmpty()) { - ServletRequestAttributes attrs = - (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); - if (attrs != null) { - HttpServletRequest request = attrs.getRequest(); - try { - jwtToken = CookieUtil.getJwtTokenFromCookie(request); - } catch (Exception e) { - logger.error("Error while getting JWT token from cookie: {}", e.getMessage()); - } + ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + + if ((jwtToken == null || jwtToken.isEmpty()) && attrs != null) { + HttpServletRequest request = attrs.getRequest(); + try { + jwtToken = CookieUtil.getJwtTokenFromCookie(request); + } catch (Exception e) { + logger.error("Error while getting JWT token from cookie: {}", e.getMessage()); + } + + String jwtTokenHeader = request.getHeader("JwtToken"); + if (jwtTokenHeader != null && !jwtTokenHeader.isEmpty()) { + jwtToken = jwtTokenHeader; } } @@ -41,7 +65,6 @@ public static HttpEntity createRequestEntity(Object body, String authori headers.add(HttpHeaders.COOKIE, "Jwttoken=" + jwtToken); } - return new HttpEntity<>(body, headers); } } \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d172f4aa..2e6ce84f 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -7,6 +7,8 @@ spring.datasource.tomcat.remove-abandoned=true spring.datasource.tomcat.remove-abandoned-timeout=1800 spring.datasource.tomcat.logAbandoned=true spring.datasource.continue-on-error=true +spring.datasource.tomcat.max-wait=60000 + ## below line added by neeraj for reset abandoned DB connection from connection pool spring.datasource.tomcat.jdbc-interceptors=ResetAbandonedTimer @@ -46,3 +48,8 @@ logging.level.org.springframework=INFO spring.main.allow-circular-references=true spring.main.allow-bean-definition-overriding=true + +spring.datasource.tomcat.testOnBorrow=true +spring.datasource.tomcat.validationQuery=SELECT 1 +spring.datasource.tomcat.validationInterval=30000 # 30 sec +logging.level.org.apache.tomcat.jdbc.pool=DEBUG