Skip to content

fix: resolve 5 bugs in scheduling, specialist, JWT, and config layers#69

Open
PragyaTripathi990 wants to merge 1 commit intoPSMRI:mainfrom
PragyaTripathi990:fix/bugfixes-scheduler
Open

fix: resolve 5 bugs in scheduling, specialist, JWT, and config layers#69
PragyaTripathi990 wants to merge 1 commit intoPSMRI:mainfrom
PragyaTripathi990:fix/bugfixes-scheduler

Conversation

@PragyaTripathi990
Copy link
Copy Markdown

@PragyaTripathi990 PragyaTripathi990 commented May 7, 2026

Summary

  • Fixed silently swallowed TMException in SchedulingServiceImpl — replaced IntStream.forEach lambda with a plain for loop so exceptions propagate; added @Transactional(rollbackFor = TMException.class) for atomicity
  • Fixed timezone-sensitive deprecated Date APIs — replaced Timestamp.getHours()/getMinutes() with toLocalDateTime().toLocalTime() and deprecated new Date(year, month, date) constructors with LocalDate.ofInstant(..., ZoneId.systemDefault())
  • Fixed ArrayIndexOutOfBoundsException risk in SpecialistServiceImpl.getAllSpecialist — added bounds guard before accessing action[6]
  • Fixed HTTP 500 on logout with expired token in JwtUtil.invalidateToken — removed erroneous RuntimeException rethrow in catch block
  • Fixed wrong property key in ConfigProperties.getExtendExpiryTime — changed from "iemr.session.expiry.time" (integer) to "iemr.extend.expiry.time" (boolean) so session extension config is read correctly

Test plan

  • markAvailability with a date range: verify TMException on a conflict rolls back all inserts
  • Scheduling on a non-UTC server: verify slot indices are correct
  • getAllSpecialist returns results without ArrayIndexOutOfBoundsException
  • Logout with an expired JWT returns HTTP 200, not 500
  • Setting iemr.extend.expiry.time=true causes getExtendExpiryTime() to return true

Summary by CodeRabbit

  • Bug Fixes

    • Corrected configuration property reference for session extension settings.
    • Added validation to prevent crashes when processing specialist records with incomplete data.
    • Improved token invalidation to gracefully handle expired tokens.
  • Refactor

    • Enhanced scheduling with timezone-aware date normalization.
    • Strengthened transactional consistency for availability management.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Walkthrough

This PR introduces timezone-aware date handling and transactional semantics in the scheduling service, relaxes token invalidation error handling, corrects a configuration property reference, and adds defensive validation for specialist query results across four independent services.

Changes

Scheduling Service Timezone & Transactional Enhancement

Layer / File(s) Summary
Java Time API Dependencies
src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java
Imports added for LocalDate, LocalTime, ZoneId, and @Transactional to support timezone-aware date conversions.
Slot Time Calculation
src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java
updateString derives startslot/endslot from Timestamp values via LocalDateTimeLocalTime conversion instead of direct hour/minute field access.
Date Normalization
src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java
markAvailability, markUnavailability, and bookSlot normalize input dates to start-of-day in system default timezone using LocalDate, replacing deprecated Date(year, month, date) constructors.
Transactional & Exception Handling
src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java
markAvailability annotated with @Transactional(rollbackFor = TMException.class); availability-building loop refactored from IntStream with catch/printStackTrace to for loop that propagates TMException per method signature.

Service Fixes & Configuration Corrections

Layer / File(s) Summary
Configuration Property
src/main/java/com/iemr/tm/utils/config/ConfigProperties.java
getExtendExpiryTime() reads iemr.extend.expiry.time instead of iemr.session.expiry.time.
Token Invalidation
src/main/java/com/iemr/tm/utils/JwtUtil.java
invalidateToken no longer throws RuntimeException for expired/invalid tokens; treats them as successful no-op, denying only valid tokens with non-null jti and remaining expiration time.
Data Validation
src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java
getAllSpecialist skips repository result rows with fewer than 7 elements, preventing out-of-bounds index access during Specialist object construction.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% 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 'fix: resolve 5 bugs in scheduling, specialist, JWT, and config layers' accurately summarizes the main change—addressing multiple bugs across different service layers and components.
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

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.

- SchedulingServiceImpl: replace IntStream.forEach lambda that silently
  swallowed TMException with a plain for-loop so checked exceptions
  propagate correctly; add @transactional so partial DB writes on error
  are rolled back atomically
- SchedulingServiceImpl: replace deprecated Timestamp.getHours()/
  getMinutes() with toLocalDateTime().toLocalTime() to avoid
  timezone-sensitive slot index miscalculations; replace deprecated
  new Date(year,month,date) constructors with LocalDate + ZoneId
