update code

This commit is contained in:
Mohd-Arham
2025-12-12 15:09:43 +05:30
13 changed files with 182 additions and 82 deletions
@@ -44,7 +44,7 @@ public class SecurityConfig {
"/webjars/**", "/webjars/**",
"/error") "/error")
.permitAll() .permitAll()
.requestMatchers("/payment/callback/startPayment") .requestMatchers("/payment/callback/startPayment","/checkTicketStatus/complaints/")
.permitAll().requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .permitAll().requestMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated()) .anyRequest().authenticated())
.exceptionHandling(ex -> ex.authenticationEntryPoint(jwtAuthenticationEntryPoint)) .exceptionHandling(ex -> ex.authenticationEntryPoint(jwtAuthenticationEntryPoint))
@@ -6,75 +6,67 @@ import java.time.LocalDateTime;
import jakarta.persistence.PrePersist; import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate; import jakarta.persistence.PreUpdate;
/**
* Generic JPA entity listener that populates common audit fields on entities.
*
* Behavior:
* - On PrePersist: sets createdAt/creationDate/createdEpochDate if present (only when null),
* and forces isDeleted/deleted to false if those fields exist.
* - On PreUpdate: sets modifiedDate/modifiedEpochDate/updatedAt/updatedOn if present.
*
* This uses reflection so entities don't need to extend a specific base class.
*/
public class AuditListener { public class AuditListener {
@PrePersist @PrePersist
public void prePersist(Object entity) { public void prePersist(Object entity) {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
setIfNull(entity, "createdAt", now);
setIfNull(entity, "createdOn", now); // Creation fields
setIfNull(entity, "creationDate", now == null ? null : now.toString()); setIfNull(entity, "createDateTime", now);
setIfNull(entity, "createdBy", null); // handle manually in service if needed
setIfNull(entity, "createdEpochDate", System.currentTimeMillis()); setIfNull(entity, "createdEpochDate", System.currentTimeMillis());
// Ensure isDeleted / deleted exists and is set to false on create // Set isDeleted = false on creation
setAlways(entity, "isDeleted", Boolean.FALSE); setAlways(entity, "isDeleted", Boolean.FALSE);
} }
/*@PreUpdate /*
public void preUpdate(Object entity) { * @PreUpdate public void preUpdate(Object entity) { LocalDateTime now =
LocalDateTime now = LocalDateTime.now(); * LocalDateTime.now();
setIfNull(entity, "modifiedDate", now == null ? null : now.toString()); *
setIfNull(entity, "modifiedEpochDate", System.currentTimeMillis()); * // Update fields setAlways(entity, "updatedDateTime", now); setIfNull(entity,
setIfNull(entity, "updatedAt", now); * "updatedBy", null); // you can override manually in service setAlways(entity,
setIfNull(entity, "updatedOn", now); * "modifiedEpochDate", System.currentTimeMillis()); }
} */
*/
private void setIfNull(Object entity, String fieldName, Object value) { private void setIfNull(Object entity, String fieldName, Object value) {
try { try {
Field f = findField(entity.getClass(), fieldName); Field f = findField(entity.getClass(), fieldName);
if (f == null) return; if (f == null) return;
boolean accessible = f.canAccess(entity); boolean accessible = f.canAccess(entity);
f.setAccessible(true); f.setAccessible(true);
Object current = f.get(entity);
if (current == null && value != null) { Object currentValue = f.get(entity);
if (currentValue == null) {
f.set(entity, value); f.set(entity, value);
} }
f.setAccessible(accessible); f.setAccessible(accessible);
} catch (Exception e) { } catch (Exception ignored) {}
// ignore reflection failures
}
} }
private void setAlways(Object entity, String fieldName, Object value) { private void setAlways(Object entity, String fieldName, Object value) {
try { try {
Field f = findField(entity.getClass(), fieldName); Field f = findField(entity.getClass(), fieldName);
if (f == null) return; if (f == null) return;
boolean accessible = f.canAccess(entity); boolean accessible = f.canAccess(entity);
f.setAccessible(true); f.setAccessible(true);
f.set(entity, value); f.set(entity, value);
f.setAccessible(accessible); f.setAccessible(accessible);
} catch (Exception e) { } catch (Exception ignored) {}
// ignore reflection failures
}
} }
private Field findField(Class<?> cls, String name) { private Field findField(Class<?> cls, String name) {
Class<?> cur = cls; Class<?> current = cls;
while (cur != null && cur != Object.class) { while (current != null && current != Object.class) {
try { try {
return cur.getDeclaredField(name); return current.getDeclaredField(name);
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {
cur = cur.getSuperclass(); current = current.getSuperclass();
} }
} }
return null; return null;
@@ -17,25 +17,25 @@ import lombok.Setter;
@Getter @Getter
@Setter @Setter
public abstract class Auditable { public abstract class Auditable {
@Column(name = "create_date_time")
private LocalDateTime createDateTime;
@Column(name = "created_at") @Column(name = "updated_date_time")
private LocalDateTime createdAt; private LocalDateTime updatedDateTime;
@Column(name = "updated_at") @Column(name = "create_by")
private LocalDateTime updatedAt; private LocalDateTime createdBy;
@Column(name = "created_on") @Column(name = "updated_by")
private LocalDateTime createdOn; private LocalDateTime updatedBy;
@Column(name = "updated_on") @Column(name = "created_epoch_date")
private LocalDateTime updatedOn; private Long createdEpochDate;
@Column(name = "created_epoch_date") @Column(name = "modified_epoch_date")
private Long createdEpochDate; private Long modifiedEpochDate;
@Column(name = "modified_epoch_date") @Column(name = "is_deleted")
private Long modifiedEpochDate; private Boolean isDeleted = Boolean.FALSE;
@Column(name = "is_deleted")
private Boolean isDeleted = Boolean.FALSE;
} }
@@ -1,5 +1,6 @@
package com.billpaymentservice.bbps.entites; package com.billpaymentservice.bbps.entites;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue; import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType; import jakarta.persistence.GenerationType;
@@ -2,6 +2,8 @@ package com.billpaymentservice.bbps.exception;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -12,6 +14,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.NoHandlerFoundException; import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.client.ResourceAccessException;
import com.billpaymentservice.bbps.dto.ResponseModel; import com.billpaymentservice.bbps.dto.ResponseModel;
@@ -90,16 +93,13 @@ public class GlobalExceptionHandler {
logger.warn("Invalid JSON received for endpoint {}: {}", endpoint, shortMsg); logger.warn("Invalid JSON received for endpoint {}: {}", endpoint, shortMsg);
Map<String, Object> data = Map.of(
"exception", ex.getClass().getName(),
"message", shortMsg
);
ResponseModel<?> resp = new ResponseModel<>( ResponseModel<?> resp = new ResponseModel<>(
"[" + endpoint + "] Invalid JSON received", "Invalid JSON received",
"FAILED", "FAILED",
HttpStatus.BAD_REQUEST.value(), HttpStatus.BAD_REQUEST.value(),
data null
); );
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resp); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(resp);
@@ -164,6 +164,79 @@ public class GlobalExceptionHandler {
return ResponseEntity.status(httpStatus).body(resp); return ResponseEntity.status(httpStatus).body(resp);
} }
// ------------------------- RESOURCE ACCESS / TIMEOUT / CONNECT ------------------------
@ExceptionHandler(ResourceAccessException.class)
public ResponseEntity<ResponseModel<?>> handleResourceAccess(
ResourceAccessException ex,
HttpServletRequest request,
HandlerMethod handlerMethod) {
String context = buildErrorContext(ex, request, handlerMethod);
logger.error("ResourceAccessException → {}", context, ex);
Throwable cause = ex.getCause();
String message;
HttpStatus status;
if (cause instanceof SocketTimeoutException) {
message = "Server timeout - server may be down";
status = HttpStatus.GATEWAY_TIMEOUT; // 504
} else if (cause instanceof ConnectException) {
message = "Server unavailable - connection refused";
status = HttpStatus.SERVICE_UNAVAILABLE; // 503
} else {
message = "Server unreachable: " + ex.getMessage();
status = HttpStatus.SERVICE_UNAVAILABLE;
}
ResponseModel<?> resp = new ResponseModel<>(
message,
"FAILED",
status.value(),
null
);
return ResponseEntity.status(status).body(resp);
}
@ExceptionHandler(SocketTimeoutException.class)
public ResponseEntity<ResponseModel<?>> handleSocketTimeout(
SocketTimeoutException ex,
HttpServletRequest request,
HandlerMethod handlerMethod) {
String context = buildErrorContext(ex, request, handlerMethod);
logger.error("SocketTimeoutException → {}", context, ex);
ResponseModel<?> resp = new ResponseModel<>(
"Server timeout - server is down",
"FAILED",
HttpStatus.GATEWAY_TIMEOUT.value(),
null
);
return ResponseEntity.status(HttpStatus.GATEWAY_TIMEOUT).body(resp);
}
@ExceptionHandler(ConnectException.class)
public ResponseEntity<ResponseModel<?>> handleConnectException(
ConnectException ex,
HttpServletRequest request,
HandlerMethod handlerMethod) {
String context = buildErrorContext(ex, request, handlerMethod);
logger.error("ConnectException → {}", context, ex);
ResponseModel<?> resp = new ResponseModel<>(
"Server unavailable - connection refused",
"FAILED",
HttpStatus.SERVICE_UNAVAILABLE.value(),
null
);
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(resp);
}
// ------------------------- GENERIC EXCEPTION ------------------------ // ------------------------- GENERIC EXCEPTION ------------------------
@ExceptionHandler(Exception.class) @ExceptionHandler(Exception.class)
public ResponseEntity<ResponseModel<?>> handleAll( public ResponseEntity<ResponseModel<?>> handleAll(
@@ -2,6 +2,7 @@ package com.billpaymentservice.bbps.serviceImpl;
import java.util.HashMap; import java.util.HashMap;
import java.net.ConnectException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -12,6 +13,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestClient; import org.springframework.web.client.RestClient;
import org.springframework.web.client.ResourceAccessException;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
@@ -24,6 +26,15 @@ public class HttpService {
private final RestClient restClient; private final RestClient restClient;
private final ObjectMapper objectMapper = new ObjectMapper(); private final ObjectMapper objectMapper = new ObjectMapper();
// Helper to produce server-down/timeout style responses
private HashMap<String, String> buildServerDownResponse(String code, String message, Exception e) {
HashMap<String, String> response = new HashMap<>();
response.put("respCode", code);
response.put("data", message);
log.error("❌ {} - {}", code, message, e);
return response;
}
public HashMap<String, String> postRequest(String url, String payload, HttpHeaders customHeaders) { public HashMap<String, String> postRequest(String url, String payload, HttpHeaders customHeaders) {
@@ -60,6 +71,15 @@ public class HttpService {
response.put("respCode", "403"); response.put("respCode", "403");
response.put("data", "FORBIDDEN - Check credentials in HttpService"); response.put("data", "FORBIDDEN - Check credentials in HttpService");
} catch (ResourceAccessException e) {
// This often wraps timeouts or connection refused
Throwable cause = e.getCause();
if (cause instanceof ConnectException) {
return buildServerDownResponse("503", "Server unavailable - connection refused", e);
} else {
return buildServerDownResponse("503", "Server unreachable: " + e.getMessage(), e);
}
} catch (Exception e) { } catch (Exception e) {
log.error("❌ HttpService Exception: {}", e.getMessage()); log.error("❌ HttpService Exception: {}", e.getMessage());
response.put("respCode", "500"); response.put("respCode", "500");
@@ -97,6 +117,13 @@ public class HttpService {
log.error("❌ HTTP Error: {}", httpException.getMessage(), httpException); log.error("❌ HTTP Error: {}", httpException.getMessage(), httpException);
response.put("respCode", String.valueOf(httpException.getStatusCode().value())); response.put("respCode", String.valueOf(httpException.getStatusCode().value()));
response.put("data", httpException.getResponseBodyAsString()); response.put("data", httpException.getResponseBodyAsString());
} catch (ResourceAccessException e) {
Throwable cause = e.getCause();
if (cause instanceof ConnectException) {
return buildServerDownResponse("503", "Server unavailable - connection refused", e);
} else {
return buildServerDownResponse("503", "Server unreachable: " + e.getMessage(), e);
}
} catch (Exception e) { } catch (Exception e) {
log.error("❌ Exception during GET call: {}", e.getMessage(), e); log.error("❌ Exception during GET call: {}", e.getMessage(), e);
response.put("respCode", "500"); response.put("respCode", "500");
@@ -133,6 +160,13 @@ public class HttpService {
log.error("❌ HTTP Error: {}", httpException.getMessage(), httpException); log.error("❌ HTTP Error: {}", httpException.getMessage(), httpException);
response.put("respCode", String.valueOf(httpException.getStatusCode().value())); response.put("respCode", String.valueOf(httpException.getStatusCode().value()));
response.put("data", httpException.getResponseBodyAsString()); response.put("data", httpException.getResponseBodyAsString());
} catch (ResourceAccessException e) {
Throwable cause = e.getCause();
if (cause instanceof ConnectException) {
return buildServerDownResponse("503", "Server unavailable - connection refused", e);
} else {
return buildServerDownResponse("503", "Server unreachable: " + e.getMessage(), e);
}
} catch (Exception e) { } catch (Exception e) {
log.error("❌ Exception during GET call: {}", e.getMessage(), e); log.error("❌ Exception during GET call: {}", e.getMessage(), e);
response.put("respCode", "500"); response.put("respCode", "500");
@@ -171,6 +205,13 @@ public class HttpService {
response.put("respCode", String.valueOf(e.getStatusCode().value())); response.put("respCode", String.valueOf(e.getStatusCode().value()));
response.put("data", e.getResponseBodyAsString()); // still HTML or error string response.put("data", e.getResponseBodyAsString()); // still HTML or error string
} catch (ResourceAccessException e) {
Throwable cause = e.getCause();
if (cause instanceof ConnectException) {
return buildServerDownResponse("503", "Server unavailable - connection refused", e);
} else {
return buildServerDownResponse("503", "Server unreachable: " + e.getMessage(), e);
}
} catch (Exception e) { } catch (Exception e) {
log.error("❌ FORM POST Exception: {}", e.getMessage(), e); log.error("❌ FORM POST Exception: {}", e.getMessage(), e);
@@ -181,7 +222,4 @@ public class HttpService {
return response; return response;
} }
} }
@@ -192,7 +192,6 @@ public class PaymentServiceImpl implements PaymentService {
String apiName = BBPSConstant.API_CHECK_TRANSACTION_STATUS; String apiName = BBPSConstant.API_CHECK_TRANSACTION_STATUS;
String txnId = helper.generateTxnId(15); String txnId = helper.generateTxnId(15);
String requestId = transactionStatusRequest.getReqId(); String requestId = transactionStatusRequest.getReqId();
// START log for internal transaction status check // START log for internal transaction status check
LOGGER.info("[{}] START (internal) | checkTxnId={} | reqId={} | bankTxnId={}", apiName, txnId, requestId, LOGGER.info("[{}] START (internal) | checkTxnId={} | reqId={} | bankTxnId={}", apiName, txnId, requestId,
transactionStatusRequest.getTxnId()); transactionStatusRequest.getTxnId());
@@ -3,7 +3,7 @@ package com.billpaymentservice.bbps.util;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
public class BBPSConstant { public class BBPSConstant extends BBPS_RESPONSE_COD_CONSTANT {
// Jwt Token Expiration Time // Jwt Token Expiration Time
public static final long JWT_EXPIRATION_MS = 1000 * 60 * 60 * 24; // 24 hours public static final long JWT_EXPIRATION_MS = 1000 * 60 * 60 * 24; // 24 hours
@@ -0,0 +1,5 @@
package com.billpaymentservice.bbps.util;
public class BBPS_RESPONSE_COD_CONSTANT {
}
@@ -720,11 +720,8 @@ public class BillerMapperHelper {
parent.setUserId(responseWrapper.getUserId()); parent.setUserId(responseWrapper.getUserId());
// Map incoming DTO date strings into Auditable LocalDateTime fields // Map incoming DTO date strings into Auditable LocalDateTime fields
LocalDateTime parentCreatedOn = parseToLocalDateTime(responseWrapper.getCreationDate()); LocalDateTime parentCreatedOn = parseToLocalDateTime(responseWrapper.getCreationDate());
if (parentCreatedOn != null)
parent.setCreatedOn(parentCreatedOn);
LocalDateTime parentUpdatedOn = parseToLocalDateTime(responseWrapper.getModifiedDate()); LocalDateTime parentUpdatedOn = parseToLocalDateTime(responseWrapper.getModifiedDate());
if (parentUpdatedOn != null)
parent.setUpdatedOn(parentUpdatedOn);
parent.setCreatedEpochDate(responseWrapper.getCreatedEpochDate()); parent.setCreatedEpochDate(responseWrapper.getCreatedEpochDate());
parent.setModifiedEpochDate(responseWrapper.getModifiedEpochDate()); parent.setModifiedEpochDate(responseWrapper.getModifiedEpochDate());
parent.setReqId(reqId); parent.setReqId(reqId);
@@ -967,12 +964,10 @@ public class BillerMapperHelper {
// DATES // DATES
// Map incoming DTO date strings into Auditable LocalDateTime fields // Map incoming DTO date strings into Auditable LocalDateTime fields
LocalDateTime bmCreatedOn = parseToLocalDateTime(responseWrapper.getCreationDate()); LocalDateTime bmCreatedOn = parseToLocalDateTime(responseWrapper.getCreationDate());
if (bmCreatedOn != null) {
billMaster.setCreatedOn(bmCreatedOn);
}
LocalDateTime bmUpdatedOn = parseToLocalDateTime(responseWrapper.getModifiedDate()); LocalDateTime bmUpdatedOn = parseToLocalDateTime(responseWrapper.getModifiedDate());
if (bmUpdatedOn != null) { if (bmUpdatedOn != null) {
billMaster.setUpdatedOn(bmUpdatedOn); billMaster.setUpdatedDateTime(bmUpdatedOn);
} }
billMaster.setCreatedEpochDate(responseWrapper.getCreatedEpochDate()); billMaster.setCreatedEpochDate(responseWrapper.getCreatedEpochDate());
billMaster.setModifiedEpochDate(responseWrapper.getModifiedEpochDate()); billMaster.setModifiedEpochDate(responseWrapper.getModifiedEpochDate());
@@ -1107,16 +1102,12 @@ public class BillerMapperHelper {
record.setQrString(Optional.ofNullable(apiResponse.getResponseData().getQrString()).orElse("NO_QR")); record.setQrString(Optional.ofNullable(apiResponse.getResponseData().getQrString()).orElse("NO_QR"));
// parse createdOn string into LocalDateTime and set on Auditable // parse createdOn string into LocalDateTime and set on Auditable
LocalDateTime createdOn = parseToLocalDateTime(apiResponse.getResponseData().getCreatedOn()); LocalDateTime createdOn = parseToLocalDateTime(apiResponse.getResponseData().getCreatedOn());
if (createdOn == null)
createdOn = LocalDateTime.now();
record.setCreatedOn(createdOn);
// default status pending
record.setTxnStatus("PENDING"); record.setTxnStatus("PENDING");
} else { } else {
record.setAmount("0.00"); record.setAmount("0.00");
record.setMid(request.getMid()); record.setMid(request.getMid());
record.setTxnStatus("PENDING"); record.setTxnStatus("PENDING");
record.setCreatedOn(LocalDateTime.now());
} }
// store the original request body and raw response // store the original request body and raw response
@@ -184,8 +184,6 @@ public class Helper {
user.setName(request.getName()); user.setName(request.getName());
user.setEmail(request.getEmail()); user.setEmail(request.getEmail());
user.setMid(request.getMid()); user.setMid(request.getMid());
// set audit createdOn timestamp
user.setCreatedOn(LocalDateTime.now());
// Generate a unique userId (UUID) // Generate a unique userId (UUID)
String uniqueUserId = generateUniqueUserId(); String uniqueUserId = generateUniqueUserId();
user.setUserId(uniqueUserId); user.setUserId(uniqueUserId);
@@ -18,11 +18,14 @@ swagger.server.description=Local Development Server
# DataSource # DataSource
spring.datasource.url=jdbc:postgresql://localhost:5432/devdbuat spring.datasource.url=jdbc:postgresql://localhost:5432/bbps_new_updated
spring.datasource.username=postgres
spring.datasource.password=UAT@DB_2025
#spring.datasource.password=himanshu@123 #spring.datasource.url=jdbc:postgresql://localhost:5432/bbps_enhanced
>>>>>>> Stashed changes
spring.datasource.username=postgres
#spring.datasource.password=UAT@DB_2025
spring.datasource.password=himanshu@123
spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.type=com.zaxxer.hikari.HikariDataSource
+1 -1
View File
@@ -21,7 +21,7 @@ spring.profiles.active=local
# DataSource # DataSource
spring.datasource.url=jdbc:postgresql://localhost:5432/BBPS_Enhanced spring.datasource.url=jdbc:postgresql://localhost:5432/devdbuat
spring.datasource.username=postgres spring.datasource.username=postgres
#spring.datasource.password=UAT@DB_2025 #spring.datasource.password=UAT@DB_2025