Skip to content

fix: resolve 5 bugs across controller, feed worker, and patient data handler#145

Open
PragyaTripathi990 wants to merge 2 commits into
PSMRI:mainfrom
PragyaTripathi990:fix/bug-fixes-controller-feed-patient-data
Open

fix: resolve 5 bugs across controller, feed worker, and patient data handler#145
PragyaTripathi990 wants to merge 2 commits into
PSMRI:mainfrom
PragyaTripathi990:fix/bug-fixes-controller-feed-patient-data

Conversation

@PragyaTripathi990
Copy link
Copy Markdown

@PragyaTripathi990 PragyaTripathi990 commented May 14, 2026

Summary

This PR fixes 5 real engineering bugs identified across the health ID controller, clinical feed worker, and patient data handler layers of the FHIR-API service.

Bug 1 — HTTP 200 returned on error (CreateHealthIdRecord)

Both endpoints (/mapHealthIDToBeneficiary and /addHealthIdRecord) caught FHIRException and set an error state but still returned HTTP 200 OK. API clients had no way to distinguish success from failure via HTTP status. Fixed by returning ResponseEntity<String> with HttpStatus.INTERNAL_SERVER_ERROR on error and ResponseEntity.ok() on success.

Bug 2 — Sensitive patient data logged at INFO level (CreateHealthIdRecord)

Full request and response bodies (containing ABHA numbers, patient identifiers) were logged at INFO level on every API call. This is a data privacy violation in a healthcare context. Replaced with safe summary log messages that confirm the operation without exposing patient data.

Bug 3 — Bare Exception throws instead of domain exception (ClinicalFeedWorker)

