diff --git a/Makefile b/Makefile
index 959d60c7..c312ce16 100644
--- a/Makefile
+++ b/Makefile
@@ -1,25 +1,25 @@
all: build
start:
- @docker compose up -d
+ @docker-compose -f docker-compose.ci.yml up -d
build:
@./gradlew build --warning-mode all
lint:
- @docker exec codelytv-ddd_example-java ./gradlew spotlessCheck
+ @docker exec codely-java_ddd_example-test_server ./gradlew spotlessCheck
run-tests:
@./gradlew test --warning-mode all
test:
- @docker exec codelytv-ddd_example-java ./gradlew test --warning-mode all
+ @docker exec codely-java_ddd_example-test_server ./gradlew test --warning-mode all
run:
@./gradlew :run
ping-mysql:
- @docker exec codelytv-java_ddd_example-mysql mysqladmin --user=root --password= --host "127.0.0.1" ping --silent
+ @docker exec codely-java_ddd_example-mysql mysqladmin --user=root --password= --host "127.0.0.1" ping --silent
# Start the app
start-mooc_backend:
diff --git a/apps/main/resources/.env b/apps/main/resources/.env
index ac2f8345..cd58c259 100644
--- a/apps/main/resources/.env
+++ b/apps/main/resources/.env
@@ -1,8 +1,8 @@
# MOOC #
#--------------------------------#
-MOOC_BACKEND_SERVER_PORT=8081
+MOOC_BACKEND_SERVER_PORT=8030
# MySql
-MOOC_DATABASE_HOST=codelytv-java_ddd_example-mysql
+MOOC_DATABASE_HOST=codely-java_ddd_example-mysql
MOOC_DATABASE_PORT=3306
MOOC_DATABASE_NAME=mooc
MOOC_DATABASE_USER=root
@@ -10,25 +10,25 @@ MOOC_DATABASE_PASSWORD=
# BACKOFFICE #
#--------------------------------#
-BACKOFFICE_FRONTEND_SERVER_PORT=8090
-BACKOFFICE_BACKEND_SERVER_PORT=8091
+BACKOFFICE_BACKEND_SERVER_PORT=8040
+BACKOFFICE_FRONTEND_SERVER_PORT=8041
# MySql
-BACKOFFICE_DATABASE_HOST=codelytv-java_ddd_example-mysql
+BACKOFFICE_DATABASE_HOST=codely-java_ddd_example-mysql
BACKOFFICE_DATABASE_PORT=3306
BACKOFFICE_DATABASE_NAME=backoffice
BACKOFFICE_DATABASE_USER=root
BACKOFFICE_DATABASE_PASSWORD=
# Elasticsearch
-BACKOFFICE_ELASTICSEARCH_HOST=codelytv-java_ddd_example-elasticsearch
+BACKOFFICE_ELASTICSEARCH_HOST=codely-java_ddd_example-elasticsearch
BACKOFFICE_ELASTICSEARCH_PORT=9200
BACKOFFICE_ELASTICSEARCH_INDEX_PREFIX=backoffice
# COMMON #
#--------------------------------#
# RabbitMQ
-RABBITMQ_HOST=codelytv-java_ddd_example-rabbitmq
+RABBITMQ_HOST=codely-java_ddd_example-rabbitmq
RABBITMQ_PORT=5672
-RABBITMQ_LOGIN=codelytv
+RABBITMQ_LOGIN=codely
RABBITMQ_PASSWORD=c0d3ly
RABBITMQ_EXCHANGE=domain_events
RABBITMQ_MAX_RETRIES=5
diff --git a/docker-compose.ci.yml b/docker-compose.ci.yml
new file mode 100755
index 00000000..654ffd12
--- /dev/null
+++ b/docker-compose.ci.yml
@@ -0,0 +1,55 @@
+version: '3'
+
+services:
+ shared_mysql:
+ container_name: codely-java_ddd_example-mysql
+ image: mysql:8
+ platform: linux/amd64
+ ports:
+ - "3306:3306"
+ environment:
+ - MYSQL_ROOT_PASSWORD=
+ - MYSQL_ALLOW_EMPTY_PASSWORD=yes
+ entrypoint:
+ sh -c "
+ echo 'CREATE DATABASE IF NOT EXISTS mooc;CREATE DATABASE IF NOT EXISTS backoffice;' > /docker-entrypoint-initdb.d/init.sql;
+ /usr/local/bin/docker-entrypoint.sh --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
+ "
+ command: ["--default-authentication-plugin=mysql_native_password"]
+
+ shared_rabbitmq:
+ container_name: codely-java_ddd_example-rabbitmq
+ image: 'rabbitmq:3.7-management'
+ platform: linux/amd64
+ restart: unless-stopped
+ ports:
+ - "5630:5672"
+ - "8090:15672"
+ environment:
+ - RABBITMQ_DEFAULT_USER=codely
+ - RABBITMQ_DEFAULT_PASS=c0d3ly
+
+ backoffice_elasticsearch:
+ container_name: codely-java_ddd_example-elasticsearch
+ image: 'elasticsearch:6.8.4'
+ platform: linux/amd64
+ restart: unless-stopped
+ ports:
+ - "9300:9300"
+ - "9200:9200"
+ environment:
+ - discovery.type=single-node
+
+ test_server_java:
+ container_name: codely-java_ddd_example-test_server
+ build:
+ context: .
+ dockerfile: Dockerfile
+ restart: unless-stopped
+ volumes:
+ - .:/app:delegated
+ depends_on:
+ - shared_mysql
+ - shared_rabbitmq
+ - backoffice_elasticsearch
+ tty: true
diff --git a/docker-compose.yml b/docker-compose.yml
index 4d6015c0..3da6fcb7 100755
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,8 +1,8 @@
version: '3'
services:
- mysql:
- container_name: codelytv-java_ddd_example-mysql
+ shared_mysql:
+ container_name: codely-java_ddd_example-mysql
image: mysql:8
platform: linux/amd64
ports:
@@ -17,8 +17,8 @@ services:
"
command: ["--default-authentication-plugin=mysql_native_password"]
- rabbitmq:
- container_name: codelytv-java_ddd_example-rabbitmq
+ shared_rabbitmq:
+ container_name: codely-java_ddd_example-rabbitmq
image: 'rabbitmq:3.7-management'
platform: linux/amd64
restart: unless-stopped
@@ -26,11 +26,11 @@ services:
- "5630:5672"
- "8090:15672"
environment:
- - RABBITMQ_DEFAULT_USER=codelytv
+ - RABBITMQ_DEFAULT_USER=codely
- RABBITMQ_DEFAULT_PASS=c0d3ly
- elasticsearch:
- container_name: codelytv-java_ddd_example-elasticsearch
+ backoffice_elasticsearch:
+ container_name: codely-java_ddd_example-elasticsearch
image: 'elasticsearch:6.8.4'
platform: linux/amd64
restart: unless-stopped
@@ -40,20 +40,74 @@ services:
environment:
- discovery.type=single-node
- java:
- container_name: codelytv-ddd_example-java
+ backoffice_backend_server_java:
+ container_name: codely-java_ddd_example-backoffice_backend_server
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
- platform: linux/amd64
ports:
- - "8030:8080"
+ - "8040:8040"
volumes:
- .:/app:delegated
- env_file:
- - .env
- tty: true
+ - backoffice_backend_gradle_cache:/app/.gradle
+ depends_on:
+ - shared_mysql
+ - shared_rabbitmq
+ - backoffice_elasticsearch
+ command: ["./gradlew", "bootRun", "--args", "backoffice_backend server"]
+
+ backoffice_frontend_server_java:
+ container_name: codely-java_ddd_example-backoffice_frontend_server
+ build:
+ context: .
+ dockerfile: Dockerfile
+ restart: unless-stopped
+ ports:
+ - "8041:8041"
+ volumes:
+ - .:/app:delegated
+ - backoffice_frontend_gradle_cache:/app/.gradle
+ depends_on:
+ - shared_mysql
+ - shared_rabbitmq
+ - backoffice_elasticsearch
+ command: ["./gradlew", "bootRun", "--args", "backoffice_frontend server"]
+
+ mooc_backend_server_java:
+ container_name: codely-java_ddd_example-mooc_backend_server
+ build:
+ context: .
+ dockerfile: Dockerfile
+ restart: unless-stopped
+ ports:
+ - "8030:8030"
+ volumes:
+ - .:/app:delegated
+ - mooc_backend_gradle_cache:/app/.gradle
depends_on:
- - mysql
- - rabbitmq
+ - shared_mysql
+ - shared_rabbitmq
+ - backoffice_elasticsearch
+ command: ["./gradlew", "bootRun", "--args", "mooc_backend server"]
+
+ test_server_java:
+ container_name: codely-java_ddd_example-test_server
+ build:
+ context: .
+ dockerfile: Dockerfile
+ restart: unless-stopped
+ volumes:
+ - .:/app:delegated
+ - test_gradle_cache:/app/.gradle
+ depends_on:
+ - shared_mysql
+ - shared_rabbitmq
+ - backoffice_elasticsearch
+ tty: true
+
+volumes:
+ backoffice_backend_gradle_cache:
+ backoffice_frontend_gradle_cache:
+ mooc_backend_gradle_cache:
+ test_gradle_cache:
diff --git a/src/backoffice/main/tv/codely/backoffice/shared/infrastructure/persistence/BackofficeElasticsearchConfiguration.java b/src/backoffice/main/tv/codely/backoffice/shared/infrastructure/persistence/BackofficeElasticsearchConfiguration.java
index 582309c9..98c0f1ad 100644
--- a/src/backoffice/main/tv/codely/backoffice/shared/infrastructure/persistence/BackofficeElasticsearchConfiguration.java
+++ b/src/backoffice/main/tv/codely/backoffice/shared/infrastructure/persistence/BackofficeElasticsearchConfiguration.java
@@ -10,6 +10,7 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.ResourcePatternResolver;
+import tv.codely.shared.domain.Utils;
import tv.codely.shared.infrastructure.config.Parameter;
import tv.codely.shared.infrastructure.config.ParameterNotExist;
import tv.codely.shared.infrastructure.elasticsearch.ElasticsearchClient;
@@ -29,27 +30,33 @@ public BackofficeElasticsearchConfiguration(Parameter config, ResourcePatternRes
}
@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")
- );
+ public ElasticsearchClient elasticsearchClient() throws ParameterNotExist, Exception {
+ 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");
+ Utils.retry(10, 10000, () -> {
+ try {
+ generateIndexIfNotExists(client, "backoffice");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
return client;
}
diff --git a/src/mooc/main/resources/database/mooc.sql b/src/mooc/main/resources/database/mooc.sql
index 0a92a816..6cc6def8 100644
--- a/src/mooc/main/resources/database/mooc.sql
+++ b/src/mooc/main/resources/database/mooc.sql
@@ -17,6 +17,7 @@ CREATE TABLE IF NOT EXISTS courses_counter (
ENGINE = InnoDB
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_unicode_ci;
+INSERT IGNORE INTO courses_counter (id, total, existing_courses) VALUES ('efbaff16-8fcd-4689-9fc9-ec545d641c46', 0, '[]');
CREATE TABLE IF NOT EXISTS steps (
id CHAR(36) NOT NULL,
diff --git a/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CoursesCounter.hbm.xml b/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CoursesCounter.hbm.xml
index 575782d9..8ea74820 100644
--- a/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CoursesCounter.hbm.xml
+++ b/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CoursesCounter.hbm.xml
@@ -16,7 +16,7 @@
-
+
tv.codely.mooc.courses.domain.CourseId
diff --git a/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CustomTypes.hbm.xml b/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CustomTypes.hbm.xml
deleted file mode 100644
index f80d380b..00000000
--- a/src/mooc/main/tv/codely/mooc/courses_counter/infrastructure/persistence/hibernate/CustomTypes.hbm.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
-
-
diff --git a/src/shared/main/tv/codely/shared/domain/Utils.java b/src/shared/main/tv/codely/shared/domain/Utils.java
index b0b26f75..53dbc3ea 100644
--- a/src/shared/main/tv/codely/shared/domain/Utils.java
+++ b/src/shared/main/tv/codely/shared/domain/Utils.java
@@ -47,4 +47,27 @@ public static String toCamel(String text) {
public static String toCamelFirstLower(String text) {
return CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, text);
}
+
+ public static void retry(int numberOfRetries, long waitTimeInMillis, Runnable operation) throws Exception {
+ for (int i = 0; i < numberOfRetries; i++) {
+ try {
+ operation.run();
+ return; // Success, exit the method
+ } catch (Exception ex) {
+ System.out.println("Retry " + (i + 1) + "/" + numberOfRetries + " fail. Retrying…");
+ if (i >= numberOfRetries - 1) {
+ throw ex;
+ }
+
+ try {
+ Thread.sleep(waitTimeInMillis);
+ } catch (InterruptedException ie) {
+ Thread.currentThread().interrupt();
+
+ throw new Exception("Operation interrupted while retrying", ie);
+ }
+ }
+ }
+ }
+
}
diff --git a/src/shared/main/tv/codely/shared/infrastructure/bus/event/DomainEventSubscriberInformation.java b/src/shared/main/tv/codely/shared/infrastructure/bus/event/DomainEventSubscriberInformation.java
index da88eb38..e14d3d2c 100644
--- a/src/shared/main/tv/codely/shared/infrastructure/bus/event/DomainEventSubscriberInformation.java
+++ b/src/shared/main/tv/codely/shared/infrastructure/bus/event/DomainEventSubscriberInformation.java
@@ -44,6 +44,6 @@ public List> subscribedEvents() {
}
public String formatRabbitMqQueueName() {
- return String.format("codelytv.%s.%s.%s", contextName(), moduleName(), Utils.toSnake(className()));
+ return String.format("codely.%s.%s.%s", contextName(), moduleName(), Utils.toSnake(className()));
}
}
diff --git a/src/shared/main/tv/codely/shared/infrastructure/hibernate/HibernateConfigurationFactory.java b/src/shared/main/tv/codely/shared/infrastructure/hibernate/HibernateConfigurationFactory.java
index 14551810..2dbd1bad 100644
--- a/src/shared/main/tv/codely/shared/infrastructure/hibernate/HibernateConfigurationFactory.java
+++ b/src/shared/main/tv/codely/shared/infrastructure/hibernate/HibernateConfigurationFactory.java
@@ -110,13 +110,19 @@ private List subdirectoriesFor(String contextName) {
}
private String[] mappingFilesIn(String path) {
- String[] files = new File(path).list((current, name) -> new File(current, name).getName().contains(".hbm.xml"));
+ List fileList = new ArrayList<>();
- if (null == files) {
- return new String[0];
- }
+ String[] hbmFiles = new File(path).list((current, name) -> new File(current, name).getName().contains(".hbm.xml"));
+ String[] ormFiles = new File(path).list((current, name) -> new File(current, name).getName().contains(".orm.xml"));
+
+ if (hbmFiles != null) {
+ fileList.addAll(Arrays.asList(hbmFiles));
+ }
+ if (ormFiles != null) {
+ fileList.addAll(Arrays.asList(ormFiles));
+ }
- return files;
+ return fileList.toArray(new String[0]);
}
private Properties hibernateProperties() {
diff --git a/src/shared/main/tv/codely/shared/infrastructure/hibernate/JsonListType.java b/src/shared/main/tv/codely/shared/infrastructure/hibernate/JsonListType.java
index 024f880d..188dd98b 100644
--- a/src/shared/main/tv/codely/shared/infrastructure/hibernate/JsonListType.java
+++ b/src/shared/main/tv/codely/shared/infrastructure/hibernate/JsonListType.java
@@ -19,7 +19,6 @@
import java.util.*;
public class JsonListType implements UserType, DynamicParameterizedType {
- private static final int[] SQL_TYPES = new int[]{Types.LONGVARCHAR};
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
private JavaType valueType = null;
private Class> classType = null;
@@ -44,24 +43,6 @@ public int hashCode(Object x) throws HibernateException {
return Objects.hashCode(x);
}
- @Override
- public Object nullSafeGet(
- ResultSet resultSet,
- int i,
- SharedSessionContractImplementor sharedSessionContractImplementor,
- Object o
- ) throws SQLException {
- try {
- String json = resultSet.getString(i);
- if (json == null) {
- return null;
- }
- return OBJECT_MAPPER.readValue(json, valueType);
- } catch (IOException e) {
- throw new SQLException("Exception deserializing JSON", e);
- }
- }
-
@Override
public void nullSafeSet(
PreparedStatement st,
@@ -72,21 +53,28 @@ public void nullSafeSet(
nullSafeSet(st, value, index);
}
- public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
- String value = rs.getString(names[0]).replace("\"value\"", "").replace("{:", "").replace("}", "");
- Object result = null;
- if (valueType == null) {
- throw new HibernateException("Value type not set.");
- }
- if (value != null && !value.equals("")) {
- try {
- result = OBJECT_MAPPER.readValue(value, valueType);
- } catch (IOException e) {
- throw new HibernateException("Exception deserializing value " + value, e);
- }
- }
- return result;
- }
+ @Override
+ public Object nullSafeGet(
+ ResultSet resultSet,
+ int index,
+ SharedSessionContractImplementor session,
+ Object owner
+ ) throws HibernateException, SQLException {
+
+ String value = resultSet.getString(index).replace("\"value\"", "").replace("{:", "").replace("}", "");
+ Object result = null;
+ if (valueType == null) {
+ throw new HibernateException("Value type not set.");
+ }
+ if (value != null && !value.equals("")) {
+ try {
+ result = OBJECT_MAPPER.readValue(value, valueType);
+ } catch (IOException e) {
+ throw new HibernateException("Exception deserializing value " + value, e);
+ }
+ }
+ return result;
+ }
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
StringWriter sw = new StringWriter();