- SpecialistServiceImpl.getAllSpecialist: add action.length < 7 bounds
  guard before accessing action[6] to prevent ArrayIndexOutOfBounds
  when the query returns fewer columns than expected
- JwtUtil.invalidateToken: remove RuntimeException rethrow in catch
  block; an already-expired/invalid token is a no-op, not an error —
  prevents HTTP 500 on logout with expired tokens
- ConfigProperties.getExtendExpiryTime: fix wrong property key from
  "iemr.session.expiry.time" (numeric) to "iemr.extend.expiry.time"
  (boolean) so session extension actually reads the correct config flag
@PragyaTripathi990 PragyaTripathi990 force-pushed the fix/bugfixes-scheduler branch from 29dc94b to 7d4cad6 Compare May 9, 2026 13:37
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 9, 2026

Copy link
Copy Markdown

@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java (1)

158-159: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Day-span calculation is DST-sensitive and can skip/duplicate dates.

(endDate.getTime() - startDate.getTime()) / 86400000 is not stable across DST transitions, so loop bounds can be wrong. Use LocalDate + ChronoUnit.DAYS and iterate date objects directly.

Suggested fix
+import java.time.temporal.ChronoUnit;
...
-		Integer durationDays = (int) ((endDate.getTime() - startDate.getTime()) / 86400000);
+		LocalDate startLocalDate = LocalDate.ofInstant(startDate.toInstant(), ZoneId.systemDefault());
+		LocalDate endLocalDate = LocalDate.ofInstant(endDate.toInstant(), ZoneId.systemDefault());
+		long durationDays = ChronoUnit.DAYS.between(startLocalDate, endLocalDate);
...
-		for (int e = 0; e <= durationDays; e++) {
-			Date i = new Date(startDate.getTime());
-			i.setDate(i.getDate() + e);
-			Integer day = i.getDay();
+		for (long e = 0; e <= durationDays; e++) {
+			LocalDate d = startLocalDate.plusDays(e);
+			Date i = Date.from(d.atStartOfDay(ZoneId.systemDefault()).toInstant());
+			Integer day = i.getDay();

Also applies to: 182-185

🤖 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/iemr/tm/service/schedule/SchedulingServiceImpl.java` around
lines 158 - 159, The current day-span calculation using Integer durationDays =
(int) ((endDate.getTime() - startDate.getTime()) / 86400000) is DST-sensitive
and can produce wrong loop bounds; update SchedulingServiceImpl to convert the
Date objects (startDate, endDate) to java.time.LocalDate and compute the span
with java.time.temporal.ChronoUnit.DAYS (or iterate from startLocalDate to
endLocalDate using LocalDate.plusDays()) when building the loop that currently
uses durationDays; replace both the occurrence around the durationDays variable
and the similar logic at the later block (lines referenced 182-185) to operate
on LocalDate instances rather than millis arithmetic so iteration is stable
across DST transitions.
🧹 Nitpick comments (2)
src/main/java/com/iemr/tm/utils/JwtUtil.java (1)

65-67: 💤 Low value

LGTM - logout gracefully handles invalid tokens.

The silent success on exception is correct behavior for logout endpoints. When a token is already expired or malformed, attempting to invalidate it should not fail.

Optional improvement: consider adding debug-level logging to aid troubleshooting:

🔍 Optional logging enhancement
 		} catch (Exception e) {
 			// Token is already expired or invalid — nothing to denylist, treat as success
+			logger.debug("Token invalidation skipped (already expired/invalid): {}", e.getMessage());
 		}
🤖 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/iemr/tm/utils/JwtUtil.java` around lines 65 - 67, The catch
block in JwtUtil that swallows exceptions during token invalidation should
remain silent for correctness but add a debug-level log to aid troubleshooting;
inside the catch (Exception e) in JwtUtil (the logout/token invalidation
method), call the class logger at debug/trace level including a short message
and e.getMessage()/exception to record expired/malformed tokens without changing
behavior or returning an error.
src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java (1)

55-66: ⚡ Quick win

Consider adding similar bounds checking to getspecialistUser for consistency.

The getspecialistUser method accesses array indices 0-10 without bounds validation, while getAllSpecialist now has defensive checks. If the repository can return malformed data in one method, it may also occur in the other.

🛡️ Proposed fix to add bounds checking
 	if (obj.size() > 0) {
 		for (Object[] action : obj) {
+			if (action.length < 11) {
+				logger.warn("Skipping malformed specialist row with {} columns (expected 11) for specializationID: {}, parkingPlaceID: {}", 
+					action.length, specializationID, parkingplaceID);
+				continue;
+			}
 			specialistList.add(new Specialist((String) action[0], ((Number) action[1]).longValue(),
 					(String) action[2], (String) action[3], (String) action[4], ((Number) action[5]).longValue(),
 					(String) action[6], (String) action[7], (String) action[8], (String) action[9],
 					(String) action[10]));
🤖 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/iemr/tm/service/specialist/SpecialistServiceImpl.java`
around lines 55 - 66, In SpecialistServiceImpl, update the getspecialistUser
method to mirror the defensive checks used in the getspecialistSP handling:
ensure the returned List<Object[]> (from specializationRepo.getspecialistUser)
is not null/empty and for each Object[] verify its length is at least 11 before
indexing; when a row is malformed skip it (or log a warning) and only construct
new Specialist instances after safely casting numeric fields using ((Number)
action[index]).longValue() and string fields with (String) action[index].
🤖 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/iemr/tm/service/schedule/SchedulingServiceImpl.java`:
- Around line 97-103: In SchedulingServiceImpl, validate the computed slot
window before calling slotdetail.substring: after computing startLocal,
endLocal, startslot and endslot, check that startslot < endslot, both are >= 0,
and endslot <= slotdetail.length(); if any of these checks fail throw a
TMException with a clear message (e.g., "Invalid slot window: startslot X
endslot Y for slotdetail length Z") instead of allowing
StringIndexOutOfBoundsException; update the code paths that use
startslot/endslot (the substring call referencing slotdetail) to rely on this
validation.

In `@src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java`:
- Line 76: Replace the silent skip of malformed CSV/array rows in
SpecialistServiceImpl by logging the skipped row for troubleshooting: when you
encounter the check if (action.length < 7) in the method that processes "action"
entries, emit a warning (e.g., logger.warn) that includes the row contents
(Arrays.toString(action) or similar) and any context (e.g., patientId or loop
index if available) before continuing, so malformed data is recorded for later
diagnosis.

---

Outside diff comments:
In `@src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java`:
- Around line 158-159: The current day-span calculation using Integer
durationDays = (int) ((endDate.getTime() - startDate.getTime()) / 86400000) is
DST-sensitive and can produce wrong loop bounds; update SchedulingServiceImpl to
convert the Date objects (startDate, endDate) to java.time.LocalDate and compute
the span with java.time.temporal.ChronoUnit.DAYS (or iterate from startLocalDate
to endLocalDate using LocalDate.plusDays()) when building the loop that
currently uses durationDays; replace both the occurrence around the durationDays
variable and the similar logic at the later block (lines referenced 182-185) to
operate on LocalDate instances rather than millis arithmetic so iteration is
stable across DST transitions.

---

Nitpick comments:
In `@src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java`:
- Around line 55-66: In SpecialistServiceImpl, update the getspecialistUser
method to mirror the defensive checks used in the getspecialistSP handling:
ensure the returned List<Object[]> (from specializationRepo.getspecialistUser)
is not null/empty and for each Object[] verify its length is at least 11 before
indexing; when a row is malformed skip it (or log a warning) and only construct
new Specialist instances after safely casting numeric fields using ((Number)
action[index]).longValue() and string fields with (String) action[index].

In `@src/main/java/com/iemr/tm/utils/JwtUtil.java`:
- Around line 65-67: The catch block in JwtUtil that swallows exceptions during
token invalidation should remain silent for correctness but add a debug-level
log to aid troubleshooting; inside the catch (Exception e) in JwtUtil (the
logout/token invalidation method), call the class logger at debug/trace level
including a short message and e.getMessage()/exception to record
expired/malformed tokens without changing behavior or returning an error.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9fa07d03-e758-4aba-bf8d-c7f868b0eada

📥 Commits

Reviewing files that changed from the base of the PR and between 4ffd8c3 and 7d4cad6.

📒 Files selected for processing (4)
  • src/main/java/com/iemr/tm/service/schedule/SchedulingServiceImpl.java
  • src/main/java/com/iemr/tm/service/specialist/SpecialistServiceImpl.java
  • src/main/java/com/iemr/tm/utils/JwtUtil.java
  • src/main/java/com/iemr/tm/utils/config/ConfigProperties.java

Comment on lines +97 to 103
LocalTime startLocal = startTime.toLocalDateTime().toLocalTime();
LocalTime endLocal = endTime.toLocalDateTime().toLocalTime();
Integer startslot = ((startLocal.getHour() * 60) + startLocal.getMinute()) / 5;
Integer endslot = ((endLocal.getHour() * 60) + endLocal.getMinute()) / 5;

String currentstatus = slotdetail.substring(startslot, endslot);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add explicit slot-window validation before substring access.

substring(startslot, endslot) can throw runtime exceptions when input times are inverted/equal or out of day bounds. Fail fast with TMException instead of bubbling StringIndexOutOfBoundsException.

Suggested fix
 		Integer startslot = ((startLocal.getHour() * 60) + startLocal.getMinute()) / 5;
 		Integer endslot = ((endLocal.getHour() * 60) + endLocal.getMinute()) / 5;
+		if (startslot < 0 || endslot > slotdetail.length() || endslot <= startslot) {
+			throw new TMException("Invalid slot time range");
+		}
 		
 		String currentstatus = slotdetail.substring(startslot, endslot);
📝 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
LocalTime startLocal = startTime.toLocalDateTime().toLocalTime();
LocalTime endLocal = endTime.toLocalDateTime().toLocalTime();
Integer startslot = ((startLocal.getHour() * 60) + startLocal.getMinute()) / 5;
Integer endslot = ((endLocal.getHour() * 60) + endLocal.getMinute()) / 5;
String currentstatus = slotdetail.substring(startslot, endslot);
LocalTime startLocal = startTime.toLocalDateTime().toLocalTime();
LocalTime endLocal = endTime.toLocalDateTime().toLocalTime();
Integer startslot = ((startLocal.getHour() * 60) + startLocal.getMinute()) / 5;
Integer endslot = ((endLocal.getHour() * 60) + endLocal.getMinute()) / 5;
if (startslot < 0 || endslot > slotdetail.length() || endslot <= startslot) {
throw new TMException("Invalid slot time range");
}
String currentstatus = slotdetail.substring(startslot, endslot);
🤖 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/iemr/tm/service/schedule/SchedulingServiceImpl.java` around
lines 97 - 103, In SchedulingServiceImpl, validate the computed slot window
before calling slotdetail.substring: after computing startLocal, endLocal,
startslot and endslot, check that startslot < endslot, both are >= 0, and
endslot <= slotdetail.length(); if any of these checks fail throw a TMException
with a clear message (e.g., "Invalid slot window: startslot X endslot Y for
slotdetail length Z") instead of allowing StringIndexOutOfBoundsException;
update the code paths that use startslot/endslot (the substring call referencing
slotdetail) to rely on this validation.

List<Object[]> obj = specializationRepo.getAllSPecialistForProvider(providerservicemapID);
if (obj.size() > 0) {
for (Object[] action : obj) {
if (action.length < 7) continue;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Log skipped rows for troubleshooting data quality issues.

Silently skipping malformed rows without logging makes it difficult to detect and diagnose data quality issues or potential query bugs in production.

📝 Proposed fix to add logging
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;

 `@Service`
 public class SpecialistServiceImpl implements SpecialistService {
+
+	private static final Logger logger = LoggerFactory.getLogger(SpecialistServiceImpl.class);

 	`@Autowired`
 	SpecializationRepo specializationRepo;

Then update the check:

 		for (Object[] action : obj) {
-			if (action.length < 7) continue;
+			if (action.length < 7) {
+				logger.warn("Skipping malformed specialist row with {} columns (expected 7) for providerServiceMapID: {}", 
+					action.length, providerservicemapID);
+				continue;
+			}
 			specialistList.add(new Specialist(null, ((Number) action[0]).longValue(), (String) action[1],
📝 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
if (action.length < 7) continue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Suggested change
if (action.length < 7) continue;
`@Service`
public class SpecialistServiceImpl implements SpecialistService {
private static final Logger logger = LoggerFactory.getLogger(SpecialistServiceImpl.class);
`@Autowired`
SpecializationRepo specializationRepo;
Suggested change
if (action.length < 7) continue;
for (Object[] action : obj) {
if (action.length < 7) {
logger.warn("Skipping malformed specialist row with {} columns (expected 7) for providerServiceMapID: {}",
action.length, providerservicemapID);
continue;
}
specialistList.add(new Specialist(null, ((Number) action[0]).longValue(), (String) action[1],
🤖 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/iemr/tm/service/specialist/SpecialistServiceImpl.java` at
line 76, Replace the silent skip of malformed CSV/array rows in
SpecialistServiceImpl by logging the skipped row for troubleshooting: when you
encounter the check if (action.length < 7) in the method that processes "action"
entries, emit a warning (e.g., logger.warn) that includes the row contents
(Arrays.toString(action) or similar) and any context (e.g., patientId or loop
index if available) before continuing, so malformed data is recorded for later
diagnosis.

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