From 78dd74475ab9ff539ba8c827724c9b062a793dd5 Mon Sep 17 00:00:00 2001 From: himanshu Date: Wed, 29 Oct 2025 22:46:40 +0530 Subject: [PATCH] added poll back --- .../bbps/dto/BillerResponseBill.java | 4 +- .../bbps/dto/request/BaseClass.java | 57 +++++++++++++++--- .../dto/request/BillFetchByBillIdRequest.java | 4 +- .../bbps/dto/request/FetchBillRequest.java | 1 + .../bbps/entites/BeneficiaryDetails.java | 51 ++++++++++++++++ .../BeneficiaryDetailsRepository.java | 13 ++++ .../bbps/serviceImpl/AgentServiceImpl.java | 59 ++++++++++++++----- .../billpaymentservice/bbps/util/Helper.java | 40 +++++++++++++ src/main/resources/application.properties | 3 +- 9 files changed, 205 insertions(+), 27 deletions(-) create mode 100644 src/main/java/com/billpaymentservice/bbps/entites/BeneficiaryDetails.java create mode 100644 src/main/java/com/billpaymentservice/bbps/repository/BeneficiaryDetailsRepository.java diff --git a/src/main/java/com/billpaymentservice/bbps/dto/BillerResponseBill.java b/src/main/java/com/billpaymentservice/bbps/dto/BillerResponseBill.java index b08b276..a0c4807 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/BillerResponseBill.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/BillerResponseBill.java @@ -1,5 +1,7 @@ package com.billpaymentservice.bbps.dto; +import java.util.List; + import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -20,5 +22,5 @@ public class BillerResponseBill { private String dueDate; private String customerName; private boolean amountOption; - private Object tagList; // null in response, so keeping Object + private List tagList; // null in response, so keeping Object } diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/BaseClass.java b/src/main/java/com/billpaymentservice/bbps/dto/request/BaseClass.java index 9bfa4a5..b150d3a 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/request/BaseClass.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/BaseClass.java @@ -1,22 +1,61 @@ package com.billpaymentservice.bbps.dto.request; import com.billpaymentservice.bbps.dto.DeviceDetail; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -@Getter -@Setter +@Getter +@Setter @AllArgsConstructor @NoArgsConstructor -public class BaseClass { - - - private String mid; - private String secretKey; - private String txnId; - private DeviceDetail deviceDetial; +public abstract class BaseClass { + // ✅ Request me required, response me hide honge + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String mid; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String secretKey; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String txnId; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private DeviceDetail deviceDetial; + + // ✅ 10 User Defined Fields (UDF1–UDF10) + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf1; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf2; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf3; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf4; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf5; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf6; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf7; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf8; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf9; + + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) + private String udf10; } + diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/BillFetchByBillIdRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/request/BillFetchByBillIdRequest.java index b412bbb..3d9e762 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/request/BillFetchByBillIdRequest.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/BillFetchByBillIdRequest.java @@ -14,8 +14,8 @@ public class BillFetchByBillIdRequest extends BaseClass { @NotNull private String billId; - private String tenantId; // //M - private String digiledgeKey; // M + private String tenantId; + private String digiledgeKey; private String agentId; } diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/FetchBillRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/request/FetchBillRequest.java index 551b7e7..4f5b7c0 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/request/FetchBillRequest.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/FetchBillRequest.java @@ -32,4 +32,5 @@ public class FetchBillRequest extends BaseClass { private List deviceBlockTags; // M private CustomerParamsRequest customerParamsRequest; // M private List remitterIdentity; // O + } diff --git a/src/main/java/com/billpaymentservice/bbps/entites/BeneficiaryDetails.java b/src/main/java/com/billpaymentservice/bbps/entites/BeneficiaryDetails.java new file mode 100644 index 0000000..42b5909 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/entites/BeneficiaryDetails.java @@ -0,0 +1,51 @@ +package com.billpaymentservice.bbps.entites; + +import java.time.LocalDateTime; + +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + +import com.billpaymentservice.bbps.audit.Auditable; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotBlank; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Entity +@Table(name = "beneficiary_details") +public class BeneficiaryDetails extends Auditable { + + @Id + @Column(name = "org_id", nullable = false, unique = true, length = 50) + @NotBlank(message = "Organization ID cannot be blank") + private String orgId; + + @Column(name = "x_digiledge_key", nullable = false, length = 255) + @NotBlank(message = "x-digiledge-key cannot be blank") + private String xDigiledgeKey; + + @Column(name = "tenant_id", nullable = false, length = 50) + @NotBlank(message = "Tenant ID cannot be blank") + private String tenantId; + + @Column(name = "agent_id", nullable = false, length = 100) + @NotBlank(message = "Agent ID cannot be blank") + private String agentId; + + // Optional metadata fields + @Column(name = "organization_name", length = 100) + private String organizationName; + + @Column(name = "api_base_url", length = 500) + private String apiBaseUrl; +} diff --git a/src/main/java/com/billpaymentservice/bbps/repository/BeneficiaryDetailsRepository.java b/src/main/java/com/billpaymentservice/bbps/repository/BeneficiaryDetailsRepository.java new file mode 100644 index 0000000..aa7a763 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/repository/BeneficiaryDetailsRepository.java @@ -0,0 +1,13 @@ +package com.billpaymentservice.bbps.repository; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import org.springframework.web.servlet.function.ServerRequest.Headers; + +import com.billpaymentservice.bbps.entites.BeneficiaryDetails; + +@Repository +public interface BeneficiaryDetailsRepository extends JpaRepository +{ + public BeneficiaryDetails findByOrgId(String orgId); + +} diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java index 8c3c500..d5027dc 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java @@ -8,9 +8,12 @@ import com.billpaymentservice.bbps.dto.request.FetchBillRequest; import com.billpaymentservice.bbps.dto.response.BillDataResponse; import com.billpaymentservice.bbps.dto.response.BillerDataResponse; import com.billpaymentservice.bbps.dto.response.FetchBillResponse; +import com.billpaymentservice.bbps.entites.BeneficiaryDetails; import com.billpaymentservice.bbps.exception.CustomException; +import com.billpaymentservice.bbps.repository.BeneficiaryDetailsRepository; import com.billpaymentservice.bbps.service.AgentService; import com.billpaymentservice.bbps.util.BBPSConstant; +import com.billpaymentservice.bbps.util.Helper; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; @@ -25,29 +28,42 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestClient; +import org.springframework.web.servlet.function.ServerRequest.Headers; @Service @Slf4j -@RequiredArgsConstructor public class AgentServiceImpl implements AgentService { @Value("${agent.data.url}") private String agentDtaUrl; - private final RestClient restClient; - private final HttpService httpService;// ✅ injected from config - + private final RestClient restClient; + private final HttpService httpService; + private final Helper helper; + private final BeneficiaryDetailsRepository beneficiaryDetailsRepository; + + public AgentServiceImpl(RestClient restClient,HttpService httpService,Helper helper, BeneficiaryDetailsRepository beneficiaryDetailsRepository) { + this.restClient=restClient; + this.httpService=httpService; + this.helper=helper; + this.beneficiaryDetailsRepository=beneficiaryDetailsRepository; + } + @Override public ResponseModel initiateBillFetch(FetchBillRequest fetchBillRequest) { String url = agentDtaUrl+BBPSConstant.BILL_FETCH_INTI; System.out.println(url); - - HttpHeaders headers = new HttpHeaders(); - headers.set("x-digiledge-key", fetchBillRequest.getDigiledgeKey()); - headers.set("agentId", fetchBillRequest.getAgentId()); - headers.set("tenantId", fetchBillRequest.getTenantId()); + + BeneficiaryDetails headersData=beneficiaryDetailsRepository.findByOrgId("ORG001"); + + HttpHeaders headers = new HttpHeaders(); + headers.set("x-digiledge-key",headersData.getXDigiledgeKey()); + headers.set("agentId", headersData.getAgentId()); + headers.set("tenantId", headersData.getTenantId()); headers.setContentType(MediaType.APPLICATION_JSON); + + ResponseModel responseModel = new ResponseModel(); try { @@ -69,7 +85,7 @@ public class AgentServiceImpl implements AgentService { // ✅ Convert JSON string → Map Map dataMap = objectMapper.readValue(responseData, new TypeReference>() {}); - + // ✅ Validate generalResp if (!dataMap.containsKey("genericResponse")) { throw new CustomException("Invalid response structure from BBPS"); @@ -78,6 +94,19 @@ public class AgentServiceImpl implements AgentService { // ✅ Convert to your custom DTO FetchBillResponse fetchBillResponse = objectMapper.convertValue(dataMap, FetchBillResponse.class); GeneralResponse generalResponse = fetchBillResponse.getGenericResponse(); + // + //start a new thread here + helper.startPolling(fetchBillResponse, + res -> { + BillFetchByBillIdRequest pollReq = new BillFetchByBillIdRequest(); + pollReq.setBillId(res.getBillId()); + return fetchBillById(pollReq); + }, + 3, // interval in seconds + 15 // total time in seconds + ); + + // ✅ Build final ResponseModel responseModel = new ResponseModel( @@ -103,11 +132,13 @@ public class AgentServiceImpl implements AgentService { String billId = billFetchByBillIdRequest.getBillId(); String fullUrl = agentDtaUrl + BBPSConstant.BILL_FETCH_BY_ID+billId; System.out.print(fullUrl); - + + BeneficiaryDetails headersData=beneficiaryDetailsRepository.findByOrgId("ORG001"); + HttpHeaders headers = new HttpHeaders(); - headers.set("x-digiledge-key", billFetchByBillIdRequest.getDigiledgeKey()); - headers.set("agentId", billFetchByBillIdRequest.getAgentId()); - headers.set("tenantId", billFetchByBillIdRequest.getTenantId()); + headers.set("x-digiledge-key",headersData.getXDigiledgeKey()); + headers.set("agentId", headersData.getAgentId()); + headers.set("tenantId", headersData.getTenantId()); headers.setContentType(MediaType.APPLICATION_JSON); Map responseMap = httpService.getRequest(fullUrl,headers); diff --git a/src/main/java/com/billpaymentservice/bbps/util/Helper.java b/src/main/java/com/billpaymentservice/bbps/util/Helper.java index 0580122..da8b545 100644 --- a/src/main/java/com/billpaymentservice/bbps/util/Helper.java +++ b/src/main/java/com/billpaymentservice/bbps/util/Helper.java @@ -1,9 +1,13 @@ package com.billpaymentservice.bbps.util; +import java.util.function.Function; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; + +import com.billpaymentservice.bbps.dto.ResponseModel; import com.billpaymentservice.bbps.dto.request.MerchantRequestModel; import com.billpaymentservice.bbps.entites.BBPSMerchantValidation; import com.billpaymentservice.bbps.exception.CustomException; @@ -11,6 +15,7 @@ import com.billpaymentservice.bbps.repository.MerchantRepository; @Component + public class Helper { private static final Logger LOGGER = LoggerFactory.getLogger(Helper.class); @@ -24,7 +29,42 @@ public class Helper { * @param requestModel MerchantRequestModel containing merchant details * @return true if merchant exists and is active * @throws CustomException if merchant is invalid or inactive + * + * + * */ + + + + public void startPolling( + T requestObject, // Request object (any type) + Function apiCallFunction, // Function to call API + int intervalSeconds, // gap between two polls + int maxDurationSeconds // total polling time + ) { + new Thread(() -> { + try { + int maxAttempts = maxDurationSeconds / intervalSeconds; + + for (int i = 0; i < maxAttempts; i++) { + LOGGER.info("⏳ Polling attempt {}...", i + 1); + + ResponseModel response = apiCallFunction.apply(requestObject); + LOGGER.info("📥 Poll response: {}", response); + + if ("SUCCESS".equalsIgnoreCase(response.getStatus())) { + LOGGER.info("✅ Polling successful, stopping early."); + break; + } + + Thread.sleep(intervalSeconds * 1000L); + } + } catch (Exception e) { + LOGGER.error("❌ Error in polling thread: {}", e.getMessage(), e); + } + }).start(); + } + public boolean isMerchantValidAndActive(MerchantRequestModel requestModel) { if (requestModel == null || requestModel.getMid() == null) { diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c5071ed..28f1267 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -9,12 +9,13 @@ spring.jpa.hibernate.ddl-auto=update spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect # DataSource -spring.datasource.url=jdbc:postgresql://localhost:5432/TestingDB +spring.datasource.url=jdbc:postgresql://localhost:5432/BBPS spring.datasource.username=postgres spring.datasource.password=thakur@123 spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.type=com.zaxxer.hikari.HikariDataSource + # HikariCP settings spring.datasource.hikari.connection-timeout=10000 spring.datasource.hikari.minimum-idle=10