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

New Redis Driven Adapter #114

Merged
merged 4 commits into from
Feb 11, 2021
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
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ To use the plugin you need Gradle version 5.6 or later, to start add the followi

```groovy
plugins {
id "co.com.bancolombia.cleanArchitecture" version "1.8.1"
id "co.com.bancolombia.cleanArchitecture" version "1.8.2"
}
```

Expand Down Expand Up @@ -177,13 +177,14 @@ The Scaffolding Clean Architecture plugin will allow you run 8 tasks:
gradle gda --type [drivenAdapterType]
```

| Reference for **drivenAdapterType** | Name | Additional Options |
| ----------------------------------- | -------------------- | --------------------- |
| 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] |
| Reference for **drivenAdapterType** | Name | Additional Options |
| ----------------------------------- | -------------------- | -------------------------------------------------- |
| 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] |

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

Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
package=co.com.bancolombia
systemProp.version=1.8.1
systemProp.version=1.8.2
2 changes: 1 addition & 1 deletion src/main/java/co/com/bancolombia/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class Constants {
public static final String SECRETS_VERSION = "2.1.0";
public static final String RCOMMONS_ASYNC_COMMONS_STARTER_VERSION = "0.4.7";
public static final String RCOMMONS_OBJECT_MAPPER_VERSION = "0.1.0";
public static final String PLUGIN_VERSION = "1.8.1";
public static final String PLUGIN_VERSION = "1.8.2";
public static final String UNDERTOW_VERSION = "2.3.8.RELEASE";
public static final String JETTY_VERSION = "2.3.8.RELEASE";
public static final String TOMCAT_EXCLUSION = "compile.exclude group: \"org.springframework.boot\", module:\"spring-boot-starter-tomcat\"";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ public void buildModule(ModuleBuilder builder) throws IOException, CleanExceptio
builder.loadPackage();
builder.setupFromTemplate("driven-adapter/jpa-repository");
builder.appendToSettings("jpa-repository", "infrastructure/driven-adapters");
builder.appendToSettings("jpa-repository-commons", "infrastructure/helpers");
builder.appendToProperties("spring.datasource")
.put("url", "jdbc:h2:mem:test")
.put("username", "sa")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package co.com.bancolombia.factory.adapters;

import co.com.bancolombia.exceptions.CleanException;
import co.com.bancolombia.factory.ModuleBuilder;
import co.com.bancolombia.factory.ModuleFactory;
import lombok.AllArgsConstructor;
import org.gradle.api.logging.Logger;

import java.io.IOException;

@AllArgsConstructor
public class DrivenAdapterRedis implements ModuleFactory {
public static final String PARAM_MODE = "task-param-mode";

@Override
public void buildModule(ModuleBuilder builder) throws IOException, CleanException {
Logger logger = builder.getProject().getLogger();
builder.loadPackage();
String typePath = getPathType(builder.isReactive());
String modePath = getPathMode((Mode) builder.getParam(PARAM_MODE));
logger.lifecycle("Generating {} in {} mode", typePath, modePath);
builder.setupFromTemplate("driven-adapter/" + typePath + "/" + modePath);
builder.appendToSettings("redis", "infrastructure/driven-adapters");
if (builder.getBooleanParam("include-secret")) {
builder.setupFromTemplate("driven-adapter/" + typePath + "/secret");
} else {
builder.appendToProperties("spring.redis")
.put("host", "localhost")
.put("port", 6379);
}
builder.appendDependencyToModule("app-service", "implementation project(':redis')");
new DrivenAdapterSecrets().buildModule(builder);
}

protected String getPathMode(Mode mode) {
return mode == Mode.REPOSITORY ? "redis-repository" : "redis-template";
}

protected String getPathType(boolean isReactive) {
return isReactive ? "redis-reactive" : "redis";
}

public enum Mode {
REPOSITORY, TEMPLATE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ public static ModuleFactory getDrivenAdapterFactory(DrivenAdapterType type) thro
return new DrivenAdapterGeneric();
case RESTCONSUMER:
return new DrivenAdapterRestConsumer();
case REDIS:
return new DrivenAdapterRedis();
default:
throw new InvalidTaskOptionException("Driven Adapter type invalid");
}
}

public enum DrivenAdapterType {
JPA, MONGODB, ASYNCEVENTBUS, GENERIC, RESTCONSUMER
JPA, MONGODB, ASYNCEVENTBUS, GENERIC, RESTCONSUMER, REDIS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import co.com.bancolombia.Constants.BooleanOption;
import co.com.bancolombia.exceptions.CleanException;
import co.com.bancolombia.factory.ModuleFactory;
import co.com.bancolombia.factory.adapters.DrivenAdapterRedis;
import co.com.bancolombia.factory.adapters.ModuleFactoryDrivenAdapter;
import co.com.bancolombia.factory.adapters.ModuleFactoryDrivenAdapter.DrivenAdapterType;
import co.com.bancolombia.utils.Utils;
Expand All @@ -18,6 +19,7 @@ public class GenerateDrivenAdapterTask extends CleanArchitectureDefaultTask {
private DrivenAdapterType type;
private String name;
private String url = "http://localhost:8080";
private DrivenAdapterRedis.Mode mode = DrivenAdapterRedis.Mode.TEMPLATE;
private BooleanOption secret = BooleanOption.FALSE;

@Option(option = "type", description = "Set type of driven adapter to be generated")
Expand All @@ -35,6 +37,11 @@ public void setUrl(String url) {
this.url = url;
}

@Option(option = "mode", description = "Set template or reposiroty mode when REDIS type")
public void setMode(DrivenAdapterRedis.Mode mode) {
this.mode = mode;
}

@Option(option = "secret", description = "Enable secrets for this driven adapter")
public void setSecret(BooleanOption secret) {
this.secret = secret;
Expand Down Expand Up @@ -62,6 +69,7 @@ public void generateDrivenAdapterTask() throws IOException, CleanException {
logger.lifecycle("Driven Adapter type: {}", type);
builder.addParam("task-param-name", name);
builder.addParam("include-secret", secret == BooleanOption.TRUE);
builder.addParam(DrivenAdapterRedis.PARAM_MODE, mode);
builder.addParam("lombok", builder.isEnableLombok());
builder.addParam("task-param-url", url);
moduleFactory.buildModule(builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class DBSecret {

@Override
public String toString() {
return "MongoDBSecret{" +
return "DBSecret{" +
"url='" + url + '\'' +
", username='" + username + '\'' +
", password='" + password + '\'' +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
dependencies {
compile project(':model')
compile 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
compile 'org.reactivecommons.utils:object-mapper:0.1.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"folders": [
"infrastructure/driven-adapters/redis/src/test/java/{{packagePath}}/redis/repository"
],
"files": {
"driven-adapter/redis-reactive/redis-repository/helper/reactive-repository-adapter-operations.java.mustache": "infrastructure/driven-adapters/redis/src/main/java/{{packagePath}}/redis/repository/helper/ReactiveRepositoryAdapterOperations.java",
"driven-adapter/redis-reactive/redis-repository/reactive-redis-repository.java.mustache": "infrastructure/driven-adapters/redis/src/main/java/{{packagePath}}/redis/repository/ReactiveRedisRepository.java",
"driven-adapter/redis-reactive/redis-repository/reactive-redis-repository-adapter.java.mustache": "infrastructure/driven-adapters/redis/src/main/java/{{packagePath}}/redis/repository/ReactiveRedisRepositoryAdapter.java",
"driven-adapter/redis-reactive/redis-repository/build.gradle.mustache": "infrastructure/driven-adapters/redis/build.gradle"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package {{package}}.redis.repository.helper;

import org.reactivecommons.utils.ObjectMapper;
import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.lang.reflect.ParameterizedType;
import java.util.function.Function;

import static org.springframework.data.domain.Example.of;

public abstract class ReactiveRepositoryAdapterOperations<E, D, I, R extends ReactiveCrudRepository<D, I> & ReactiveQueryByExampleExecutor<D>> {

protected R repository;
protected ObjectMapper mapper;
private final Class<D> dataClass;
private final Function<D, E> toEntityFn;

@SuppressWarnings("unchecked")
public ReactiveRepositoryAdapterOperations(R repository, ObjectMapper mapper, Function<D, E> toEntityFn) {
this.repository = repository;
this.mapper = mapper;
ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
this.dataClass = (Class<D>) genericSuperclass.getActualTypeArguments()[1];
this.toEntityFn = toEntityFn;
}

public Mono<E> save(E entity) {
return Mono.just(entity)
.map(this::toData)
.flatMap(this::saveData)
.map(this::toEntity);
}

public Flux<E> saveAll(Flux<E> entities) {
return doQueryMany(repository.saveAll(entities.map(this::toData)));
}

public Mono<E> findById(I id) {
return doQuery(repository.findById(id));
}

public Flux<E> findByExample(E entity) {
return doQueryMany(repository.findAll(of(toData(entity))));
}

public Mono<Void> deleteById(I id) {
return repository.deleteById(id);
}

public Flux<E> findAll() {
return doQueryMany(repository.findAll());
}

protected Mono<E> doQuery(Mono<D> query) {
return query.map(this::toEntity);
}

protected Flux<E> doQueryMany(Flux<D> query) {
return query.map(this::toEntity);
}

protected Mono<D> saveData(D data) {
return repository.save(data);
}

protected D toData(E entity) {
return mapper.map(entity, dataClass);
}

protected E toEntity(D data) {
return toEntityFn.apply(data);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package {{package}}.redis.repository;

import {{package}}.redis.repository.helper.ReactiveRepositoryAdapterOperations;
import org.reactivecommons.utils.ObjectMapper;
import org.springframework.stereotype.Repository;

@Repository
public class ReactiveRedisRepositoryAdapter extends ReactiveRepositoryAdapterOperations<Object/* change for domain model */, Object/* change for adapter model */, String, ReactiveRedisRepository>
// implements ModelRepository from domain
{

public ReactiveRedisRepositoryAdapter(ReactiveRedisRepository repository, ObjectMapper mapper) {
/**
* Could be use mapper.mapBuilder if your domain model implement builder pattern
* super(repository, mapper, d -> mapper.mapBuilder(d,ObjectModel.ObjectModelBuilder.class).build());
* Or using mapper.map with the class of the object model
*/
super(repository, mapper, d -> mapper.map(d, Object.class/* change for domain model */));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package {{package}}.redis.repository;

import org.springframework.data.repository.query.ReactiveQueryByExampleExecutor;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;

public interface ReactiveRedisRepository extends ReactiveCrudRepository<Object/* change for adapter model */, String>, ReactiveQueryByExampleExecutor<Object/* change for adapter model */> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencies {
compile project(':model')
compile 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
compile 'com.fasterxml.jackson.core:jackson-databind'
compile 'org.reactivecommons.utils:object-mapper:0.1.0'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"folders": [
"infrastructure/driven-adapters/redis/src/test/java/{{packagePath}}/redis/template"
],
"files": {
"driven-adapter/redis-reactive/redis-template/helper/reactive-template-adapter-operations.java.mustache": "infrastructure/driven-adapters/redis/src/main/java/{{packagePath}}/redis/template/helper/ReactiveTemplateAdapterOperations.java",
"driven-adapter/redis-reactive/redis-template/reactive-redis-template-adapter.java.mustache": "infrastructure/driven-adapters/redis/src/main/java/{{packagePath}}/redis/template/ReactiveRedisTemplateAdapter.java",
"driven-adapter/redis-reactive/redis-template/build.gradle.mustache": "infrastructure/driven-adapters/redis/build.gradle"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package {{package}}.redis.template.helper;

import org.reactivecommons.utils.ObjectMapper;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import reactor.core.publisher.Mono;

import java.lang.reflect.ParameterizedType;
import java.util.function.Function;

public abstract class ReactiveTemplateAdapterOperations<E, K, V> {
private final ReactiveRedisTemplate<K, V> template;
private final Class<V> dataClass;
protected ObjectMapper mapper;
private final Function<V, E> toEntityFn;

@SuppressWarnings("unchecked")
public ReactiveTemplateAdapterOperations(ReactiveRedisConnectionFactory connectionFactory, ObjectMapper mapper, Function<V, E> toEntityFn) {
this.mapper = mapper;
ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass();
this.dataClass = (Class<V>) genericSuperclass.getActualTypeArguments()[2];
this.toEntityFn = toEntityFn;

RedisSerializationContext<K, V> serializationContext =
RedisSerializationContext.<K, V>newSerializationContext(new Jackson2JsonRedisSerializer<>(dataClass))
.build();

template = new ReactiveRedisTemplate<>(connectionFactory, serializationContext);
}

public Mono<E> save(K key, E entity) {
return Mono.just(entity)
.map(this::toValue)
.flatMap(value -> template.opsForValue().set(key, value))
.thenReturn(entity);
}

public Mono<E> save(K key, E entity, long expirationMillis) {
return save(key, entity)
.flatMap(v -> template.expire(key, Duration.ofMillis(expirationMillis)).thenReturn(v));
}

public Mono<E> findById(K key) {
return template.opsForValue().get(key)
.map(this::toEntity);
}

protected V toValue(E entity) {
return mapper.map(entity, dataClass);
}

protected E toEntity(V data) {
return data != null ? toEntityFn.apply(data) : null;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package {{package}}.redis.template;

import {{package}}.redis.template.helper.ReactiveTemplateAdapterOperations;
import org.reactivecommons.utils.ObjectMapper;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Component
public class ReactiveRedisTemplateAdapter extends ReactiveTemplateAdapterOperations<Object/* change for domain model */, String, Object/* change for adapter model */>
// implements ModelRepository from domain
{
public ReactiveRedisTemplateAdapter(ReactiveRedisConnectionFactory connectionFactory, ObjectMapper mapper) {
/**
* Could be use mapper.mapBuilder if your domain model implement builder pattern
* super(repository, mapper, d -> mapper.mapBuilder(d,ObjectModel.ObjectModelBuilder.class).build());
* Or using mapper.map with the class of the object model
*/
super(connectionFactory, mapper, d -> mapper.map(d, Object.class/* change for domain model */));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"folders": [],
"files": {
"driven-adapter/redis-reactive/secret/redis-config.java.mustache": "applications/app-service/src/main/java/{{packagePath}}/config/RedisConfig.java"
}
}
Loading