diff --git a/src/main/java/io/codef/api/CodefExecutorManager.java b/src/main/java/io/codef/api/CodefExecutorManager.java index 5ac77ce..5a83736 100644 --- a/src/main/java/io/codef/api/CodefExecutorManager.java +++ b/src/main/java/io/codef/api/CodefExecutorManager.java @@ -6,49 +6,21 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -// 실행기 관리를 위한 클래스 -public class CodefExecutorManager implements AutoCloseable { - private final ScheduledExecutorService scheduler; +public class CodefExecutorManager { + private final Executor virtualThreadExecutor; - private CodefExecutorManager(ScheduledExecutorService scheduler, Executor virtualThreadExecutor) { - this.scheduler = scheduler; + private CodefExecutorManager(Executor virtualThreadExecutor) { this.virtualThreadExecutor = virtualThreadExecutor; } public static CodefExecutorManager create() { return new CodefExecutorManager( - Executors.newScheduledThreadPool(1), - Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory()) - ); - } - - public CompletableFuture scheduleRequest( - EasyCodefRequest request, - long delayMs, - SingleReqFacade facade - ) { - return scheduleDelayedExecution(delayMs) - .thenComposeAsync( - ignored -> executeRequest(request, facade), - virtualThreadExecutor - ); - } - - private CompletableFuture scheduleDelayedExecution(long delayMs) { - CompletableFuture future = new CompletableFuture<>(); - scheduler.schedule( - () -> future.complete(null), - delayMs, - TimeUnit.MILLISECONDS - ); - return future; + Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory())); } - private CompletableFuture executeRequest( + public CompletableFuture executeRequest( EasyCodefRequest request, SingleReqFacade facade ) { @@ -57,9 +29,4 @@ private CompletableFuture executeRequest( virtualThreadExecutor ); } - - @Override - public void close() { - scheduler.shutdown(); - } } \ No newline at end of file diff --git a/src/main/java/io/codef/api/ResponseHandler.java b/src/main/java/io/codef/api/ResponseHandler.java index a65fec0..be176a1 100644 --- a/src/main/java/io/codef/api/ResponseHandler.java +++ b/src/main/java/io/codef/api/ResponseHandler.java @@ -1,50 +1,71 @@ package io.codef.api; -import static io.codef.api.dto.EasyCodefRequest.ACCESS_TOKEN; -import static io.codef.api.dto.EasyCodefResponse.DATA; -import static io.codef.api.dto.EasyCodefResponse.RESULT; - import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; +import io.codef.api.constants.CodefResponseCode; import io.codef.api.dto.EasyCodefResponse; import io.codef.api.error.CodefError; import io.codef.api.error.CodefException; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpStatus; +import org.apache.hc.core5.http.ParseException; +import org.apache.hc.core5.http.io.entity.EntityUtils; + import java.io.IOException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.util.List; import java.util.Optional; import java.util.function.Function; -import org.apache.hc.core5.http.ClassicHttpResponse; -import org.apache.hc.core5.http.HttpStatus; -import org.apache.hc.core5.http.ParseException; -import org.apache.hc.core5.http.io.entity.EntityUtils; + +import static io.codef.api.dto.EasyCodefRequest.ACCESS_TOKEN; +import static io.codef.api.dto.EasyCodefResponse.DATA; +import static io.codef.api.dto.EasyCodefResponse.RESULT; public class ResponseHandler { + private static final String UTF_8 = StandardCharsets.UTF_8.toString(); + public static boolean isSuccessResponse(EasyCodefResponse response) { + return CodefResponseCode.CF_00000.equals(response.code()); + } + + public static boolean isAddAuthResponse(EasyCodefResponse response) { + return CodefResponseCode.CF_03002.equals(response.code()); + } + + public static boolean isAddAuthExceedResponse(EasyCodefResponse response) { + return CodefResponseCode.CF_12872.equals(response.code()); + } + + public static boolean isFailureResponse(EasyCodefResponse response) { + return !isSuccessResponse(response) && !isAddAuthResponse(response); + } + /** * 토큰 응답 처리 */ public String handleTokenResponse(ClassicHttpResponse response) throws CodefException { return handleHttpResponse( - response, - this::parseAccessToken, - CodefError.OAUTH_UNAUTHORIZED, - CodefError.OAUTH_INTERNAL_ERROR, - false + response, + this::parseAccessToken, + CodefError.OAUTH_UNAUTHORIZED, + CodefError.OAUTH_INTERNAL_ERROR, + false ); } /** * 상품 응답 처리 */ - public EasyCodefResponse handleProductResponse(ClassicHttpResponse response) throws CodefException { + public EasyCodefResponse handleProductResponse(ClassicHttpResponse response) + throws CodefException { return handleHttpResponse( - response, - this::parseProductResponse, - CodefError.CODEF_API_UNAUTHORIZED, - CodefError.CODEF_API_SERVER_ERROR, - true + response, + this::parseProductResponse, + CodefError.CODEF_API_UNAUTHORIZED, + CodefError.CODEF_API_SERVER_ERROR, + true ); } @@ -52,11 +73,11 @@ public EasyCodefResponse handleProductResponse(ClassicHttpResponse response) thr * 공통 HTTP 응답 처리 로직 */ private T handleHttpResponse( - ClassicHttpResponse response, - Function parser, - CodefError unauthorizedError, - CodefError defaultError, - boolean requireUrlDecoding + ClassicHttpResponse response, + Function parser, + CodefError unauthorizedError, + CodefError defaultError, + boolean requireUrlDecoding ) throws CodefException { String responseBody = extractResponseBody(response, requireUrlDecoding); @@ -70,7 +91,8 @@ private T handleHttpResponse( /** * HTTP 응답 본문 추출 */ - private String extractResponseBody(ClassicHttpResponse response, boolean requiresDecoding) throws CodefException { + private String extractResponseBody(ClassicHttpResponse response, boolean requiresDecoding) + throws CodefException { try { String responseBody = EntityUtils.toString(response.getEntity()); return requiresDecoding ? URLDecoder.decode(responseBody, UTF_8) : responseBody; @@ -99,17 +121,38 @@ private EasyCodefResponse parseProductResponse(String responseBody) throws Codef try { JSONObject jsonResponse = JSON.parseObject(responseBody); - EasyCodefResponse.Result result = Optional.ofNullable(jsonResponse.getJSONObject(RESULT)) + EasyCodefResponse.Result result = parseResult(jsonResponse); + Object data = parseData(jsonResponse); + + return new EasyCodefResponse(result, data); + } catch (Exception exception) { + throw CodefException.of(CodefError.PARSE_ERROR, exception); + } + } + + private EasyCodefResponse.Result parseResult(JSONObject jsonResponse) throws CodefException { + return Optional.ofNullable(jsonResponse.getJSONObject(RESULT)) .map(object -> object.to(EasyCodefResponse.Result.class)) .orElseThrow(() -> CodefException.from(CodefError.PARSE_ERROR)); + } - Object data = Optional.ofNullable(jsonResponse.getJSONObject(DATA)) + private Object parseData(JSONObject jsonResponse) throws CodefException { + try { + return parseObjectData(jsonResponse); + } catch (Exception e) { + return parseArrayData(jsonResponse); + } + } + + private Object parseObjectData(JSONObject jsonResponse) throws CodefException { + return Optional.ofNullable(jsonResponse.getJSONObject(DATA)) .map(obj -> obj.to(Object.class)) .orElseThrow(() -> CodefException.from(CodefError.PARSE_ERROR)); + } - return new EasyCodefResponse(result, data); - } catch (Exception e) { - throw CodefException.of(CodefError.PARSE_ERROR, e); - } + private List parseArrayData(JSONObject jsonResponse) throws CodefException { + return Optional.ofNullable(jsonResponse.getJSONArray(DATA)) + .map(obj -> obj.to(List.class)) + .orElseThrow(() -> CodefException.from(CodefError.PARSE_ERROR)); } } \ No newline at end of file diff --git a/src/main/java/io/codef/api/ResponseLogger.java b/src/main/java/io/codef/api/ResponseLogger.java new file mode 100644 index 0000000..c4c7718 --- /dev/null +++ b/src/main/java/io/codef/api/ResponseLogger.java @@ -0,0 +1,101 @@ +package io.codef.api; + +import com.alibaba.fastjson2.JSON; +import io.codef.api.dto.EasyCodefResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; +import java.util.Optional; + +import static io.codef.api.constants.CodefResponseCode.*; + +public class ResponseLogger { + private static final Logger log = LoggerFactory.getLogger(ResponseLogger.class); + + private ResponseLogger() { + } + + + public static void logResponseStatus(EasyCodefResponse response) { + logBasicInfo(response); + + switch (response.code()) { + case CF_00000: + logSuccessResponse(); + break; + + case CF_03002: + logAddAuthRequired(response); + break; + + case CF_12872: + logAuthExceeded(); + break; + + default: + logError(response); + break; + } + } + + public static void logStatusSummary(List responses) { + long successCount = responses.stream().filter(ResponseHandler::isSuccessResponse).count(); + long addAuthCount = responses.stream().filter(ResponseHandler::isAddAuthResponse).count(); + long failureCount = responses.stream().filter(ResponseHandler::isFailureResponse).count(); + + log.info("Total Responses Count = {}\n", responses.size()); + logStatus(successCount, addAuthCount, failureCount); + } + + private static void logBasicInfo(EasyCodefResponse response) { + log.info("Response Status Code : {}", response.code()); + log.info("Transaction Id : {}", response.transactionId()); + } + + private static void logSuccessResponse() { + log.info("Successfully returned Value from Codef API\n"); + } + + private static void logAddAuthRequired(EasyCodefResponse response) { + Object data = response.data(); + String addAuthMethod = JSON.parseObject(data.toString()).getString("method"); + log.warn("Additional authentication required | method : {}\n", addAuthMethod); + } + + private static void logAuthExceeded() { + log.error("Retry limit for additional authentication exceeded. " + + "Please restart the process from the initial request.\n"); + } + + private static void logError(EasyCodefResponse response) { + log.error("Failed to get proper scrapping response. Check the Error errorMessage And StatusCode"); + log.error("> message : {}", response.result().message()); + log.error("> extraMessage : {}", response.result().extraMessage()); + } + + private static void logStatus( + long successCount, + long addAuthCount, + long failureCount + ) { + Optional.of(successCount) + .filter(ResponseLogger::isExist) + .ifPresent(count -> log.info("Success Response Status [ {} ] Count : {}", CF_00000, count)); + + Optional.of(addAuthCount) + .filter(ResponseLogger::isExist) + .ifPresent(count -> log.info("AddAuth Response Status [ {} ] Count : {}", CF_03002, count)); + + Optional.of(failureCount) + .filter(ResponseLogger::isExist) + .ifPresentOrElse( + count -> log.warn("Failure Response Status [ Else ] Count : {}\n", count), + () -> log.info("No Failure Responses\n") + ); + } + + private static boolean isExist(Long count) { + return count > 0; + } +} diff --git a/src/main/java/io/codef/api/facade/MultipleReqFacade.java b/src/main/java/io/codef/api/facade/MultipleReqFacade.java index 91ad38d..0b05527 100644 --- a/src/main/java/io/codef/api/facade/MultipleReqFacade.java +++ b/src/main/java/io/codef/api/facade/MultipleReqFacade.java @@ -12,11 +12,13 @@ import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; import java.util.stream.IntStream; // 다중 요청 처리기 public class MultipleReqFacade { - private static final long REQUEST_DELAY_MS = 700L; + + private static final long REQUEST_DELAY_INTERVAL = 700L; private final SingleReqFacade singleReqFacade; private final MultipleRequestStorage multipleRequestStorage; @@ -37,19 +39,38 @@ public EasyCodefResponse requestMultipleProduct(List requests) validateRequests(requests); assignSsoId(requests, UUID.randomUUID().toString()); - try { - List> futures = scheduleRequests(requests); + List> futures = scheduleRequests(requests); + + CompletableFuture firstCompleted = + CompletableFuture.anyOf(futures.toArray(new CompletableFuture[0])) + .thenApply(result -> (EasyCodefResponse) result); + + EasyCodefResponse result = firstCompleted.join(); + multipleRequestStorage.store(result.transactionId(), futures); + + return result; + } - CompletableFuture firstCompleted = - CompletableFuture.anyOf(futures.toArray(new CompletableFuture[0])) - .thenApply(result -> (EasyCodefResponse) result); - EasyCodefResponse result = firstCompleted.join(); - multipleRequestStorage.store(result.transactionId(), futures); + private List> scheduleRequests( + List requests + ) { + return IntStream.range(0, requests.size()) + .mapToObj(i -> { + applyDelay(i); + return executorManager.executeRequest(requests.get(i), singleReqFacade); + }) + .toList(); + } - return result; - } finally { - executorManager.close(); + private void applyDelay(int index) { + if (index > 0) { + try { + TimeUnit.MILLISECONDS.sleep(index * REQUEST_DELAY_INTERVAL); + } catch (InterruptedException exception) { + Thread.currentThread().interrupt(); + throw CodefException.of(CodefError.IO_ERROR, exception); + } } } @@ -61,16 +82,4 @@ private void validateRequests(List requests) { private void assignSsoId(List requests, String uuid) { requests.forEach(request -> request.requestBody().put(SSO_ID, uuid)); } - - private List> scheduleRequests( - List requests - ) { - return IntStream.range(0, requests.size()) - .mapToObj(i -> executorManager.scheduleRequest( - requests.get(i), - i * REQUEST_DELAY_MS, - singleReqFacade - )) - .toList(); - } } diff --git a/src/main/java/io/codef/api/facade/SimpleAuthCertFacade.java b/src/main/java/io/codef/api/facade/SimpleAuthCertFacade.java index e4e6253..775218f 100644 --- a/src/main/java/io/codef/api/facade/SimpleAuthCertFacade.java +++ b/src/main/java/io/codef/api/facade/SimpleAuthCertFacade.java @@ -1,23 +1,21 @@ package io.codef.api.facade; -import static io.codef.api.constants.CodefResponseCode.CF_03002; -import static io.codef.api.constants.CodefResponseCode.CF_12872; -import static io.codef.api.dto.EasyCodefRequest.TRUE; - -import com.alibaba.fastjson2.JSON; -import io.codef.api.constants.CodefResponseCode; +import io.codef.api.ResponseHandler; +import io.codef.api.ResponseLogger; import io.codef.api.dto.EasyCodefRequest; import io.codef.api.dto.EasyCodefResponse; import io.codef.api.error.CodefException; import io.codef.api.storage.MultipleRequestStorage; import io.codef.api.storage.SimpleAuthStorage; import io.codef.api.vo.CodefSimpleAuth; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; +import java.util.Map; + +import static io.codef.api.dto.EasyCodefRequest.TRUE; + public class SimpleAuthCertFacade { private static final Logger log = LoggerFactory.getLogger(SimpleAuthCertFacade.class); @@ -26,91 +24,38 @@ public class SimpleAuthCertFacade { private final SimpleAuthStorage simpleAuthStorage; private final MultipleRequestStorage multipleRequestStorage; - public SimpleAuthCertFacade( - SingleReqFacade singleReqFacade, - SimpleAuthStorage simpleAuthStorage, - MultipleRequestStorage multipleRequestStorage - ) { + public SimpleAuthCertFacade(SingleReqFacade singleReqFacade, + SimpleAuthStorage simpleAuthStorage, MultipleRequestStorage multipleRequestStorage) { this.singleReqFacade = singleReqFacade; this.simpleAuthStorage = simpleAuthStorage; this.multipleRequestStorage = multipleRequestStorage; } - public EasyCodefResponse requestSimpleAuthCertification(String transactionId) throws CodefException { + public EasyCodefResponse requestSimpleAuthCertification(String transactionId) + throws CodefException { CodefSimpleAuth simpleAuth = simpleAuthStorage.get(transactionId); EasyCodefRequest enrichedRequest = enrichRequestWithTwoWayInfo(simpleAuth); EasyCodefResponse response = singleReqFacade.requestProduct(enrichedRequest); - simpleAuthStorage.updateIfRequired( - simpleAuth.requestUrl(), - enrichedRequest, - response, - transactionId - ); + simpleAuthStorage.updateIfRequired(simpleAuth.requestUrl(), enrichedRequest, response); - logResponseStatus(response, transactionId); + ResponseLogger.logResponseStatus(response); return response; } - public List requestMultipleSimpleAuthCertification( - String transactionId - ) throws CodefException { + public List requestMultipleSimpleAuthCertification(String transactionId) + throws CodefException { EasyCodefResponse firstResponse = requestSimpleAuthCertification(transactionId); - return isSuccessResponse(firstResponse) + return ResponseHandler.isSuccessResponse(firstResponse) ? combineWithRemainingResponses(firstResponse, transactionId) : returnFirstResponse(firstResponse); } - private void logAddAuthResponseStatus( - EasyCodefResponse response, - String transactionId, - String resultStatusCode - ) { - if (resultStatusCode.equals(CF_03002)) { - Object data = response.data(); - String addAuthMethod = JSON.parseObject(data.toString()).getString("method"); - - log.warn("Additional authentication required | method : {}\n", addAuthMethod); - } else if (resultStatusCode.equals(CF_12872)) { - log.warn( - "Retry limit for additional authentication exceeded. " - + "Please restart the process from the initial request.\n" - ); - } - } - - private void logDefaultResponseStatus(String transactionId, String resultStatusCode) { - log.info("Result Status Code : {}", resultStatusCode); - log.info("Transaction Id : {}", transactionId); - } - - private void logResponseStatus( - EasyCodefResponse response, - String transactionId - ) { - String resultStatusCode = response.code(); - logDefaultResponseStatus(transactionId, resultStatusCode); - - logAddAuthResponseStatus(response, transactionId, resultStatusCode); - } - private List returnFirstResponse(EasyCodefResponse firstErrorResponse) { return List.of(firstErrorResponse); } - private boolean isSuccessResponse(EasyCodefResponse response) { - return CodefResponseCode.CF_00000.equals(response.code()); - } - - private boolean isAddAuthResponse(EasyCodefResponse response) { - return CodefResponseCode.CF_03002.equals(response.code()); - } - - private boolean isFailureResponse(EasyCodefResponse response) { - return !isSuccessResponse(response) && !isAddAuthResponse(response); - } - private EasyCodefRequest enrichRequestWithTwoWayInfo(CodefSimpleAuth simpleAuth) { EasyCodefRequest request = simpleAuth.request(); Map body = request.requestBody(); @@ -122,33 +67,13 @@ private EasyCodefRequest enrichRequestWithTwoWayInfo(CodefSimpleAuth simpleAuth) return request; } - private List combineWithRemainingResponses(EasyCodefResponse firstResponse, - String transactionId) throws CodefException { - - log.info("Await Responses called By transactionId `{}`", transactionId); - List responses = multipleRequestStorage.getRemainingResponses( - transactionId); - log.info("Await Responses Count = {}", responses.size()); - + private List combineWithRemainingResponses( + EasyCodefResponse firstResponse, + String transactionId + ) throws CodefException { + List responses = multipleRequestStorage.getRemainingResponses(transactionId); responses.add(firstResponse); - List allResponseCodes = responses.stream().map(EasyCodefResponse::code).toList(); - log.info("Total Responses Count = {}\n", responses.size()); - - long successCount = responses.stream().filter(this::isSuccessResponse).count(); - long addAuthCount = responses.stream().filter(this::isAddAuthResponse).count(); - long failureCount = responses.stream().filter(this::isFailureResponse).count(); - - log.info("Success Response Status [CF-00000] Count : {}", successCount); - log.info("AddAuth Response Status [CF-03002] Count : {}", addAuthCount); - log.warn("Failure Response Status [ Else ] Count : {}", failureCount); - - if (failureCount > 0) { - responses.stream() - .filter(this::isFailureResponse) - .map(EasyCodefResponse::code) - .collect(Collectors.groupingBy(code -> code, Collectors.counting())) - .forEach((code, count) -> log.warn("> Error code : {}, Count: {}", code, count)); - } + ResponseLogger.logStatusSummary(responses); return responses; } diff --git a/src/main/java/io/codef/api/facade/SingleReqFacade.java b/src/main/java/io/codef/api/facade/SingleReqFacade.java index c0d1ebf..007802d 100644 --- a/src/main/java/io/codef/api/facade/SingleReqFacade.java +++ b/src/main/java/io/codef/api/facade/SingleReqFacade.java @@ -2,6 +2,7 @@ import io.codef.api.EasyCodefConnector; import io.codef.api.EasyCodefToken; +import io.codef.api.ResponseLogger; import io.codef.api.constants.CodefClientType; import io.codef.api.dto.EasyCodefRequest; import io.codef.api.dto.EasyCodefResponse; @@ -31,7 +32,8 @@ public EasyCodefResponse requestProduct(EasyCodefRequest request) throws CodefEx EasyCodefResponse response = EasyCodefConnector.requestProduct(request, validToken, requestUrl); - simpleAuthStorage.storeIfRequired(request, response, requestUrl); + simpleAuthStorage.storeIfAddAuthResponse(request, response, requestUrl); + ResponseLogger.logResponseStatus(response); return response; } diff --git a/src/main/java/io/codef/api/storage/MultipleRequestStorage.java b/src/main/java/io/codef/api/storage/MultipleRequestStorage.java index 069b14b..c3aa144 100644 --- a/src/main/java/io/codef/api/storage/MultipleRequestStorage.java +++ b/src/main/java/io/codef/api/storage/MultipleRequestStorage.java @@ -4,21 +4,26 @@ import io.codef.api.dto.EasyCodefResponse; import io.codef.api.error.CodefError; import io.codef.api.error.CodefException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class MultipleRequestStorage { - private final Map>> storage = new HashMap<>(); + private static final Logger log = LoggerFactory.getLogger(MultipleRequestStorage.class); + private final ConcurrentHashMap>> storage = new ConcurrentHashMap<>(); public List getRemainingResponses( String transactionId ) throws CodefException { + log.info("Await Responses called By transactionId `{}`", transactionId); + final List> futures = storage.get(transactionId); CodefValidator.requireNonNullElseThrow(futures, CodefError.SIMPLE_AUTH_FAILED); @@ -35,6 +40,8 @@ public List getRemainingResponses( .collect(Collectors.toCollection(ArrayList::new)); storage.remove(transactionId); + + log.info("Await Responses Count = {}", results.size()); return results; } catch (Exception e) { throw CodefException.from(CodefError.SIMPLE_AUTH_FAILED); diff --git a/src/main/java/io/codef/api/storage/SimpleAuthStorage.java b/src/main/java/io/codef/api/storage/SimpleAuthStorage.java index edaaf9e..e297653 100644 --- a/src/main/java/io/codef/api/storage/SimpleAuthStorage.java +++ b/src/main/java/io/codef/api/storage/SimpleAuthStorage.java @@ -6,15 +6,15 @@ import io.codef.api.error.CodefError; import io.codef.api.error.CodefException; import io.codef.api.vo.CodefSimpleAuth; -import java.util.HashMap; -import java.util.Map; + import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; public class SimpleAuthStorage { - private final Map storage = new HashMap<>(); + private final ConcurrentHashMap storage = new ConcurrentHashMap<>(); - public void storeIfRequired( + public void storeIfAddAuthResponse( EasyCodefRequest request, EasyCodefResponse response, String requestUrl @@ -35,8 +35,10 @@ public CodefSimpleAuth get(String transactionId) throws CodefException { public void updateIfRequired( String path, EasyCodefRequest request, - EasyCodefResponse response, String transactionId + EasyCodefResponse response ) { + String transactionId = response.transactionId(); + Optional.ofNullable(response.code()) .filter(code -> code.equals(CodefResponseCode.CF_03002)) .ifPresentOrElse(