Two throw new Exception(...) calls were used inside readPatientEncounterFeeds where FHIRException (the project's own domain exception) should have been used. This broke the exception hierarchy and made it impossible for callers to catch specific error types. Replaced with throw new FHIRException(...).

Bug 4 — Silent exception swallowing in outer feed loop (ClinicalFeedWorker)

Four outer catch blocks (IllegalArgumentException, FeedException, IOException, Exception) silently reset the pointer to 0 with no logging whatsoever. Production failures in feed processing were completely invisible. Added logger.error(...) to each catch block.

Bug 5 — Unsafe feed URL pointer parsing (ClinicalFeedWorker)

Both feed pointer parse sites (in encounterFeedManager and inside the next-archive loop) called Integer.parseInt(arr[arr.length - 1]) without guarding against empty strings or non-numeric values. A malformed feed URL would throw an uncaught NumberFormatException. Added bounds check, empty string guard, and NumberFormatException handling with fallback to atomsFeedStartPage.

Bug 6 — Missing @Transactional on dual DB writes (PatientDataGatewayServiceImpl)

Both overloads of generatePatientProfileAMRIT_SaveTo_Mongo performed two separate database operations (MongoDB write + processed flag update in MySQL) without a transaction boundary. A failure between the two writes would leave data in an inconsistent state. Added @Transactional(rollbackFor = FHIRException.class) to both methods.

Bug 7 — Copy-paste bug in address line check (PatientDataGatewayServiceImpl)

The condition if (getAddressLine1() != null || getAddressLine1() != null || getAddressLine1() != null) checked the same field three times due to a copy-paste error. AddressLine2 and AddressLine3 were never checked, so patient addresses with only lines 2 or 3 were silently ignored. Fixed to check AddressLine1 || AddressLine2 || AddressLine3.

Files Changed

  • src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java
  • src/main/java/com/wipro/fhir/service/atoms/feed/bahmni/ClinicalFeedWorker.java
  • src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • API endpoints now return proper HTTP status codes (200 for success, 500 for errors) with improved error logging and clearer failure messages
    • Enhanced error handling and observability for feed processing and pagination workflows
    • Fixed address field validation during patient profile generation
    • Added transaction management to ensure data persistence reliability

Review Change Stack

…handler

- CreateHealthIdRecord: return ResponseEntity with HTTP 500 on FHIRException
  instead of always returning HTTP 200; replace full request/response body
  logging at INFO with safe summary messages to prevent patient data leaks
- ClinicalFeedWorker: replace bare Exception throws with FHIRException for
  domain consistency; add error logging to outer catch blocks that were
  silently swallowing feed processing failures; guard both feed URL pointer
  parsings with bounds check and NumberFormatException handling to prevent
  crashes on malformed URLs
- PatientDataGatewayServiceImpl: add @transactional to both overloads of
  generatePatientProfileAMRIT_SaveTo_Mongo so MongoDB write and processed-flag
  update are atomic; fix copy-paste bug where all three address line OR
  conditions checked getAddressLine1() instead of lines 1, 2, and 3

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

📝 Walkthrough

Walkthrough

This PR updates HealthID controller endpoints to return typed HTTP responses and improved logging, makes ClinicalFeedWorker pagination parsing and error logging more defensive and changes some failures to throw FHIRException, and adds transactional annotations plus an address-line conditional fix in the patient data gateway.

Changes

FHIR API Error Handling and Robustness Improvements

Layer / File(s) Summary
HealthID Controller Response Handling
src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java
Endpoints mapHealthIDToBeneficiary and addRecordToHealthIdTable now return ResponseEntity<String> with OutputResponse bodies; log generic request receipt; return HTTP 200 on success and HTTP 500 on FHIRException or unexpected exceptions; added HttpStatus/ResponseEntity imports.
Feed Processing Pagination and Error Observability
src/main/java/com/wipro/fhir/service/atoms/feed/bahmni/ClinicalFeedWorker.java
linkSelf and next-archive pagination pointers are parsed defensively with guarded Integer parsing and fallbacks; missing/failed encounter persistence now throws FHIRException; feed-page catch blocks log page pointer and exception messages and reset pointer.
Patient Data Transaction Management and Address Field Fix
src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java
Both generatePatientProfileAMRIT_SaveTo_Mongo overloads annotated with @Transactional(rollbackFor = FHIRException.class) and wrap processed-flag updates in try/catch that logs IDs and rethrows FHIRException on failure; address-line presence conditional corrected to check AddressLine2/3.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit hops through error paths so clear,
With HTTP codes and transactions dear,
Pointers parsed with care and grace,
Addresses fixed in their rightful place! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: bug fixes across three specific components (controller, feed worker, patient data handler).
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java (2)

69-73: ⚡ Quick win

Consider catching broader exceptions for consistent error responses.

Currently only FHIRException is caught and formatted into an OutputResponse. Other runtime exceptions (e.g., NullPointerException, IllegalArgumentException) will propagate as unformatted 500 errors, creating inconsistent API responses for clients.

🛡️ Suggested approach to handle all exceptions consistently
 	} catch (FHIRException e) {
 		response.setError(5000, e.getMessage());
 		logger.error("NDHM_FHIR error adding health record: {}", e.getMessage());
 		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.toString());
+	} catch (Exception e) {
+		response.setError(5000, "An unexpected error occurred");
+		logger.error("NDHM_FHIR unexpected error adding health record", e);
+		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.toString());
 	}

