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 3 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
4 changes: 3 additions & 1 deletion 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 @@ -184,6 +184,8 @@ The Scaffolding Clean Architecture plugin will allow you run 8 tasks:
| mongodb | Mongo Repository | --secret [true-false] |
| asynceventbus | Async Event Bus | |
| restconsumer | Rest Client Consumer | --url [url] |
| redis | Redis Template | --secret [true-false] |
| redisrepository | Redis Repository | --secret [true-false] |
juancgalvis marked this conversation as resolved.
Show resolved Hide resolved

_**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 {
private final Mode 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();
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() {
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,16 @@ public static ModuleFactory getDrivenAdapterFactory(DrivenAdapterType type) thro
return new DrivenAdapterGeneric();
case RESTCONSUMER:
return new DrivenAdapterRestConsumer();
case REDISREPOSITORY:
return new DrivenAdapterRedis(DrivenAdapterRedis.Mode.REPOSITORY);
case REDIS:
return new DrivenAdapterRedis(DrivenAdapterRedis.Mode.TEMPLATE);
default:
throw new InvalidTaskOptionException("Driven Adapter type invalid");
}
}

public enum DrivenAdapterType {
JPA, MONGODB, ASYNCEVENTBUS, GENERIC, RESTCONSUMER
JPA, MONGODB, ASYNCEVENTBUS, GENERIC, RESTCONSUMER, REDISREPOSITORY, REDIS
}
}
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"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package {{package}}.config;

import co.com.bancolombia.commons.secretsmanager.exceptions.SecretException;
import co.com.bancolombia.commons.secretsmanager.manager.GenericManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.ReactiveRedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

@Configuration
public class RedisConfig {

@Bean
public RedisStandaloneConfiguration redisConfig(@Value("${aws.secretName}") String secret, GenericManager manager)
throws SecretException {
// Load secret here
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
// Update values here
return configuration;
}

@Bean
public ReactiveRedisConnectionFactory redisConnectionFactory(RedisStandaloneConfiguration configuration) {
return new LettuceConnectionFactory(configuration);
}
}
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'
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/redis-repository/helper/repository-adapter-operations.java.mustache": "infrastructure/driven-adapters/redis/src/main/java/{{packagePath}}/redis/repository/helper/RepositoryAdapterOperations.java",
"driven-adapter/redis/redis-repository/redis-repository.java.mustache": "infrastructure/driven-adapters/redis/src/main/java/{{packagePath}}/redis/repository/RedisRepository.java",
"driven-adapter/redis/redis-repository/redis-repository-adapter.java.mustache": "infrastructure/driven-adapters/redis/src/main/java/{{packagePath}}/redis/repository/RedisRepositoryAdapter.java",
"driven-adapter/redis/redis-repository/build.gradle.mustache": "infrastructure/driven-adapters/redis/build.gradle"
}
}
Loading