diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..fc47934
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,27 @@
+name: Build Verification
+
+on:
+ push:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ java-version: [17, 21, 23]
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v2
+
+ - name: Set up JDK ${{ matrix.java-version }}
+ uses: actions/setup-java@v2
+ with:
+ java-version: ${{ matrix.java-version }}
+ distribution: 'temurin'
+
+ - name: Grant execute permission for gradlew
+ run: chmod +x gradlew
+
+ - name: Build with JDK ${{ matrix.java-version }}
+ run: ./gradlew build
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index ba79d55..db168cc 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,13 +1,15 @@
name: Publish to Maven Central Repository
on:
- push:
- branches:
- - master
+ workflow_run:
+ workflows: ["Verify"]
+ types:
+ - completed
jobs:
publish:
runs-on: ubuntu-latest
+ if: ${{ github.event.workflow_run.conclusion == 'success' && github.ref == 'refs/heads/master' }}
steps:
- name: Checkout code
@@ -52,4 +54,4 @@ jobs:
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
run: |
- ./gradlew publishAllPublicationsToMavenCentralRepository --stacktrace --debug
\ No newline at end of file
+ ./gradlew publishAllPublicationsToMavenCentralRepository --stacktrace --debug
diff --git a/.gitignore b/.gitignore
index f13fb54..9931ea6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,4 @@ out
test-output
atlassian-ide-plugin.xml
.gradletasknamecache
+/src/test/java/io/codef/api/EasyCodefTokenTest.java
diff --git a/README.md b/README.md
index 946097b..9af3b91 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+
EasyCodef Java V2
+
+
+
+## Release
[![Build Status](https://img.shields.io/github/actions/workflow/status/codef-io/easycodef-java-v2/publish.yml?style=for-the-badge&logo=gradle&color=02303A)](https://github.com/codef-io/easycodef-java-v2/actions?query=branch%3Amaster)
[![Last Commit](https://img.shields.io/github/last-commit/codef-io/easycodef-java-v2/master?style=for-the-badge&label=LAST%20BUILD&logo=Github&color=181717)](https://github.com/codef-io/easycodef-java-v2)
[![Maven Central](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)](https://central.sonatype.com/artifact/io.codef.api/easycodef-java-v2)
-
-### Snippets
+## Snippets
- Gradle(Kotlin)
```gradle
- implementation("io.codef.api:easycodef-java-v2:2.0.0-alpha-002")
+ implementation("io.codef.api:easycodef-java-v2:2.0.0-alpha-003")
```
- Gradle(short)
```gradle
- implementation 'io.codef.api:easycodef-java-v2:2.0.0-alpha-002'
+ implementation 'io.codef.api:easycodef-java-v2:2.0.0-alpha-003'
```
- Maven
@@ -41,12 +42,40 @@
io.codef.api
easycodef-java-v2
- 2.0.0-alpha-002
+ 2.0.0-alpha-003
```
-## LISENCE
+## Get It !
-
+- 예제 코드
+ ```java
+ EasyCodef easyCodef = EasyCodefBuilder.builder()
+ .clientType(CodefClientType.DEMO)
+ .clientId("your-client-id")
+ .clientSecret("your-client-secret")
+ .publicKey("your-public-key")
+ .build();
+
+ EasyCodefRequest request = EasyCodefRequestBuilder.builder()
+ .path("/v1/kr/public/hw/nip-cdc-list/my-vaccination")
+ .organization("0011")
+ .requestBody("loginType", "1")
+ .requestBody("userId", "your-nhis-id")
+ .secureRequestBody("userPassword", "your-nhis-password")
+ .secureWith(easyCodef)
+ .build();
+
+ EasyCodefResponse easyCodefResponse = easyCodef.requestProduct(request);
+
+ final EasyCodefResponse.Result result = easyCodefResponse.result();
+ final Object data = easyCodefResponse.data();
+ ```
+
+---
+
+
+
+MIT © | LICENSE
+
-MIT © Hectodata Co,. Ltd [LICENSE](https://github.com/codef-io/easycodef-java-v2/blob/master/LICENSE) 파일을 참고하세요.
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index e818dc4..bab98e5 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -10,7 +10,7 @@ plugins {
group = "io.codef.api"
-version = "2.0.0-alpha-002"
+version = "2.0.0-alpha-003"
signing {
useInMemoryPgpKeys(
@@ -72,6 +72,11 @@ dependencies {
*/
implementation("com.fasterxml.jackson.core:jackson-databind:2.18.1")
+ /**
+ * 2024-10-17 Latest
+ */
+ implementation("com.alibaba:fastjson:2.0.53")
+
/**
* 2024-06-12 Latest
* https://mvnrepository.com/artifact/commons-codec/commons-codec
diff --git a/src/main/java/io/codef/api/CodefError.java b/src/main/java/io/codef/api/CodefError.java
deleted file mode 100644
index d33f05a..0000000
--- a/src/main/java/io/codef/api/CodefError.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package io.codef.api;
-
-public enum CodefError {
- INVALID_CLIENT_ID(
- "clientId must be a properly formatted UUID string. Please check your clientId and ensure it matches the UUID format.",
- EasyCodefReferenceUrl.KEY
- ),
- INVALID_CLIENT_SECRET(
- "clientSecret must be a properly formatted UUID string. Please check your clientSecret and ensure it matches the UUID format.",
- EasyCodefReferenceUrl.KEY
- ),
- INVALID_PUBLIC_KEY(
- "publicKey is required and cannot be null.",
- EasyCodefReferenceUrl.KEY
- ),
- OAUTH_UNAUTHORIZED(
- "Failed to authenticate with the Codef OAuth server. Please verify your clientId and clientSecret values.",
- EasyCodefReferenceUrl.KEY
- ),
- OAUTH_INTERNAL_ERROR(
- "An error occurred on the Codef OAuth server (500 Internal Server Error). Please try again later, or contact support if the issue persists.",
- EasyCodefReferenceUrl.KEY
- ),
- OAUTH_CONNECTION_ERROR(
- "The connection to the OAUTH server failed. Please check if `https://oauth.codef.io` is accessible.",
- EasyCodefReferenceUrl.DEV_GUIDE_REST_API
- );
-
- private final String message;
- private final EasyCodefReferenceUrl referenceUrl;
-
- CodefError(
- String message,
- EasyCodefReferenceUrl referenceUrl
- ) {
- this.message = message;
- this.referenceUrl = referenceUrl;
- }
-
- private static final String MESSAGE_FORMAT = "[EasyCodef] %s\n%s";
-
- public String getMessage() {
- return String.format(MESSAGE_FORMAT, message, referenceUrl.getUrl());
- }
-}
\ No newline at end of file
diff --git a/src/main/java/io/codef/api/CodefUrl.java b/src/main/java/io/codef/api/CodefUrl.java
deleted file mode 100644
index 4506d2d..0000000
--- a/src/main/java/io/codef/api/CodefUrl.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package io.codef.api;
-
-public class CodefUrl {
- public static final String CODEF_OAUTH_SERVER = "https://oauth.codef.io";
-}
diff --git a/src/main/java/io/codef/api/CodefValidator.java b/src/main/java/io/codef/api/CodefValidator.java
index 6079c18..757237a 100644
--- a/src/main/java/io/codef/api/CodefValidator.java
+++ b/src/main/java/io/codef/api/CodefValidator.java
@@ -1,9 +1,12 @@
package io.codef.api;
+import io.codef.api.error.CodefError;
+import io.codef.api.error.CodefException;
+
import java.util.Optional;
import java.util.UUID;
-public class CodefValidator {
+final class CodefValidator {
private CodefValidator() {
}
diff --git a/src/main/java/io/codef/api/EasyCodef.java b/src/main/java/io/codef/api/EasyCodef.java
index cf721e7..afb505e 100644
--- a/src/main/java/io/codef/api/EasyCodef.java
+++ b/src/main/java/io/codef/api/EasyCodef.java
@@ -1,16 +1,38 @@
package io.codef.api;
+import io.codef.api.constants.CodefClientType;
+import io.codef.api.dto.EasyCodefRequest;
+import io.codef.api.dto.EasyCodefResponse;
+import io.codef.api.util.RsaUtil;
-public class EasyCodef {
+import java.security.PublicKey;
- private EasyCodefToken easyCodefToken;
- private EasyCodefProperty property;
+public class EasyCodef {
+ private final PublicKey publicKey;
+ private final CodefClientType clientType;
+ private final EasyCodefToken easyCodefToken;
protected EasyCodef(
- EasyCodefToken easyCodefToken,
- EasyCodefProperty property
+ EasyCodefBuilder builder,
+ EasyCodefToken easyCodefToken
) {
+ this.publicKey = RsaUtil.generatePublicKey(builder.getPublicKey());
+ this.clientType = builder.getClientType();
this.easyCodefToken = easyCodefToken;
- this.property = property;
+ }
+
+ public EasyCodefResponse requestProduct(EasyCodefRequest request) {
+ final String requestUrl = generateRequestUrl(request);
+ easyCodefToken.validateAndRefreshToken();
+
+ return EasyCodefConnector.requestProduct(request, easyCodefToken, requestUrl);
+ }
+
+ private String generateRequestUrl(EasyCodefRequest request) {
+ return clientType.getHost() + request.path();
+ }
+
+ public PublicKey getPublicKey() {
+ return publicKey;
}
}
\ No newline at end of file
diff --git a/src/main/java/io/codef/api/EasyCodefBuilder.java b/src/main/java/io/codef/api/EasyCodefBuilder.java
new file mode 100644
index 0000000..f173e6f
--- /dev/null
+++ b/src/main/java/io/codef/api/EasyCodefBuilder.java
@@ -0,0 +1,79 @@
+package io.codef.api;
+
+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;
+ private CodefClientType clientType;
+
+ public static EasyCodefBuilder builder() {
+ return new EasyCodefBuilder();
+ }
+
+ public EasyCodefBuilder publicKey(String publicKey) {
+ this.publicKey = CodefValidator.requireNonNullElseThrow(publicKey, CodefError.INVALID_PUBLIC_KEY);
+ return this;
+ }
+
+ public EasyCodefBuilder clientId(String clientId) {
+ this.clientId = parseUUID(clientId, CodefError.INVALID_CLIENT_ID);
+ return this;
+ }
+
+ public EasyCodefBuilder clientSecret(String clientSecret) {
+ this.clientSecret = parseUUID(clientSecret, CodefError.INVALID_CLIENT_SECRET);
+ return this;
+ }
+
+ public EasyCodefBuilder clientType(CodefClientType clientType) {
+ this.clientType = clientType;
+ return this;
+ }
+
+ public EasyCodef build() {
+ validatePropertyArguments();
+ EasyCodefToken easyCodefToken = new EasyCodefToken(this);
+
+ return new EasyCodef(this, easyCodefToken);
+ }
+
+ private void validatePropertyArguments() {
+ CodefValidator.requireNonNullElseThrow(publicKey, CodefError.NULL_PUBLIC_KEY);
+ CodefValidator.requireNonNullElseThrow(clientId, CodefError.NULL_CLIENT_ID);
+ CodefValidator.requireNonNullElseThrow(clientSecret, CodefError.NULL_CLIENT_SECRET);
+ CodefValidator.requireNonNullElseThrow(clientType, CodefError.NULL_CLIENT_TYPE);
+ }
+
+ private UUID parseUUID(String value, CodefError error) {
+ CodefValidator.requireNonNullElseThrow(value, error);
+ CodefValidator.requireValidUUIDPattern(value, error);
+
+ try {
+ return UUID.fromString(value);
+ } catch (Exception exception) {
+ throw CodefException.of(error, exception);
+ }
+ }
+
+ protected String getPublicKey() {
+ return publicKey;
+ }
+
+ protected UUID getClientId() {
+ return clientId;
+ }
+
+ protected UUID getClientSecret() {
+ return clientSecret;
+ }
+
+ protected CodefClientType getClientType() {
+ return clientType;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/codef/api/EasyCodefConnector.java b/src/main/java/io/codef/api/EasyCodefConnector.java
index 4229a28..0cce18a 100644
--- a/src/main/java/io/codef/api/EasyCodefConnector.java
+++ b/src/main/java/io/codef/api/EasyCodefConnector.java
@@ -1,20 +1,34 @@
package io.codef.api;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import io.codef.api.constants.CodefHost;
+import io.codef.api.constants.CodefPath;
+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 org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.core5.http.io.entity.EntityUtils;
+import org.apache.hc.core5.http.io.entity.StringEntity;
+
+import java.net.URLDecoder;
import static org.apache.hc.client5.http.auth.StandardAuthScheme.BASIC;
+import static org.apache.hc.client5.http.auth.StandardAuthScheme.BEARER;
import static org.apache.hc.core5.http.HttpHeaders.AUTHORIZATION;
final class EasyCodefConnector {
static String issueToken(String codefOAuthToken) {
+ System.out.println("issue Token !!!\n\n");
final String BASIC_TOKEN_FORMAT = BASIC + " %s";
+ final String accessTokenParameter = "access_token";
try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
- HttpPost httpPost = new HttpPost(CodefUrl.CODEF_OAUTH_SERVER + CodefUri.ISSUE_TOKEN);
+ HttpPost httpPost = new HttpPost(CodefHost.CODEF_OAUTH_SERVER + CodefPath.ISSUE_TOKEN);
httpPost.addHeader(AUTHORIZATION, String.format(BASIC_TOKEN_FORMAT, codefOAuthToken));
return httpClient.execute(httpPost, response -> {
@@ -29,8 +43,42 @@ static String issueToken(String codefOAuthToken) {
}
String httpResponse = EntityUtils.toString(response.getEntity());
- return ObjectMapperUtil.getInstance().readTree(httpResponse).path("access_token").asText();
+
+ return JSON.parseObject(httpResponse).getString(accessTokenParameter);
+ });
+ } catch (CodefException exception) {
+ throw exception;
+ } catch (Exception exception) {
+ throw CodefException.of(CodefError.OAUTH_CONNECTION_ERROR, exception);
+ }
+ }
+
+ static EasyCodefResponse requestProduct(
+ EasyCodefRequest request,
+ EasyCodefToken token,
+ String requestUrl
+ ) {
+ final String BEARER_TOKEN_FORMAT = BEARER + " %s";
+
+ try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) {
+ HttpPost httpPost = new HttpPost(requestUrl);
+ httpPost.addHeader(AUTHORIZATION, String.format(BEARER_TOKEN_FORMAT, token.getAccessToken()));
+ String rawRequest = JSON.toJSONString(request.requestParams());
+ httpPost.setEntity(new StringEntity(rawRequest));
+
+ return httpClient.execute(httpPost, response -> {
+ String httpResponse = EntityUtils.toString(response.getEntity());
+ String decodedResponse = URLDecoder.decode(httpResponse, "UTF-8");
+
+ // TODO {"error":"invalid_token","error_description":"Cannot convert access token to JSON","code":"CF-09990","message":"OAUTH2.0 토큰 에러입니다. 메시지를 확인하세요."}
+ JSONObject jsonResponseObject = JSON.parseObject(decodedResponse);
+
+ EasyCodefResponse.Result resultResponse = jsonResponseObject.getJSONObject("result").to(EasyCodefResponse.Result.class);
+ Object dataResponse = jsonResponseObject.getJSONObject("data").to(Object.class);
+ return new EasyCodefResponse(resultResponse, dataResponse);
});
+ } catch (CodefException exception) {
+ throw exception;
} catch (Exception exception) {
throw CodefException.of(CodefError.OAUTH_CONNECTION_ERROR, exception);
}
diff --git a/src/main/java/io/codef/api/EasyCodefProperty.java b/src/main/java/io/codef/api/EasyCodefProperty.java
deleted file mode 100644
index f0c83a1..0000000
--- a/src/main/java/io/codef/api/EasyCodefProperty.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package io.codef.api;
-
-import java.util.UUID;
-
-public class EasyCodefProperty {
-
- private String publicKey;
- private UUID clientId;
- private UUID clientSecret;
-
- public static EasyCodefProperty builder() {
- return new EasyCodefProperty();
- }
-
- public EasyCodefProperty publicKey(String publicKey) {
- this.publicKey = CodefValidator.requireNonNullElseThrow(publicKey, CodefError.INVALID_PUBLIC_KEY);
- return this;
- }
-
- public EasyCodefProperty clientId(String clientId) {
- this.clientId = parseUUID(clientId, CodefError.INVALID_CLIENT_ID);
- return this;
- }
-
- public EasyCodefProperty clientSecret(String clientSecret) {
- this.clientSecret = parseUUID(clientSecret, CodefError.INVALID_CLIENT_SECRET);
- return this;
- }
-
- public EasyCodef build() {
- CodefValidator.requireNonNullElseThrow(publicKey, CodefError.INVALID_PUBLIC_KEY);
- CodefValidator.requireNonNullElseThrow(clientId, CodefError.INVALID_CLIENT_ID);
- CodefValidator.requireNonNullElseThrow(clientSecret, CodefError.INVALID_CLIENT_SECRET);
-
- EasyCodefToken easyCodefToken = EasyCodefToken.of(this);
- return new EasyCodef(easyCodefToken, this);
- }
-
- private UUID parseUUID(
- String value,
- CodefError error
- ) {
- CodefValidator.requireNonNullElseThrow(value, error);
- CodefValidator.requireValidUUIDPattern(value, error);
-
- try {
- return UUID.fromString(value);
- } catch (Exception exception) {
- throw CodefException.of(error, exception);
- }
- }
-
- protected String getPublicKey() {
- return publicKey;
- }
-
- protected String getCombinedKey() {
- final String KEY_FORMAT = "%s:%s";
- return String.format(KEY_FORMAT, clientId, clientSecret);
- }
-}
\ No newline at end of file
diff --git a/src/main/java/io/codef/api/EasyCodefServiceType.java b/src/main/java/io/codef/api/EasyCodefServiceType.java
deleted file mode 100644
index f3cd5fb..0000000
--- a/src/main/java/io/codef/api/EasyCodefServiceType.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package io.codef.api;
-
-public enum EasyCodefServiceType {
- API("https://api.codef.io"),
- DEMO("https://development.codef.io");
-
- private final String uri;
-
- EasyCodefServiceType(String uri) {
- this.uri = uri;
- }
-}
diff --git a/src/main/java/io/codef/api/EasyCodefToken.java b/src/main/java/io/codef/api/EasyCodefToken.java
index 9ecb959..47ff82c 100644
--- a/src/main/java/io/codef/api/EasyCodefToken.java
+++ b/src/main/java/io/codef/api/EasyCodefToken.java
@@ -1,26 +1,32 @@
package io.codef.api;
+import java.time.LocalDateTime;
import java.util.Base64;
public class EasyCodefToken {
+ private final String oauthToken;
+ private String accessToken;
+ private LocalDateTime expiresAt;
- private String codefOAuthToken;
- private String codefAccessToken;
- private EasyCodefServiceType serviceType;
+ protected EasyCodefToken(EasyCodefBuilder builder) {
+ final int VALIDITY_PERIOD_DAYS = 7;
+ final String DELIMITER = ":";
- private EasyCodefToken(
- EasyCodefProperty property
- ) {
- this.codefOAuthToken = generateBase64OAuthToken(property);
- this.codefAccessToken = EasyCodefConnector.issueToken(codefOAuthToken);
+ String combinedKey = String.join(DELIMITER, builder.getClientId().toString(), builder.getClientSecret().toString());
+ this.oauthToken = Base64.getEncoder().encodeToString(combinedKey.getBytes());
+ this.accessToken = EasyCodefConnector.issueToken(oauthToken);
+ this.expiresAt = LocalDateTime.now().plusDays(VALIDITY_PERIOD_DAYS);
}
- protected static EasyCodefToken of(EasyCodefProperty property) {
- return new EasyCodefToken(property);
+ public EasyCodefToken validateAndRefreshToken() {
+ if (expiresAt.isBefore(LocalDateTime.now().plusHours(24))) {
+ this.accessToken = EasyCodefConnector.issueToken(oauthToken);
+ this.expiresAt = LocalDateTime.now().plusDays(7);
+ }
+ return this;
}
- private static String generateBase64OAuthToken(EasyCodefProperty property) {
- String combinedKey = property.getCombinedKey();
- return Base64.getEncoder().encodeToString(combinedKey.getBytes());
+ public String getAccessToken() {
+ return accessToken;
}
}
diff --git a/src/main/java/io/codef/api/ObjectMapperUtil.java b/src/main/java/io/codef/api/ObjectMapperUtil.java
deleted file mode 100644
index c56e29d..0000000
--- a/src/main/java/io/codef/api/ObjectMapperUtil.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package io.codef.api;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-
-public class ObjectMapperUtil {
-
- private ObjectMapperUtil() {
- }
-
- private static class ObjectMapperInitializer {
- private static final ObjectMapper INSTANCE = new ObjectMapper();
- }
-
- public static ObjectMapper getInstance() {
- return ObjectMapperInitializer.INSTANCE;
- }
-}
diff --git a/src/main/java/io/codef/api/constants/CodefClientType.java b/src/main/java/io/codef/api/constants/CodefClientType.java
new file mode 100644
index 0000000..65e112f
--- /dev/null
+++ b/src/main/java/io/codef/api/constants/CodefClientType.java
@@ -0,0 +1,16 @@
+package io.codef.api.constants;
+
+public enum CodefClientType {
+ API(CodefHost.CODEF_API),
+ DEMO(CodefHost.CODEF_API_DEMO);
+
+ private final String host;
+
+ CodefClientType(String host) {
+ this.host = host;
+ }
+
+ public String getHost() {
+ return host;
+ }
+}
diff --git a/src/main/java/io/codef/api/constants/CodefHost.java b/src/main/java/io/codef/api/constants/CodefHost.java
new file mode 100644
index 0000000..d7c8fba
--- /dev/null
+++ b/src/main/java/io/codef/api/constants/CodefHost.java
@@ -0,0 +1,7 @@
+package io.codef.api.constants;
+
+public final class CodefHost {
+ public static final String CODEF_OAUTH_SERVER = "https://oauth.codef.io";
+ public static final String CODEF_API_DEMO = "https://development.codef.io";
+ public static final String CODEF_API = "https://api.codef.io";
+}
diff --git a/src/main/java/io/codef/api/CodefUri.java b/src/main/java/io/codef/api/constants/CodefPath.java
similarity index 62%
rename from src/main/java/io/codef/api/CodefUri.java
rename to src/main/java/io/codef/api/constants/CodefPath.java
index ff6b787..fcb55a0 100644
--- a/src/main/java/io/codef/api/CodefUri.java
+++ b/src/main/java/io/codef/api/constants/CodefPath.java
@@ -1,5 +1,5 @@
-package io.codef.api;
+package io.codef.api.constants;
-public class CodefUri {
+public final class CodefPath {
public static final String ISSUE_TOKEN = "/oauth/token?grant_type=client_credentials&scope=read";
}
diff --git a/src/main/java/io/codef/api/EasyCodefReferenceUrl.java b/src/main/java/io/codef/api/constants/CodefReferenceUrl.java
similarity index 61%
rename from src/main/java/io/codef/api/EasyCodefReferenceUrl.java
rename to src/main/java/io/codef/api/constants/CodefReferenceUrl.java
index 7e10252..483c302 100644
--- a/src/main/java/io/codef/api/EasyCodefReferenceUrl.java
+++ b/src/main/java/io/codef/api/constants/CodefReferenceUrl.java
@@ -1,12 +1,14 @@
-package io.codef.api;
+package io.codef.api.constants;
-public enum EasyCodefReferenceUrl {
+public enum CodefReferenceUrl {
KEY("https://codef.io/account/keys"),
- DEV_GUIDE_REST_API("https://developer.codef.io/common-guide/rest-api");
+ DEV_GUIDE_REST_API("https://developer.codef.io/common-guide/rest-api"),
+ GITHUB("https://github.com/codef-io/easycodef-java-v2"),
+ PRODUCT("https://developer.codef.io/product/api");
private final String url;
- EasyCodefReferenceUrl(String url) {
+ CodefReferenceUrl(String url) {
this.url = url;
}
diff --git a/src/main/java/io/codef/api/dto/EasyCodefRequest.java b/src/main/java/io/codef/api/dto/EasyCodefRequest.java
new file mode 100644
index 0000000..11319b3
--- /dev/null
+++ b/src/main/java/io/codef/api/dto/EasyCodefRequest.java
@@ -0,0 +1,9 @@
+package io.codef.api.dto;
+
+import java.util.HashMap;
+
+public record EasyCodefRequest(
+ String path,
+ HashMap requestParams
+) {
+}
\ No newline at end of file
diff --git a/src/main/java/io/codef/api/dto/EasyCodefRequestBuilder.java b/src/main/java/io/codef/api/dto/EasyCodefRequestBuilder.java
new file mode 100644
index 0000000..509d793
--- /dev/null
+++ b/src/main/java/io/codef/api/dto/EasyCodefRequestBuilder.java
@@ -0,0 +1,88 @@
+package io.codef.api.dto;
+
+import io.codef.api.EasyCodef;
+import io.codef.api.error.CodefError;
+import io.codef.api.error.CodefException;
+import io.codef.api.util.RsaUtil;
+
+import java.util.HashMap;
+
+public class EasyCodefRequestBuilder {
+
+ private final HashMap generalRequestBody;
+ private final HashMap secureRequestBody;
+ private String path;
+ private EasyCodef easyCodef;
+
+ private EasyCodefRequestBuilder() {
+ this.generalRequestBody = new HashMap<>();
+ this.secureRequestBody = new HashMap<>();
+ }
+
+ public static EasyCodefRequestBuilder builder() {
+ return new EasyCodefRequestBuilder();
+ }
+
+ public EasyCodefRequestBuilder organization(Object value) {
+ generalRequestBody.put("organization", value);
+ return this;
+ }
+
+ public EasyCodefRequestBuilder path(String path) {
+ this.path = path;
+
+ if(!path.startsWith("/v1")) {
+ throw CodefException.from(CodefError.INVALID_PATH_REQUESTED);
+ }
+ return this;
+ }
+
+ public EasyCodefRequestBuilder requestBody(
+ String param,
+ Object value
+ ) {
+ generalRequestBody.put(param, value);
+ return this;
+ }
+
+ public EasyCodefRequestBuilder secureRequestBody(
+ String param,
+ String value
+ ) {
+ secureRequestBody.put(param, value);
+ return this;
+ }
+
+ public EasyCodefRequestBuilder secureWith(EasyCodef easyCodef) {
+ this.easyCodef = easyCodef;
+ return this;
+ }
+
+ public EasyCodefRequest build() {
+ final HashMap requests = new HashMap<>();
+ final String EASY_CODEF_JAVA_FLAG = "easyCodefJavaV2";
+
+ if (!secureRequestBody.isEmpty()) {
+ if (easyCodef == null) {
+ throw CodefException.from(CodefError.NEED_TO_SECURE_WITH_METHOD);
+ } else {
+ secureRequestBody.forEach((key, value) -> {
+ String encryptedValue = RsaUtil.encryptRSA(value, easyCodef.getPublicKey());
+ secureRequestBody.put(key, encryptedValue);
+ });
+ }
+ }
+
+ if (path == null) {
+ throw CodefException.from(CodefError.NEED_TO_PATH_METHOD);
+ }
+
+ if (generalRequestBody.get("organization") == null) {
+ throw CodefException.from(CodefError.NEED_TO_ORGANIZATION_METHOD);
+ }
+
+ this.requestBody(EASY_CODEF_JAVA_FLAG, true);
+ this.generalRequestBody.putAll(secureRequestBody);
+ return new EasyCodefRequest(path, generalRequestBody);
+ }
+}
diff --git a/src/main/java/io/codef/api/dto/EasyCodefResponse.java b/src/main/java/io/codef/api/dto/EasyCodefResponse.java
new file mode 100644
index 0000000..2a91a08
--- /dev/null
+++ b/src/main/java/io/codef/api/dto/EasyCodefResponse.java
@@ -0,0 +1,15 @@
+package io.codef.api.dto;
+
+public record EasyCodefResponse(
+ Result result,
+ Object data
+) {
+
+ public record Result(
+ String code,
+ String extraMessage,
+ String message,
+ String transactionId
+ ) {
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/codef/api/error/CodefError.java b/src/main/java/io/codef/api/error/CodefError.java
new file mode 100644
index 0000000..b99c9de
--- /dev/null
+++ b/src/main/java/io/codef/api/error/CodefError.java
@@ -0,0 +1,83 @@
+package io.codef.api.error;
+
+import io.codef.api.constants.CodefReferenceUrl;
+
+public enum CodefError {
+ INVALID_CLIENT_ID(
+ "clientId must be a properly formatted UUID string. Please check your clientId and ensure it matches the UUID format.",
+ CodefReferenceUrl.KEY
+ ),
+ INVALID_CLIENT_SECRET(
+ "clientSecret must be a properly formatted UUID string. Please check your clientSecret and ensure it matches the UUID format.",
+ CodefReferenceUrl.KEY
+ ),
+ INVALID_PUBLIC_KEY(
+ "publicKey is required and cannot be null.",
+ CodefReferenceUrl.KEY
+ ),
+ NULL_CLIENT_ID(
+ "clientId is required and cannot be null.",
+ CodefReferenceUrl.KEY
+ ),
+ NULL_CLIENT_SECRET(
+ "clientSecret is required and cannot be null.",
+ CodefReferenceUrl.KEY
+ ),
+ NULL_PUBLIC_KEY(
+ "publicKey is required and cannot be null.",
+ CodefReferenceUrl.KEY
+ ),
+ NULL_CLIENT_TYPE(
+ "clientType is required and cannot be null.",
+ CodefReferenceUrl.KEY
+ ),
+ OAUTH_UNAUTHORIZED(
+ "Failed to authenticate with the Codef OAuth server (401 Unauthorized). Please verify your clientId and clientSecret values.",
+ CodefReferenceUrl.KEY
+ ),
+ OAUTH_INTERNAL_ERROR(
+ "An error occurred on the Codef OAuth server (500 Internal Server Error). Please try again later, or contact support if the issue persists.",
+ CodefReferenceUrl.KEY
+ ),
+ OAUTH_CONNECTION_ERROR(
+ "The connection to the OAUTH server failed. Please check if `https://oauth.codef.io` is accessible.",
+ CodefReferenceUrl.DEV_GUIDE_REST_API
+ ),
+ RSA_ENCRYPTION_ERROR(
+ "An error occurred on RSA Encryption. Please check your publicKey",
+ CodefReferenceUrl.KEY
+ ),
+ NEED_TO_SECURE_WITH_METHOD(
+ "To encrypt the parameters, you must call the following method: EasyCodefRequestBuilder.builder().secureWith(easyCodef).",
+ CodefReferenceUrl.GITHUB
+ ),
+ NEED_TO_PATH_METHOD(
+ "To request codef product, you must call the following method: EasyCodefRequestBuilder.builder().path(\"/v1/kr/***/***...\").",
+ CodefReferenceUrl.GITHUB
+ ),
+ NEED_TO_ORGANIZATION_METHOD(
+ "To request codef product, you must call the following method: EasyCodefRequestBuilder.builder().organization(\"0xxx\").",
+ CodefReferenceUrl.GITHUB
+ ),
+ INVALID_PATH_REQUESTED(
+ "The path should be requested in the following format: `/v1/kr/***/***/...`",
+ CodefReferenceUrl.PRODUCT
+ );
+
+ private final String message;
+ private final CodefReferenceUrl referenceUrl;
+
+ CodefError(
+ String message,
+ CodefReferenceUrl referenceUrl
+ ) {
+ this.message = message;
+ this.referenceUrl = referenceUrl;
+ }
+
+ private static final String MESSAGE_FORMAT = "[EasyCodef] %s\n%s";
+
+ public String getMessage() {
+ return String.format(MESSAGE_FORMAT, message, referenceUrl.getUrl());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/codef/api/CodefException.java b/src/main/java/io/codef/api/error/CodefException.java
similarity index 97%
rename from src/main/java/io/codef/api/CodefException.java
rename to src/main/java/io/codef/api/error/CodefException.java
index a21f2b5..75a98b1 100644
--- a/src/main/java/io/codef/api/CodefException.java
+++ b/src/main/java/io/codef/api/error/CodefException.java
@@ -1,4 +1,4 @@
-package io.codef.api;
+package io.codef.api.error;
import java.io.Serial;
diff --git a/src/main/java/io/codef/api/util/RsaUtil.java b/src/main/java/io/codef/api/util/RsaUtil.java
new file mode 100644
index 0000000..36b4502
--- /dev/null
+++ b/src/main/java/io/codef/api/util/RsaUtil.java
@@ -0,0 +1,44 @@
+package io.codef.api.util;
+
+import io.codef.api.error.CodefError;
+import io.codef.api.error.CodefException;
+
+import javax.crypto.Cipher;
+import java.security.KeyFactory;
+import java.security.PublicKey;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+
+public class RsaUtil {
+ public static String encryptRSA(String plainText, PublicKey publicKey) {
+ try {
+ Cipher cipher = initializeCipher(publicKey);
+
+ byte[] bytePlain = cipher.doFinal(plainText.getBytes());
+ return Base64.getEncoder().encodeToString(bytePlain);
+ } catch (Exception exception) {
+ throw CodefException.of(CodefError.RSA_ENCRYPTION_ERROR, exception);
+ }
+ }
+
+ public static PublicKey generatePublicKey(String publicKey) {
+ final byte[] decodedPublicKey = Base64.getDecoder().decode(publicKey);
+
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance("RSA");
+ return keyFactory.generatePublic(new X509EncodedKeySpec(decodedPublicKey));
+ } catch (Exception exception) {
+ throw CodefException.of(CodefError.RSA_ENCRYPTION_ERROR, exception);
+ }
+ }
+
+ private static Cipher initializeCipher(PublicKey key) {
+ try {
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ return cipher;
+ } catch (Exception exception) {
+ throw CodefException.of(CodefError.RSA_ENCRYPTION_ERROR, exception);
+ }
+ }
+}
diff --git a/src/test/java/io/codef/api/EasyCodefTokenTest.java b/src/test/java/io/codef/api/EasyCodefTokenTest.java
deleted file mode 100644
index dfce55d..0000000
--- a/src/test/java/io/codef/api/EasyCodefTokenTest.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.codef.api;
-
-import org.junit.jupiter.api.Test;
-
-/**
- * EasyCodef 토큰 발급 사용예시
- */
-public class EasyCodefTokenTest {
-
- @Test
- public void usageExample() {
- }
-}