Note: The generic catch logs the full exception for debugging but returns a safe message to avoid leaking internal details.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java`
around lines 69 - 73, The current catch in CreateHealthIdRecord only handles
FHIRException, so other runtime errors leak unformatted 500s; add a broader
catch(Exception e) after the existing FHIRException catch to set the same
OutputResponse error (use a safe/generic message and the same error code), log
the full exception (logger.error with the exception object, not just
e.getMessage()) and return
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.toString())
so all exceptions produce a consistent, safe API response.

48-52: ⚡ Quick win

Consider catching broader exceptions for consistent error responses.

Currently only FHIRException is caught and formatted into an OutputResponse. Other runtime exceptions (e.g., NullPointerException, IllegalArgumentException) will propagate as unformatted 500 errors, creating inconsistent API responses for clients.

🛡️ Suggested approach to handle all exceptions consistently
 	} catch (FHIRException e) {
 		response.setError(5000, e.getMessage());
 		logger.error("NDHM_FHIR error mapping ABHA to beneficiary: {}", e.getMessage());
 		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.toString());
+	} catch (Exception e) {
+		response.setError(5000, "An unexpected error occurred");
+		logger.error("NDHM_FHIR unexpected error mapping ABHA to beneficiary", e);
+		return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.toString());
 	}

Note: The generic catch logs the full exception for debugging but returns a safe message to avoid leaking internal details.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java`
around lines 48 - 52, The current try-catch in CreateHealthIdRecord only catches
FHIRException so other runtime exceptions escape unformatted; add a broader
catch (e.g., a catch(Exception e) after the existing FHIRException catch) to
handle all errors consistently: log the full exception (stacktrace) via
logger.error and set the OutputResponse with a generic 500 error message using
response.setError(...), then return
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.toString())
so CreateHealthIdRecord always returns a uniform API error format for any
exception.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java`:
- Line 38: The method mapHealthIDToBeneficiary in CreateHealthIdRecord was
changed from returning String to ResponseEntity<String>, which is a breaking API
change; either revert the controller signature back to String and return the raw
String from HealthIDService (preserve behavior of
HealthIDService.mapHealthIDToBeneficiary) or, if you must return ResponseEntity,
add a clear compatibility layer (e.g., keep the old endpoint/signature or
provide an overloaded endpoint) and update API docs and external client
integration notes; locate the method mapHealthIDToBeneficiary in
CreateHealthIdRecord and adjust the return type/return value accordingly and
ensure API documentation (OpenAPI/Swagger) and any client-facing contract are
updated to reflect the chosen change.

In
`@src/main/java/com/wipro/fhir/service/atoms/feed/bahmni/ClinicalFeedWorker.java`:
- Around line 95-102: The pointer parsing logic in ClinicalFeedWorker leaves
pointer/tempPointer as 0 when the last URL segment is empty or non-numeric (or
parses to a non-positive value), which can silently terminate the while (pointer
> 0) loop; update both parsing sites to validate the last path segment and treat
any empty, non-numeric, or <=0 parsed values as invalid and set
pointer/tempPointer = atomsFeedStartPage; ensure the logger records the invalid
value (feed.getLinkSelf()) and that the code never leaves pointer as 0 after
parsing so the feed loop has a safe fallback.

In
`@src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java`:
- Around line 93-94: The service method generatePatientProfileAMRIT_SaveTo_Mongo
currently uses `@Transactional` but only the JPA transaction manager is active, so
Mongo writes from savePatientProfileDataToMongo and MySQL updates via
updateProcessedFlagForProfileCreated are not coordinated and can leave stores
inconsistent; fix by either (A) enabling multi-store transactions: add
`@EnableTransactionManagement`, register a MongoTransactionManager bean (MongoDB
must support transactions i.e., replica set), create a ChainedTransactionManager
combining the JpaTransactionManager and MongoTransactionManager and annotate
generatePatientProfileAMRIT_SaveTo_Mongo to use that chained manager so both
mongoRepository.saveAll(...) and updateProcessedFlagForProfileCreated run in one
atomic transaction, or (B) implement explicit compensation/error-handling: wrap
savePatientProfileDataToMongo and updateProcessedFlagForProfileCreated in a
try/catch and roll back the completed store change manually if the other fails;
apply the same fix to the other affected method(s) referenced in the comment.

---

Nitpick comments:
In `@src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java`:
- Around line 69-73: The current catch in CreateHealthIdRecord only handles
FHIRException, so other runtime errors leak unformatted 500s; add a broader
catch(Exception e) after the existing FHIRException catch to set the same
OutputResponse error (use a safe/generic message and the same error code), log
the full exception (logger.error with the exception object, not just
e.getMessage()) and return
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.toString())
so all exceptions produce a consistent, safe API response.
- Around line 48-52: The current try-catch in CreateHealthIdRecord only catches
FHIRException so other runtime exceptions escape unformatted; add a broader
catch (e.g., a catch(Exception e) after the existing FHIRException catch) to
handle all errors consistently: log the full exception (stacktrace) via
logger.error and set the OutputResponse with a generic 500 error message using
response.setError(...), then return
ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.toString())
so CreateHealthIdRecord always returns a uniform API error format for any
exception.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 23d80451-4231-4bfe-b71e-1a39de968f88

📥 Commits

Reviewing files that changed from the base of the PR and between a16a5c5 and f78e321.

📒 Files selected for processing (3)
  • src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java
  • src/main/java/com/wipro/fhir/service/atoms/feed/bahmni/ClinicalFeedWorker.java
  • src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java

@Operation(summary = "Map ABHA to beneficiary")
@PostMapping(value = { "/mapHealthIDToBeneficiary" })
public String mapHealthIDToBeneficiary(
public ResponseEntity<String> mapHealthIDToBeneficiary(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Find usages of mapHealthIDToBeneficiary that might be affected by the signature change

# Search for method calls in Java/test files
rg -n --type java -C3 'mapHealthIDToBeneficiary\s*\(' -g '!CreateHealthIdRecord.java'

# Search for REST client calls or URL references
rg -n --type java -C3 '/mapHealthIDToBeneficiary' -g '!CreateHealthIdRecord.java'

Repository: PSMRI/FHIR-API

Length of output: 2734


🏁 Script executed:

#!/bin/bash

# First, find and read the CreateHealthIdRecord.java file to see the actual signature
echo "=== Finding CreateHealthIdRecord.java ==="
fd -name "CreateHealthIdRecord.java"

# Then read the file around line 38
echo -e "\n=== Reading the method signature ==="
sed -n '35,50p' "$(fd -name 'CreateHealthIdRecord.java')"

# Search for test files that might call this method
echo -e "\n=== Searching for test callers ==="
rg -n --type java 'mapHealthIDToBeneficiary' --iglob '*test*' --iglob '*Test*'

# Search for all references to mapHealthIDToBeneficiary across all file types
echo -e "\n=== Searching all references (including properties, configs, REST clients) ==="
rg -n 'mapHealthIDToBeneficiary' --type-list
rg -n 'mapHealthIDToBeneficiary'

Repository: PSMRI/FHIR-API

Length of output: 2005


🏁 Script executed:

#!/bin/bash

# Read the CreateHealthIdRecord.java file
echo "=== CreateHealthIdRecord.java content ==="
cat -n "src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java" | head -80

# Check if there are any test files for this controller
echo -e "\n=== Looking for test files ==="
fd -type f "CreateHealthIdRecord"
fd -type f "Test" -path "*healthID*"

Repository: PSMRI/FHIR-API

Length of output: 4217


Breaking REST API change requires external client validation.

The return type changed from String to ResponseEntity<String> (line 38). This is a breaking change for any external REST clients consuming this endpoint. While the underlying service layer (HealthIDService) remains unchanged, REST clients calling /healthIDRecord/mapHealthIDToBeneficiary will receive a different response structure and must be updated accordingly. Ensure external client integrations and API documentation are updated to reflect this change.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java`
at line 38, The method mapHealthIDToBeneficiary in CreateHealthIdRecord was
changed from returning String to ResponseEntity<String>, which is a breaking API
change; either revert the controller signature back to String and return the raw
String from HealthIDService (preserve behavior of
HealthIDService.mapHealthIDToBeneficiary) or, if you must return ResponseEntity,
add a clear compatibility layer (e.g., keep the old endpoint/signature or
provide an overloaded endpoint) and update API docs and external client
integration notes; locate the method mapHealthIDToBeneficiary in
CreateHealthIdRecord and adjust the return type/return value accordingly and
ensure API documentation (OpenAPI/Swagger) and any client-facing contract are
updated to reflect the chosen change.

