Skip to content

Commit

Permalink
Integrate elasticsearch
Browse files Browse the repository at this point in the history
  • Loading branch information
rgomezcasas committed Nov 18, 2019
1 parent 2e7ce89 commit 3df63eb
Show file tree
Hide file tree
Showing 10 changed files with 302 additions and 2 deletions.
4 changes: 4 additions & 0 deletions apps/main/resources/.env
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ BACKOFFICE_DATABASE_PORT=3306
BACKOFFICE_DATABASE_NAME=backoffice
BACKOFFICE_DATABASE_USER=root
BACKOFFICE_DATABASE_PASSWORD=
# Elasticsearch
BACKOFFICE_ELASTICSEARCH_HOST=127.0.0.1
BACKOFFICE_ELASTICSEARCH_PORT=9200
BACKOFFICE_ELASTICSEARCH_INDEX_PREFIX=backoffice

# COMMON #
#--------------------------------#
Expand Down
9 changes: 7 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ allprojects {
set('springCloudVersion', "Hoxton.M3")
}

ext {
set('elasticsearch.version', '6.8.4')
}

dependencies {
// Prod
implementation 'org.apache.logging.log4j:log4j-core:2.12.1'
implementation 'org.apache.logging.log4j:log4j-api:2.12.1'
implementation 'com.vlkan.log4j2:log4j2-logstash-layout:0.19'

implementation 'io.github.cdimascio:java-dotenv:5.1.3'

implementation 'org.hibernate:hibernate-core:5.4.5.Final'
Expand All @@ -30,7 +34,8 @@ allprojects {
implementation 'javax.xml.bind:jaxb-api:2.3.1'
implementation 'org.reflections:reflections:0.9.11'
implementation 'org.springframework.boot:spring-boot-starter-amqp'

implementation 'org.elasticsearch.client:elasticsearch-rest-client:6.8.4'
implementation 'org.elasticsearch.client:elasticsearch-rest-high-level-client:6.8.4'
runtime 'mysql:mysql-connector-java:8.0.17'

// Test
Expand Down
31 changes: 31 additions & 0 deletions doc/endpoints/backoffice_frontend.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ELASTIC - Search
POST localhost:9200/backoffice_courses/_search
Content-Type: application/json

{
"query": {
"term": {
"name": "Pepe"
}
}
}

###
# ELASTIC - Search
POST localhost:9200/backoffice_courses/_search
Content-Type: application/json

###

PUT localhost:9200/backoffice_courses/_settings
Content-Type: application/json

{
"index": {
"blocks": {
"read_only_allow_delete": "false"
}
}
}

###
10 changes: 10 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ services:
- RABBITMQ_DEFAULT_USER=codelytv
- RABBITMQ_DEFAULT_PASS=c0d3ly

elasticsearch:
container_name: codelytv-java_ddd_skeleton-elasticsearch
image: 'elasticsearch:6.8.4'
restart: unless-stopped
ports:
- 9300:9300
- 9200:9200
environment:
- discovery.type=single-node

java:
container_name: codelytv-ddd_skeleton-java
build:
Expand Down
20 changes: 20 additions & 0 deletions src/backoffice/main/resources/database/backoffice/courses.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"mappings": {
"courses": {
"properties": {
"id": {
"type": "keyword",
"index": true
},
"name": {
"type": "text",
"index": true
},
"duration": {
"type": "text",
"index": true
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package tv.codely.backoffice.courses.domain;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

public final class BackofficeCourse {
private final String id;
private final String name;
Expand All @@ -17,6 +21,14 @@ public BackofficeCourse(String id, String name, String duration) {
this.duration = duration;
}

public static BackofficeCourse fromPrimitives(Map<String, Object> plainData) {
return new BackofficeCourse(
(String) plainData.get("id"),
(String) plainData.get("name"),
(String) plainData.get("duration")
);
}

public String id() {
return id;
}
Expand All @@ -28,4 +40,12 @@ public String name() {
public String duration() {
return duration;
}

public HashMap<String, Serializable> toPrimitives() {
return new HashMap<String, Serializable>() {{
put("id", id);
put("name", name);
put("duration", duration);
}};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package tv.codely.backoffice.courses.infrastructure.persistence;

import org.springframework.context.annotation.Primary;
import tv.codely.backoffice.courses.domain.BackofficeCourse;
import tv.codely.backoffice.courses.domain.BackofficeCourseRepository;
import tv.codely.shared.domain.Service;
import tv.codely.shared.domain.criteria.Criteria;
import tv.codely.shared.infrastructure.elasticsearch.ElasticsearchClient;
import tv.codely.shared.infrastructure.elasticsearch.ElasticsearchRepository;

import java.util.List;

@Primary
@Service
public final class ElasticsearchBackofficeCourseRepository extends ElasticsearchRepository<BackofficeCourse> implements BackofficeCourseRepository {
public ElasticsearchBackofficeCourseRepository(ElasticsearchClient client) {
super(client);
}

@Override
public void save(BackofficeCourse course) {
persist(course.id(), course.toPrimitives());
}

@Override
public List<BackofficeCourse> searchAll() {
return searchAllInElastic(BackofficeCourse::fromPrimitives);
}

@Override
public List<BackofficeCourse> matching(Criteria criteria) {
return searchAllInElastic(BackofficeCourse::fromPrimitives);
}

@Override
protected String moduleName() {
return "courses";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package tv.codely.backoffice.shared.infrastructure.persistence;

import org.apache.http.HttpHost;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
import tv.codely.shared.infrastructure.config.Parameter;
import tv.codely.shared.infrastructure.config.ParameterNotExist;
import tv.codely.shared.infrastructure.elasticsearch.ElasticsearchClient;

import java.io.IOException;
import java.util.Objects;
import java.util.Scanner;

@Configuration
public class BackofficeElasticsearchConfiguration {
private final Parameter config;
private final ResourcePatternResolver resourceResolver;

public BackofficeElasticsearchConfiguration(Parameter config, ResourcePatternResolver resourceResolver) {
this.config = config;
this.resourceResolver = resourceResolver;
}

@Bean
public ElasticsearchClient elasticsearchClient() throws ParameterNotExist, IOException {
ElasticsearchClient client = new ElasticsearchClient(
new RestHighLevelClient(
RestClient.builder(
new HttpHost(
config.get("BACKOFFICE_ELASTICSEARCH_HOST"),
config.getInt("BACKOFFICE_ELASTICSEARCH_PORT"),
"http"
)
)
),
RestClient.builder(
new HttpHost(
config.get("BACKOFFICE_ELASTICSEARCH_HOST"),
config.getInt("BACKOFFICE_ELASTICSEARCH_PORT"),
"http"
)).build(),
config.get("BACKOFFICE_ELASTICSEARCH_INDEX_PREFIX")
);

generateIndexIfNotExists(client, "backoffice");

return client;
}

private void generateIndexIfNotExists(ElasticsearchClient client, String contextName) throws IOException {
Resource[] jsonsIndexes = resourceResolver.getResources(
String.format("classpath:database/%s/*.json", contextName)
);

for (Resource jsonIndex : jsonsIndexes) {
String indexName = Objects.requireNonNull(jsonIndex.getFilename()).replace(".json", "");

if (!indexExists(indexName, client)) {
String indexBody = new Scanner(
jsonIndex.getInputStream(),
"UTF-8"
).useDelimiter("\\A").next();

Request request = new Request("PUT", indexName);
request.setJsonEntity(indexBody);

client.lowLevelClient().performRequest(request);
}
}
}

private boolean indexExists(String indexName, ElasticsearchClient client) throws IOException {
return client.highLevelClient().indices().exists(new GetIndexRequest(indexName), RequestOptions.DEFAULT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package tv.codely.shared.infrastructure.elasticsearch;

import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;

import java.io.IOException;
import java.io.Serializable;
import java.util.HashMap;

public final class ElasticsearchClient {
private final RestHighLevelClient highLevelClient;
private final RestClient lowLevelClient;
private final String indexPrefix;

public ElasticsearchClient(RestHighLevelClient highLevelClient, RestClient lowLevelClient, String indexPrefix) {
this.highLevelClient = highLevelClient;
this.lowLevelClient = lowLevelClient;
this.indexPrefix = indexPrefix;
}

public RestHighLevelClient highLevelClient() {
return highLevelClient;
}

public RestClient lowLevelClient() {
return lowLevelClient;
}

public String indexPrefix() {
return indexPrefix;
}

public void persist(String moduleName, String id, HashMap<String, Serializable> plainBody) throws IOException {
IndexRequest request = new IndexRequest(indexFor(moduleName), moduleName, id).source(plainBody);

highLevelClient().index(request, RequestOptions.DEFAULT);
}

public String indexFor(String moduleName) {
return String.format("%s_%s", indexPrefix(), moduleName);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package tv.codely.shared.infrastructure.elasticsearch;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;

import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public abstract class ElasticsearchRepository<T> {
private final ElasticsearchClient client;

public ElasticsearchRepository(ElasticsearchClient client) {
this.client = client;
}

abstract protected String moduleName();

protected List<T> searchAllInElastic(Function<Map<String, Object>, T> unserializer) {
SearchRequest request = new SearchRequest(client.indexFor(moduleName()));
try {
SearchResponse response = client.highLevelClient().search(request, RequestOptions.DEFAULT);

return Arrays.stream(response.getHits().getHits())
.map(hit -> unserializer.apply(hit.getSourceAsMap()))
.collect(Collectors.toList());
} catch (IOException e) {
e.printStackTrace();
}

return Collections.emptyList();
}

protected void persist(String id, HashMap<String, Serializable> plainBody) {
try {
client.persist(moduleName(), id, plainBody);
} catch (IOException e) {
e.printStackTrace();
}
}
}

0 comments on commit 3df63eb

Please sign in to comment.