Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@
<p align="center">
<a href="https://github.com/codef-io/easycodef-java-v2/actions?query=branch%3Amaster"><img align="center" src="https://img.shields.io/github/actions/workflow/status/codef-io/easycodef-java-v2/publish.yml?style=for-the-badge&logo=gradle&color=02303A" alt="Build Status"/></a>
<a href="https://github.com/codef-io/easycodef-java-v2"><img align="center" src="https://img.shields.io/github/last-commit/codef-io/easycodef-java-v2/master?style=for-the-badge&label=LAST%20BUILD&logo=Github&color=181717" alt="Last Commit"/></a>
<a href="https://central.sonatype.com/artifact/io.codef.api/easycodef-java-v2/2.0.0-alpha-005"><img align="center" src="https://img.shields.io/maven-central/v/io.codef.api/easycodef-java-v2.svg?style=for-the-badge&label=Maven%20Central&logo=apache-maven&color=C71A36" alt="Maven Central"/></a>
<a href="https://central.sonatype.com/artifact/io.codef.api/easycodef-java-v2/2.0.0-beta-001"><img align="center" src="https://img.shields.io/maven-central/v/io.codef.api/easycodef-java-v2.svg?style=for-the-badge&label=Maven%20Central&logo=apache-maven&color=C71A36" alt="Maven Central"/></a>
</p>

<br><br>

### easycodef-java-v2

