Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d829343
Build failed resolved
ravishanigarapu Apr 16, 2025
eb9cc5b
Merge branch 'PSMRI:develop' into develop
ravishanigarapu May 20, 2025
71c072d
jwttoken and user-agent validation
ravishanigarapu May 22, 2025
b4eeadf
null check
ravishanigarapu May 22, 2025
722893f
Code optimize and performance
ravishanigarapu Jul 30, 2025
a79da7f
Performance increase
ravishanigarapu Jul 30, 2025
94b0b27
Merge branch 'develop' into develop
ravishanigarapu Jul 30, 2025
19bd619
Build errors
ravishanigarapu Jul 30, 2025
7f46e65
Test cases ignored
ravishanigarapu Jul 30, 2025
a16090b
Ignored test cases
ravishanigarapu Jul 30, 2025
2cac39d
Security hotspot fix
ravishanigarapu Jul 31, 2025
bfa8575
security hotspot issue
ravishanigarapu Aug 1, 2025
1f3c87b
performance check
ravishanigarapu Aug 1, 2025
ca5d7a4
Increased performance issue while generating BeneficiaryID (#46)
ravishanigarapu Aug 1, 2025
e079f4a
Uncommented test file
ravishanigarapu Aug 5, 2025
5166320
Merge branch 'develop' into develop
ravishanigarapu Aug 5, 2025
eea7dee
Corrected test cases
ravishanigarapu Aug 5, 2025
921f69f
indent format change
ravishanigarapu Aug 5, 2025
372de77
Coderabbit comments
ravishanigarapu Aug 6, 2025
ac13f53
test cases corrected
ravishanigarapu Aug 7, 2025
877c772
Test cases corrected
ravishanigarapu Aug 7, 2025
603590f
1 test case failing
ravishanigarapu Aug 7, 2025
1ed97bf
Corrected junit test cases
ravishanigarapu Aug 7, 2025
68ec126
Test cases corrected
ravishanigarapu Aug 7, 2025
7307f1d
test cases
ravishanigarapu Aug 7, 2025
ce83428
code rabbit comments addressed
ravishanigarapu Aug 7, 2025
fe48e8b
removed unused imports
ravishanigarapu Aug 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,15 @@
*/
package com.iemr.common.bengen.service;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Timestamp;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -43,17 +42,34 @@
import com.iemr.common.bengen.utils.Generator;
import com.iemr.common.bengen.utils.config.ConfigProperties;

import jakarta.annotation.PreDestroy;
import jakarta.transaction.Transactional;

@Service
public class GenerateBeneficiaryService {
private static final Logger logger = LoggerFactory.getLogger(GenerateBeneficiaryService.class);
private ExecutorService executor = Executors.newCachedThreadPool();

private static final int BATCH_SIZE = 500;
Comment on lines 51 to +52
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

ExecutorService is never shutdown - potential resource leak.

The ExecutorService at line 51 is created but never shutdown, which can lead to thread leaks.

Add proper lifecycle management:

+import javax.annotation.PreDestroy;

 @Service
 public class GenerateBeneficiaryService {
     private static final Logger logger = LoggerFactory.getLogger(GenerateBeneficiaryService.class);
     private ExecutorService executor = Executors.newCachedThreadPool();
     
+    @PreDestroy
+    public void cleanup() {
+        logger.info("Shutting down executor service");
+        executor.shutdown();
+        try {
+            if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
+                executor.shutdownNow();
+            }
+        } catch (InterruptedException e) {
+            executor.shutdownNow();
+            Thread.currentThread().interrupt();
+        }
+    }
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private ExecutorService executor = Executors.newCachedThreadPool();
private static final int BATCH_SIZE = 500;
// … other imports …
import javax.annotation.PreDestroy;
@Service
public class GenerateBeneficiaryService {
private static final Logger logger = LoggerFactory.getLogger(GenerateBeneficiaryService.class);
private ExecutorService executor = Executors.newCachedThreadPool();
private static final int BATCH_SIZE = 500;
@PreDestroy
public void cleanup() {
logger.info("Shutting down executor service");
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
// … existing methods …
}
πŸ€– Prompt for AI Agents
In src/main/java/com/iemr/common/bengen/service/GenerateBeneficiaryService.java
around lines 51 to 52, the ExecutorService is instantiated but never shut down,
causing potential thread leaks. Add a method to properly shut down the executor,
such as a shutdown or close method, and ensure it is called when the service is
no longer needed. Use executor.shutdown() followed by awaitTermination to
gracefully stop the threads.

private static final String ADMIN_BATCH = "admin-batch";
@Autowired
JdbcTemplate jdbcTemplate;

@Autowired
BeneficiaryIdRepo beneficiaryIdRepo;

@PreDestroy
public void cleanup() {
logger.info("Shutting down executor service");
executor.shutdown();
try {
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
executor.shutdownNow();
}
} catch (InterruptedException e) {
executor.shutdownNow();
Thread.currentThread().interrupt();
}
}
public void generateBeneficiaryIDs() throws Exception {
logger.info("BengenApplication.run start");
long strt = System.currentTimeMillis();
Expand All @@ -64,80 +80,57 @@ public void generateBeneficiaryIDs() throws Exception {
createFile();
});

/*
* executor.submit(() -> { logger.info("Running: " +
* Thread.currentThread().getName()); createFile(); });
*
* executor.submit(() -> { logger.info("Running: " +
* Thread.currentThread().getName()); createFile(); });
*/
// }

long fin = System.currentTimeMillis() - strt;
logger.info("BengenApplication.run finish. time = " + fin + " ms.");
}

@Transactional
public void createFile() {
logger.info("BengenApplication.createFile start");
long strt = System.currentTimeMillis();

try {
File file = File.createTempFile("" + System.currentTimeMillis(), ".csv");
logger.info("File: " + file.getAbsolutePath());
FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw);
Integer bentobeGenerate = ConfigProperties.getInteger("no-of-benID-to-be-generate");
bw.write(createQuery(bentobeGenerate).toString());
bw.flush();
bw.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
long fin = System.currentTimeMillis() - strt;
logger.info("BengenApplication.createFile finish. time = " + fin + " ms.");
}

public StringBuffer createQuery(Integer num) {
logger.info("BengenApplication.createQuery start");
long strt = System.currentTimeMillis();

Generator g = new Generator();
StringBuffer sb = new StringBuffer(
"INSERT INTO `db_identity`.`m_beneficiaryregidmapping` " +
"(`BeneficiaryID`,`Provisioned`,`Deleted`," +
"`CreatedDate`,`CreatedBy`) VALUES ");

// INSERT INTO `db_identity`.`m_beneficiaryregidmapping`
// (`BeneficiaryID`,`Provisioned`,`Deleted`,`CreatedDate`,`CreatedBy`) VALUES
// (<{BeneficiaryID: }>, <{Provisioned: b'0'}>, <{Deleted: b'0'}>,
// <{CreatedDate: CURRENT_TIMESTAMP}>, <{CreatedBy: }>);

Timestamp ts = Timestamp.from(Instant.now());

for (int i = 0; i < num; i++) {
sb.append("( ");
sb.append(g.generateBeneficiaryId())
.append(",")
.append("b'0'")
.append(",")
.append("b'0'")
.append(",")
.append("'")
.append(ts)
.append("',")
.append("'admin-batch'")
.append("");
sb.append(" ), ");
Integer count = ConfigProperties.getInteger("no-of-benID-to-be-generate");

List<Object[]> batchArgs = createBatchData(count);

// Batch insert using JdbcTemplate
String sql = "INSERT INTO `db_identity`.`m_beneficiaryregidmapping` "
+ "(`BeneficiaryID`, `Provisioned`, `Deleted`, `CreatedDate`, `CreatedBy`) "
+ "VALUES (?, b'0', b'0', ?, ?)";

for (int i = 0; i < batchArgs.size(); i += BATCH_SIZE) {
List<Object[]> batch = batchArgs.subList(i, Math.min(i + BATCH_SIZE, batchArgs.size()));
try {
jdbcTemplate.batchUpdate(sql, batch);
} catch (Exception e) {
logger.error("Failed to insert batch starting at index {}: {}", i, e.getMessage());
throw new RuntimeException("Batch insert failed", e);
}
}

sb.deleteCharAt(sb.lastIndexOf(","));

jdbcTemplate.execute(sb.toString());

long fin = System.currentTimeMillis() - strt;
logger.info("BengenApplication.createQuery finish. time = " + fin + " ms.");
logger.info("BengenApplication.createFile finish. time = " + fin + " ms.");
}

return sb;
public List<Object[]> createBatchData(int num) {
logger.info("BengenApplication.createBatchData start");
long strt = System.currentTimeMillis();

Timestamp ts = Timestamp.from(Instant.now());
Generator g = new Generator();

// Use parallelStream to generate Beneficiary IDs concurrently
List<Object[]> data = IntStream.range(0, num).parallel()
.mapToObj(i -> new Object[]{
g.generateBeneficiaryId(), // Assuming it's thread-safe
ts,
ADMIN_BATCH
})
.collect(Collectors.toList());

long fin = System.currentTimeMillis() - strt;
logger.info("BengenApplication.createBatchData finish. time = " + fin + " ms.");
return data;
}

public void testLoopGenr() {
Expand Down
174 changes: 68 additions & 106 deletions src/main/java/com/iemr/common/bengen/utils/Generator.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
package com.iemr.common.bengen.utils;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.concurrent.ThreadLocalRandom;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -31,125 +34,84 @@
* @author Sunil.K.Sundaram
*/
public class Generator {

private static final Logger log = LoggerFactory.getLogger(Generator.class);

public BigInteger generateBeneficiaryId(){
BigInteger bid1 = generateFirst();
BigInteger bid2 = generateNumN(10);
if (log.isDebugEnabled()){
log.debug("bid1: "+bid1+" length: "+getDigitCount(bid1));
log.debug("bid2: "+bid2+" length: "+getDigitCount(bid2));
}

BigInteger bid = bid1.add(bid2).multiply(new BigInteger("10"));
String chsum = Verhoeff.generateVerhoeff(bid.toString());
if (log.isDebugEnabled()){
log.debug("bid: "+bid+" length: "+getDigitCount(bid)+" chsum: " + chsum);
}

bid = bid.add(new BigInteger(chsum));
if (log.isDebugEnabled()){
log.debug("BENEFICIARY ID: " + bid /*+ ": Length: " + getDigitCount(bid)*/);
}
return bid;
}

public BigInteger generateFirst(){
int one = getRandomNumRadRange(2, 9);

BigInteger bn = new BigInteger(""+one).multiply(new BigInteger("10").pow(10));
return bn;
}

protected BigInteger generateNumN(int n){
int myArr1[] = new int[n];
int myArr2[] = new int[n];
private static final Logger log = LoggerFactory.getLogger(Generator.class);
private static final BigInteger TEN = BigInteger.TEN;
private static final BigInteger TEN_POW_10 = TEN.pow(10);

private static final SecureRandom SECURE_RANDOM = new SecureRandom();

for(int i=0;i<=n-1;i++){
myArr1[i] = getRandomNum();
}
public BigInteger generateBeneficiaryId() {
BigInteger bid1 = generateFirst();
BigInteger bid2 = generateNumN(10);

int count = n-1;
for(int i=0; i <= myArr1.length-1 ; i++){
int num;
if(count == 0){
num = getRandomNum();
} else {
num = getRandomNumRad(count);
}

int tmp = num;
myArr2[count] = myArr1[i];
myArr1[i] = tmp;
count--;
}
if (log.isDebugEnabled()) {
log.debug("bid1: {} length: {}", bid1, getDigitCount(bid1));
log.debug("bid2: {} length: {}", bid2, getDigitCount(bid2));
}

StringBuilder str = new StringBuilder();
for(int i=0;i<myArr2.length;i++){
str.append(myArr2[i]);
}
BigInteger bid = bid1.add(bid2).multiply(TEN);
String checksum = Verhoeff.generateVerhoeff(bid.toString());

BigInteger bn = new BigInteger(str.toString());
if (log.isDebugEnabled()) {
log.debug("bid: {} length: {} chsum: {}", bid, getDigitCount(bid), checksum);
}

return bn;
}
bid = bid.add(new BigInteger(checksum));
if (log.isDebugEnabled()) {
log.debug("BENEFICIARY ID: {}", bid);
}

public int getDigitCount(BigInteger number) {
double factor = Math.log(2) / Math.log(10);
final int digitCount = (int) (factor * number.bitLength() + 1);
if (BigInteger.TEN.pow(digitCount - 1).compareTo(number) > 0) {
return digitCount - 1;
}
return digitCount;
}

public int getRandomNum(){
int num = (int) (Math.random() * 100 % 10);
if (log.isDebugEnabled()){
log.debug("Rand generated: " + num);
}
return num;
}
return bid;
}

public BigInteger generateFirst() {
int digit = getRandomInRange(2, 9);
return BigInteger.valueOf(digit).multiply(TEN_POW_10);
}

public int getRandomNumRad(int rad){
int num = getRandomNum();
num = num % rad;
if (log.isDebugEnabled()){
log.debug("Rand generated ("+ rad + "): " + num);
protected BigInteger generateNumN(int n) {
StringBuilder sb = new StringBuilder(n);
for (int i = 0; i < n; i++) {
sb.append(getRandomDigit());
}
return num;
return new BigInteger(sb.toString());
}

public int getRandomNumRadRange(int rad1, int rad2){
int num = getRandomNum();
if(num >= rad1 && num <= rad2){
return num;
} else {
num = getRandomNumRadRange(rad1, rad2);
}
public int getDigitCount(BigInteger number) {
double factor = Math.log10(2);
int digits = (int) (factor * number.bitLength() + 1);
return (TEN.pow(digits - 1).compareTo(number) > 0) ? digits - 1 : digits;
}

if (log.isDebugEnabled()){
log.debug("Rand range generated: " + num);
}
return num;
}
private int getRandomDigit() {
return SECURE_RANDOM.nextInt(10);

public void displayArrays(int[] myArr, int[] myArr2){
StringBuilder str = new StringBuilder();
for(int i=0;i<myArr.length;i++){
str.append(myArr[i]);
}
if (log.isDebugEnabled()){
log.debug("myarr : " + str);
}
}

str = new StringBuilder();
for(int i=0;i<myArr2.length;i++){
str.append(myArr2[i]);
}
if (log.isDebugEnabled()){
log.debug("myarr2: " + str);
private int getRandomInRange(int min, int max) {
if (min > max) {
throw new IllegalArgumentException("min must be <= max");
}
if (max == Integer.MAX_VALUE || (long) max - min + 1 > Integer.MAX_VALUE) {
return SECURE_RANDOM.nextInt(min, max + 1);
}
}
return SECURE_RANDOM.nextInt(min, max + 1);
}

// Optional: only if you need debugging arrays
public void displayArrays(int[] arr1, int[] arr2) {
if (!log.isDebugEnabled()) return;

log.debug("myarr : {}", intArrayToString(arr1));
log.debug("myarr2 : {}", intArrayToString(arr2));
}

private String intArrayToString(int[] array) {
StringBuilder sb = new StringBuilder(array.length);
for (int value : array) {
sb.append(value);
}
return sb.toString();
}
}
Loading
Loading