Comment on lines +93 to 94
@Transactional(rollbackFor = FHIRException.class)
public String generatePatientProfileAMRIT_SaveTo_Mongo(String Authorization) throws FHIRException {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Transaction manager and `@EnableTransactionManagement` declarations =="
rg -n -C3 '@EnableTransactionManagement|PlatformTransactionManager|MongoTransactionManager|JpaTransactionManager|ChainedTransactionManager|transactionManagerRef' $(fd -t f '.*\.java$' src || true)

echo
echo "== Mongo config presence (templates/factories/transaction manager) =="
rg -n -C3 'MongoTemplate|MongoDatabaseFactory|MongoTransactionManager|AbstractMongoClientConfiguration' $(fd -t f '.*\.java$' src || true)

echo
echo "== savePatientProfileDataToMongo implementation and annotations =="
rg -n -C5 'savePatientProfileDataToMongo\s*\(' $(fd -t f '.*\.java$' src || true)

echo
echo "== Repository update method definition =="
rg -n -C5 'updateProcessedFlagForProfileCreated\s*\(' $(fd -t f '.*\.java$' src || true)

Repository: PSMRI/FHIR-API

Length of output: 11637


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== FhirApiApplication.java full content ==="
cat -n src/main/java/com/wipro/fhir/FhirApiApplication.java

echo
echo "=== Application configuration files ==="
fd -t f -e properties -e yml -e yaml src || true | head -20
rg -l 'application' . --max-depth 2 2>/dev/null | grep -E '\.(properties|yml|yaml)$' | head -20

echo
echo "=== Check application.properties for spring.data.mongodb and transaction configs ==="
fd -t f 'application.*properties' . | xargs cat 2>/dev/null | grep -i -E 'mongodb|transaction|jpa' || echo "No matches"

echo
echo "=== Check application.yml/yaml for spring.data.mongodb and transaction configs ==="
fd -t f 'application.*\.ya?ml' . | xargs cat 2>/dev/null | grep -A5 -B5 -i -E 'mongodb|transaction|jpa' || echo "No matches"

echo
echo "=== Search for `@Bean` definitions related to transaction manager ==="
rg -n '@Bean.*Transaction|TransactionManager|MongoTemplate' --type java src || echo "No additional matches"

Repository: PSMRI/FHIR-API

Length of output: 2853


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Find all .properties and .yml files ==="
find . -type f \( -name '*.properties' -o -name '*.yml' -o -name '*.yaml' \) 2>/dev/null | head -20

echo
echo "=== Check src/main/resources directory ==="
ls -la src/main/resources/ 2>/dev/null || echo "Directory not found"

echo
echo "=== Content of application.properties if it exists ==="
cat src/main/resources/application.properties 2>/dev/null || echo "File not found"

echo
echo "=== Content of application.yml if it exists ==="
cat src/main/resources/application.yml 2>/dev/null || echo "File not found"

echo
echo "=== Check for Spring Boot configuration in pom.xml (spring-data-mongodb vs spring-boot-starter-data-jpa) ==="
rg -A2 -B2 'spring-data-mongodb|spring-boot-starter-data-jpa|spring-boot-starter-data-rest' pom.xml 2>/dev/null || echo "Not found in pom.xml"

echo
echo "=== Check if mongoTemplate operations are wrapped in any TX manager binding ==="
rg -n 'mongoTemplate\.|transactionManager\|@Transactional.*mongodb' src --type java | head -20

Repository: PSMRI/FHIR-API

Length of output: 5970


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Full pom.xml search for mongodb dependency ==="
rg 'mongodb|mongo' pom.xml -i

echo
echo "=== Check environment property files for MongoDB config ==="
echo "--- common_example.properties ---"
cat src/main/environment/common_example.properties | grep -i -E 'mongo|mongodb' || echo "No MongoDB config"

echo
echo "--- common_ci.properties ---"
cat src/main/environment/common_ci.properties | grep -i -E 'mongo|mongodb' || echo "No MongoDB config"

echo
echo "--- common_docker.properties ---"
cat src/main/environment/common_docker.properties | grep -i -E 'mongo|mongodb' || echo "No MongoDB config"

echo
echo "=== Check if MongoTemplate bean in FhirApiApplication is actually used or if it fails ==="
rg -n 'MongoTemplate|mongoTemplate' src --type java | grep -v '://' | head -30

Repository: PSMRI/FHIR-API

Length of output: 1638


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Search for `@EnableTransactionManagement` or explicit MongoTransactionManager bean ==="
rg -n '@EnableTransactionManagement|@Bean.*MongoTransactionManager|new MongoTransactionManager' src --type java

echo
echo "=== Check savePatientProfileDataToMongo full implementation ==="
sed -n '654,670p' src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java

echo
echo "=== Check the transactional method calling savePatientProfileDataToMongo (around line 87) ==="
sed -n '70,95p' src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java

echo
echo "=== Verify if `@Transactional` on service method covers nested Mongo operations ==="
rg -B5 '@Override' src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java | grep -A5 'generatePatientProfileAMRIT_SaveTo_Mongo'

Repository: PSMRI/FHIR-API

Length of output: 147


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Check savePatientProfileDataToMongo full implementation ==="
sed -n '654,670p' src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java

echo
echo "=== Check the transactional method calling savePatientProfileDataToMongo (lines 70-95) ==="
sed -n '70,95p' src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java

echo
echo "=== Check PatientDataGatewayServiceImpl around the `@Transactional` method (lines 93-114) ==="
sed -n '93,114p' src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java

Repository: PSMRI/FHIR-API

Length of output: 3181


@Transactional here does not provide atomic rollback across MongoDB and MySQL stores.

These methods span Mongo writes (savePatientProfileDataToMongomongoRepository.saveAll()) and MySQL updates (updateProcessedFlagForProfileCreated). The savePatientProfileDataToMongo() method has no transaction management, while only the MySQL repository method carries @Transactional. This leaves the Mongo operation unmanaged, risking inconsistent state: if the Mongo save succeeds but the MySQL update fails (or vice versa), one store commits while the other doesn't.

No @EnableTransactionManagement, MongoTransactionManager bean, or ChainedTransactionManager configuration was found. Without explicit cross-store transaction coordination, the @Transactional annotation on the service method only binds to the JPA transaction manager and cannot guarantee atomicity.

Also applies to: lines 117–119

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java`
around lines 93 - 94, The service method
generatePatientProfileAMRIT_SaveTo_Mongo currently uses `@Transactional` but only
the JPA transaction manager is active, so Mongo writes from
savePatientProfileDataToMongo and MySQL updates via
updateProcessedFlagForProfileCreated are not coordinated and can leave stores
inconsistent; fix by either (A) enabling multi-store transactions: add
`@EnableTransactionManagement`, register a MongoTransactionManager bean (MongoDB
must support transactions i.e., replica set), create a ChainedTransactionManager
combining the JpaTransactionManager and MongoTransactionManager and annotate
generatePatientProfileAMRIT_SaveTo_Mongo to use that chained manager so both
mongoRepository.saveAll(...) and updateProcessedFlagForProfileCreated run in one
atomic transaction, or (B) implement explicit compensation/error-handling: wrap
savePatientProfileDataToMongo and updateProcessedFlagForProfileCreated in a
try/catch and roll back the completed store change manually if the other fails;
apply the same fix to the other affected method(s) referenced in the comment.

- CreateHealthIdRecord: add catch(Exception e) to both endpoints so all
  unhandled runtime exceptions return a consistent 500 OutputResponse
  instead of leaking unformatted errors to clients
- ClinicalFeedWorker: guard parsed pointer against non-positive values
  and empty path segments at both parsing sites; fallback to
  atomsFeedStartPage so the feed loop never silently exits on bad URLs
- PatientDataGatewayServiceImpl: wrap MySQL updateProcessedFlag call in
  try/catch on both overloads; log affected IDs and re-throw on failure
  to surface cross-store inconsistency (Mongo+MySQL) explicitly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
46.3% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java (1)

104-119: ⚡ Quick win

Extract the duplicated post-save reconciliation block into a private helper.

Lines 104-119 and 138-153 are essentially identical (build ids, call updateProcessedFlagForProfileCreated, log + rethrow on failure, reassign ppList). Drift between the two copies (e.g., changing the log message or exception type in one place but not the other) is the typical failure mode here.

♻️ Suggested extraction
-		List<PatientDemographicModel_NDHM_Patient_Profile> savedList = feedPatientProfileToMongoDB(ppList);
-
-		if (savedList != null && savedList.size() > 0) {
-			List<Long> ids = new ArrayList<>();
-			ids.add((long) 0);
-			for (PatientDemographicModel_NDHM_Patient_Profile pp : savedList) {
-				ids.add(pp.getTriggerTableAIId());
-			}
-			try {
-				tRG_PatientResourceData_Repo.updateProcessedFlagForProfileCreated(ids);
-			} catch (Exception e) {
-				// Mongo save succeeded but MySQL update failed — stores are now inconsistent.
-				// Log affected IDs so ops can manually reconcile; re-throw to signal failure.
-				logger.error("MySQL update failed after Mongo save — inconsistent state. Affected IDs: {}. Error: {}", ids, e.getMessage());
-				throw new FHIRException("Failed to update processed flag after Mongo save. " + e.getMessage());
-			}
-			ppList = savedList;
-		}
+		List<PatientDemographicModel_NDHM_Patient_Profile> savedList = feedPatientProfileToMongoDB(ppList);
+		ppList = markSavedProfilesProcessed(savedList, ppList);

And add once:

private List<PatientDemographicModel_NDHM_Patient_Profile> markSavedProfilesProcessed(
        List<PatientDemographicModel_NDHM_Patient_Profile> savedList,
        List<PatientDemographicModel_NDHM_Patient_Profile> fallback) throws FHIRException {
    if (savedList == null || savedList.isEmpty()) {
        return fallback;
    }
    List<Long> ids = new ArrayList<>();
    ids.add(0L);
    for (PatientDemographicModel_NDHM_Patient_Profile pp : savedList) {
        ids.add(pp.getTriggerTableAIId());
    }
    try {
        tRG_PatientResourceData_Repo.updateProcessedFlagForProfileCreated(ids);
    } catch (Exception e) {
        logger.error("MySQL update failed after Mongo save — inconsistent state. Affected IDs: {}. Error: {}",
                ids, e.getMessage());
        throw new FHIRException("Failed to update processed flag after Mongo save. " + e.getMessage());
    }
    return savedList;
}

Also applies to: 138-153

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java`
around lines 104 - 119, Extract the duplicated post-save reconciliation into a
private helper (e.g., private List<PatientDemographicModel_NDHM_Patient_Profile>
markSavedProfilesProcessed(List<PatientDemographicModel_NDHM_Patient_Profile>
savedList, List<PatientDemographicModel_NDHM_Patient_Profile> fallback) throws
FHIRException) that checks savedList for null/empty and returns fallback if so,
builds the ids list (adding 0L and each pp.getTriggerTableAIId()), calls
tRG_PatientResourceData_Repo.updateProcessedFlagForProfileCreated(ids), and on
exception logs the ids and e.getMessage() via logger.error and rethrows a
FHIRException with the error message; replace the two identical blocks in
PatientDataGatewayServiceImpl with calls to this helper and assign its return to
ppList.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java`:
- Around line 104-119: Extract the duplicated post-save reconciliation into a
private helper (e.g., private List<PatientDemographicModel_NDHM_Patient_Profile>
markSavedProfilesProcessed(List<PatientDemographicModel_NDHM_Patient_Profile>
savedList, List<PatientDemographicModel_NDHM_Patient_Profile> fallback) throws
FHIRException) that checks savedList for null/empty and returns fallback if so,
builds the ids list (adding 0L and each pp.getTriggerTableAIId()), calls
tRG_PatientResourceData_Repo.updateProcessedFlagForProfileCreated(ids), and on
exception logs the ids and e.getMessage() via logger.error and rethrows a
FHIRException with the error message; replace the two identical blocks in
PatientDataGatewayServiceImpl with calls to this helper and assign its return to
ppList.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8f8e65c5-d7a5-458d-a8d8-c437e8e99c8e

📥 Commits

Reviewing files that changed from the base of the PR and between f78e321 and 788398e.

📒 Files selected for processing (3)
  • src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java
  • src/main/java/com/wipro/fhir/service/atoms/feed/bahmni/ClinicalFeedWorker.java
  • src/main/java/com/wipro/fhir/service/patient_data_handler/PatientDataGatewayServiceImpl.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/main/java/com/wipro/fhir/controller/healthID/CreateHealthIdRecord.java
  • src/main/java/com/wipro/fhir/service/atoms/feed/bahmni/ClinicalFeedWorker.java

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant