diff --git a/src/main/java/com/billpaymentservice/bbps/config/RestClientConfig.java b/src/main/java/com/billpaymentservice/bbps/config/RestClientConfig.java new file mode 100644 index 0000000..52ef5aa --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/RestClientConfig.java @@ -0,0 +1,38 @@ +package com.billpaymentservice.bbps.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.web.client.RestClient; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.security.cert.X509Certificate; + +@Configuration +public class RestClientConfig { + + @Bean + public RestClient restClient() throws Exception { + // ✅ Create trust all SSL context + SSLContext sslContext = SSLContext.getInstance("TLS"); + TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[0]; + } + public void checkClientTrusted(X509Certificate[] certs, String authType) { + } + public void checkServerTrusted(X509Certificate[] certs, String authType) { + } + } + }; + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + + // ✅ Create RestClient with custom SSL context + return RestClient.builder() + .requestFactory(new HttpComponentsClientHttpRequestFactory()) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/controller/AgentController.java b/src/main/java/com/billpaymentservice/bbps/controller/AgentController.java new file mode 100644 index 0000000..95e66ff --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/controller/AgentController.java @@ -0,0 +1,36 @@ +package com.billpaymentservice.bbps.controller; + +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import com.billpaymentservice.bbps.dto.ResponseModel; +import com.billpaymentservice.bbps.dto.request.FetchBillRequest; +import com.billpaymentservice.bbps.service.AgentService; + +@RestController +@RequestMapping("/agent") +public class AgentController { + + private final AgentService agentService; + + public AgentController(AgentService agentService) { + this.agentService = agentService; + } + + /** + * Fetches bill details from external BBPS service + */ + @PostMapping( + value = "/requestBillFetch", + consumes = MediaType.APPLICATION_JSON_VALUE, + produces = MediaType.APPLICATION_JSON_VALUE + ) + public ResponseEntity requestBillFetch( + @Validated @RequestBody FetchBillRequest fetchBillRequest) { + + ResponseModel response = agentService.initiateBillFetch(fetchBillRequest); + return ResponseEntity.ok(response); + } +} 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 764ded4..551b7e7 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/request/FetchBillRequest.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/FetchBillRequest.java @@ -10,15 +10,19 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import lombok.ToString; @Getter @Setter @AllArgsConstructor @NoArgsConstructor +@ToString public class FetchBillRequest extends BaseClass { private String tenantId; // M private String billerId; // M - private String billerName; // M + private String billerName; //M + private String digiledgeKey; // M + private String agentId; // M private String billerCategory; // M private String clientReqId; // C private String macAdress; // C diff --git a/src/main/java/com/billpaymentservice/bbps/dto/response/FetchBillResponse.java b/src/main/java/com/billpaymentservice/bbps/dto/response/FetchBillResponse.java index 9c4ab56..26ffa59 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/response/FetchBillResponse.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/response/FetchBillResponse.java @@ -1,19 +1,19 @@ package com.billpaymentservice.bbps.dto.response; import com.billpaymentservice.bbps.dto.GeneralResponse; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; - @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class FetchBillResponse { - + @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) private GeneralResponse genericResponse; private String billId; private String refId; @@ -28,6 +28,4 @@ public class FetchBillResponse { private String modifiedDate; private long createdEpochDate; private long modifiedEpochDate; - - } diff --git a/src/main/java/com/billpaymentservice/bbps/service/AgentService.java b/src/main/java/com/billpaymentservice/bbps/service/AgentService.java new file mode 100644 index 0000000..3357ab1 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/service/AgentService.java @@ -0,0 +1,10 @@ +package com.billpaymentservice.bbps.service; + +import com.billpaymentservice.bbps.dto.ResponseModel; +import com.billpaymentservice.bbps.dto.request.FetchBillRequest; + +public interface AgentService { + + public ResponseModel initiateBillFetch(FetchBillRequest fetchBillRequest); + +} diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java new file mode 100644 index 0000000..5658fd6 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java @@ -0,0 +1,89 @@ +package com.billpaymentservice.bbps.serviceImpl; + +import com.billpaymentservice.bbps.dto.GeneralResponse; +import com.billpaymentservice.bbps.dto.ResponseModel; +import com.billpaymentservice.bbps.dto.request.FetchBillRequest; +import com.billpaymentservice.bbps.dto.response.FetchBillResponse; +import com.billpaymentservice.bbps.exception.CustomException; +import com.billpaymentservice.bbps.service.AgentService; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.http.*; +import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClient; + +@Service +@Slf4j +@RequiredArgsConstructor +public class AgentServiceImpl implements AgentService { + + private final RestClient restClient; + private final HttpService httpService;// ✅ injected from config + + @Override + public ResponseModel initiateBillFetch(FetchBillRequest fetchBillRequest) { + String url = "https://bbps-staging.digiledge.in/agent/bill-payment-new/couapp/bills/fetch"; + + HttpHeaders headers = new HttpHeaders(); + headers.set("x-digiledge-key", fetchBillRequest.getDigiledgeKey()); + headers.set("agentId", fetchBillRequest.getAgentId()); + headers.set("tenantId", fetchBillRequest.getTenantId()); + headers.setContentType(MediaType.APPLICATION_JSON); + + ResponseModel responseModel = new ResponseModel(); + + try { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + + // ✅ Convert request to JSON + String json = objectMapper.writeValueAsString(fetchBillRequest); + + // ✅ Call the API using httpService + Map responseMap = httpService.postRequest(url, json, headers); + String responseData = responseMap.get("data"); + + log.info("📦 Bill Fetch API Response: {}", responseData); + + if (responseData == null || responseData.isEmpty()) { + throw new CustomException("Empty response from BBPS server"); + } + + // ✅ 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"); + } + + // ✅ Convert to your custom DTO + FetchBillResponse fetchBillResponse = objectMapper.convertValue(dataMap, FetchBillResponse.class); + GeneralResponse generalResponse = fetchBillResponse.getGenericResponse(); + + // ✅ Build final ResponseModel + responseModel = new ResponseModel( + generalResponse.getMessage(), + generalResponse.getStatus(), + Integer.parseInt(generalResponse.getStatusCode()), + fetchBillResponse + ); + + } catch (Exception e) { + log.error("❌ Exception in initiateBillFetch(): {}", e.getMessage(), e); + responseModel.setStatus("500"); + responseModel.setMessage("Exception occurred"); + responseModel.setData(e.getMessage()); + } + + return responseModel; + } + +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/HttpService.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/HttpService.java index df49df5..76c821a 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/HttpService.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/HttpService.java @@ -1,8 +1,6 @@ package com.billpaymentservice.bbps.serviceImpl; -import java.net.http.HttpClient; -import java.time.Duration; import java.util.HashMap; import org.slf4j.Logger; @@ -12,53 +10,64 @@ import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.http.client.JdkClientHttpRequestFactory; import org.springframework.stereotype.Service; -import java.time.Duration; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpServerErrorException; import org.springframework.web.client.RestClient; +import com.billpaymentservice.bbps.dto.request.FetchBillRequest; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.AllArgsConstructor; + @Service +@AllArgsConstructor public class HttpService { private static final Logger log = LoggerFactory.getLogger(HttpService.class); private final RestClient restClient; + private final ObjectMapper objectMapper = new ObjectMapper(); - HttpService() { - HttpClient httpClient = HttpClient.newBuilder() - .connectTimeout(Duration.ofSeconds(5)) - .build(); + - JdkClientHttpRequestFactory factory = new JdkClientHttpRequestFactory(httpClient); - factory.setReadTimeout(Duration.ofSeconds(10)); - - this.restClient = RestClient.builder() - .requestFactory(factory) - .build(); - } - - public HashMap postRequest(String url, String payload) { + public HashMap postRequest(String url, String payload, HttpHeaders customHeaders) { HashMap response = new HashMap<>(); try { HttpHeaders headers = new HttpHeaders(); + + if (customHeaders != null) { + customHeaders.forEach((key, value) -> { + if (!key.equalsIgnoreCase(HttpHeaders.CONTENT_TYPE)) { + headers.addAll(key, value); + } + }); + } + headers.setContentType(MediaType.APPLICATION_JSON); - log.info("📡 Bank POST Request to URL: {}", url); + // ✅ MAKE THE REQUEST ResponseEntity restResponse = restClient.post() - .uri(url) - .headers(h -> h.addAll(headers)) - .body(payload) - .retrieve() - .toEntity(String.class); + .uri(url) + .headers(h -> h.addAll(headers)) + .body(payload) + .retrieve() + .toEntity(String.class); response.put("respCode", String.valueOf(restResponse.getStatusCode().value())); response.put("data", restResponse.getBody()); + + log.info("✅ HttpService Response Status: {}", restResponse.getStatusCode()); - } catch (HttpClientErrorException | HttpServerErrorException httpException) { - response.put("respCode", String.valueOf(httpException.getStatusCode())); - response.put("data", "Exception : " + httpException.getResponseBodyAsString()); + } catch (HttpClientErrorException.Forbidden e) { + // ✅ SPECIAL 403 HANDLING + log.error("🚫 HttpService: 403 FORBIDDEN"); + response.put("respCode", "403"); + response.put("data", "FORBIDDEN - Check credentials in HttpService"); + } catch (Exception e) { - response.put("data", "Exception :" + e.getMessage()); - log.error("❌ Exception during POST call to {} -> {}", url, e.getMessage()); + log.error("❌ HttpService Exception: {}", e.getMessage()); + response.put("respCode", "500"); + response.put("data", "HttpService Error: " + e.getMessage()); } + return response; } diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java index 07c8b4c..5b1a410 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java @@ -155,7 +155,6 @@ public class MasterDataServiceImpl implements MasterDataService { } - @Override public ResponseModel fetchMasterDataCategoryWise(MerchantRequestModel requestModel, String category, int pageStart, int pageEnd) { diff --git a/src/main/java/com/billpaymentservice/bbps/util/BBPSConstant.java b/src/main/java/com/billpaymentservice/bbps/util/BBPSConstant.java index 91fefa8..e974435 100644 --- a/src/main/java/com/billpaymentservice/bbps/util/BBPSConstant.java +++ b/src/main/java/com/billpaymentservice/bbps/util/BBPSConstant.java @@ -28,5 +28,6 @@ public class BBPSConstant { public static final String BILLER_DATA_FETCH_URL="/billersById?billerId="; public static final String CUSTOMPARAM_URL="/customerParam?billerId="; + public static final String BILL_FETCH_INTI="/couapp/bills/fetch"; } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index e99dcd1..c5071ed 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -27,9 +27,9 @@ spring.datasource.hikari.auto-commit=true logging.level.io.github.resilience4j.retry=DEBUG - # BBPS URLs master.data.url = https://bbps-staging.digiledge.in/agent/cou-master/masters +agent.data.url=https://bbps-staging.digiledge.in/agent/bill-payment-new # Resilience4j Retry