From 877a505e43cc5b780eab8ca410a8c63ce1949486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?MITZY=20VALENCIA=20ORDO=C3=91EZ?= Date: Tue, 28 Apr 2020 16:25:57 -0500 Subject: [PATCH 1/5] A - The entities All details in ANSWERS.md --- ANSWERS.md | 2 +- cars/ford-uml.png | Bin 0 -> 17078 bytes cars/pom.xml | 31 ++++ .../com/mooveit/cars/domain/BaseModel.java | 34 ++++ .../java/com/mooveit/cars/domain/Brand.java | 19 ++ .../java/com/mooveit/cars/domain/Engine.java | 23 +++ .../java/com/mooveit/cars/domain/Model.java | 20 ++ .../com/mooveit/cars/domain/SubModel.java | 21 +++ .../java/com/mooveit/cars/domain/Wheel.java | 22 +++ .../cars/repositories/BrandRepository.java | 9 + .../cars/repositories/EngineRepository.java | 9 + .../cars/repositories/ModelRepository.java | 9 + .../cars/repositories/SubModelRepository.java | 9 + .../cars/repositories/WheelRepository.java | 9 + .../db/changelog/changes/cars1-test.yaml | 174 ++++++++++++++++++ .../db/changelog/db.changelog-master.yaml | 3 + cars/src/main/resources/liquibase.properties | 6 + 17 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 cars/ford-uml.png create mode 100644 cars/src/main/java/com/mooveit/cars/domain/BaseModel.java create mode 100644 cars/src/main/java/com/mooveit/cars/domain/Brand.java create mode 100644 cars/src/main/java/com/mooveit/cars/domain/Engine.java create mode 100644 cars/src/main/java/com/mooveit/cars/domain/Model.java create mode 100644 cars/src/main/java/com/mooveit/cars/domain/SubModel.java create mode 100644 cars/src/main/java/com/mooveit/cars/domain/Wheel.java create mode 100644 cars/src/main/java/com/mooveit/cars/repositories/BrandRepository.java create mode 100644 cars/src/main/java/com/mooveit/cars/repositories/EngineRepository.java create mode 100644 cars/src/main/java/com/mooveit/cars/repositories/ModelRepository.java create mode 100644 cars/src/main/java/com/mooveit/cars/repositories/SubModelRepository.java create mode 100644 cars/src/main/java/com/mooveit/cars/repositories/WheelRepository.java create mode 100644 cars/src/main/resources/db/changelog/changes/cars1-test.yaml create mode 100644 cars/src/main/resources/db/changelog/db.changelog-master.yaml create mode 100644 cars/src/main/resources/liquibase.properties diff --git a/ANSWERS.md b/ANSWERS.md index 9cd3f0d..473e36b 100644 --- a/ANSWERS.md +++ b/ANSWERS.md @@ -1,7 +1,7 @@ # Challenge answers ## A - The entities - +### I modify pom to add liquibase (https://www.liquibase.org/) dependency and the uml model image (ford-uml.png) ## B - Ingest the data ## C - Expose data with a RESTful API diff --git a/cars/ford-uml.png b/cars/ford-uml.png new file mode 100644 index 0000000000000000000000000000000000000000..d554ed67427c6e2422f0b996f19982c3ef583934 GIT binary patch literal 17078 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 1.8 + src/main/resources/db/changelog/db.changelog-master.yaml @@ -49,6 +50,16 @@ spring-boot-starter-test test + + + org.liquibase + liquibase-core + + + org.springframework.boot + spring-boot-devtools + true + @@ -57,6 +68,26 @@ org.springframework.boot spring-boot-maven-plugin + + org.liquibase + liquibase-maven-plugin + + ${diffChangeLogFile} + src/main/resources/liquibase.properties + + + + org.liquibase.ext + liquibase-hibernate5 + 3.6 + + + javax.validation + validation-api + 2.0.1.Final + + + diff --git a/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java b/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java new file mode 100644 index 0000000..f3b6084 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java @@ -0,0 +1,34 @@ +package com.mooveit.cars.domain; + +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.MappedSuperclass; + +import lombok.NonNull; + +@MappedSuperclass +public class BaseModel { + + @Id + @GeneratedValue + private Integer idModel; + + private @NonNull String name; + + private String line; + + private String fromYear; + + private String toYear; + + @ManyToOne + @JoinColumn (name = "wheel") + private @NonNull Wheel wheel; + + @ManyToOne + @JoinColumn (name = "engine") + private @NonNull Engine engine; + +} diff --git a/cars/src/main/java/com/mooveit/cars/domain/Brand.java b/cars/src/main/java/com/mooveit/cars/domain/Brand.java new file mode 100644 index 0000000..7148a6f --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/domain/Brand.java @@ -0,0 +1,19 @@ +package com.mooveit.cars.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +import lombok.Data; +import lombok.NonNull; + +@Data +@Entity +public class Brand { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Integer idBrand; + private @NonNull String name; +} diff --git a/cars/src/main/java/com/mooveit/cars/domain/Engine.java b/cars/src/main/java/com/mooveit/cars/domain/Engine.java new file mode 100644 index 0000000..711a61c --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/domain/Engine.java @@ -0,0 +1,23 @@ +package com.mooveit.cars.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import lombok.Data; +import lombok.NonNull; + +@Data +@Entity +public class Engine { + + @Id + @GeneratedValue + private Integer idEngine; + + private @NonNull Integer power; + + private @NonNull String type; + + +} diff --git a/cars/src/main/java/com/mooveit/cars/domain/Model.java b/cars/src/main/java/com/mooveit/cars/domain/Model.java new file mode 100644 index 0000000..52d3858 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/domain/Model.java @@ -0,0 +1,20 @@ +package com.mooveit.cars.domain; + +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; + +@Data +@EqualsAndHashCode(callSuper=false) +@Entity +public class Model extends BaseModel{ + + @ManyToOne + @JoinColumn (name = "brand") + private @NonNull Brand brand; + +} diff --git a/cars/src/main/java/com/mooveit/cars/domain/SubModel.java b/cars/src/main/java/com/mooveit/cars/domain/SubModel.java new file mode 100644 index 0000000..bb291e3 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/domain/SubModel.java @@ -0,0 +1,21 @@ +package com.mooveit.cars.domain; + +import javax.persistence.Entity; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NonNull; + +@Data +@EqualsAndHashCode(callSuper=false) +@Entity +public class SubModel extends BaseModel { + + @ManyToOne + @JoinColumn (name = "model") + private @NonNull Model model; + + +} diff --git a/cars/src/main/java/com/mooveit/cars/domain/Wheel.java b/cars/src/main/java/com/mooveit/cars/domain/Wheel.java new file mode 100644 index 0000000..1c7ac99 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/domain/Wheel.java @@ -0,0 +1,22 @@ +package com.mooveit.cars.domain; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import lombok.Data; +import lombok.NonNull; + +@Data +@Entity +public class Wheel { + + @Id + @GeneratedValue + private Integer idWheel; + + private @NonNull String size; + + private @NonNull String type; + +} diff --git a/cars/src/main/java/com/mooveit/cars/repositories/BrandRepository.java b/cars/src/main/java/com/mooveit/cars/repositories/BrandRepository.java new file mode 100644 index 0000000..542f9f3 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/repositories/BrandRepository.java @@ -0,0 +1,9 @@ +package com.mooveit.cars.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mooveit.cars.domain.Brand; + +public interface BrandRepository extends JpaRepository { + +} diff --git a/cars/src/main/java/com/mooveit/cars/repositories/EngineRepository.java b/cars/src/main/java/com/mooveit/cars/repositories/EngineRepository.java new file mode 100644 index 0000000..eaa0bb9 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/repositories/EngineRepository.java @@ -0,0 +1,9 @@ +package com.mooveit.cars.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mooveit.cars.domain.Engine; + +public interface EngineRepository extends JpaRepository { + +} diff --git a/cars/src/main/java/com/mooveit/cars/repositories/ModelRepository.java b/cars/src/main/java/com/mooveit/cars/repositories/ModelRepository.java new file mode 100644 index 0000000..61377c1 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/repositories/ModelRepository.java @@ -0,0 +1,9 @@ +package com.mooveit.cars.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mooveit.cars.domain.Model; + +public interface ModelRepository extends JpaRepository { + +} diff --git a/cars/src/main/java/com/mooveit/cars/repositories/SubModelRepository.java b/cars/src/main/java/com/mooveit/cars/repositories/SubModelRepository.java new file mode 100644 index 0000000..58cd826 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/repositories/SubModelRepository.java @@ -0,0 +1,9 @@ +package com.mooveit.cars.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mooveit.cars.domain.SubModel; + +public interface SubModelRepository extends JpaRepository { + +} diff --git a/cars/src/main/java/com/mooveit/cars/repositories/WheelRepository.java b/cars/src/main/java/com/mooveit/cars/repositories/WheelRepository.java new file mode 100644 index 0000000..141bde4 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/repositories/WheelRepository.java @@ -0,0 +1,9 @@ +package com.mooveit.cars.repositories; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.mooveit.cars.domain.Wheel; + +public interface WheelRepository extends JpaRepository { + +} diff --git a/cars/src/main/resources/db/changelog/changes/cars1-test.yaml b/cars/src/main/resources/db/changelog/changes/cars1-test.yaml new file mode 100644 index 0000000..e22a4f6 --- /dev/null +++ b/cars/src/main/resources/db/changelog/changes/cars1-test.yaml @@ -0,0 +1,174 @@ +databaseChangeLog: +- changeSet: + id: 1-1 + author: mitzyvo + changes: + - createTable: + columns: + - column: + constraints: + primaryKey: true + primaryKeyName: brand_id_pk + autoIncrement: true + name: id_brand + type: INT + - column: + constraints: + nullable: false + name: name + type: VARCHAR(50) + tableName: brand + - createTable: + columns: + - column: + autoIncrement: true + constraints: + primaryKey: true + primaryKeyName: engine_id_pk + name: id_engine + type: INT + - column: + constraints: + nullable: false + name: power + type: INT + - column: + constraints: + nullable: false + name: type + type: VARCHAR(50) + tableName: engine + - createTable: + columns: + - column: + autoIncrement: true + constraints: + primaryKey: true + primaryKeyName: wheel_id_pk + name: id_wheel + type: INT + - column: + constraints: + nullable: false + name: size + type: VARCHAR(10) + - column: + constraints: + nullable: false + name: type + type: VARCHAR(50) + tableName: wheel + - createTable: + columns: + - column: + autoIncrement: true + constraints: + primaryKey: true + primaryKeyName: model_id_pk + name: id_model + type: INT + - column: + constraints: + nullable: false + name: name + type: VARCHAR(50) + - column: + name: line + type: VARCHAR(50) + - column: + constraints: + nullable: false + name: from_year + type: VARCHAR(4) + - column: + name: to_year + type: VARCHAR(4) + - column: + name: active + type: BOOLEAN + defaultValueBoolean: true + - column: + constraints: + nullable: false + foreignKeyName: fk_model_brand + referencedTableName: brand + referencedColumnNames: id_brand + validateForeignKey: true + name: brand + type: INT + - column: + constraints: + nullable: false + foreignKeyName: fk_model_engine + referencedTableName: engine + referencedColumnNames: id_engine + validateForeignKey: true + name: engine + type: INT + - column: + constraints: + nullable: false + foreignKeyName: fk_model_wheel + referencedTableName: wheel + referencedColumnNames: id_wheel + validateForeignKey: true + name: wheel + type: INT + tableName: model + - createTable: + columns: + - column: + autoIncrement: true + constraints: + primaryKey: true + primaryKeyName: sub_model_id_pk + name: id_model + type: INT + - column: + constraints: + nullable: false + name: name + type: VARCHAR(50) + - column: + name: line + type: VARCHAR(50) + - column: + constraints: + nullable: false + name: from_year + type: VARCHAR(4) + - column: + name: to_year + type: VARCHAR(4) + - column: + name: active + type: BOOLEAN + defaultValueBoolean: true + - column: + constraints: + nullable: false + foreignKeyName: fk_sub_model_model + referencedTableName: model + referencedColumnNames: id_model + validateForeignKey: true + name: model + type: INT + - column: + constraints: + nullable: false + foreignKeyName: fk_sub_model_engine + referencedTableName: engine + referencedColumnNames: id_engine + validateForeignKey: true + name: engine + type: INT + - column: + constraints: + nullable: false + foreignKeyName: fk_sub_model_wheel + referencedTableName: wheel + referencedColumnNames: id_wheel + validateForeignKey: true + name: wheel + type: INT + tableName: sub_model \ No newline at end of file diff --git a/cars/src/main/resources/db/changelog/db.changelog-master.yaml b/cars/src/main/resources/db/changelog/db.changelog-master.yaml new file mode 100644 index 0000000..837d14c --- /dev/null +++ b/cars/src/main/resources/db/changelog/db.changelog-master.yaml @@ -0,0 +1,3 @@ +databaseChangeLog: + - include: + file: classpath*:db/changelog/changes/cars1-test.yaml \ No newline at end of file diff --git a/cars/src/main/resources/liquibase.properties b/cars/src/main/resources/liquibase.properties new file mode 100644 index 0000000..552d6d0 --- /dev/null +++ b/cars/src/main/resources/liquibase.properties @@ -0,0 +1,6 @@ +changeLogFile=classpath:db/changelog/db.changelog-master.yaml +url=jdbc:h2:mem:carsdb;DB_CLOSE_ON_EXIT=FALSE +username=sa +password= +driver=org.h2.Driver +referenceUrl=hibernate:spring:com.mooveit.cars.domain?dialect=org.hibernate.dialect.H2Dialect&hibernate.physical_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy&hibernate.implicit_naming_strategy=org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy \ No newline at end of file From 82e51f997f22fcd652f64cab7a2519bcb5bc56ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?MITZY=20VALENCIA=20ORDO=C3=91EZ?= Date: Sun, 3 May 2020 14:28:52 -0500 Subject: [PATCH 2/5] B - Ingest the data --- ANSWERS.md | 6 +- cars/pom.xml | 9 +++ .../configurations/LoadDataConfiguration.java | 18 ++++++ .../com/mooveit/cars/domain/BaseModel.java | 11 +++- .../java/com/mooveit/cars/domain/Brand.java | 7 +++ .../java/com/mooveit/cars/domain/Engine.java | 12 +++- .../java/com/mooveit/cars/domain/Model.java | 9 ++- .../com/mooveit/cars/domain/SubModel.java | 4 +- .../java/com/mooveit/cars/domain/Wheel.java | 11 +++- .../com/mooveit/cars/dto/CatalogueDTO.java | 22 +++++++ .../java/com/mooveit/cars/dto/EngineDTO.java | 18 ++++++ .../java/com/mooveit/cars/dto/ModelDTO.java | 36 +++++++++++ .../com/mooveit/cars/dto/SubModelDTO.java | 29 +++++++++ .../java/com/mooveit/cars/dto/WheelDTO.java | 19 ++++++ .../cars/repositories/BrandRepository.java | 4 ++ .../mooveit/cars/service/BrandService.java | 21 +++++++ .../mooveit/cars/service/EngineService.java | 35 +++++++++++ .../cars/service/LoadGeneralDataService.java | 48 ++++++++++++++ .../mooveit/cars/service/ModelService.java | 52 ++++++++++++++++ .../mooveit/cars/service/SubModelService.java | 51 +++++++++++++++ .../mooveit/cars/service/WheelService.java | 35 +++++++++++ .../mooveit/cars/tasks/FordIngesterTask.java | 31 ++++++++-- .../cars/utils/JacksonXmlDataConvert.java | 45 ++++++++++++++ cars/src/main/resources/application.yml | 6 ++ cars/src/main/resources/csv/brands.csv | 3 + .../db/changelog/changes/cars1-test.yaml | 28 +++++++-- .../db/changelog/db.changelog-master.yaml | 3 +- .../cars/service/EngineServiceTest.java | 32 ++++++++++ .../cars/utils/JacksonXmlDataConvertTest.java | 34 ++++++++++ cars/src/test/resources/ford-example.xml | 62 +++++++++++++++++++ 30 files changed, 680 insertions(+), 21 deletions(-) create mode 100644 cars/src/main/java/com/mooveit/cars/configurations/LoadDataConfiguration.java create mode 100644 cars/src/main/java/com/mooveit/cars/dto/CatalogueDTO.java create mode 100644 cars/src/main/java/com/mooveit/cars/dto/EngineDTO.java create mode 100644 cars/src/main/java/com/mooveit/cars/dto/ModelDTO.java create mode 100644 cars/src/main/java/com/mooveit/cars/dto/SubModelDTO.java create mode 100644 cars/src/main/java/com/mooveit/cars/dto/WheelDTO.java create mode 100644 cars/src/main/java/com/mooveit/cars/service/BrandService.java create mode 100644 cars/src/main/java/com/mooveit/cars/service/EngineService.java create mode 100644 cars/src/main/java/com/mooveit/cars/service/LoadGeneralDataService.java create mode 100644 cars/src/main/java/com/mooveit/cars/service/ModelService.java create mode 100644 cars/src/main/java/com/mooveit/cars/service/SubModelService.java create mode 100644 cars/src/main/java/com/mooveit/cars/service/WheelService.java create mode 100644 cars/src/main/java/com/mooveit/cars/utils/JacksonXmlDataConvert.java create mode 100644 cars/src/main/resources/csv/brands.csv create mode 100644 cars/src/test/java/com/mooveit/cars/service/EngineServiceTest.java create mode 100644 cars/src/test/java/com/mooveit/cars/utils/JacksonXmlDataConvertTest.java create mode 100644 cars/src/test/resources/ford-example.xml diff --git a/ANSWERS.md b/ANSWERS.md index 473e36b..3db937a 100644 --- a/ANSWERS.md +++ b/ANSWERS.md @@ -1,8 +1,12 @@ # Challenge answers ## A - The entities -### I modify pom to add liquibase (https://www.liquibase.org/) dependency and the uml model image (ford-uml.png) +- I modify pom to add liquibase (https://www.liquibase.org/) dependency and the uml model image (ford-uml.png). + ## B - Ingest the data +- I add a property to load a couple of brands, besides of create the need it services to process the DTOs +based on the XML file. +- Add the util class JacksonXmlDataConvert to convert XML file data to DTOs ## C - Expose data with a RESTful API diff --git a/cars/pom.xml b/cars/pom.xml index ac2c786..b160124 100644 --- a/cars/pom.xml +++ b/cars/pom.xml @@ -60,6 +60,15 @@ spring-boot-devtools true + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + + org.springframework.boot + spring-boot-configuration-processor + true + diff --git a/cars/src/main/java/com/mooveit/cars/configurations/LoadDataConfiguration.java b/cars/src/main/java/com/mooveit/cars/configurations/LoadDataConfiguration.java new file mode 100644 index 0000000..2b6dfd2 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/configurations/LoadDataConfiguration.java @@ -0,0 +1,18 @@ +package com.mooveit.cars.configurations; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Component +@ConfigurationProperties(prefix="load-data") +public class LoadDataConfiguration { + + private String file; + private String brandName; + +} diff --git a/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java b/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java index f3b6084..c3de0c7 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java +++ b/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java @@ -1,27 +1,32 @@ package com.mooveit.cars.domain; import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.MappedSuperclass; +import lombok.Data; +import lombok.NoArgsConstructor; import lombok.NonNull; +@Data +@NoArgsConstructor @MappedSuperclass public class BaseModel { @Id - @GeneratedValue + @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer idModel; private @NonNull String name; - private String line; - private String fromYear; private String toYear; + + private boolean active; @ManyToOne @JoinColumn (name = "wheel") diff --git a/cars/src/main/java/com/mooveit/cars/domain/Brand.java b/cars/src/main/java/com/mooveit/cars/domain/Brand.java index 7148a6f..b5621fd 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/Brand.java +++ b/cars/src/main/java/com/mooveit/cars/domain/Brand.java @@ -1,14 +1,19 @@ package com.mooveit.cars.domain; +import java.util.Set; + import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.OneToMany; import lombok.Data; +import lombok.NoArgsConstructor; import lombok.NonNull; @Data +@NoArgsConstructor @Entity public class Brand { @@ -16,4 +21,6 @@ public class Brand { @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer idBrand; private @NonNull String name; + @OneToMany + private Set model; } diff --git a/cars/src/main/java/com/mooveit/cars/domain/Engine.java b/cars/src/main/java/com/mooveit/cars/domain/Engine.java index 711a61c..f498af4 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/Engine.java +++ b/cars/src/main/java/com/mooveit/cars/domain/Engine.java @@ -2,22 +2,30 @@ import javax.persistence.Entity; import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import lombok.Data; +import lombok.NoArgsConstructor; import lombok.NonNull; @Data +@NoArgsConstructor @Entity public class Engine { @Id - @GeneratedValue + @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer idEngine; private @NonNull Integer power; private @NonNull String type; - + public Engine(@NonNull Integer power, @NonNull String type) { + super(); + this.power = power; + this.type = type; + } + } diff --git a/cars/src/main/java/com/mooveit/cars/domain/Model.java b/cars/src/main/java/com/mooveit/cars/domain/Model.java index 52d3858..ac53db9 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/Model.java +++ b/cars/src/main/java/com/mooveit/cars/domain/Model.java @@ -1,14 +1,19 @@ package com.mooveit.cars.domain; +import java.util.Set; + import javax.persistence.Entity; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import lombok.NonNull; @Data +@NoArgsConstructor @EqualsAndHashCode(callSuper=false) @Entity public class Model extends BaseModel{ @@ -16,5 +21,7 @@ public class Model extends BaseModel{ @ManyToOne @JoinColumn (name = "brand") private @NonNull Brand brand; - + private @NonNull String type; + @OneToMany + private Set subModels; } diff --git a/cars/src/main/java/com/mooveit/cars/domain/SubModel.java b/cars/src/main/java/com/mooveit/cars/domain/SubModel.java index bb291e3..867ef22 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/SubModel.java +++ b/cars/src/main/java/com/mooveit/cars/domain/SubModel.java @@ -6,9 +6,11 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; import lombok.NonNull; @Data +@NoArgsConstructor @EqualsAndHashCode(callSuper=false) @Entity public class SubModel extends BaseModel { @@ -17,5 +19,5 @@ public class SubModel extends BaseModel { @JoinColumn (name = "model") private @NonNull Model model; - + private String line; } diff --git a/cars/src/main/java/com/mooveit/cars/domain/Wheel.java b/cars/src/main/java/com/mooveit/cars/domain/Wheel.java index 1c7ac99..fbee55a 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/Wheel.java +++ b/cars/src/main/java/com/mooveit/cars/domain/Wheel.java @@ -2,21 +2,30 @@ import javax.persistence.Entity; import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import lombok.Data; +import lombok.NoArgsConstructor; import lombok.NonNull; @Data +@NoArgsConstructor @Entity public class Wheel { @Id - @GeneratedValue + @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer idWheel; private @NonNull String size; private @NonNull String type; + public Wheel(@NonNull String size, @NonNull String type) { + super(); + this.size = size; + this.type = type; + } + } diff --git a/cars/src/main/java/com/mooveit/cars/dto/CatalogueDTO.java b/cars/src/main/java/com/mooveit/cars/dto/CatalogueDTO.java new file mode 100644 index 0000000..98f683a --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/dto/CatalogueDTO.java @@ -0,0 +1,22 @@ +package com.mooveit.cars.dto; + +import java.util.List; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@JacksonXmlRootElement(localName = "CATALOGUE") +public class CatalogueDTO { + + @JacksonXmlProperty(localName = "MODEL") + @JacksonXmlElementWrapper(useWrapping = false) + private List model; +} diff --git a/cars/src/main/java/com/mooveit/cars/dto/EngineDTO.java b/cars/src/main/java/com/mooveit/cars/dto/EngineDTO.java new file mode 100644 index 0000000..cef32fd --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/dto/EngineDTO.java @@ -0,0 +1,18 @@ +package com.mooveit.cars.dto; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class EngineDTO { + + @JacksonXmlProperty(isAttribute = true) + private Integer power; + @JacksonXmlProperty(isAttribute = true) + private String type; +} diff --git a/cars/src/main/java/com/mooveit/cars/dto/ModelDTO.java b/cars/src/main/java/com/mooveit/cars/dto/ModelDTO.java new file mode 100644 index 0000000..b33cef4 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/dto/ModelDTO.java @@ -0,0 +1,36 @@ +package com.mooveit.cars.dto; + +import java.util.List; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class ModelDTO { + + @JacksonXmlProperty(isAttribute = true) + private String name; + @JacksonXmlProperty(isAttribute = true) + private String from; + @JacksonXmlProperty(isAttribute = true) + private String to; + @JacksonXmlProperty(isAttribute = true) + private String type; + @JacksonXmlProperty(isAttribute = true) + private String line; + @JacksonXmlProperty(localName = "ENGINE") + private EngineDTO engine; + @JacksonXmlProperty(localName = "WHEELS") + private WheelDTO wheel; + + @JacksonXmlProperty(localName = "SUBMODELS") + @JacksonXmlElementWrapper(useWrapping = true) + private List subModels; + +} diff --git a/cars/src/main/java/com/mooveit/cars/dto/SubModelDTO.java b/cars/src/main/java/com/mooveit/cars/dto/SubModelDTO.java new file mode 100644 index 0000000..920a248 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/dto/SubModelDTO.java @@ -0,0 +1,29 @@ +package com.mooveit.cars.dto; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class SubModelDTO { + + @JacksonXmlProperty(isAttribute = true) + private String name; + @JacksonXmlProperty(isAttribute = true) + private String from; + @JacksonXmlProperty(isAttribute = true) + private String to; + @JacksonXmlProperty(isAttribute = true) + private String type; + @JacksonXmlProperty(isAttribute = true) + private String line; + @JacksonXmlProperty(localName = "ENGINE") + private EngineDTO engine; + @JacksonXmlProperty(localName = "WHEELS") + private WheelDTO wheel; + +} diff --git a/cars/src/main/java/com/mooveit/cars/dto/WheelDTO.java b/cars/src/main/java/com/mooveit/cars/dto/WheelDTO.java new file mode 100644 index 0000000..10c0576 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/dto/WheelDTO.java @@ -0,0 +1,19 @@ +package com.mooveit.cars.dto; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +public class WheelDTO { + + @JacksonXmlProperty(isAttribute = true) + private String size; + @JacksonXmlProperty(isAttribute = true) + private String type; + +} diff --git a/cars/src/main/java/com/mooveit/cars/repositories/BrandRepository.java b/cars/src/main/java/com/mooveit/cars/repositories/BrandRepository.java index 542f9f3..78c9db4 100644 --- a/cars/src/main/java/com/mooveit/cars/repositories/BrandRepository.java +++ b/cars/src/main/java/com/mooveit/cars/repositories/BrandRepository.java @@ -1,9 +1,13 @@ package com.mooveit.cars.repositories; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import com.mooveit.cars.domain.Brand; public interface BrandRepository extends JpaRepository { + List findByName(String name); + } diff --git a/cars/src/main/java/com/mooveit/cars/service/BrandService.java b/cars/src/main/java/com/mooveit/cars/service/BrandService.java new file mode 100644 index 0000000..89b07fd --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/service/BrandService.java @@ -0,0 +1,21 @@ +package com.mooveit.cars.service; + +import org.springframework.stereotype.Service; + +import com.mooveit.cars.domain.Brand; +import com.mooveit.cars.repositories.BrandRepository; + +@Service +public class BrandService { + + private final BrandRepository brandRepo; + + public BrandService(BrandRepository brandRepo) { + super(); + this.brandRepo = brandRepo; + } + + public Brand findOneBrandByName (String brandName) { + return brandRepo.findByName(brandName).stream().findFirst().orElse(new Brand()); + } +} diff --git a/cars/src/main/java/com/mooveit/cars/service/EngineService.java b/cars/src/main/java/com/mooveit/cars/service/EngineService.java new file mode 100644 index 0000000..5fba663 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/service/EngineService.java @@ -0,0 +1,35 @@ +package com.mooveit.cars.service; + +import java.util.Optional; + +import org.springframework.data.domain.Example; +import org.springframework.stereotype.Service; + +import com.mooveit.cars.domain.Engine; +import com.mooveit.cars.dto.EngineDTO; +import com.mooveit.cars.repositories.EngineRepository; + +@Service +public class EngineService { + + private Engine engine; + private final EngineRepository engineRepo; + + public EngineService(EngineRepository engineRepo) { + super(); + this.engineRepo = engineRepo; + } + + /** + * Method to get data and check for update/insert + * @param dto {@link EngineDTO} + * @return {@link Engine} the found entity + */ + public Engine processEngineEntityFromDto (EngineDTO dto) { + engine = new Engine(dto.getPower(), dto.getType()); + Optional opEngine = engineRepo.findOne(Example.of(engine)); + if(!opEngine.isPresent()) engine = engineRepo.saveAndFlush(engine); + else engine = opEngine.get(); + return engine; + } +} diff --git a/cars/src/main/java/com/mooveit/cars/service/LoadGeneralDataService.java b/cars/src/main/java/com/mooveit/cars/service/LoadGeneralDataService.java new file mode 100644 index 0000000..0fba56d --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/service/LoadGeneralDataService.java @@ -0,0 +1,48 @@ +package com.mooveit.cars.service; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.mooveit.cars.domain.Brand; +import com.mooveit.cars.domain.Model; +import com.mooveit.cars.dto.CatalogueDTO; +import com.mooveit.cars.dto.ModelDTO; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class LoadGeneralDataService { + + private Model model; + + @Autowired + private BrandService brandService; + @Autowired + private ModelService modelService; + @Autowired + private SubModelService subModelService; + + /** + * Method to process {@link CatalogueDTO} object mapped from XML File + * by a given brand + * @param catDTO {@link CatalogueDTO} + * @param brandName {@link String} from application file + */ + public void loadDataFromCatalogueDTO (CatalogueDTO catDTO, String brandName) { + //Get the entity of the brand + log.info("Searching entity of the brand {}",brandName); + Brand brand = brandService.findOneBrandByName(brandName); + //Let's insert the Models + for(ModelDTO modelDto: catDTO.getModel()) { + log.info("processing model {} ",modelDto.getName()); + model = modelService.processModelEntityFromDto(modelDto, brand); + //Now check if has SubModel objects + modelDto.getSubModels().forEach(obModel -> { + log.info("processing subModel {}",obModel.getName()); + subModelService.processSubModelEntityFromDto(obModel, model); + }); + } + log.info("loadData finish..."); + } +} diff --git a/cars/src/main/java/com/mooveit/cars/service/ModelService.java b/cars/src/main/java/com/mooveit/cars/service/ModelService.java new file mode 100644 index 0000000..a19ba95 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/service/ModelService.java @@ -0,0 +1,52 @@ +package com.mooveit.cars.service; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.stereotype.Service; + +import com.mooveit.cars.domain.Brand; +import com.mooveit.cars.domain.Model; +import com.mooveit.cars.dto.ModelDTO; +import com.mooveit.cars.repositories.ModelRepository; + +@Service +public class ModelService { + + private final ModelRepository modelRepo; + private Model model; + + @Autowired + private EngineService engineService; + + @Autowired + private WheelService wheelService; + + public ModelService(ModelRepository modelRepo) { + super(); + this.modelRepo = modelRepo; + } + + /** + * Method to get data and check for update/insert + * @param dto {@link ModelDTO} + * @param brand + * @return {@link Model} the found entity + */ + public Model processModelEntityFromDto (ModelDTO dto, Brand brand) { + model = new Model(); + model.setFromYear(dto.getFrom()); + model.setToYear(dto.getTo()); + model.setType(dto.getType()); + model.setName(dto.getName()); + Optional opModel = modelRepo.findOne(Example.of(model)); + if (!opModel.isPresent()) { + model.setBrand(brand); + model.setEngine(engineService.processEngineEntityFromDto(dto.getEngine())); + model.setWheel(wheelService.processWheelEntityFromDto(dto.getWheel())); + model = modelRepo.saveAndFlush(model); + } else model = opModel.get(); + return model; + } +} diff --git a/cars/src/main/java/com/mooveit/cars/service/SubModelService.java b/cars/src/main/java/com/mooveit/cars/service/SubModelService.java new file mode 100644 index 0000000..59bff31 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/service/SubModelService.java @@ -0,0 +1,51 @@ +package com.mooveit.cars.service; + +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Example; +import org.springframework.stereotype.Service; + +import com.mooveit.cars.domain.Model; +import com.mooveit.cars.domain.SubModel; +import com.mooveit.cars.dto.SubModelDTO; +import com.mooveit.cars.repositories.SubModelRepository; + +@Service +public class SubModelService { + + private SubModel subModel; + private final SubModelRepository subModelRepo; + + @Autowired + private EngineService engineService; + @Autowired + private WheelService wheelService; + + public SubModelService(SubModelRepository subModelRepo) { + super(); + this.subModelRepo = subModelRepo; + } + + /** + * Method to get data and check for update/insert + * @param dto {@link SubModelDTO} + * @param model {@link Model} + * @return {@link SubModel} + */ + public SubModel processSubModelEntityFromDto (SubModelDTO dto, Model model) { + subModel = new SubModel(); + subModel.setLine(dto.getLine()); + subModel.setName(dto.getName()); + Optional opSubModel = subModelRepo.findOne(Example.of(subModel)); + if(!opSubModel.isPresent()) { + subModel.setModel(model); + subModel.setFromYear(dto.getFrom()); + subModel.setToYear(dto.getTo()); + subModel.setEngine(engineService.processEngineEntityFromDto(dto.getEngine())); + subModel.setWheel(wheelService.processWheelEntityFromDto(dto.getWheel())); + subModel = subModelRepo.saveAndFlush(subModel); + } else subModel = opSubModel.get(); + return subModel; + } +} diff --git a/cars/src/main/java/com/mooveit/cars/service/WheelService.java b/cars/src/main/java/com/mooveit/cars/service/WheelService.java new file mode 100644 index 0000000..2a2d8b4 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/service/WheelService.java @@ -0,0 +1,35 @@ +package com.mooveit.cars.service; + +import java.util.Optional; + +import org.springframework.data.domain.Example; +import org.springframework.stereotype.Service; + +import com.mooveit.cars.domain.Wheel; +import com.mooveit.cars.dto.WheelDTO; +import com.mooveit.cars.repositories.WheelRepository; + +@Service +public class WheelService { + + private Wheel wheel; + private final WheelRepository wheelRepo; + + public WheelService(WheelRepository wheelRepo) { + super(); + this.wheelRepo = wheelRepo; + } + + /** + * Method to get data and check for update/insert + * @param dto {@link WheelDTO} + * @return {@link Wheel} the found entity + */ + public Wheel processWheelEntityFromDto(WheelDTO dto) { + wheel = new Wheel(dto.getSize(), dto.getType()); + Optional opWheel = wheelRepo.findOne(Example.of(wheel)); + if(!opWheel.isPresent()) wheel = wheelRepo.saveAndFlush(wheel); + else wheel = opWheel.get(); + return wheel; + } +} diff --git a/cars/src/main/java/com/mooveit/cars/tasks/FordIngesterTask.java b/cars/src/main/java/com/mooveit/cars/tasks/FordIngesterTask.java index a04f791..f9e9fac 100644 --- a/cars/src/main/java/com/mooveit/cars/tasks/FordIngesterTask.java +++ b/cars/src/main/java/com/mooveit/cars/tasks/FordIngesterTask.java @@ -1,15 +1,36 @@ package com.mooveit.cars.tasks; -import lombok.extern.slf4j.Slf4j; +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import com.mooveit.cars.configurations.LoadDataConfiguration; +import com.mooveit.cars.service.LoadGeneralDataService; +import com.mooveit.cars.utils.JacksonXmlDataConvert; + +import lombok.extern.slf4j.Slf4j; + @Slf4j @Service public class FordIngesterTask { - @Scheduled(cron = "${cars.ford.ingester.runCron}") - public void ingestFile() { - log.warn("Not implemented yet."); - } + @Autowired + private LoadGeneralDataService loadGDService; + + @Autowired + private LoadDataConfiguration ldConfig; + + @Scheduled(cron = "${cars.ford.ingester.runCron}") + public void ingestFile() { + log.debug("Starting process ingestFile..."); + try { + loadGDService.loadDataFromCatalogueDTO( + JacksonXmlDataConvert.getInstance().getFordDataXml(ldConfig.getFile()), ldConfig.getBrandName()); + } catch (IOException e) { + log.error("Error reading file ->", e); + } + log.debug("Task ingestFile finish"); + } } diff --git a/cars/src/main/java/com/mooveit/cars/utils/JacksonXmlDataConvert.java b/cars/src/main/java/com/mooveit/cars/utils/JacksonXmlDataConvert.java new file mode 100644 index 0000000..a11c507 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/utils/JacksonXmlDataConvert.java @@ -0,0 +1,45 @@ +package com.mooveit.cars.utils; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; + +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.mooveit.cars.dto.CatalogueDTO; + +public class JacksonXmlDataConvert { + + public static JacksonXmlDataConvert getInstance() { + return new JacksonXmlDataConvert(); + } + /** + * Method to process xml data into a CatalogueDTO + * with Jackson lib + * @param url XmlFile directory + * @return {@link CatalogueDTO} + * @throws FileNotFoundException + * @throws IOException + */ + public CatalogueDTO getFordDataXml (String url) throws FileNotFoundException, IOException { + File file = new File(url); + XmlMapper xmlMapper = new XmlMapper(); + String xml = inputStreamToString(new FileInputStream(file)); + CatalogueDTO catalogueData = xmlMapper.readValue(xml, CatalogueDTO.class); + return catalogueData; + } + + public String inputStreamToString(InputStream is) throws IOException { + StringBuilder sb = new StringBuilder(); + String line; + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + while ((line = br.readLine()) != null) { + sb.append(line); + } + br.close(); + return sb.toString(); + } +} diff --git a/cars/src/main/resources/application.yml b/cars/src/main/resources/application.yml index 436f591..9865e49 100644 --- a/cars/src/main/resources/application.yml +++ b/cars/src/main/resources/application.yml @@ -12,3 +12,9 @@ spring: jpa: database-platform: 'org.hibernate.dialect.H2Dialect' h2.console.enabled: true + +load-data: + file: + src/main/resources/ford-example.xml + brandName: + ford diff --git a/cars/src/main/resources/csv/brands.csv b/cars/src/main/resources/csv/brands.csv new file mode 100644 index 0000000..9a1809d --- /dev/null +++ b/cars/src/main/resources/csv/brands.csv @@ -0,0 +1,3 @@ +name +ford +chevrolet diff --git a/cars/src/main/resources/db/changelog/changes/cars1-test.yaml b/cars/src/main/resources/db/changelog/changes/cars1-test.yaml index e22a4f6..b6509dc 100644 --- a/cars/src/main/resources/db/changelog/changes/cars1-test.yaml +++ b/cars/src/main/resources/db/changelog/changes/cars1-test.yaml @@ -37,7 +37,7 @@ databaseChangeLog: nullable: false name: type type: VARCHAR(50) - tableName: engine + tableName: engine - createTable: columns: - column: @@ -57,7 +57,7 @@ databaseChangeLog: nullable: false name: type type: VARCHAR(50) - tableName: wheel + tableName: wheel - createTable: columns: - column: @@ -73,7 +73,7 @@ databaseChangeLog: name: name type: VARCHAR(50) - column: - name: line + name: type type: VARCHAR(50) - column: constraints: @@ -133,8 +133,6 @@ databaseChangeLog: name: line type: VARCHAR(50) - column: - constraints: - nullable: false name: from_year type: VARCHAR(4) - column: @@ -171,4 +169,22 @@ databaseChangeLog: validateForeignKey: true name: wheel type: INT - tableName: sub_model \ No newline at end of file + tableName: sub_model +- changeSet: + id: 1-2 + author: mitzyvo + changes: + - loadData: + columns: + - column: + name: name + type: STRING + commentLineStartsWith: A String + encoding: UTF-8 + file: csv/brands.csv + quotchar: '''' + relativeToChangelogFile: false + separator: ',' + tableName: brand + usePreparedStatements: true + \ No newline at end of file diff --git a/cars/src/main/resources/db/changelog/db.changelog-master.yaml b/cars/src/main/resources/db/changelog/db.changelog-master.yaml index 837d14c..83d4224 100644 --- a/cars/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/cars/src/main/resources/db/changelog/db.changelog-master.yaml @@ -1,3 +1,4 @@ databaseChangeLog: - include: - file: classpath*:db/changelog/changes/cars1-test.yaml \ No newline at end of file + file: db/changelog/changes/cars1-test.yaml + \ No newline at end of file diff --git a/cars/src/test/java/com/mooveit/cars/service/EngineServiceTest.java b/cars/src/test/java/com/mooveit/cars/service/EngineServiceTest.java new file mode 100644 index 0000000..61adab2 --- /dev/null +++ b/cars/src/test/java/com/mooveit/cars/service/EngineServiceTest.java @@ -0,0 +1,32 @@ +package com.mooveit.cars.service; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.mooveit.cars.domain.Engine; +import com.mooveit.cars.dto.EngineDTO; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class EngineServiceTest { + + @Autowired + private EngineService engineService; + private EngineDTO engineDTO; + + @Test + public void testProcessEngineEntityFromDto() { + engineDTO = new EngineDTO(); + engineDTO.setPower(1000); + engineDTO.setType("GAS"); + Engine engine = engineService.processEngineEntityFromDto(engineDTO); + assertNotNull(engine); + assertEquals(engineDTO.getType(), engine.getType()); + } + +} diff --git a/cars/src/test/java/com/mooveit/cars/utils/JacksonXmlDataConvertTest.java b/cars/src/test/java/com/mooveit/cars/utils/JacksonXmlDataConvertTest.java new file mode 100644 index 0000000..461151d --- /dev/null +++ b/cars/src/test/java/com/mooveit/cars/utils/JacksonXmlDataConvertTest.java @@ -0,0 +1,34 @@ +package com.mooveit.cars.utils; + +import static org.junit.Assert.*; + +import java.io.FileNotFoundException; +import java.io.IOException; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import com.mooveit.cars.dto.CatalogueDTO; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class JacksonXmlDataConvertTest { + + @Test + public void testGetFordDataXml() { + JacksonXmlDataConvert mapper = new JacksonXmlDataConvert(); + try { + String url = "src/test/resources/ford-example.xml"; + CatalogueDTO result = mapper.getFordDataXml(url); + assertNotNull(result); + assertTrue(result.getModel().get(0).getName().equals("Aspire")); + } catch (FileNotFoundException e) { + fail("Something go wrong with file location..."); + } catch (IOException e) { + fail("Something go wrong while reading the file..."); + } + } + +} diff --git a/cars/src/test/resources/ford-example.xml b/cars/src/test/resources/ford-example.xml new file mode 100644 index 0000000..c852dae --- /dev/null +++ b/cars/src/test/resources/ford-example.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 88098ca55710d5582fc82a65ec552842ba0604b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?MITZY=20VALENCIA=20ORDO=C3=91EZ?= Date: Sun, 3 May 2020 17:26:37 -0500 Subject: [PATCH 3/5] C - Expose data with a RESTful API --- ANSWERS.md | 1 + cars/pom.xml | 1 + .../cars/controllers/SubModelController.java | 31 +++++++++ .../com/mooveit/cars/domain/BaseModel.java | 2 + .../java/com/mooveit/cars/domain/Brand.java | 3 + .../java/com/mooveit/cars/domain/Model.java | 5 ++ .../com/mooveit/cars/domain/SubModel.java | 3 + .../mooveit/cars/dto/DefaultMessageDTO.java | 23 +++++++ .../cars/repositories/SubModelRepository.java | 4 ++ .../mooveit/cars/service/SubModelService.java | 44 ++++++++++++- .../controllers/SubModelControllerTest.java | 66 +++++++++++++++++++ .../cars/service/SubModelServiceTest.java | 33 ++++++++++ 12 files changed, 215 insertions(+), 1 deletion(-) create mode 100644 cars/src/main/java/com/mooveit/cars/controllers/SubModelController.java create mode 100644 cars/src/main/java/com/mooveit/cars/dto/DefaultMessageDTO.java create mode 100644 cars/src/test/java/com/mooveit/cars/controllers/SubModelControllerTest.java create mode 100644 cars/src/test/java/com/mooveit/cars/service/SubModelServiceTest.java diff --git a/ANSWERS.md b/ANSWERS.md index 3db937a..899c0f9 100644 --- a/ANSWERS.md +++ b/ANSWERS.md @@ -9,6 +9,7 @@ based on the XML file. - Add the util class JacksonXmlDataConvert to convert XML file data to DTOs ## C - Expose data with a RESTful API +- Added Jackson annotation to support bidirectional relationships and get the entity as a json object ## D - Adding images diff --git a/cars/pom.xml b/cars/pom.xml index b160124..30affe4 100644 --- a/cars/pom.xml +++ b/cars/pom.xml @@ -80,6 +80,7 @@ org.liquibase liquibase-maven-plugin + 3.6.3 ${diffChangeLogFile} src/main/resources/liquibase.properties diff --git a/cars/src/main/java/com/mooveit/cars/controllers/SubModelController.java b/cars/src/main/java/com/mooveit/cars/controllers/SubModelController.java new file mode 100644 index 0000000..c0a1bf1 --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/controllers/SubModelController.java @@ -0,0 +1,31 @@ +package com.mooveit.cars.controllers; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.mooveit.cars.service.SubModelService; + +@RestController +@RequestMapping("/cars") +public class SubModelController { + + private final SubModelService modelService; + + public SubModelController(SubModelService modelService) { + super(); + this.modelService = modelService; + } + + @GetMapping("/by_id") + public Object getCarModelById(@RequestParam(value = "id", defaultValue = "0") Integer id) { + return modelService.getModelById(id); + } + + @GetMapping("/by_brand") + public Object getCarsByBrand (@RequestParam(value = "brandName") String brandName) { + return modelService.getAllModelsByBrandName(brandName); + } + +} diff --git a/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java b/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java index c3de0c7..582282c 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java +++ b/cars/src/main/java/com/mooveit/cars/domain/BaseModel.java @@ -1,5 +1,6 @@ package com.mooveit.cars.domain; +import javax.persistence.Column; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @@ -26,6 +27,7 @@ public class BaseModel { private String toYear; + @Column(columnDefinition = "boolean default true") private boolean active; @ManyToOne diff --git a/cars/src/main/java/com/mooveit/cars/domain/Brand.java b/cars/src/main/java/com/mooveit/cars/domain/Brand.java index b5621fd..e022647 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/Brand.java +++ b/cars/src/main/java/com/mooveit/cars/domain/Brand.java @@ -8,6 +8,8 @@ import javax.persistence.Id; import javax.persistence.OneToMany; +import com.fasterxml.jackson.annotation.JsonBackReference; + import lombok.Data; import lombok.NoArgsConstructor; import lombok.NonNull; @@ -21,6 +23,7 @@ public class Brand { @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer idBrand; private @NonNull String name; + @JsonBackReference @OneToMany private Set model; } diff --git a/cars/src/main/java/com/mooveit/cars/domain/Model.java b/cars/src/main/java/com/mooveit/cars/domain/Model.java index ac53db9..6855b51 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/Model.java +++ b/cars/src/main/java/com/mooveit/cars/domain/Model.java @@ -7,6 +7,9 @@ import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonManagedReference; + import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -18,10 +21,12 @@ @Entity public class Model extends BaseModel{ + @JsonManagedReference @ManyToOne @JoinColumn (name = "brand") private @NonNull Brand brand; private @NonNull String type; + @JsonBackReference @OneToMany private Set subModels; } diff --git a/cars/src/main/java/com/mooveit/cars/domain/SubModel.java b/cars/src/main/java/com/mooveit/cars/domain/SubModel.java index 867ef22..adb9d77 100644 --- a/cars/src/main/java/com/mooveit/cars/domain/SubModel.java +++ b/cars/src/main/java/com/mooveit/cars/domain/SubModel.java @@ -4,6 +4,8 @@ import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; +import com.fasterxml.jackson.annotation.JsonManagedReference; + import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -15,6 +17,7 @@ @Entity public class SubModel extends BaseModel { + @JsonManagedReference @ManyToOne @JoinColumn (name = "model") private @NonNull Model model; diff --git a/cars/src/main/java/com/mooveit/cars/dto/DefaultMessageDTO.java b/cars/src/main/java/com/mooveit/cars/dto/DefaultMessageDTO.java new file mode 100644 index 0000000..9db424f --- /dev/null +++ b/cars/src/main/java/com/mooveit/cars/dto/DefaultMessageDTO.java @@ -0,0 +1,23 @@ +package com.mooveit.cars.dto; + +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@NoArgsConstructor +@Getter +@Setter +@ToString +public class DefaultMessageDTO { + + private String message; + private boolean error; + + public DefaultMessageDTO(String message, boolean error) { + super(); + this.message = message; + this.error = error; + } + +} diff --git a/cars/src/main/java/com/mooveit/cars/repositories/SubModelRepository.java b/cars/src/main/java/com/mooveit/cars/repositories/SubModelRepository.java index 58cd826..49f678d 100644 --- a/cars/src/main/java/com/mooveit/cars/repositories/SubModelRepository.java +++ b/cars/src/main/java/com/mooveit/cars/repositories/SubModelRepository.java @@ -1,9 +1,13 @@ package com.mooveit.cars.repositories; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; +import com.mooveit.cars.domain.Brand; import com.mooveit.cars.domain.SubModel; public interface SubModelRepository extends JpaRepository { + List findAllByModelBrand (Brand brand); } diff --git a/cars/src/main/java/com/mooveit/cars/service/SubModelService.java b/cars/src/main/java/com/mooveit/cars/service/SubModelService.java index 59bff31..102ed42 100644 --- a/cars/src/main/java/com/mooveit/cars/service/SubModelService.java +++ b/cars/src/main/java/com/mooveit/cars/service/SubModelService.java @@ -1,13 +1,16 @@ package com.mooveit.cars.service; +import java.util.List; import java.util.Optional; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Example; import org.springframework.stereotype.Service; +import com.mooveit.cars.domain.Brand; import com.mooveit.cars.domain.Model; import com.mooveit.cars.domain.SubModel; +import com.mooveit.cars.dto.DefaultMessageDTO; import com.mooveit.cars.dto.SubModelDTO; import com.mooveit.cars.repositories.SubModelRepository; @@ -15,12 +18,16 @@ public class SubModelService { private SubModel subModel; + private DefaultMessageDTO dmDTO; + private Optional opSubModel; private final SubModelRepository subModelRepo; @Autowired private EngineService engineService; @Autowired private WheelService wheelService; + @Autowired + private BrandService brandService; public SubModelService(SubModelRepository subModelRepo) { super(); @@ -37,7 +44,7 @@ public SubModel processSubModelEntityFromDto (SubModelDTO dto, Model model) { subModel = new SubModel(); subModel.setLine(dto.getLine()); subModel.setName(dto.getName()); - Optional opSubModel = subModelRepo.findOne(Example.of(subModel)); + opSubModel = subModelRepo.findOne(Example.of(subModel)); if(!opSubModel.isPresent()) { subModel.setModel(model); subModel.setFromYear(dto.getFrom()); @@ -48,4 +55,39 @@ public SubModel processSubModelEntityFromDto (SubModelDTO dto, Model model) { } else subModel = opSubModel.get(); return subModel; } + + /** + * Method to consult a car model by id + * @param id + * @return {@link DefaultMessageDTO} if does not exit or the entity founded + */ + public Object getModelById (Integer id) { + opSubModel = subModelRepo.findById(id); + if (opSubModel.isPresent()) { + return opSubModel.get(); + } else { + dmDTO = new DefaultMessageDTO("The car with id "+id+" does not exist",false); + return dmDTO; + } + } + + /** + * Method to get all the cars by the brand name + * @param brandName + * @return {@link DefaultMessageDTO} if does not exit or the list entity + */ + public Object getAllModelsByBrandName (String brandName) { + Brand brand = brandService.findOneBrandByName(brandName); + if (brand.getIdBrand() != null) { + List listModel = subModelRepo.findAllByModelBrand(brand); + if (listModel.isEmpty()) { + dmDTO = new DefaultMessageDTO("The cars for the brand "+brandName+" does not exist",false); + return dmDTO; + } + return listModel; + } else { + dmDTO = new DefaultMessageDTO("The brand "+brandName+" was not identify",false); + return dmDTO; + } + } } diff --git a/cars/src/test/java/com/mooveit/cars/controllers/SubModelControllerTest.java b/cars/src/test/java/com/mooveit/cars/controllers/SubModelControllerTest.java new file mode 100644 index 0000000..b93d5c3 --- /dev/null +++ b/cars/src/test/java/com/mooveit/cars/controllers/SubModelControllerTest.java @@ -0,0 +1,66 @@ +package com.mooveit.cars.controllers; + +import static org.junit.Assert.fail; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; + +import com.mooveit.cars.service.SubModelService; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SubModelControllerTest { + + private MockMvc restMvc; + + @Autowired + private HttpMessageConverter[] httpMessageConverters; + + @Autowired + private SubModelService modelService; + + @Before + public void setup() { + MockitoAnnotations.initMocks(this); + SubModelController modelController = new SubModelController(modelService); + this.restMvc = MockMvcBuilders.standaloneSetup(modelController).setMessageConverters(httpMessageConverters) + .build(); + } + + @Test + public void testGetCarModelById() { + try { + restMvc.perform(get("/cars/by_id?id=1") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(print()); + } catch (Exception e) { + fail("Something go wrong calling the service "); + } + } + + @Test + public void testGetCarsByBrand() { + try { + restMvc.perform(get("/cars/by_brand?brandName=ford") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andDo(print()); + } catch (Exception e) { + fail("Something go wrong calling the service "); + } + } + +} diff --git a/cars/src/test/java/com/mooveit/cars/service/SubModelServiceTest.java b/cars/src/test/java/com/mooveit/cars/service/SubModelServiceTest.java new file mode 100644 index 0000000..0c30131 --- /dev/null +++ b/cars/src/test/java/com/mooveit/cars/service/SubModelServiceTest.java @@ -0,0 +1,33 @@ +package com.mooveit.cars.service; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class SubModelServiceTest { + + @Autowired + private SubModelService modelService; + + @Test + public void testGetModelById() { + Object response = modelService.getModelById(10000); + assertNotNull(response); + assertTrue(response.getClass().getName().equals("com.mooveit.cars.dto.DefaultMessageDTO")); + } + + @Test + public void testGetAllModelsByBrandName() { + Object listModel = modelService.getAllModelsByBrandName("kawasaki"); + assertNotNull(listModel); + assertTrue(listModel.getClass().getName().equals("com.mooveit.cars.dto.DefaultMessageDTO")); + } + +} From 05598d8d2a6c4f4c1910f2a70f6d63eba1e62027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?MITZY=20VALENCIA=20ORDO=C3=91EZ?= Date: Sun, 3 May 2020 18:13:15 -0500 Subject: [PATCH 4/5] D - Adding images --- ANSWERS.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ANSWERS.md b/ANSWERS.md index 899c0f9..31d8761 100644 --- a/ANSWERS.md +++ b/ANSWERS.md @@ -12,5 +12,11 @@ based on the XML file. - Added Jackson annotation to support bidirectional relationships and get the entity as a json object ## D - Adding images +*Option 1: To manage the files in database, first will add a column with type CLOB or BLOB in the SubModel table, +and assign a filename according to a pattern given by the SubModel, like name-line, and limit the type of file extension +(.jpg, .png, .jpeg, etc), and add a few properties for restriction as limit the size of file. + +*Option 2: Add a column in SubModel table to refer a URL where the file is saved in a storage in cloud +like Amazon Simple Storage Service (Amazon S3). ## E - Improvements \ No newline at end of file From 59c19755841b4eff31887ce285cc640a0541de09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?MITZY=20VALENCIA=20ORDO=C3=91EZ?= Date: Sun, 3 May 2020 18:25:16 -0500 Subject: [PATCH 5/5] E - Improvements there could be more improvements but those are the ones just came out of my mind --- ANSWERS.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ANSWERS.md b/ANSWERS.md index 31d8761..e2e5a2a 100644 --- a/ANSWERS.md +++ b/ANSWERS.md @@ -19,4 +19,11 @@ and assign a filename according to a pattern given by the SubModel, like name-li *Option 2: Add a column in SubModel table to refer a URL where the file is saved in a storage in cloud like Amazon Simple Storage Service (Amazon S3). -## E - Improvements \ No newline at end of file +## E - Improvements +- Add some validation for value column as Model.Type where the values are constant. +- Add other REST services to have CRUDs of the left entities. +- Add Swagger API for document the REST services. +- Add a few Views as Welcome Page and other to manage information. +- Add log configuration to manage the different types to see in console (DEBUG,TRACE, etc). +- Add profile configuration to handle a Development and Production version for compilation. +- Add SonarQube configuration to ensure code quality. \ No newline at end of file