diff --git a/hexagonal-architecture/.gitignore b/hexagonal-architecture/.gitignore
new file mode 100644
index 0000000000..ae3c172604
--- /dev/null
+++ b/hexagonal-architecture/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/hexagonal-architecture/pom.xml b/hexagonal-architecture/pom.xml
new file mode 100644
index 0000000000..c8eceae21a
--- /dev/null
+++ b/hexagonal-architecture/pom.xml
@@ -0,0 +1,14 @@
+
+ 4.0.0
+ com.baeldung.hexagonal
+ hexagonal-architecture
+ jar
+ hexagonal-architecture
+
+ com.baeldung
+ parent-java
+ 0.0.1-SNAPSHOT
+ ../parent-java
+
+
\ No newline at end of file
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/Application.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/Application.java
new file mode 100644
index 0000000000..4691d498f4
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/Application.java
@@ -0,0 +1,27 @@
+package com.baeldung.hexagonal;
+
+import java.io.File;
+
+import com.baeldung.hexagonal.domain.EmployeeService;
+import com.baeldung.hexagonal.output.EmployeeCsvWriter;
+import com.baeldung.hexagonal.output.EmployeeLogger;
+import com.baeldung.hexagonal.output.EmployeeOutput;
+import com.baeldung.hexagonal.storage.EmployeeRepository;
+import com.baeldung.hexagonal.storage.InMemoryEmployeeRepository;
+import com.baeldung.hexagonal.ui.EmployeeConsoleInputImpl;
+import com.baeldung.hexagonal.ui.EmployeeInput;
+
+public class Application {
+
+ public static void main(String[] args) {
+ EmployeeRepository repository = new InMemoryEmployeeRepository();
+ EmployeeOutput output = new EmployeeLogger();
+ EmployeeOutput csvOutput = new EmployeeCsvWriter(new File(".").getAbsolutePath(), "output.csv");
+ EmployeeService service = new EmployeeService(repository, csvOutput);
+ EmployeeInput ui = new EmployeeConsoleInputImpl();
+ ui.collectData(service);
+ service.generateOutput();
+
+ }
+
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/domain/Employee.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/domain/Employee.java
new file mode 100644
index 0000000000..91b22d0d11
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/domain/Employee.java
@@ -0,0 +1,70 @@
+package com.baeldung.hexagonal.domain;
+
+import java.math.BigDecimal;
+
+public class Employee {
+ private Long id;
+ private String firstName;
+ private String lastName;
+ private String employeeId;
+ private BigDecimal salary;
+
+ public Employee(
+ Long id,
+ String firstName,
+ String lastName,
+ String employeeId,
+ BigDecimal salary) {
+ this.id = id;
+ this.firstName = firstName;
+ this.lastName = lastName;
+ this.employeeId = employeeId;
+ this.salary = salary;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmployeeId() {
+ return employeeId;
+ }
+
+ public void setEmployeeId(String employeeId) {
+ this.employeeId = employeeId;
+ }
+
+ public BigDecimal getSalary() {
+ return salary;
+ }
+
+ public void setSalary(BigDecimal salary) {
+ this.salary = salary;
+ }
+
+ @Override
+ public String toString() {
+ return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", employeeId=" + employeeId + ", salary=" + salary + "]";
+ }
+
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/domain/EmployeeService.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/domain/EmployeeService.java
new file mode 100644
index 0000000000..12b2028035
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/domain/EmployeeService.java
@@ -0,0 +1,26 @@
+package com.baeldung.hexagonal.domain;
+
+
+import java.util.List;
+
+import com.baeldung.hexagonal.output.EmployeeOutput;
+import com.baeldung.hexagonal.storage.EmployeeRepository;
+
+public class EmployeeService {
+ private EmployeeRepository employeeRepository;
+ private EmployeeOutput employeeOutput;
+
+ public EmployeeService(EmployeeRepository employeeRepository, EmployeeOutput employeeOutput) {
+ this.employeeRepository = employeeRepository;
+ this.employeeOutput = employeeOutput;
+ }
+
+ public Long add(Employee employee) {
+ return employeeRepository.save(employee);
+ }
+
+ public void generateOutput() {
+ List employees = employeeRepository.findAll();
+ employeeOutput.writeAll(employees);
+ }
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeCsvWriter.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeCsvWriter.java
new file mode 100644
index 0000000000..c434d19525
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeCsvWriter.java
@@ -0,0 +1,64 @@
+package com.baeldung.hexagonal.output;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+
+import com.baeldung.hexagonal.domain.Employee;
+
+public class EmployeeCsvWriter implements EmployeeOutput {
+ private File outputFile;
+
+ public EmployeeCsvWriter(String path, String fileName) throws IllegalArgumentException {
+ if (fileName == null || path == null || fileName.length() == 0 || path.length() == 0) {
+ throw new IllegalArgumentException("Path and FileName are required");
+ } else if (!fileName.endsWith(".csv")) {
+ throw new IllegalArgumentException("File name must be a .csv file");
+ }
+
+ System.out.println(path);
+ if (!path.endsWith("/")) path += "/";
+
+ outputFile = new File(path, fileName);
+ }
+
+ @Override
+ public void writeAll(List employees) {
+ BufferedWriter writer = null;
+
+ try {
+ writer = new BufferedWriter(new FileWriter(outputFile));
+ for (Iterator it = employees.iterator(); it.hasNext();) {
+ Employee emp = it.next();
+ StringBuffer empLine = new StringBuffer();
+ empLine.append(emp.getId());
+ empLine.append(",");
+ empLine.append(emp.getFirstName());
+ empLine.append(",");
+ empLine.append(emp.getLastName());
+ empLine.append(",");
+ empLine.append(emp.getEmployeeId());
+ empLine.append(",");
+ empLine.append(emp.getSalary());
+ writer.write(empLine.toString());
+ writer.newLine();
+ }
+ writer.flush();
+ } catch (IOException ioe) {
+ //handle the exception
+ } finally {
+ if (writer != null) {
+ try {
+ writer.close();
+ } catch (IOException e) {
+ //handle the exception
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeLogger.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeLogger.java
new file mode 100644
index 0000000000..681e631012
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeLogger.java
@@ -0,0 +1,17 @@
+package com.baeldung.hexagonal.output;
+
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.baeldung.hexagonal.domain.Employee;
+
+public class EmployeeLogger implements EmployeeOutput {
+ private static final Logger LOG = LoggerFactory.getLogger(EmployeeLogger.class);
+
+ @Override
+ public void writeAll(List employees) {
+ employees.forEach(employee -> LOG.info(employee.toString()));
+ }
+
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeOutput.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeOutput.java
new file mode 100644
index 0000000000..979c06e1f4
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/output/EmployeeOutput.java
@@ -0,0 +1,9 @@
+package com.baeldung.hexagonal.output;
+
+import java.util.List;
+
+import com.baeldung.hexagonal.domain.Employee;
+
+public interface EmployeeOutput {
+ public void writeAll(List employees);
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/storage/EmployeeRepository.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/storage/EmployeeRepository.java
new file mode 100644
index 0000000000..f12584f8e1
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/storage/EmployeeRepository.java
@@ -0,0 +1,11 @@
+package com.baeldung.hexagonal.storage;
+
+import java.util.List;
+
+import com.baeldung.hexagonal.domain.Employee;
+
+public interface EmployeeRepository {
+ public Long save(Employee employee);
+ public Employee findById(Long id);
+ public List findAll();
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/storage/InMemoryEmployeeRepository.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/storage/InMemoryEmployeeRepository.java
new file mode 100644
index 0000000000..e860c16462
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/storage/InMemoryEmployeeRepository.java
@@ -0,0 +1,31 @@
+package com.baeldung.hexagonal.storage;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.baeldung.hexagonal.domain.Employee;
+
+public class InMemoryEmployeeRepository implements EmployeeRepository {
+ private static Map employees = new HashMap<>();
+
+ @Override
+ public Long save(Employee employee) {
+ Long id = employee.getId();
+ employees.put(id, employee);
+ return id;
+ }
+
+ @Override
+ public Employee findById(Long id) {
+ return employees.get(id);
+ }
+
+ @Override
+ public List findAll() {
+ List all = new ArrayList(employees.values());
+ return all;
+ }
+
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/ui/EmployeeConsoleInputImpl.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/ui/EmployeeConsoleInputImpl.java
new file mode 100644
index 0000000000..5f613f7bf9
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/ui/EmployeeConsoleInputImpl.java
@@ -0,0 +1,53 @@
+package com.baeldung.hexagonal.ui;
+
+import java.math.BigDecimal;
+import java.util.Scanner;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.baeldung.hexagonal.domain.Employee;
+import com.baeldung.hexagonal.domain.EmployeeService;
+
+public class EmployeeConsoleInputImpl implements EmployeeInput {
+ private static final Logger LOG = LoggerFactory.getLogger(EmployeeConsoleInputImpl.class);
+
+ public void enterEmployee(EmployeeService service, Scanner scanner) {
+
+ LOG.info("ID: ");
+ System.out.print("> ");
+ Long id = scanner.nextLong();
+ LOG.info("First Name: ");
+ System.out.print("> ");
+ String firstName = scanner.next();
+ LOG.info("Last Name: ");
+ System.out.print("> ");
+ String lastName = scanner.next();
+ LOG.info("Employee ID: ");
+ System.out.print("> ");
+ String employeeId = scanner.next();
+ LOG.info("Salary: " );
+ System.out.print("> ");
+ BigDecimal salary = scanner.nextBigDecimal();
+
+ Employee employee = new Employee(id, firstName, lastName, employeeId, salary);
+ service.add(employee);
+
+ }
+
+ @Override
+ public void collectData(EmployeeService service) {
+ try (final Scanner scanner = new Scanner(System.in)) {
+ String keepGoing = "Y";
+ do {
+ LOG.info("Enter information for an employee");
+ enterEmployee(service, scanner);
+ LOG.info("Do you want to enter another employee? (Y/N)");
+ System.out.print("> ");
+ keepGoing = scanner.next();
+ if (keepGoing.length() > 1) keepGoing = keepGoing.substring(0, 1);
+ } while (keepGoing.equalsIgnoreCase("Y"));
+ }
+ }
+
+}
diff --git a/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/ui/EmployeeInput.java b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/ui/EmployeeInput.java
new file mode 100644
index 0000000000..62156fc6d9
--- /dev/null
+++ b/hexagonal-architecture/src/main/java/com/baeldung/hexagonal/ui/EmployeeInput.java
@@ -0,0 +1,7 @@
+package com.baeldung.hexagonal.ui;
+
+import com.baeldung.hexagonal.domain.EmployeeService;
+
+public interface EmployeeInput {
+ void collectData(EmployeeService service);
+}