diff --git a/src/main/java/io/codef/api/EasyCodef.java b/src/main/java/io/codef/api/EasyCodef.java index 53e1c05..9b9bdab 100644 --- a/src/main/java/io/codef/api/EasyCodef.java +++ b/src/main/java/io/codef/api/EasyCodef.java @@ -24,10 +24,13 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class EasyCodef { private static final long REQUEST_DELAY_MS = 700L; + private static final Logger log = LoggerFactory.getLogger(EasyCodef.class); private final SimpleAuthStorage simpleAuthStorage; private final MultipleRequestStorage multipleRequestStorage; @@ -35,15 +38,30 @@ public class EasyCodef { private final CodefClientType clientType; private final EasyCodefToken easyCodefToken; - protected EasyCodef( - EasyCodefBuilder builder, - EasyCodefToken easyCodefToken - ) { + protected EasyCodef(EasyCodefBuilder builder) { + this.publicKey = RsaUtil.generatePublicKey(builder.getPublicKey()); + log.info("EasyCodef RSA public key successfully initialized."); + this.clientType = builder.getClientType(); - this.easyCodefToken = easyCodefToken; + log.info("Your Codef clientType {} is successfully initialized.", clientType); + + this.easyCodefToken = new EasyCodefToken(builder); this.simpleAuthStorage = new SimpleAuthStorage(); this.multipleRequestStorage = new MultipleRequestStorage(); + + log.info("=================================================="); + log.info("Your EasyCodef Entity is successfully initialized!"); + log.info("==================================================\n"); + } + + private List returnFirstErrorResponse( + EasyCodefResponse firstResponse, + String transactionId + ) { + log.info("Result Status Code : {}", firstResponse.code()); + + return List.of(firstResponse); } /** @@ -53,10 +71,10 @@ public EasyCodefResponse requestProduct(EasyCodefRequest request) throws CodefEx String requestUrl = buildRequestUrl(request); EasyCodefToken validToken = easyCodefToken.validateAndRefreshToken(); - EasyCodefResponse response = EasyCodefConnector.requestProduct(request, validToken, - requestUrl); - simpleAuthStorage.storeIfRequired(request, response, requestUrl); + EasyCodefResponse response = + EasyCodefConnector.requestProduct(request, validToken, requestUrl); + simpleAuthStorage.storeIfRequired(request, response, requestUrl); return response; } @@ -66,9 +84,11 @@ public EasyCodefResponse requestProduct(EasyCodefRequest request) throws CodefEx public EasyCodefResponse requestMultipleProduct(List requests) throws CodefException { validateRequests(requests); + easyCodefToken.validateAndRefreshToken(); assignSsoId(requests, UUID.randomUUID().toString()); var executors = createExecutors(); + try { return processMultipleRequests(requests, executors); } finally { @@ -82,6 +102,7 @@ public EasyCodefResponse requestMultipleProduct(List requests) public EasyCodefResponse requestSimpleAuthCertification(String transactionId) throws CodefException { CodefSimpleAuth simpleAuth = simpleAuthStorage.get(transactionId); + easyCodefToken.validateAndRefreshToken(); EasyCodefRequest enrichedRequest = enrichRequestWithTwoWayInfo(simpleAuth); EasyCodefResponse response = executeSimpleAuthRequest(enrichedRequest, @@ -94,6 +115,8 @@ public EasyCodefResponse requestSimpleAuthCertification(String transactionId) transactionId ); + log.info("Result Status Code : {}", response.code()); + return response; } @@ -103,10 +126,11 @@ public EasyCodefResponse requestSimpleAuthCertification(String transactionId) public List requestMultipleSimpleAuthCertification(String transactionId) throws CodefException { CodefSimpleAuth simpleAuth = simpleAuthStorage.get(transactionId); + easyCodefToken.validateAndRefreshToken(); EasyCodefRequest enrichedRequest = enrichRequestWithTwoWayInfo(simpleAuth); - EasyCodefResponse firstResponse = executeSimpleAuthRequest(enrichedRequest, - simpleAuth.requestUrl()); + EasyCodefResponse firstResponse = + executeSimpleAuthRequest(enrichedRequest, simpleAuth.requestUrl()); simpleAuthStorage.updateIfRequired( simpleAuth.requestUrl(), @@ -116,8 +140,8 @@ public List requestMultipleSimpleAuthCertification(String tra ); return isSuccessful(firstResponse) - ? combineWithRemainingResponses(firstResponse, transactionId) - : List.of(firstResponse); + ? combineWithRemainingResponses(firstResponse, transactionId) // Case CF-00000 + : returnFirstErrorResponse(firstResponse, transactionId); } // Private helper methods @@ -153,10 +177,20 @@ private List combineWithRemainingResponses( EasyCodefResponse firstResponse, String transactionId ) throws CodefException { - List remainingResponses = multipleRequestStorage.getRemainingResponses( - transactionId); + + log.info("remainingResponses called By transactionId `{}`", transactionId); + + List remainingResponses = + multipleRequestStorage.getRemainingResponses(transactionId); + + log.info("Await Response Count = {}", remainingResponses.size()); List allResponses = new ArrayList<>(remainingResponses); allResponses.add(firstResponse); + + log.info("Total Response Count = {}", allResponses.size()); + log.info("Result Status Codes : {}", + allResponses.stream().map(EasyCodefResponse::code).toList()); + return allResponses; } @@ -180,12 +214,12 @@ private EasyCodefResponse processMultipleRequests( List requests, CodefExecutors codefExecutors ) throws CodefException { - List> futures = scheduleRequests(requests, - codefExecutors); + List> futures = + scheduleRequests(requests, codefExecutors); - CompletableFuture firstCompleted = CompletableFuture.anyOf( - futures.toArray(new CompletableFuture[0]) - ).thenApply(result -> (EasyCodefResponse) result); + CompletableFuture firstCompleted = + CompletableFuture.anyOf(futures.toArray(new CompletableFuture[0])) + .thenApply(result -> (EasyCodefResponse) result); EasyCodefResponse result = firstCompleted.join(); multipleRequestStorage.store(result.transactionId(), futures); diff --git a/src/main/java/io/codef/api/EasyCodefBuilder.java b/src/main/java/io/codef/api/EasyCodefBuilder.java index 25f3307..f3e5226 100644 --- a/src/main/java/io/codef/api/EasyCodefBuilder.java +++ b/src/main/java/io/codef/api/EasyCodefBuilder.java @@ -39,9 +39,8 @@ public EasyCodefBuilder clientType(CodefClientType clientType) { public EasyCodef build() { validatePropertyArguments(); - EasyCodefToken easyCodefToken = new EasyCodefToken(this); - return new EasyCodef(this, easyCodefToken); + return new EasyCodef(this); } private void validatePropertyArguments() { diff --git a/src/main/java/io/codef/api/EasyCodefConnector.java b/src/main/java/io/codef/api/EasyCodefConnector.java index 1f7f462..250a824 100644 --- a/src/main/java/io/codef/api/EasyCodefConnector.java +++ b/src/main/java/io/codef/api/EasyCodefConnector.java @@ -11,15 +11,19 @@ import io.codef.api.dto.EasyCodefResponse; import io.codef.api.error.CodefError; import io.codef.api.error.CodefException; +import io.codef.api.logger.JsonLogUtil; import io.codef.api.util.HttpClientUtil; import java.io.IOException; import java.nio.charset.StandardCharsets; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.core5.http.ClassicHttpResponse; import org.apache.hc.core5.http.io.entity.StringEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class EasyCodefConnector { + private static final Logger log = LoggerFactory.getLogger(EasyCodefConnector.class); private static final ResponseHandler responseHandler = new ResponseHandler(); private EasyCodefConnector() { @@ -74,7 +78,19 @@ private static T executeRequest( ResponseProcessor processor ) { try (var httpClient = HttpClientUtil.createClient()) { - return httpClient.execute(request, processor::process); + log.info("[{}] Codef API Request", request.hashCode()); + log.info("> Request Host : {}://{}", request.getScheme(), + request.getAuthority().toString()); + log.info("> Requset Uri : {}\n", request.getRequestUri()); + + return httpClient.execute(request, response -> { + log.info("[{}] Codef API Response", request.hashCode()); + log.info("> Response Status : {}", response.getCode()); + T result = processor.process(response); + log.info("> Response ā†’\n{}\n", JsonLogUtil.toPrettyJson(result)); + + return result; + }); } catch (IOException exception) { throw CodefException.of(CodefError.IO_ERROR, exception); } diff --git a/src/main/java/io/codef/api/EasyCodefToken.java b/src/main/java/io/codef/api/EasyCodefToken.java index 0a304f0..6eeec8a 100644 --- a/src/main/java/io/codef/api/EasyCodefToken.java +++ b/src/main/java/io/codef/api/EasyCodefToken.java @@ -3,14 +3,19 @@ import java.time.LocalDateTime; import java.util.Base64; import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class EasyCodefToken { + private static final Logger log = LoggerFactory.getLogger(EasyCodefToken.class); + private final String oauthToken; private String accessToken; private LocalDateTime expiresAt; protected EasyCodefToken(EasyCodefBuilder builder) { + final int VALIDITY_PERIOD_DAYS = 7; final String DELIMITER = ":"; @@ -18,13 +23,23 @@ protected EasyCodefToken(EasyCodefBuilder builder) { builder.getClientSecret().toString()); this.oauthToken = Base64.getEncoder().encodeToString(combinedKey.getBytes()); + log.info("Codef OAuth Token : {}", oauthToken); + log.info("Codef OAuth Token successfully initialized.\n"); + this.accessToken = EasyCodefConnector.requestToken(oauthToken); + log.info("Codef API AccessToken : {}", accessToken); + this.expiresAt = LocalDateTime.now().plusDays(VALIDITY_PERIOD_DAYS); + + log.info( + "Codef API AccessToken expiry at {} but, EasyCodef will handle automatic renewal", + expiresAt + ); + log.info("Codef API AccessToken successfully initialized.\n"); } public EasyCodefToken validateAndRefreshToken() { - Optional.of(expiresAt) - .filter(this::isTokenExpiringSoon) + Optional.of(expiresAt).filter(this::isTokenExpiringSoon) .ifPresent(expiry -> refreshToken()); return this; @@ -32,11 +47,23 @@ public EasyCodefToken validateAndRefreshToken() { private boolean isTokenExpiringSoon(LocalDateTime expiry) { return expiry.isBefore(LocalDateTime.now().plusHours(24)); + } private void refreshToken() { + log.info( + "Codef API AccessToken expiry at {} so EasyCodef refresh token", + expiresAt + ); this.accessToken = EasyCodefConnector.requestToken(oauthToken); + log.info("Codef API AccessToken : {}", accessToken); + this.expiresAt = LocalDateTime.now().plusDays(7); + + log.info( + "AccessToken Refresh completed. Now, Codef accessToken expiry at {}.", + expiresAt + ); } public String getAccessToken() { diff --git a/src/main/java/io/codef/api/constants/CodefReferenceUrl.java b/src/main/java/io/codef/api/constants/CodefReferenceUrl.java index 9648332..0c61ca5 100644 --- a/src/main/java/io/codef/api/constants/CodefReferenceUrl.java +++ b/src/main/java/io/codef/api/constants/CodefReferenceUrl.java @@ -25,4 +25,8 @@ public enum CodefReferenceUrl { public String getUrl() { return String.format(MESSAGE_FORMAT, url); } + + public String getRawUrl() { + return url; + } } diff --git a/src/main/java/io/codef/api/dto/EasyCodefRequestBuilder.java b/src/main/java/io/codef/api/dto/EasyCodefRequestBuilder.java index 589f000..5d3a6aa 100644 --- a/src/main/java/io/codef/api/dto/EasyCodefRequestBuilder.java +++ b/src/main/java/io/codef/api/dto/EasyCodefRequestBuilder.java @@ -12,9 +12,13 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class EasyCodefRequestBuilder { + private static final Logger log = LoggerFactory.getLogger(EasyCodefRequestBuilder.class); + private final HashMap generalRequestBody; private final HashMap secureRequestBody; private String path; @@ -80,7 +84,13 @@ public EasyCodefRequest build() { this.requestBody(EASY_CODEF_JAVA_FLAG, true); this.generalRequestBody.putAll(secureRequestBody); - return new EasyCodefRequest(path, generalRequestBody); + EasyCodefRequest easyCodefRequest = new EasyCodefRequest(path, generalRequestBody); + +// log.info("[EasyCodef] request object has been successfully built [ {} ]"); +// log.info(">> path = {}", path); +// log.info(">> requestBody = {}", generalRequestBody); + + return easyCodefRequest; } private void encryptSecureRequestBody() { diff --git a/src/main/java/io/codef/api/error/CodefError.java b/src/main/java/io/codef/api/error/CodefError.java index 5d60de4..f5ffb95 100644 --- a/src/main/java/io/codef/api/error/CodefError.java +++ b/src/main/java/io/codef/api/error/CodefError.java @@ -116,4 +116,12 @@ public enum CodefError { public String getMessage() { return String.format(MESSAGE_FORMAT, message, referenceUrl.getUrl()); } + + public String getRawMessage() { + return message; + } + + public CodefReferenceUrl getReferenceUrl() { + return referenceUrl; + } } \ No newline at end of file diff --git a/src/main/java/io/codef/api/error/CodefException.java b/src/main/java/io/codef/api/error/CodefException.java index 846d5a4..42c65f6 100644 --- a/src/main/java/io/codef/api/error/CodefException.java +++ b/src/main/java/io/codef/api/error/CodefException.java @@ -1,12 +1,15 @@ package io.codef.api.error; import java.io.Serial; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class CodefException extends RuntimeException { @Serial private static final long serialVersionUID = 1L; + private static final Logger log = LoggerFactory.getLogger(CodefException.class); private static final String LOG_WITH_CAUSE_FORMAT = "%s\nā†’ %s\n\n"; private final CodefError codefError; @@ -21,6 +24,9 @@ private CodefException(CodefError codefError, Exception exception) { exception ); this.codefError = codefError; + + log.error(codefError.getMessage()); + log.error(exception.getMessage()); } private CodefException( @@ -28,11 +34,17 @@ private CodefException( String extraMessage ) { super(codefError.getMessage() + '\n' + extraMessage); + log.error(codefError.getMessage()); + log.error(extraMessage); this.codefError = codefError; } private CodefException(CodefError codefError) { super(codefError.getMessage() + '\n'); + + log.error("{}", codefError.getRawMessage()); + log.error("{}", codefError.getReferenceUrl().getRawUrl()); + this.codefError = codefError; } diff --git a/src/main/java/io/codef/api/logger/JsonLogUtil.java b/src/main/java/io/codef/api/logger/JsonLogUtil.java new file mode 100644 index 0000000..08b36ff --- /dev/null +++ b/src/main/java/io/codef/api/logger/JsonLogUtil.java @@ -0,0 +1,19 @@ +package io.codef.api.logger; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class JsonLogUtil { + + private static final Logger log = LoggerFactory.getLogger(JsonLogUtil.class); + + public static String toPrettyJson(Object obj) { + return JSON.toJSONString(obj, + JSONWriter.Feature.PrettyFormat, + JSONWriter.Feature.WriteMapNullValue, + JSONWriter.Feature.WriteNullListAsEmpty + ); + } +} \ No newline at end of file