added poll back

This commit is contained in:
himanshu
2025-10-29 22:46:40 +05:30
parent 5325f26a64
commit 78dd74475a
9 changed files with 205 additions and 27 deletions
@@ -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<Detail> tagList; // null in response, so keeping Object
}
@@ -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;
}
@@ -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;
}
@@ -32,4 +32,5 @@ public class FetchBillRequest extends BaseClass {
private List<Tag> deviceBlockTags; // M
private CustomerParamsRequest customerParamsRequest; // M
private List<RemitterIdentity> remitterIdentity; // O
}
@@ -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<String> {
@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;
}
@@ -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<BeneficiaryDetails,String>
{
public BeneficiaryDetails findByOrgId(String orgId);
}
@@ -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<String, Object> dataMap = objectMapper.readValue(responseData, new TypeReference<Map<String, Object>>() {});
// ✅ 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<String, String> responseMap = httpService.getRequest(fullUrl,headers);
@@ -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 <T> void startPolling(
T requestObject, // Request object (any type)
Function<T, ResponseModel> 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) {
+2 -1
View File
@@ -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