> [!TIP]
> - **[EasyCodef V2 Wiki](https://github.com/codef-io/easycodef-java-v2/wiki)**

Expand All @@ -42,5 +40,12 @@
> - [Hectodata Homepage](https://hectodata.co.kr/)
> - [Hecto Tech Blog](https://blog.hectodata.co.kr/)

<br>

> 🤠&nbsp;**Contributors**<br><br>
> <a href="https://github.com/codef-io/easycodef-java-v2/graphs/contributors">
> <img width="30px" src="https://contrib.rocks/image?repo=codef-io/easycodef-java-v2" />
> </a>

<br>
<br>
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ plugins {


group = "io.codef.api"
version = "2.0.0-alpha-005"
version = "2.0.0-beta-001"

signing {
useInMemoryPgpKeys(
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/io/codef/api/CodefValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,31 @@

import io.codef.api.error.CodefError;
import io.codef.api.error.CodefException;

import java.util.Optional;
import java.util.UUID;

public class CodefValidator {

private CodefValidator() {
}

public static <T> T requireNonNullElseThrow(
T object,
CodefError codefError
T object,
CodefError codefError
) {
return Optional.ofNullable(object)
.orElseThrow(() -> CodefException.from(codefError));
.orElseThrow(() -> CodefException.from(codefError));
}

public static void requireValidUUIDPattern(
String uuid,
CodefError codefError
String uuid,
CodefError codefError
) {
final String UUID_REGULAR_EXPRESSION = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$";

Optional.ofNullable(uuid)
.filter(uuids -> uuids.matches(UUID_REGULAR_EXPRESSION))
.map(UUID::fromString)
.orElseThrow(() -> CodefException.from(codefError));
.filter(uuids -> uuids.matches(UUID_REGULAR_EXPRESSION))
.map(UUID::fromString)
.orElseThrow(() -> CodefException.from(codefError));
}
}
126 changes: 71 additions & 55 deletions src/main/java/io/codef/api/EasyCodef.java
Original file line number Diff line number Diff line change
@@ -1,35 +1,44 @@
package io.codef.api;

import static io.codef.api.dto.EasyCodefRequest.SSO_ID;
import static io.codef.api.dto.EasyCodefRequest.TRUE;

import io.codef.api.constants.CodefClientType;
import io.codef.api.constants.CodefResponseCode;
import io.codef.api.dto.CodefSimpleAuth;
import io.codef.api.dto.EasyCodefRequest;
import io.codef.api.dto.EasyCodefResponse;
import io.codef.api.error.CodefError;
import io.codef.api.error.CodefException;
import io.codef.api.storage.MultipleRequestStorage;
import io.codef.api.storage.SimpleAuthStorage;
import io.codef.api.util.RsaUtil;

import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;
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;
import java.util.stream.IntStream;

import static io.codef.api.dto.EasyCodefRequest.SSO_ID;
import static io.codef.api.dto.EasyCodefRequest.TRUE;

public class EasyCodef {

private static final long REQUEST_DELAY_MS = 700L;

private final SimpleAuthStorage simpleAuthStorage;
private final MultipleRequestStorage multipleRequestStorage;
private final PublicKey publicKey;
private final CodefClientType clientType;
private final EasyCodefToken easyCodefToken;

protected EasyCodef(EasyCodefBuilder builder, EasyCodefToken easyCodefToken) {
protected EasyCodef(
EasyCodefBuilder builder,
EasyCodefToken easyCodefToken
) {
this.publicKey = RsaUtil.generatePublicKey(builder.getPublicKey());
this.clientType = builder.getClientType();
this.easyCodefToken = easyCodefToken;
Expand All @@ -44,7 +53,8 @@ public EasyCodefResponse requestProduct(EasyCodefRequest request) throws CodefEx
String requestUrl = buildRequestUrl(request);
EasyCodefToken validToken = easyCodefToken.validateAndRefreshToken();

EasyCodefResponse response = EasyCodefConnector.requestProduct(request, validToken, requestUrl);
EasyCodefResponse response = EasyCodefConnector.requestProduct(request, validToken,
requestUrl);
simpleAuthStorage.storeIfRequired(request, response, requestUrl);

return response;
Expand All @@ -53,11 +63,10 @@ public EasyCodefResponse requestProduct(EasyCodefRequest request) throws CodefEx
/**
* 다중 상품 요청
*/
public EasyCodefResponse requestMultipleProduct(List<EasyCodefRequest> requests) throws CodefException {
public EasyCodefResponse requestMultipleProduct(List<EasyCodefRequest> requests)
throws CodefException {
validateRequests(requests);

String uuid = UUID.randomUUID().toString();
assignSsoId(requests, uuid);
assignSsoId(requests, UUID.randomUUID().toString());

var executors = createExecutors();
try {
Expand All @@ -70,17 +79,19 @@ public EasyCodefResponse requestMultipleProduct(List<EasyCodefRequest> requests)
/**
* 단건 간편인증 완료 요청
*/
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 = executeSimpleAuthRequest(enrichedRequest, simpleAuth.requestUrl());
EasyCodefResponse response = executeSimpleAuthRequest(enrichedRequest,
simpleAuth.requestUrl());

simpleAuthStorage.updateIfRequired(
simpleAuth.requestUrl(),
enrichedRequest,
response,
transactionId
simpleAuth.requestUrl(),
enrichedRequest,
response,
transactionId
);

return response;
Expand All @@ -89,25 +100,26 @@ public EasyCodefResponse requestSimpleAuthCertification(String transactionId) th
/**
* 다건 간편인증 완료 요청
*/
public List<EasyCodefResponse> requestMultipleSimpleAuthCertification(String transactionId) throws CodefException {
public List<EasyCodefResponse> requestMultipleSimpleAuthCertification(String transactionId)
throws CodefException {
CodefSimpleAuth simpleAuth = simpleAuthStorage.get(transactionId);

EasyCodefRequest enrichedRequest = enrichRequestWithTwoWayInfo(simpleAuth);
EasyCodefResponse firstResponse = executeSimpleAuthRequest(enrichedRequest, simpleAuth.requestUrl());
EasyCodefResponse firstResponse = executeSimpleAuthRequest(enrichedRequest,
simpleAuth.requestUrl());

simpleAuthStorage.updateIfRequired(
simpleAuth.requestUrl(),
enrichedRequest,
firstResponse,
transactionId
simpleAuth.requestUrl(),
enrichedRequest,
firstResponse,
transactionId
);

return isSuccessful(firstResponse)
? combineWithRemainingResponses(firstResponse, transactionId)
: List.of(firstResponse);
? combineWithRemainingResponses(firstResponse, transactionId)
: List.of(firstResponse);
}


// Private helper methods

private String buildRequestUrl(EasyCodefRequest request) {
Expand All @@ -125,8 +137,10 @@ private EasyCodefRequest enrichRequestWithTwoWayInfo(CodefSimpleAuth simpleAuth)
return request;
}

private EasyCodefResponse executeSimpleAuthRequest(EasyCodefRequest request, String requestUrl)
throws CodefException {
private EasyCodefResponse executeSimpleAuthRequest(
EasyCodefRequest request,
String requestUrl
) throws CodefException {
EasyCodefToken validToken = easyCodefToken.validateAndRefreshToken();
return EasyCodefConnector.requestProduct(request, validToken, requestUrl);
}
Expand All @@ -136,19 +150,19 @@ private boolean isSuccessful(EasyCodefResponse response) {
}

private List<EasyCodefResponse> combineWithRemainingResponses(
EasyCodefResponse firstResponse,
String transactionId
EasyCodefResponse firstResponse,
String transactionId
) throws CodefException {
List<EasyCodefResponse> remainingResponses = multipleRequestStorage.getRemainingResponses(transactionId);
List<EasyCodefResponse> remainingResponses = multipleRequestStorage.getRemainingResponses(
transactionId);
List<EasyCodefResponse> allResponses = new ArrayList<>(remainingResponses);
allResponses.add(firstResponse);
return allResponses;
}

private void validateRequests(List<EasyCodefRequest> requests) {
if (requests == null || requests.isEmpty()) {
throw new IllegalArgumentException("Requests cannot be null or empty");
}
requests.forEach(
request -> CodefValidator.requireNonNullElseThrow(request, CodefError.REQUEST_NULL));
}

private void assignSsoId(List<EasyCodefRequest> requests, String uuid) {
Expand All @@ -157,19 +171,20 @@ private void assignSsoId(List<EasyCodefRequest> requests, String uuid) {

private CodefExecutors createExecutors() {
return new CodefExecutors(
Executors.newScheduledThreadPool(1),
Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory())
Executors.newScheduledThreadPool(1),
Executors.newThreadPerTaskExecutor(Thread.ofVirtual().factory())
);
}

private EasyCodefResponse processMultipleRequests(
List<EasyCodefRequest> requests,
CodefExecutors codefExecutors
List<EasyCodefRequest> requests,
CodefExecutors codefExecutors
) throws CodefException {
List<CompletableFuture<EasyCodefResponse>> futures = scheduleRequests(requests, codefExecutors);
List<CompletableFuture<EasyCodefResponse>> futures = scheduleRequests(requests,
codefExecutors);

CompletableFuture<EasyCodefResponse> firstCompleted = CompletableFuture.anyOf(
futures.toArray(new CompletableFuture[0])
futures.toArray(new CompletableFuture[0])
).thenApply(result -> (EasyCodefResponse) result);

EasyCodefResponse result = firstCompleted.join();
Expand All @@ -179,34 +194,34 @@ private EasyCodefResponse processMultipleRequests(
}

private List<CompletableFuture<EasyCodefResponse>> scheduleRequests(
List<EasyCodefRequest> requests,
CodefExecutors codefExecutors
List<EasyCodefRequest> requests,
CodefExecutors codefExecutors
) {
return IntStream.range(0, requests.size())
.mapToObj(i -> scheduleRequest(requests.get(i), i * REQUEST_DELAY_MS, codefExecutors))
.toList();
.mapToObj(i -> scheduleRequest(requests.get(i), i * REQUEST_DELAY_MS, codefExecutors))
.toList();
}

private CompletableFuture<EasyCodefResponse> scheduleRequest(
EasyCodefRequest request,
long delayMs,
CodefExecutors codefExecutors
EasyCodefRequest request,
long delayMs,
CodefExecutors codefExecutors
) {
CompletableFuture<EasyCodefResponse> future = new CompletableFuture<>();

codefExecutors.scheduler.schedule(
() -> executeRequest(request, codefExecutors.virtualThreadExecutor, future),
delayMs,
TimeUnit.MILLISECONDS
() -> executeRequest(request, codefExecutors.virtualThreadExecutor, future),
delayMs,
TimeUnit.MILLISECONDS
);

return future;
}

private void executeRequest(
EasyCodefRequest request,
Executor executor,
CompletableFuture<EasyCodefResponse> future
EasyCodefRequest request,
Executor executor,
CompletableFuture<EasyCodefResponse> future
) {
CompletableFuture.supplyAsync(() -> {
try {
Expand All @@ -232,8 +247,9 @@ public PublicKey getPublicKey() {
}

private record CodefExecutors(
ScheduledExecutorService scheduler,
Executor virtualThreadExecutor
ScheduledExecutorService scheduler,
Executor virtualThreadExecutor
) {

}
}
5 changes: 3 additions & 2 deletions src/main/java/io/codef/api/EasyCodefBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import io.codef.api.constants.CodefClientType;
import io.codef.api.error.CodefError;
import io.codef.api.error.CodefException;

import java.util.UUID;

public class EasyCodefBuilder {

private String publicKey;
private UUID clientId;
private UUID clientSecret;
Expand All @@ -17,7 +17,8 @@ public static EasyCodefBuilder builder() {
}

public EasyCodefBuilder publicKey(String publicKey) {
this.publicKey = CodefValidator.requireNonNullElseThrow(publicKey, CodefError.NULL_PUBLIC_KEY);
this.publicKey = CodefValidator.requireNonNullElseThrow(publicKey,
CodefError.NULL_PUBLIC_KEY);
return this;
}

Expand Down
Loading