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 eeb54e9f..524094e5 100644 --- a/src/main/java/com/iemr/mmu/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java +++ b/src/main/java/com/iemr/mmu/controller/dataSyncLayerCentral/MMUDataSyncVanToServer.java @@ -63,12 +63,8 @@ public String dataSyncToServer(@RequestBody String requestOBJ, @RequestHeader(value = "Authorization") String Authorization, HttpServletRequest request) { OutputResponse response = new OutputResponse(); - logger.info("test: vanto server auth="+Authorization); try { - String jwtToken = CookieUtil.getJwtTokenFromCookie(request); - logger.info("test: vanto server token="+jwtToken); - - String s = getDataFromVanAndSyncToDBImpl.syncDataToServer(requestOBJ, Authorization, jwtToken); + String s = getDataFromVanAndSyncToDBImpl.syncDataToServer(requestOBJ, Authorization); if (s != null) response.setResponse(s); else diff --git a/src/main/java/com/iemr/mmu/service/dataSyncActivity/DataSyncRepository.java b/src/main/java/com/iemr/mmu/service/dataSyncActivity/DataSyncRepository.java index b039a47f..9b020a4e 100644 --- a/src/main/java/com/iemr/mmu/service/dataSyncActivity/DataSyncRepository.java +++ b/src/main/java/com/iemr/mmu/service/dataSyncActivity/DataSyncRepository.java @@ -28,7 +28,10 @@ import javax.sql.DataSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.annotation.CreatedDate; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; @@ -50,6 +53,8 @@ public class DataSyncRepository { @Autowired private SyncUtilityClassRepo syncutilityClassRepo; + private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + private JdbcTemplate getJdbcTemplate() { return new JdbcTemplate(dataSource); @@ -64,7 +69,7 @@ public List> getDataForGivenSchemaAndTable(String schema, St if (table != null && table.equalsIgnoreCase("m_beneficiaryregidmapping")) { baseQuery = " SELECT " + columnNames + " FROM " + schema + "." + table - + " WHERE provisioned is true AND processed <> 'P' AND vanID is not null "; + + " WHERE provisioned is true AND processed != 'P' AND vanID is not null "; } else { if (table != null && (table.equalsIgnoreCase("t_patientissue") || table.equalsIgnoreCase("t_physicalstockentry") || table.equalsIgnoreCase("t_stockadjustment") @@ -75,30 +80,36 @@ public List> getDataForGivenSchemaAndTable(String schema, St || table.equalsIgnoreCase("t_itemstockexit"))) { baseQuery = " SELECT " + columnNames + " FROM " + schema + "." + table - + " WHERE processed <> 'P' AND SyncFacilityID is not null "; + + " WHERE processed != 'P' AND SyncFacilityID is not null "; } else { baseQuery = " SELECT " + columnNames + " FROM " + schema + "." + table - + " WHERE processed <> 'P' AND vanID is not null "; + + " WHERE processed != 'P' AND vanID is not null "; } } + resultSetList = jdbcTemplate.queryForList(baseQuery); return resultSetList; } - - public int updateProcessedFlagInVan(String schemaName, String tableName, StringBuilder vanSerialNos, String autoIncreamentColumn, String user) throws Exception { jdbcTemplate = getJdbcTemplate(); - String query = " UPDATE " + schemaName + "." + tableName - + " SET processed = 'P' , SyncedDate = ?, Syncedby = ? WHERE " + autoIncreamentColumn - + " IN (" + vanSerialNos + ")"; + String query = ""; - Timestamp syncedDate = new Timestamp(System.currentTimeMillis()); - int updatedRows = jdbcTemplate.update(query, syncedDate, user); + if (tableName != null && tableName.toLowerCase().equals("i_ben_flow_outreach")) { + query = "UPDATE " + schemaName + "." + tableName + + " SET created_date = ? , processed = 'P', SyncedDate = ?, Syncedby = ? " + + "WHERE " + autoIncreamentColumn + " IN (" + vanSerialNos + ")"; + } else { + query = "UPDATE " + schemaName + "." + tableName + + " SET CreatedDate = ? , processed = 'P', SyncedDate = ?, Syncedby = ? " + + "WHERE " + autoIncreamentColumn + " IN (" + vanSerialNos + ")"; + } + Timestamp syncedDate = new Timestamp(System.currentTimeMillis()); + int updatedRows = jdbcTemplate.update(query, syncedDate, syncedDate, user); return updatedRows; } @@ -119,4 +130,4 @@ public int[] updateLatestMasterInLocal(String query, List syncDataList // ---------------------------------- End of Download Repository -} +} \ No newline at end of file diff --git a/src/main/java/com/iemr/mmu/service/dataSyncActivity/UploadDataToServerImpl.java b/src/main/java/com/iemr/mmu/service/dataSyncActivity/UploadDataToServerImpl.java index 9476ecc7..2c24dc2c 100644 --- a/src/main/java/com/iemr/mmu/service/dataSyncActivity/UploadDataToServerImpl.java +++ b/src/main/java/com/iemr/mmu/service/dataSyncActivity/UploadDataToServerImpl.java @@ -243,32 +243,8 @@ private void setResponseStatus(Map groupIdStatus, int groupId, S groupIdStatus.put("groupId", String.valueOf(groupId)); groupIdStatus.put("status", serverAcknowledgement); responseStatus.add(groupIdStatus); - logger.info("Response from data sync: {}", responseStatus); } -// private boolean setResponseStatus(Map groupIdStatus, int groupId, String serverAcknowledgement, -// List> responseStatus, boolean isProgress) { -// if (serverAcknowledgement != null) { -// groupIdStatus.put("groupId", String.valueOf(groupId)); -// groupIdStatus.put("status", serverAcknowledgement); -// responseStatus.add(groupIdStatus); -// logger.info("Response from data sync", responseStatus); -// } else if (isProgress) { -// groupIdStatus.put("groupId", String.valueOf(groupId)); -// groupIdStatus.put("status", "pending"); -// responseStatus.add(groupIdStatus); -// logger.info("Response from data sync", responseStatus); -// } else { -// isProgress = true; -// groupIdStatus.put("groupId", String.valueOf(groupId)); -// groupIdStatus.put("status", "failed"); -// responseStatus.add(groupIdStatus); -// logger.info("Response from data sync", responseStatus); -// } -// return isProgress; -// -// } - /** * * @param syncTableDetailsIDs @@ -299,7 +275,6 @@ public List getVanAndServerColumnList(Integer groupID) throws private List> getDataToSync(String schemaName, String tableName, String columnNames) throws Exception { - logger.info("Fetching data to sync for schema: {}, table: {}, columns: {}", schemaName, tableName, columnNames); List> resultSetList = dataSyncRepository.getDataForGivenSchemaAndTable(schemaName, tableName, columnNames); if (resultSetList != null) { @@ -343,14 +318,11 @@ private List> getBatchOfAskedSizeDataToSync(List> dataToBesync, String user, String Authorization, String token) throws Exception { - logger.debug( - "Entering syncDataToServer with vanID: {}, schemaName: '{}', tableName: '{}', vanAutoIncColumnName: '{}', serverColumns: '{}', user: '{}'", - vanID, schemaName, tableName, vanAutoIncColumnName, serverColumns, user); + RestTemplate restTemplate = new RestTemplate(); Integer facilityID = masterVanRepo.getFacilityID(vanID); - logger.debug("Fetched facilityID for vanID {}: {}", vanID, facilityID); // serialize null GsonBuilder gsonBuilder = new GsonBuilder(); @@ -368,33 +340,18 @@ public String syncDataToServer(int vanID, String schemaName, String tableName, S dataMap.put("facilityID", facilityID); String requestOBJ = gson.toJson(dataMap); - - HttpEntity request = RestTemplateUtil.createRequestEntity(requestOBJ, Authorization,token); - logger.info("Before Data sync upload Url" + dataSyncUploadUrl); + HttpEntity request = RestTemplateUtil.createRequestEntity(requestOBJ, Authorization,"datasync"); ResponseEntity response = restTemplate.exchange(dataSyncUploadUrl, HttpMethod.POST, request, String.class); - logger.info("Received response from data sync URL: {}", response); - logger.info("Received response from data sync URL: {}", dataSyncUploadUrl); - - logger.info("After Data sync upload Url" + dataSyncUploadUrl); - /** - * if data successfully synced then getVanSerialNo of synced data to update - * processed flag - */ + int i = 0; if (response != null && response.hasBody()) { JSONObject obj = new JSONObject(response.getBody()); if (obj != null && obj.has("statusCode") && obj.getInt("statusCode") == 200) { StringBuilder vanSerialNos = getVanSerialNoListForSyncedData(vanAutoIncColumnName, dataToBesync); - logger.info( - "Updating processed flag for schemaName: {}, tableName: {}, vanSerialNos: {}, vanAutoIncColumnName: {}, user: {}", - schemaName, tableName, vanSerialNos.toString(), vanAutoIncColumnName, user); - // update table for processed flag = "P" - logger.info(schemaName + "|" + tableName + "|" + vanSerialNos.toString() + "|" + vanAutoIncColumnName - + "|" + user); + i = dataSyncRepository.updateProcessedFlagInVan(schemaName, tableName, vanSerialNos, vanAutoIncColumnName, user); - logger.debug("Updated processed flag in database. Records affected: {}", i); } } if (i > 0) @@ -435,4 +392,4 @@ public String getDataSyncGroupDetails() { return null; } -} +} \ No newline at end of file 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 bdba82d0..a5d8422d 100644 --- a/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/DataSyncRepositoryCentral.java +++ b/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/DataSyncRepositoryCentral.java @@ -21,19 +21,21 @@ */ package com.iemr.mmu.service.dataSyncLayerCentral; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.sql.DataSource; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Service; -import javax.sql.DataSource; -import java.sql.Timestamp; -import java.sql.Statement; // Import Statement for batchUpdate result interpretation -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; +import com.iemr.mmu.data.syncActivity_syncLayer.SyncUploadDataDigester; @Service public class DataSyncRepositoryCentral { @@ -42,7 +44,6 @@ public class DataSyncRepositoryCentral { private JdbcTemplate jdbcTemplate; - // Lazily initialize jdbcTemplate to ensure DataSource is available private JdbcTemplate getJdbcTemplate() { if (this.jdbcTemplate == null) { this.jdbcTemplate = new JdbcTemplate(dataSource); @@ -50,161 +51,176 @@ private JdbcTemplate getJdbcTemplate() { return this.jdbcTemplate; } - private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + private final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName()); + + private static final Set VALID_SCHEMAS = Set.of("public", "db_iemr", "db_identity","apl_db_iemr","apl_db_identity","db_iemr_sync","db_identity_sync"); + + 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; + } - // Data Upload Repository public int checkRecordIsAlreadyPresentOrNot(String schemaName, String tableName, String vanSerialNo, String vanID, - String vanAutoIncColumnName, int syncFacilityID) { + String vanAutoIncColumnName, int syncFacilityID) { jdbcTemplate = getJdbcTemplate(); - List params = new ArrayList<>(); - StringBuilder queryBuilder = new StringBuilder("SELECT "); - queryBuilder.append(vanAutoIncColumnName); - queryBuilder.append(" FROM "); - queryBuilder.append(schemaName).append(".").append(tableName); + 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 = ?"); - StringBuilder whereClause = new StringBuilder(); - whereClause.append(" WHERE "); - whereClause.append("VanSerialNo = ?"); params.add(vanSerialNo); - if (Arrays.asList("t_patientissue", "t_physicalstockentry", "t_stockadjustment", "t_saitemmapping", + 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) { - - whereClause.append(" AND "); - whereClause.append("SyncFacilityID = ?"); + queryBuilder.append(" AND SyncFacilityID = ?"); params.add(syncFacilityID); - } else { - whereClause.append(" AND "); - whereClause.append("VanID = ?"); + queryBuilder.append(" AND VanID = ?"); params.add(vanID); } - queryBuilder.append(whereClause); - String query = queryBuilder.toString(); - Object[] queryParams = params.toArray(); - - logger.debug("Checking record existence query: {} with params: {}", query, Arrays.toString(queryParams)); - System.out.println("Checking record existence query: " + query + " with params: " + Arrays.toString(queryParams)); - try { - List> resultSet = jdbcTemplate.queryForList(query, queryParams); - if (resultSet != null && !resultSet.isEmpty()) { - System.out.println("Record found for table " + tableName + ": VanSerialNo=" + vanSerialNo + ", VanID=" + vanID); - logger.debug("Record found for table {}: VanSerialNo={}, VanID={}", tableName, vanSerialNo, vanID); - return 1; - } else { - System.out.println("No record found for table " + tableName + ": VanSerialNo=" + vanSerialNo + ", VanID=" + vanID); - logger.debug("No record found for table {}: VanSerialNo={}, VanID={}", tableName, vanSerialNo, vanID); - return 0; - } - } catch (org.springframework.dao.EmptyResultDataAccessException e) { - System.out.println("No record found (EmptyResultDataAccessException) for table " + tableName + ": VanSerialNo=" + vanSerialNo + ", VanID=" + vanID); - logger.debug("No record found (EmptyResultDataAccessException) for table {}: VanSerialNo={}, VanID={}", tableName, vanSerialNo, vanID); - return 0; + List> resultSet = jdbcTemplate.queryForList(queryBuilder.toString(), params.toArray()); + return (resultSet != null && !resultSet.isEmpty()) ? 1 : 0; } catch (Exception e) { - System.out.println("Database error during checkRecordIsAlreadyPresentOrNot for table " + tableName + ": VanSerialNo=" + vanSerialNo + ", VanID=" + vanID); - logger.error("Database error during checkRecordIsAlreadyPresentOrNot for table {}: VanSerialNo={}, VanID={}. Error: {}", tableName, vanSerialNo, vanID, e.getMessage(), e); - throw new RuntimeException("Failed to check record existence: " + e.getMessage(), e); // Re-throw or handle as appropriate + logger.error("Error checking record presence: {}", e.getMessage(), e); + throw new RuntimeException("Failed to check record existence: " + e.getMessage(), e); } } - // Method for synchronization of data to central DB public int[] syncDataToCentralDB(String schema, String tableName, String serverColumns, String query, - List syncDataList) { + List syncDataList) { jdbcTemplate = getJdbcTemplate(); - logger.info("Executing batch operation for table: {}. Query type: {}. Number of records: {}", tableName, query.startsWith("INSERT") ? "INSERT" : "UPDATE", syncDataList.size()); - logger.debug("Query: {}", query); -System.out.println("Executing batch operation for table: " + tableName + ". Query type: " + (query.startsWith("INSERT") ? "INSERT" : "UPDATE") + ". Number of records: " + syncDataList.size()); try { - // Start batch insert/update - int[] i = jdbcTemplate.batchUpdate(query, syncDataList); - System.out.println("Batch operation completed for table " + tableName + ". Results: " + Arrays.toString(i)); - logger.info("Batch operation completed for table {}. Results: {}", tableName, Arrays.toString(i)); - return i; + + return jdbcTemplate.batchUpdate(query, syncDataList); } catch (Exception e) { - logger.error("Exception during batch update for table {}: {}", tableName, e.getMessage(), e); - System.out.println("Exception during batch update for table " + tableName + ": " + e.getMessage()); - // Log the error with detailed information - // Re-throw the exception to be handled by the service layer, so specific errors can be captured. - throw new RuntimeException("Batch sync failed for table " + tableName + ": " + e.getMessage(), e); + logger.error("Batch sync failed for table {}: {}", tableName, e.getMessage(), e); + throw new RuntimeException("Batch sync failed: " + e.getMessage(), e); } } - // End of Data Upload Repository - public List> getMasterDataFromTable(String schema, String table, String columnNames, - String masterType, Timestamp lastDownloadDate, Integer vanID, Integer psmID) throws Exception { + String masterType, Timestamp lastDownloadDate, Integer vanID, Integer psmID) { jdbcTemplate = getJdbcTemplate(); - List> resultSetList = new ArrayList<>(); - StringBuilder baseQueryBuilder = new StringBuilder(" SELECT ").append(columnNames).append(" FROM ").append(schema).append(".").append(table); 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) { - baseQueryBuilder.append(" WHERE LastModDate >= ? "); + queryBuilder.append(" WHERE LastModDate >= ?"); params.add(lastDownloadDate); - if (masterType.equalsIgnoreCase("V")) { - baseQueryBuilder.append(" AND VanID = ? "); + if ("V".equalsIgnoreCase(masterType)) { + queryBuilder.append(" AND VanID = ?"); params.add(vanID); - } else if (masterType.equalsIgnoreCase("P")) { - baseQueryBuilder.append(" AND ProviderServiceMapID = ? "); + } else if ("P".equalsIgnoreCase(masterType)) { + queryBuilder.append(" AND ProviderServiceMapID = ?"); params.add(psmID); } } else { - if (masterType.equalsIgnoreCase("V")) { - baseQueryBuilder.append(" WHERE VanID = ? "); + queryBuilder.append(" WHERE "); + if ("V".equalsIgnoreCase(masterType)) { + queryBuilder.append("VanID = ?"); params.add(vanID); - } else if (masterType.equalsIgnoreCase("P")) { - baseQueryBuilder.append(" WHERE ProviderServiceMapID = ? "); + } else if ("P".equalsIgnoreCase(masterType)) { + queryBuilder.append("ProviderServiceMapID = ?"); params.add(psmID); } } } - String finalQuery = baseQueryBuilder.toString(); - logger.info("Select query central: {}", finalQuery); - logger.info("Last Downloaded Date: {}", lastDownloadDate); - logger.info("Query Params: {}", params); - System.out.println("Select query central: " + finalQuery); - System.out.println("Last Downloaded Date: " + lastDownloadDate); - System.out.println("Query Params: " + params); - try { - if (params.isEmpty()) { - resultSetList = jdbcTemplate.queryForList(finalQuery); - } else { - resultSetList = jdbcTemplate.queryForList(finalQuery, params.toArray()); - } + // 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) { - System.out.println("Error fetching master data from table " + table + ": " + e.getMessage()); - logger.error("Error fetching master data from table {}: {}", table, e.getMessage(), e); + logger.error("Error fetching master data: {}", e.getMessage(), e); throw new RuntimeException("Failed to fetch master data: " + e.getMessage(), e); } -System.out.println("Result set Details size: " + resultSetList.size()); - logger.info("Result set Details size: {}", resultSetList.size()); - return resultSetList; } - public List> getBatchForBenDetails(String schema, String table, String columnNames, - String whereClause, int limit, int offset) { + public List> getBatchForBenDetails(SyncUploadDataDigester digester, + String whereClause, int limit, int offset) { jdbcTemplate = getJdbcTemplate(); - String query = "SELECT " + columnNames + " FROM " + schema + "." + table + whereClause + " LIMIT ? OFFSET ?"; - System.out.println("Fetching batch for beneficiary details. Query: " + query + ", Limit: " + limit + ", Offset: " + offset); - logger.debug("Fetching batch for beneficiary details. Query: {}, Limit: {}, Offset: {}", query, limit, offset); - try { - return jdbcTemplate.queryForList(query, limit, offset); - } catch (Exception e) { - logger.error("Error fetching batch for beneficiary details from table {}: {}", table, e.getMessage(), e); - System.out.println("Error fetching batch for beneficiary details from table " + table + ": " + e.getMessage()); - throw new RuntimeException("Failed to fetch batch data: " + e.getMessage(), e); - } - } - // End of Data Download Repository + 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); + } + } } \ No newline at end of file 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 4a97725b..cd33c2b5 100644 --- a/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/GetDataFromVanAndSyncToDBImpl.java +++ b/src/main/java/com/iemr/mmu/service/dataSyncLayerCentral/GetDataFromVanAndSyncToDBImpl.java @@ -24,10 +24,10 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.HashMap; - +import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +37,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.iemr.mmu.data.syncActivity_syncLayer.SyncUploadDataDigester; - @Service public class GetDataFromVanAndSyncToDBImpl implements GetDataFromVanAndSyncToDB { @@ -47,44 +46,57 @@ public class GetDataFromVanAndSyncToDBImpl implements GetDataFromVanAndSyncToDB @Autowired private DataSyncRepositoryCentral dataSyncRepositoryCentral; + private static final Map> TABLE_GROUPS = new HashMap<>(); static { - // Group 1: Master data or less frequently changing data - TABLE_GROUPS.put(1, Arrays.asList("m_beneficiaryregidmapping", "m_another_master_table")); - - // Group 2: Transactional data that might involve facility ID - TABLE_GROUPS.put(2, Arrays.asList("t_indent", "t_indentorder", "t_indentissue", "t_stocktransfer", "t_itemstockentry")); + 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")); - // Group 3: High volume transactional data - TABLE_GROUPS.put(3, Arrays.asList("i_beneficiarydetails", "t_patientissue", "t_physicalstockentry", - "t_stockadjustment", "t_saitemmapping", "t_patientreturn", - "t_facilityconsumption", "t_itemstockexit")); - // Add more groups as needed, up to 9 - 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(8, Arrays.asList("i_beneficiaryimage")); - 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(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")); - 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) throws Exception { - 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); - +List> dataToBesync = syncUploadDataDigester.getSyncData(); if (syncUploadDataDigester == null || syncUploadDataDigester.getTableName() == null) { logger.error("Invalid SyncUploadDataDigester object or tableName is null."); return "Error: Invalid sync request."; @@ -101,8 +113,7 @@ public String syncDataToServer(String requestOBJ, String Authorization, String t logger.error("Sync failed for m_beneficiaryregidmapping: {}", result); return "Sync failed for m_beneficiaryregidmapping."; } - } - if ("i_beneficiarydetails".equalsIgnoreCase(syncTableName)) { + } else 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."; @@ -111,28 +122,35 @@ public String syncDataToServer(String requestOBJ, String Authorization, String t return "Sync failed for i_beneficiarydetails."; } } else { - // Determine the group for the current table or iterate through all if no specific table is given + // 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. + // 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); + + for (Map map : dataToBesync) { + // if (entry.getValue().contains(syncTableName.toLowerCase())) { + if(map.get("tableName") != null + && map.get("tableName").toString().equalsIgnoreCase(syncTableName)) { + 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); + 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 + // 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(); @@ -142,26 +160,34 @@ public String syncDataToServer(String requestOBJ, String Authorization, String t try { // Create a new digester for each table within the group, // or adapt if the original digester contains data for multiple tables. - // For simplicity, assuming syncDataDigester needs to be tailored per table or group. - // If your requestOBJ contains data for only one table at a time, this loop might need adjustment + // For simplicity, assuming syncDataDigester needs to be tailored per table or + // group. + // If your requestOBJ contains data for only one table at a time, this loop + // might need adjustment // to fetch data for each table in the group. // For now, it will use the syncData from the original requestOBJ, which implies // the original requestOBJ should represent data for a single table. - // A more robust solution would involve fetching data for each table dynamically. - boolean currentTableSyncResult = syncTablesInGroup(syncUploadDataDigester.getSchemaName(), table, syncUploadDataDigester); + // A more robust solution would involve fetching data for each table + // dynamically. + 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); - // Optionally, you can choose to break here or continue to sync other tables in the group/next group + logger.error("Sync failed for table '{}' in Group {}. Error: {}", table, groupId, + errorMessage); + // Optionally, you can choose to break here or continue to sync other tables in + // the group/next group // For now, let's continue to attempt other tables within the group. } 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); + 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); // Continue to attempt other tables } } @@ -182,35 +208,35 @@ public String syncDataToServer(String requestOBJ, String Authorization, String t * with relevant data for the `currentTableName` before calling this. * In a real-world scenario, you might fetch data for each table here. */ - private boolean syncTablesInGroup(String schemaName, String currentTableName, SyncUploadDataDigester originalDigester) { + private boolean syncTablesInGroup(String schemaName, String currentTableName, + SyncUploadDataDigester originalDigester) { logger.info("Attempting generic sync for table: {}", currentTableName); // This is a simplification. In a production system, you would likely need // to retrieve the actual data for 'currentTableName' from the local DB // based on the group sync approach. For this example, we'll assume the // originalDigester's syncData is relevant or needs to be re-populated. - // Create a new digester instance or modify the existing one for the current table + // Create a new digester instance or modify the existing one for the current + // table 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.setServerColumns(originalDigester.getServerColumns()); // Assuming serverColumns is + // generic or set per table // !!! IMPORTANT: You'll need to fetch the data for 'currentTableName' from your local DB here. // The `originalDigester.getSyncData()` might not be correct for all tables in a group. // For demonstration, I'm just using the original digester's data, which is likely incorrect - // if you're syncing multiple tables from a single request. - // You'll need a method like: dataSyncRepositoryLocal.getDataForTable(currentTableName, ...) - tableSpecificDigester.setSyncData(originalDigester.getSyncData()); // Placeholder: Replace with actual data fetching - + tableSpecificDigester.setSyncData(originalDigester.getSyncData()); 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()); + private String update_M_BeneficiaryRegIdMapping_for_provisioned_benID( + SyncUploadDataDigester syncUploadDataDigester) { + List> dataToBesync = syncUploadDataDigester.getSyncData(); List syncData = new ArrayList<>(); @@ -226,20 +252,24 @@ private String update_M_BeneficiaryRegIdMapping_for_provisioned_benID(SyncUpload 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); + logger.warn( + "Skipping record in m_beneficiaryregidmapping due to missing BenRegId, BeneficiaryID, or VanID: {}", + map); } } if (!syncData.isEmpty()) { try { int[] i = dataSyncRepositoryCentral.syncDataToCentralDB(syncUploadDataDigester.getSchemaName(), - syncUploadDataDigester.getTableName(), SERVER_COLUMNS_NOT_REQUIRED, query, syncData); + syncUploadDataDigester.getTableName(), syncUploadDataDigester.getServerColumns(), 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)); + 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) { @@ -263,48 +293,47 @@ private String getqueryFor_M_BeneficiaryRegIdMapping(String schemaName, String t queryBuilder.append(" BeneficiaryID = ? "); queryBuilder.append(" AND "); queryBuilder.append(" VanID = ? "); + return queryBuilder.toString(); } 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()); - List syncData = new ArrayList<>(); + List syncData = new ArrayList<>(); - String query = getQueryFor_I_BeneficiaryDetails(syncUploadDataDigester.getSchemaName(), - syncUploadDataDigester.getTableName()); + String query = getQueryFor_I_BeneficiaryDetails(syncUploadDataDigester.getSchemaName(), + syncUploadDataDigester.getTableName()); - int limit = 1000; - int offset = 0; - int totalProcessed = 0; + int limit = 1000; + int offset = 0; + int totalProcessed = 0; - String problematicWhereClause = " WHERE Processed <> 'P' AND VanID IS NOT NULL "; // Define it explicitly + String problematicWhereClause = " WHERE Processed <> 'P' AND VanID IS NOT NULL "; // Define it explicitly while (true) { List> batch; try { - logger.info("DEBUG: Passing whereClause to getBatchForBenDetails: [{}]", problematicWhereClause); - - batch = dataSyncRepositoryCentral.getBatchForBenDetails( - syncUploadDataDigester.getSchemaName(), - syncUploadDataDigester.getTableName(), - syncUploadDataDigester.getServerColumns(), - problematicWhereClause, // Use the variable - 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 (totalProcessed > 0 || syncData.isEmpty()) { // syncData.isEmpty() means no records to process, still a "success" - logger.info("Finished processing i_beneficiarydetails. Total records processed: {}", totalProcessed); - return "data sync passed"; - } else { - logger.error("No records were processed for i_beneficiarydetails or an unknown error occurred."); - return "No data processed or sync failed for i_beneficiarydetails."; + + batch = dataSyncRepositoryCentral.getBatchForBenDetails( + syncUploadDataDigester, + problematicWhereClause, + 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 (totalProcessed > 0 || syncData.isEmpty()) { // syncData.isEmpty() means no records to process, still a + // "success" + logger.info("Finished processing i_beneficiarydetails. Total records processed: {}", totalProcessed); + return "data sync passed"; + } else { + logger.error("No records were processed for i_beneficiarydetails or an unknown error occurred."); + return "No data processed or sync failed for i_beneficiarydetails."; + } } } - } + private String getQueryFor_I_BeneficiaryDetails(String schemaName, String tableName) { StringBuilder queryBuilder = new StringBuilder(" UPDATE "); queryBuilder.append(schemaName).append(".").append(tableName); @@ -317,12 +346,11 @@ private String getQueryFor_I_BeneficiaryDetails(String schemaName, String tableN return queryBuilder.toString(); } - /** - * Handles the generic synchronization logic for tables not covered by specific handlers. + * Handles the generic synchronization logic for tables not covered by specific + * handlers. */ private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDigester) { - logger.info("Performing generic sync for table: {}", syncUploadDataDigester.getTableName()); List> dataToBesync = syncUploadDataDigester.getSyncData(); List syncDataListInsert = new ArrayList<>(); List syncDataListUpdate = new ArrayList<>(); @@ -342,10 +370,16 @@ private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDig String vanID = String.valueOf(map.get("VanID")); int syncFacilityID = 0; - // Update SyncedBy and SyncedDate in the map itself before processing + // Update SyncedBy and SyncedDate in the xmap itself before processing map.put("SyncedBy", syncUploadDataDigester.getSyncedBy()); map.put("SyncedDate", String.valueOf(LocalDateTime.now())); // Ensure column name matches DB - + if (map.get("CreatedDate") == null || map.get("created_date") == null) { + logger.info("CreatedDate was null for table: " + syncTableName + ", inserting current time"); + if(map.get("CreatedDate") == null) + map.put("CreatedDate", String.valueOf(LocalDateTime.now())); + if(map.get("created_date") == null) + map.put("created_date", String.valueOf(LocalDateTime.now())); + } // Facility ID processing if (facilityIDFromDigester != null) { // Determine the 'Processed' status based on facility ID for specific tables @@ -370,7 +404,8 @@ private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDig break; } case "t_stocktransfer": { - if (map.containsKey("TransferToFacilityID") && map.get("TransferToFacilityID") instanceof Double) { + if (map.containsKey("TransferToFacilityID") + && map.get("TransferToFacilityID") instanceof Double) { Double transferToFacilityID = (Double) map.get("TransferToFacilityID"); if (transferToFacilityID.intValue() == facilityIDFromDigester) { map.put("Processed", "P"); @@ -388,7 +423,8 @@ private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDig break; } default: - // No specific facility ID logic for other tables, maintain existing 'Processed' status or default + // No specific facility ID logic for other tables, maintain existing 'Processed' + // status or default break; } } @@ -400,13 +436,13 @@ private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDig 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); + 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 } @@ -417,7 +453,8 @@ private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDig for (String column : serverColumnsList) { Object value = map.get(column.trim()); - // Handle boolean conversion if necessary, though String.valueOf should generally work for prepared statements + // 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) { @@ -453,11 +490,15 @@ private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDig if (!syncDataListInsert.isEmpty()) { String queryInsert = getQueryToInsertDataToServerDB(schemaName, syncTableName, syncUploadDataDigester.getServerColumns()); + try { - int[] i = dataSyncRepositoryCentral.syncDataToCentralDB(schemaName, syncTableName, syncUploadDataDigester.getServerColumns(), queryInsert, syncDataListInsert); + int[] i = dataSyncRepositoryCentral.syncDataToCentralDB(schemaName, syncTableName, + syncUploadDataDigester.getServerColumns(), 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)); + 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); } @@ -469,11 +510,15 @@ private boolean performGenericTableSync(SyncUploadDataDigester syncUploadDataDig if (!syncDataListUpdate.isEmpty()) { String queryUpdate = getQueryToUpdateDataToServerDB(schemaName, syncUploadDataDigester.getServerColumns(), syncTableName); + // Ensure the update query is correct and matches the expected format try { - int[] j = dataSyncRepositoryCentral.syncDataToCentralDB(schemaName, syncTableName, SERVER_COLUMNS_NOT_REQUIRED, queryUpdate, syncDataListUpdate); + 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)); + 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); } @@ -518,16 +563,24 @@ public String getQueryToUpdateDataToServerDB(String schemaName, String serverCol StringBuilder preparedStatementSetter = new StringBuilder(); - if (columnsArr != null && columnsArr.length > 0) { + if (columnsArr != null && columnsArr.length > 0) { for (int i = 0; i < columnsArr.length; i++) { - preparedStatementSetter.append(columnsArr[i].trim()); - preparedStatementSetter.append(" = ?"); + String columnName = columnsArr[i].trim(); // ← NEW LINE + + // Special handling for CreatedDate - use COALESCE to prevent NULL + if (columnName.equalsIgnoreCase("CreatedDate")) { // ← NEW BLOCK + preparedStatementSetter.append(columnName); + preparedStatementSetter.append(" = COALESCE(?, CURRENT_TIMESTAMP)"); + } else { + preparedStatementSetter.append(columnName); + preparedStatementSetter.append(" = ?"); + } + if (i < columnsArr.length - 1) { preparedStatementSetter.append(", "); } } } - StringBuilder queryBuilder = new StringBuilder(" UPDATE "); queryBuilder.append(schemaName).append(".").append(tableName); queryBuilder.append(" SET "); @@ -549,18 +602,21 @@ public String getQueryToUpdateDataToServerDB(String schemaName, String serverCol private String getFailedRecords(int[] results, List data) { List failedRecordsInfo = new ArrayList<>(); for (int k = 0; k < results.length; k++) { - // In Spring JDBC batchUpdate, a value of Statement.EXECUTE_FAILED or Statement.SUCCESS_NO_INFO + // In Spring JDBC batchUpdate, a value of Statement.EXECUTE_FAILED or + // Statement.SUCCESS_NO_INFO // usually indicates a failure or success without specific row count. // A common return value for success is 1 (for one row updated/inserted). if (results[k] < 1) { // Assuming 1 means success, and anything else (0, -2, etc.) means failure // Attempt to get some identifiable info from the failed record if (data.get(k).length > 0) { - failedRecordsInfo.add("Record at index " + k + " (VanSerialNo/ID: " + data.get(k)[data.get(k).length - 2] + ")"); + failedRecordsInfo.add( + "Record at index " + k + " (VanSerialNo/ID: " + data.get(k)[data.get(k).length - 2] + ")"); } else { failedRecordsInfo.add("Record at index " + k + " (No identifiable info)"); } } } + logger.info("Failed records info: {}", failedRecordsInfo); return String.join("; ", failedRecordsInfo); } } \ No newline at end of file diff --git a/src/main/java/com/iemr/mmu/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/mmu/utils/JwtUserIdValidationFilter.java index 1dba0e78..fbeab7ad 100644 --- a/src/main/java/com/iemr/mmu/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/iemr/mmu/utils/JwtUserIdValidationFilter.java @@ -38,13 +38,10 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo String origin = request.getHeader("Origin"); - logger.debug("Incoming Origin: {}", origin); - logger.debug("Allowed Origins Configured: {}", allowedOrigins); - if (origin != null && isOriginAllowed(origin)) { response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); - response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, Jwttoken"); + response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, Jwttoken,serverAuthorization, ServerAuthorization, serverauthorization, Serverauthorization"); response.setHeader("Vary", "Origin"); response.setHeader("Access-Control-Allow-Credentials", "true"); } else { @@ -59,7 +56,6 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo String path = request.getRequestURI(); String contextPath = request.getContextPath(); - logger.info("JwtUserIdValidationFilter invoked for path: " + path); // Log cookies for debugging Cookie[] cookies = request.getCookies(); @@ -76,7 +72,6 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo // Log headers for debugging String jwtTokenFromHeader = request.getHeader("Jwttoken"); - logger.info("JWT token from header: "); // Skip login and public endpoints if (path.equals(contextPath + "/user/userAuthenticate") @@ -104,7 +99,6 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo return; } } else if (jwtFromHeader != null) { - logger.info("Validating JWT token from header"); if (jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtFromHeader)) { AuthorizationHeaderRequestWrapper authorizationHeaderRequestWrapper = new AuthorizationHeaderRequestWrapper( request, ""); @@ -113,7 +107,6 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo } } else { String userAgent = request.getHeader("User-Agent"); - logger.info("User-Agent: " + userAgent); if (userAgent != null && isMobileClient(userAgent) && authHeader != null) { try { UserAgentContext.setUserAgent(userAgent); @@ -123,6 +116,7 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo } return; } + } logger.warn("No valid authentication token found"); @@ -156,7 +150,8 @@ private boolean isMobileClient(String userAgent) { if (userAgent == null) return false; userAgent = userAgent.toLowerCase(); - return userAgent.contains("okhttp"); // iOS (custom clients) + logger.info("User-Agent: " + userAgent); + return userAgent.contains("okhttp") || userAgent.contains("java/"); // iOS (custom clients) } private String getJwtTokenFromCookies(HttpServletRequest request) { @@ -179,4 +174,4 @@ private void clearUserIdCookie(HttpServletResponse response) { cookie.setMaxAge(0); // Invalidate the cookie response.addCookie(cookie); } -} +} \ 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 d1ea0efd..33556d22 100644 --- a/src/main/java/com/iemr/mmu/utils/RestTemplateUtil.java +++ b/src/main/java/com/iemr/mmu/utils/RestTemplateUtil.java @@ -39,11 +39,16 @@ public static HttpEntity createRequestEntity(Object body, String authori MultiValueMap headers = new LinkedMultiValueMap<>(); headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE + ";charset=utf-8"); - - if (authorization != null && !authorization.isEmpty()) { +logger.info("token: {}", jwtToken); + if (authorization != null && !authorization.isEmpty() && !jwtToken.equalsIgnoreCase("datasync")) { headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + authorization); } + if(authorization != null && !authorization.isEmpty() && jwtToken.equalsIgnoreCase("datasync")) + { + headers.add(HttpHeaders.AUTHORIZATION, authorization); + } + if (jwtToken == null || jwtToken.isEmpty()) { ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); @@ -55,14 +60,11 @@ public static HttpEntity createRequestEntity(Object body, String authori logger.error("Error while getting JWT token from cookie: {}", e.getMessage()); } } - } + } - - if (jwtToken != null && !jwtToken.isEmpty()) { + if (jwtToken != null && !jwtToken.isEmpty() && !jwtToken.equalsIgnoreCase("datasync")) { headers.add(HttpHeaders.COOKIE, "Jwttoken=" + jwtToken); } - - return new HttpEntity<>(body, headers); } } \ No newline at end of file