From 837ebef85832c3a5fdc59929370c815bf1924510 Mon Sep 17 00:00:00 2001
From: andrebrowne <42154231+andrebrowne@users.noreply.github.com>
Date: Tue, 1 Oct 2019 12:56:55 -0400
Subject: [PATCH] Add architecture module with Hexagonal example
---
architecture/README.md | 3 ++
architecture/pom.xml | 33 ++++++++++++
.../HexagonalArchitectureTaskApplication.java | 12 +++++
.../application/task/AddNewDailyTask.java | 29 ++++++++++
.../application/task/AddNewTask.java | 22 ++++++++
.../application/task/GetTasks.java | 22 ++++++++
.../commands/task/CreateTask.java | 7 +++
.../commands/task/GetAllTasks.java | 7 +++
.../architecture/domain/task/Task.java | 53 +++++++++++++++++++
.../domain/task/TaskRepository.java | 7 +++
.../architecture/domain/task/TaskService.java | 22 ++++++++
.../framework/cli/StartupRunner.java | 25 +++++++++
.../http/task/TaskApiController.java | 42 +++++++++++++++
.../framework/http/task/TaskRequest.java | 29 ++++++++++
14 files changed, 313 insertions(+)
create mode 100644 architecture/README.md
create mode 100644 architecture/pom.xml
create mode 100644 architecture/src/main/java/com/baeldung/architecture/HexagonalArchitectureTaskApplication.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/application/task/AddNewDailyTask.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/application/task/AddNewTask.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/application/task/GetTasks.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/commands/task/CreateTask.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/commands/task/GetAllTasks.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/domain/task/Task.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/domain/task/TaskRepository.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/domain/task/TaskService.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/framework/cli/StartupRunner.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/framework/http/task/TaskApiController.java
create mode 100644 architecture/src/main/java/com/baeldung/architecture/framework/http/task/TaskRequest.java
diff --git a/architecture/README.md b/architecture/README.md
new file mode 100644
index 0000000000..be093f25ed
--- /dev/null
+++ b/architecture/README.md
@@ -0,0 +1,3 @@
+### Relevant articles
+
+- [A Quick and Practical Example of Hexagonal Architecture in Java](https://www.baeldung.com/a-quick-and-practical-example-of-hexagonal-architecture-in-java-3/)
diff --git a/architecture/pom.xml b/architecture/pom.xml
new file mode 100644
index 0000000000..4ad104293e
--- /dev/null
+++ b/architecture/pom.xml
@@ -0,0 +1,33 @@
+
+ 4.0.0
+ com.baeldung.architecture
+ architecture
+ 0.0.1-SNAPSHOT
+ architecture
+ jar
+ A Quick and Practical Example of Hexagonal Architecture in Java
+
+
+ parent-boot-2
+ com.baeldung
+ 0.0.1-SNAPSHOT
+ ../parent-boot-2
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.h2database
+ h2
+ runtime
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
diff --git a/architecture/src/main/java/com/baeldung/architecture/HexagonalArchitectureTaskApplication.java b/architecture/src/main/java/com/baeldung/architecture/HexagonalArchitectureTaskApplication.java
new file mode 100644
index 0000000000..83e4fc4c0b
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/HexagonalArchitectureTaskApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.architecture;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class HexagonalArchitectureTaskApplication {
+ public static void main(String[] args) {
+ SpringApplication.run(HexagonalArchitectureTaskApplication.class, args);
+ }
+
+}
diff --git a/architecture/src/main/java/com/baeldung/architecture/application/task/AddNewDailyTask.java b/architecture/src/main/java/com/baeldung/architecture/application/task/AddNewDailyTask.java
new file mode 100644
index 0000000000..208d1bfcc9
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/application/task/AddNewDailyTask.java
@@ -0,0 +1,29 @@
+package com.baeldung.architecture.application.task;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+
+import com.baeldung.architecture.commands.task.CreateTask;
+import com.baeldung.architecture.domain.task.Task;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class AddNewDailyTask implements CreateTask {
+
+ private AddNewTask addNewTask;
+
+ public AddNewDailyTask(AddNewTask addNewTask) {
+ this.addNewTask = addNewTask;
+ }
+
+ @Override
+ public void create(Task newTask) {
+ Instant initialDueDate = newTask.getDueDate();
+ String description = newTask.getDescription();
+ for (int i = 1; i <= 5; i++) {
+ Task task = new Task(initialDueDate.plus(i, ChronoUnit.DAYS), description);
+ addNewTask.create(task);
+ }
+ }
+};
diff --git a/architecture/src/main/java/com/baeldung/architecture/application/task/AddNewTask.java b/architecture/src/main/java/com/baeldung/architecture/application/task/AddNewTask.java
new file mode 100644
index 0000000000..2e5aff4a53
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/application/task/AddNewTask.java
@@ -0,0 +1,22 @@
+package com.baeldung.architecture.application.task;
+
+import com.baeldung.architecture.domain.task.Task;
+import com.baeldung.architecture.domain.task.TaskService;
+import com.baeldung.architecture.commands.task.*;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class AddNewTask implements CreateTask {
+
+ private TaskService taskService;
+
+ public AddNewTask(TaskService taskService) {
+ this.taskService = taskService;
+ }
+
+ @Override
+ public void create(Task newTask) {
+ taskService.createTask(newTask);
+ }
+};
diff --git a/architecture/src/main/java/com/baeldung/architecture/application/task/GetTasks.java b/architecture/src/main/java/com/baeldung/architecture/application/task/GetTasks.java
new file mode 100644
index 0000000000..54539290ba
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/application/task/GetTasks.java
@@ -0,0 +1,22 @@
+package com.baeldung.architecture.application.task;
+
+import com.baeldung.architecture.domain.task.Task;
+import com.baeldung.architecture.domain.task.TaskService;
+import com.baeldung.architecture.commands.task.*;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class GetTasks implements GetAllTasks {
+
+ private TaskService taskService;
+
+ public GetTasks(TaskService taskService) {
+ this.taskService = taskService;
+ }
+
+ @Override
+ public Iterable getAll() {
+ return taskService.getAllTasks();
+ }
+};
diff --git a/architecture/src/main/java/com/baeldung/architecture/commands/task/CreateTask.java b/architecture/src/main/java/com/baeldung/architecture/commands/task/CreateTask.java
new file mode 100644
index 0000000000..26e6da10e2
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/commands/task/CreateTask.java
@@ -0,0 +1,7 @@
+package com.baeldung.architecture.commands.task;
+
+import com.baeldung.architecture.domain.task.Task;
+
+public interface CreateTask {
+ public void create(Task newTask);
+};
diff --git a/architecture/src/main/java/com/baeldung/architecture/commands/task/GetAllTasks.java b/architecture/src/main/java/com/baeldung/architecture/commands/task/GetAllTasks.java
new file mode 100644
index 0000000000..d3c40db92f
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/commands/task/GetAllTasks.java
@@ -0,0 +1,7 @@
+package com.baeldung.architecture.commands.task;
+
+import com.baeldung.architecture.domain.task.Task;
+
+public interface GetAllTasks {
+ public Iterable getAll();
+};
diff --git a/architecture/src/main/java/com/baeldung/architecture/domain/task/Task.java b/architecture/src/main/java/com/baeldung/architecture/domain/task/Task.java
new file mode 100644
index 0000000000..240dc33571
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/domain/task/Task.java
@@ -0,0 +1,53 @@
+package com.baeldung.architecture.domain.task;
+
+import java.time.Instant;
+
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+
+@Entity
+public class Task {
+ @Id
+ @GeneratedValue(strategy=GenerationType.AUTO)
+ private Long id;
+ private Instant dueDate = Instant.now();
+ private String description;
+
+ public Task() {}
+
+ public Task(Instant dueDate, String description) {
+ this.dueDate = dueDate;
+ this.description = description;
+ }
+
+ public Task(Long id, Instant dueDate, String description) {
+ this(dueDate, description);
+ this.id = id;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Instant getDueDate() {
+ return dueDate;
+ }
+
+ public void setDueDate(Instant dueDate) {
+ this.dueDate = dueDate;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+}
diff --git a/architecture/src/main/java/com/baeldung/architecture/domain/task/TaskRepository.java b/architecture/src/main/java/com/baeldung/architecture/domain/task/TaskRepository.java
new file mode 100644
index 0000000000..d896212714
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/domain/task/TaskRepository.java
@@ -0,0 +1,7 @@
+package com.baeldung.architecture.domain.task;
+
+import org.springframework.data.repository.CrudRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface TaskRepository extends CrudRepository {};
diff --git a/architecture/src/main/java/com/baeldung/architecture/domain/task/TaskService.java b/architecture/src/main/java/com/baeldung/architecture/domain/task/TaskService.java
new file mode 100644
index 0000000000..cace0614ad
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/domain/task/TaskService.java
@@ -0,0 +1,22 @@
+package com.baeldung.architecture.domain.task;
+
+import org.springframework.stereotype.Service;
+
+@Service
+public class TaskService {
+
+ private TaskRepository taskRepository;
+
+ public TaskService(TaskRepository taskRepository) {
+ this.taskRepository = taskRepository;
+ }
+
+ public void createTask(Task task) {
+ taskRepository.save(task);
+ }
+
+ public Iterable getAllTasks() {
+ return taskRepository.findAll();
+ }
+
+};
diff --git a/architecture/src/main/java/com/baeldung/architecture/framework/cli/StartupRunner.java b/architecture/src/main/java/com/baeldung/architecture/framework/cli/StartupRunner.java
new file mode 100644
index 0000000000..260c033b71
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/framework/cli/StartupRunner.java
@@ -0,0 +1,25 @@
+package com.baeldung.architecture.framework.cli;
+
+import com.baeldung.architecture.application.task.AddNewDailyTask;
+import com.baeldung.architecture.domain.task.Task;
+
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+@Component
+public class StartupRunner implements ApplicationRunner {
+
+ AddNewDailyTask addNewDailyTask;
+
+ public StartupRunner(AddNewDailyTask addNewDailyTask) {
+ this.addNewDailyTask = addNewDailyTask;
+ }
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ System.out.println("Adding daily tasks");
+ Task task = new Task();
+ task.setDescription("Startup Task");
+ addNewDailyTask.create(task);
+ }
+}
\ No newline at end of file
diff --git a/architecture/src/main/java/com/baeldung/architecture/framework/http/task/TaskApiController.java b/architecture/src/main/java/com/baeldung/architecture/framework/http/task/TaskApiController.java
new file mode 100644
index 0000000000..c6f7bff2dd
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/framework/http/task/TaskApiController.java
@@ -0,0 +1,42 @@
+package com.baeldung.architecture.framework.http.task;
+
+import java.time.Instant;
+
+import com.baeldung.architecture.application.task.AddNewTask;
+import com.baeldung.architecture.application.task.GetTasks;
+import com.baeldung.architecture.domain.task.Task;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("task")
+public class TaskApiController {
+
+ private AddNewTask addNewTask;
+ private GetTasks getTasks;
+
+ public TaskApiController(
+ AddNewTask addNewTask,
+ GetTasks getTasks
+ ) {
+ this.addNewTask = addNewTask;
+ this.getTasks = getTasks;
+ }
+
+ @GetMapping
+ Iterable listTasks() {
+ return getTasks.getAll();
+ }
+
+ @PostMapping(consumes = "application/json", produces = "application/json")
+ void createTask(@RequestBody TaskRequest taskRequest) {
+ Task task = new Task();
+ task.setDescription(taskRequest.getDescription());
+ task.setDueDate(Instant.parse(taskRequest.getDueDate()));
+ addNewTask.create(task);
+ }
+}
\ No newline at end of file
diff --git a/architecture/src/main/java/com/baeldung/architecture/framework/http/task/TaskRequest.java b/architecture/src/main/java/com/baeldung/architecture/framework/http/task/TaskRequest.java
new file mode 100644
index 0000000000..2e353b079a
--- /dev/null
+++ b/architecture/src/main/java/com/baeldung/architecture/framework/http/task/TaskRequest.java
@@ -0,0 +1,29 @@
+package com.baeldung.architecture.framework.http.task;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+
+public class TaskRequest {
+ @JsonInclude(Include.NON_NULL)
+ private String description;
+
+ @JsonInclude(Include.NON_NULL)
+ private String dueDate;
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getDueDate() {
+ return dueDate;
+ }
+
+ public void setDueDate(String dueDate) {
+ this.dueDate = dueDate;
+ }
+
+}
\ No newline at end of file