Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Driven adapter client ktor #204

Merged
merged 12 commits into from
Jan 19, 2022
30 changes: 16 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,20 +298,22 @@ The **`generateDrivenAdapter | gda`** task will generate a module in Infrastruct
gradle gda --type [drivenAdapterType]
```

| Reference for **drivenAdapterType** | Name | Additional Options |Java | Kotlin |
|-------------------------------------|--------------------------------|----------------------------------------------------|-------|--------|
| generic | Empty Driven Adapter | --name [name] |☑|☑|
| jpa | JPA Repository | --secret [true-false] |☑|☑|
| mongodb | Mongo Repository | --secret [true-false] |☑|☑|
| asynceventbus | Async Event Bus | |☑|☑|
| restconsumer | Rest Client Consumer | --url [url] |☑|☑|
| redis | Redis | --mode [template-repository] --secret [true-false] |☑|☑|
| rsocket | RSocket Requester | |☑|☑|
| r2dbc | R2dbc Postgresql Client | |☑|☑|
| kms | AWS Key Management Service | |☑|☑|
| secrets | Secrets Manager Bancolombia | |☑|☑|
| s3 | AWS Simple Storage Service | |☑|☑|
| mq | JMS MQ Client to send messages | |☑|☑|
| Reference for **drivenAdapterType** | Name | Additional Options | Java | Kotlin |
|-------------------------------------|-------------------------------------|-------------------------------------|---------|---------|
| generic | Empty Driven Adapter | --name [name] | ☑ | ☑ |
| jpa | JPA Repository | --secret [true-false] | ☑ | ☑ |
| mongodb | Mongo Repository | --secret [true-false] | ☑ | ☑ |
| asynceventbus | Async Event Bus | | ☑ | ☑ |
| restconsumer | Rest Client Consumer | --url [url] | ☑ | ☑ |
| redis | Redis | --mode [template-repository] --secret [true-false] | ☑ | ☑ |
| rsocket | RSocket Requester | | ☑ | ☑ |
| r2dbc | R2dbc Postgresql Client | | ☑ | ☑ |
| kms | AWS Key Management Service | | ☑ | ☑ |
| secrets | Secrets Manager Bancolombia | | ☑ | ☑ |
| s3 | AWS Simple Storage Service | | ☑ | ☑ |
| mq | JMS MQ Client to send messages | | ☑ | ☑ |
| ktor | HTTP client for kotlin | | ☐ | ☑ |


_**This task will generate something like that:**_

Expand Down
20 changes: 10 additions & 10 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,20 +60,20 @@ repositories {
}

dependencies {
api 'com.github.spullara.mustache.java:compiler:0.9.6'
api 'com.fasterxml.jackson.core:jackson-databind:2.11.0'
api 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.11.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.0'
api 'commons-io:commons-io:2.7'
api 'com.github.spullara.mustache.java:compiler:0.9.10'
api 'com.fasterxml.jackson.core:jackson-databind:2.13.1'
api 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.1'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1'
api 'commons-io:commons-io:2.11.0'
api gradleApi()
testImplementation "org.mockito:mockito-core:2.9.0"
testImplementation 'junit:junit:4.12'
testImplementation 'org.mockito:mockito-core:4.2.0'
testImplementation 'junit:junit:4.13.2'
testImplementation gradleTestKit()

compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10'
compileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor 'org.projectlombok:lombok:1.18.22'
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
testImplementation "com.squareup.okhttp3:mockwebserver:4.9.0"
testImplementation 'com.squareup.okhttp3:mockwebserver:4.9.3'
}

gradlePlugin {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,20 @@ public void init() throws IOException {
writeString(new File(projectDir, "settings.gradle"), "");
writeString(
new File(projectDir, "build.gradle"),
"plugins {" + " id('co.com.bancolombia.cleanArchitecture')" + "}");
"plugins {" + " id 'co.com.bancolombia.cleanArchitecture'" + "}");
runner = GradleRunner.create();
runner.forwardOutput();
runner.withPluginClasspath();
}

public void initKotlin() throws IOException {
// Setup the test build
deleteStructure(projectDir.toPath());
Files.createDirectories(projectDir.toPath());
writeString(new File(projectDir, "settings.gradle.kts"), "");
writeString(
new File(projectDir, "build.gradle.kts"),
"plugins {" + " id(\"co.com.bancolombia.cleanArchitecture\")" + "}");
runner = GradleRunner.create();
runner.forwardOutput();
runner.withPluginClasspath();
Expand Down Expand Up @@ -968,6 +981,92 @@ public void shouldUpdateProjectWithOneDependency() {
assertEquals(result.task(":" + task).getOutcome(), TaskOutcome.SUCCESS);
}

@Test
public void canRunTaskGenerateDrivenAdapterKtorClient() throws IOException {
canRunTaskGenerateStructureKotlinWithOutParameters();
String task = "generateDrivenAdapter";
String type = "KTOR";

runner.withArguments(task, "--type=" + type);
runner.withProjectDir(projectDir);
BuildResult result = runner.build();
assertTrue(
new File(
"build/functionalTest/infrastructure/driven-adapters/ktor-client/src/main/kotlin/co/com/bancolombia/client/KtorClient.kt")
.exists());
assertTrue(
new File(
"build/functionalTest/infrastructure/driven-adapters/ktor-client/src/main/kotlin/co/com/bancolombia/client/config/KtorConfig.kt")
.exists());
assertTrue(
new File("build/functionalTest/infrastructure/driven-adapters/ktor-client/build.gradle.kts")
.exists());

assertEquals(result.task(":" + task).getOutcome(), TaskOutcome.SUCCESS);
}

@Test
public void canRunTaskGenerateStructureKotlinWithOutParameters() throws IOException {
initKotlin();
String task = "ca";

runner.withArguments(task, "--language=" + "KOTLIN");
runner.withProjectDir(projectDir);
BuildResult result = runner.build();
// Verify the result
assertTrue(new File("build/functionalTest/README.md").exists());
assertTrue(new File("build/functionalTest/.gitignore").exists());
assertTrue(new File("build/functionalTest/build.gradle.kts").exists());
assertTrue(new File("build/functionalTest/lombok.config").exists());
assertTrue(new File("build/functionalTest/settings.gradle.kts").exists());

assertTrue(new File("build/functionalTest/infrastructure/driven-adapters/").exists());
assertTrue(new File("build/functionalTest/infrastructure/entry-points").exists());
assertTrue(new File("build/functionalTest/infrastructure/helpers").exists());

assertTrue(
new File("build/functionalTest/domain/model/src/main/kotlin/co/com/bancolombia/model")
.exists());
assertTrue(
new File("build/functionalTest/domain/model/src/test/kotlin/co/com/bancolombia/model")
.exists());
assertTrue(new File("build/functionalTest/domain/model/build.gradle.kts").exists());
assertTrue(
new File("build/functionalTest/domain/usecase/src/main/kotlin/co/com/bancolombia/usecase")
.exists());
assertTrue(
new File("build/functionalTest/domain/usecase/src/test/kotlin/co/com/bancolombia/usecase")
.exists());
assertTrue(new File("build/functionalTest/domain/usecase/build.gradle.kts").exists());

assertTrue(new File("build/functionalTest/applications/app-service/build.gradle.kts").exists());
assertTrue(
new File(
"build/functionalTest/applications/app-service/src/main/kotlin/co/com/bancolombia/MainApplication.kt")
.exists());
assertTrue(
new File(
"build/functionalTest/applications/app-service/src/main/kotlin/co/com/bancolombia/config/UseCasesConfig.kt")
.exists());
assertTrue(
new File(
"build/functionalTest/applications/app-service/src/main/kotlin/co/com/bancolombia/config")
.exists());
assertTrue(
new File(
"build/functionalTest/applications/app-service/src/main/resources/application.yaml")
.exists());
assertTrue(
new File(
"build/functionalTest/applications/app-service/src/main/resources/log4j2.properties")
.exists());
assertTrue(
new File("build/functionalTest/applications/app-service/src/test/kotlin/co/com/bancolombia")
.exists());

assertEquals(result.task(":" + task).getOutcome(), TaskOutcome.SUCCESS);
}

private void writeString(File file, String string) throws IOException {
try (Writer writer = new FileWriter(file)) {
writer.write(string);
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/co/com/bancolombia/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
public class Constants {
public static final String PLUGIN_TASK_GROUP = "Clean Architecture";
public static final String SECRETS_VERSION = "3.0.0";
public static final String SPRING_BOOT_VERSION = "2.4.2";
public static final String UNDERTOW_VERSION = "2.4.2";
public static final String JETTY_VERSION = "2.4.2";
public static final String SPRING_BOOT_VERSION = "2.6.2";
public static final String UNDERTOW_VERSION = "2.6.2";
public static final String JETTY_VERSION = "2.6.2";
public static final String SONAR_VERSION = "3.0";
public static final String LOMBOK_VERSION = "1.18.16";
public static final String LOMBOK_VERSION = "1.18.22";
public static final String JACOCO_VERSION = "0.8.5";
public static final String COBERTURA_VERSION = "3.0.0";
public static final String RCOMMONS_ASYNC_COMMONS_STARTER_VERSION = "1.0.3";
public static final String RCOMMONS_OBJECT_MAPPER_VERSION = "0.1.0";
public static final String PLUGIN_VERSION = "2.1.3";
public static final String GRADLE_WRAPPER_VERSION = "6.9.1";
public static final String KOTLIN_VERSION = "1.6.10";
public static final String TOMCAT_EXCLUSION_KOTLIN =
"configurations {\n"
+ "\tall {\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public ModuleBuilder(Project project) {
params.put("projectNameLower", getProject().getName().toLowerCase());
params.put("pluginVersion", Constants.PLUGIN_VERSION);
params.put("springBootVersion", Constants.SPRING_BOOT_VERSION);
params.put("kotlinVersion", Constants.KOTLIN_VERSION);
params.put("sonarVersion", Constants.SONAR_VERSION);
params.put("jacocoVersion", Constants.JACOCO_VERSION);
params.put("gradleVersion", Constants.GRADLE_WRAPPER_VERSION);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package co.com.bancolombia.factory.adapters;

import static co.com.bancolombia.utils.Utils.buildImplementationFromProject;

import co.com.bancolombia.exceptions.CleanException;
import co.com.bancolombia.factory.ModuleBuilder;
import co.com.bancolombia.factory.ModuleFactory;
import co.com.bancolombia.factory.validations.LanguageValidation;
import java.io.IOException;

public class DrivenAdapterKtorClient implements ModuleFactory {

@Override
public void buildModule(ModuleBuilder builder) throws IOException, CleanException {
builder.runValidations(LanguageValidation.class);
builder.appendToSettings("ktor-client", "infrastructure/driven-adapters");
String dependency = buildImplementationFromProject(builder.isKotlin(), ":ktor-client");
builder.appendDependencyToModule("app-service", dependency);
builder.setupFromTemplate("driven-adapter/ktor-client");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public static ModuleFactory getDrivenAdapterFactory(DrivenAdapterType type)
return new DrivenAdapterSecrets();
case MQ:
return new DrivenAdapterMQ();
case KTOR:
return new DrivenAdapterKtorClient();
default:
throw new InvalidTaskOptionException("Driven Adapter type invalid");
}
Expand All @@ -49,6 +51,7 @@ public enum DrivenAdapterType {
KMS,
SECRETS,
S3,
MQ
MQ,
KTOR
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package co.com.bancolombia.factory.validations;

import co.com.bancolombia.exceptions.ValidationException;
import co.com.bancolombia.factory.ModuleBuilder;

public class LanguageValidation implements Validation {

@Override
public void validate(ModuleBuilder moduleBuilder) throws ValidationException {
if (!moduleBuilder.isKotlin()) {
throw new ValidationException("This module is only available for kotlin projects");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencies {
implementation(project(":model"))
implementation("io.ktor:ktor-client-cio:1.6.7")
implementation("io.ktor:ktor-client-auth:1.6.7")
implementation("io.ktor:ktor-client-logging:1.6.7")
}
15 changes: 15 additions & 0 deletions src/main/resources/driven-adapter/ktor-client/definition.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"folders": [
"infrastructure/driven-adapters/ktor-client/src/main/{{language}}/{{packagePath}}/client",
"infrastructure/driven-adapters/ktor-client/src/test/{{language}}/{{packagePath}}/client",
"infrastructure/driven-adapters/ktor-client/src/main/{{language}}/{{packagePath}}/client/config"
],
"files": {},
"java": {
},
"kotlin": {
"driven-adapter/ktor-client/build.gradle.kts.mustache": "infrastructure/driven-adapters/ktor-client/build.gradle.kts",
"driven-adapter/ktor-client/ktor-client.kt.mustache": "infrastructure/driven-adapters/ktor-client/src/main/{{language}}/{{packagePath}}/client/KtorClient.kt",
"driven-adapter/ktor-client/ktor-config.kt.mustache": "infrastructure/driven-adapters/ktor-client/src/main/{{language}}/{{packagePath}}/client/config/KtorConfig.kt"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package {{package}}.client

import io.ktor.client.*
import io.ktor.client.features.*
import io.ktor.client.request.*
import org.springframework.stereotype.Component

@Component
class KtorClient(private val client: HttpClient) {

suspend fun get(id:Long):String = runCatching {
client.get<String>(path = "any/$id")
}.onFailure {
exception ->
if (exception is RedirectResponseException)
when(exception){
is RedirectResponseException -> {/*Status codes 3XX*/}
is ClientRequestException -> {/*status codes 4XX*/ }
is ServerResponseException -> {/*status codes 5XX*/}
}
}.getOrThrow()

suspend fun post(id:Long):String = runCatching {
client.post<String>(path = "any", body = mapOf("id" to id))
}.onFailure {
exception ->
if (exception is RedirectResponseException)
when(exception){
is RedirectResponseException -> {/*Status codes 3XX*/}
is ClientRequestException -> {/*status codes 4XX*/ }
is ServerResponseException -> {/*status codes 5XX*/}
}
}.getOrThrow()

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package {{package}}.client.config

import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.features.*
//import io.ktor.client.features.auth.*
//import io.ktor.client.features.auth.providers.*
import io.ktor.client.features.logging.*
import io.ktor.client.request.*
import io.ktor.http.*
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration


@Configuration
open class KtorConfig {

@Bean
open fun getKtorClient(): HttpClient{
return HttpClient(CIO){
install(HttpTimeout) {
requestTimeoutMillis = 1000
connectTimeoutMillis = 1000
socketTimeoutMillis = 1000
}
defaultRequest {
host = "www.example.com"
url {
protocol = URLProtocol.HTTP
}
}
install(Logging) {
logger = Logger.SIMPLE
level = LogLevel.HEADERS
}
/* install(Auth) {
basic {
credentials {
BasicAuthCredentials(username = "user", password = "foobar")
}
}
digest {
credentials {
DigestAuthCredentials(username = "jetbrains", password = "foobar")
}
realm = "Access to the '/' path"
}
}*/
}
}
}
Loading