diff --git a/eureka/.gitignore b/eureka/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/eureka/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/eureka/discovery-server/.gitignore b/eureka/discovery-server/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/eureka/discovery-server/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/eureka/discovery-server/pom.xml b/eureka/discovery-server/pom.xml
new file mode 100644
index 0000000..fd67994
--- /dev/null
+++ b/eureka/discovery-server/pom.xml
@@ -0,0 +1,53 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.4
+
+
+ com.example
+ discovery-server
+ 0.0.1-SNAPSHOT
+ discovery-server
+ discovery-server
+
+ 11
+ 2021.0.1
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-server
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/eureka/discovery-server/src/main/java/com/example/discovery/DiscoveryServer.java b/eureka/discovery-server/src/main/java/com/example/discovery/DiscoveryServer.java
new file mode 100644
index 0000000..01cad77
--- /dev/null
+++ b/eureka/discovery-server/src/main/java/com/example/discovery/DiscoveryServer.java
@@ -0,0 +1,27 @@
+package com.example.discovery;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
+
+import java.io.IOException;
+
+@SpringBootApplication
+@EnableEurekaServer
+public class DiscoveryServer {
+
+ private static Logger logger = LoggerFactory.getLogger(DiscoveryServer.class);
+
+ public static void main(String... args) throws IOException {
+ // Look for configuration in discovery-server.properties or discovery-server.yml
+ System.setProperty("spring.config.name", "discovery-server");
+
+ var ctx = SpringApplication.run(DiscoveryServer.class, args);
+ assert (ctx != null);
+ logger.info("Started ...");
+ System.in.read();
+ ctx.close();
+ }
+}
diff --git a/eureka/discovery-server/src/main/resources/discovery-server.yml b/eureka/discovery-server/src/main/resources/discovery-server.yml
new file mode 100644
index 0000000..8d23338
--- /dev/null
+++ b/eureka/discovery-server/src/main/resources/discovery-server.yml
@@ -0,0 +1,20 @@
+spring:
+ application:
+ name: discovery-service
+# Configure this Discovery Server
+#TODO here you add configurations for server
+server:
+ port: 3000
+
+eureka:
+ client:
+ register-with-eureka: false
+ fetch-registry: false
+
+logging:
+ pattern:
+ console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
+ level:
+ root: INFO
+ org.springframework: DEBUG
+ com.apress.cems: DEBUG
diff --git a/eureka/discovery-server/src/test/java/com/example/discoveryserver/DiscoveryServerApplicationTests.java b/eureka/discovery-server/src/test/java/com/example/discoveryserver/DiscoveryServerApplicationTests.java
new file mode 100644
index 0000000..f102053
--- /dev/null
+++ b/eureka/discovery-server/src/test/java/com/example/discoveryserver/DiscoveryServerApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.discoveryserver;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class DiscoveryServerApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/eureka/persons-server/.gitignore b/eureka/persons-server/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/eureka/persons-server/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/eureka/persons-server/pom.xml b/eureka/persons-server/pom.xml
new file mode 100644
index 0000000..b342d8e
--- /dev/null
+++ b/eureka/persons-server/pom.xml
@@ -0,0 +1,96 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.4
+
+
+ com.example
+ persons-server
+ 0.0.1-SNAPSHOT
+ persons-server
+ persons-server
+
+ 11
+ 2021.0.1
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-server
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ com.h2database
+ h2
+ 2.1.210
+ runtime
+
+
+ com.sun.jersey.contribs
+ jersey-apache-client4
+ 1.19.4
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+ 2.13.1
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.13.1
+
+
+ javax.validation
+ validation-api
+ 2.0.1.Final
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/PersonRepo.java b/eureka/persons-server/src/main/java/com/eureka/persons/PersonRepo.java
new file mode 100644
index 0000000..5e7b169
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/PersonRepo.java
@@ -0,0 +1,36 @@
+package com.eureka.persons;
+
+import com.eureka.persons.person.Person;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public interface PersonRepo extends JpaRepository {
+
+ @Query("select p from Person p where p.username like %?1%")
+ Optional findByUsername(String username);
+
+ @Query("select p from Person p where p.username like %?1%")
+ List findByUsernameLike(String username);
+
+ @Query("select p from Person p where p.firstName=:fn")
+ List findByFirstName(@Param("fn") String firstName);
+
+ @Query("select p from Person p where p.firstName like %?1%")
+ List findByFirstNameLike(String firstName);
+
+ @Query("select p from Person p where p.lastName=:ln")
+ List findByLastName(@Param("ln") String lastName);
+
+ @Query("select p from Person p where p.lastName like %?1%")
+ List findByLastNameLike(String lastName);
+
+ @Query("select p from Person p where p.hiringDate=:hd")
+ List findByHiringDate(@Param("hd") LocalDateTime date);
+}
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/PersonsController.java b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsController.java
new file mode 100644
index 0000000..75fc8a8
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsController.java
@@ -0,0 +1,101 @@
+package com.eureka.persons;
+
+import com.eureka.persons.ex.NotFoundException;
+import com.eureka.persons.person.Person;
+import com.eureka.persons.services.PersonService;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+@RestController
+@RequestMapping("/persons")
+public class PersonsController {
+ private PersonService personService;
+
+ public PersonsController(PersonService personService) {
+ this.personService = personService;
+ }
+
+ /**
+ * Handles requests to list all persons.
+ */
+ //TODO find all persons using the functions already implemented and sort them by id
+ @ResponseStatus(HttpStatus.OK)
+ @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
+ public List list() {
+ return personService
+ .findAll().stream()
+ .sorted(Comparator.comparing(Person::getId))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Handles requests to create a person.
+ */
+ //TODO save a person to the db or throw PersonsException
+ @ResponseStatus(HttpStatus.CREATED)
+ @PostMapping
+ public void create(@RequestBody Person person, BindingResult result) {
+ if (result.hasErrors())
+ throw new PersonsException(HttpStatus.BAD_REQUEST, "Person couldn't be added!");
+
+ personService.save(person);
+ }
+
+ /**
+ * Returns the {@code Person} instance with id {@code id}
+ *
+ * @param id
+ * @return
+ */
+ //TODO find a person by id or throw NotFoundException
+ @ResponseStatus(HttpStatus.OK)
+ @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
+ public Person show(@PathVariable Long id) {
+ var personIdQuery = personService.findById(id);
+ if (personIdQuery.isEmpty())
+ throw new NotFoundException(Person.class, id);
+
+ return personIdQuery.get();
+ }
+
+ /**
+ * Updates the {@code Person} instance with id {@code id}
+ *
+ * @param updatedPerson
+ * @param id
+ * @return
+ */
+ //TODO update an existing person if found else throw NotFoundException
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ @PutMapping("/{id}")
+ public void update(@RequestBody Person updatedPerson, @PathVariable Long id) {
+ var personIdQuery = personService.findById(id);
+
+ personIdQuery.ifPresent(person -> person = updatedPerson);
+ // else
+ throw new NotFoundException(Person.class, id);
+ }
+
+ /**
+ * Delete the {@code Person} instance with id {@code id}
+ *
+ * @param id
+ */
+ //TODO delete a person
+ @ResponseStatus(HttpStatus.NO_CONTENT)
+ @DeleteMapping("/{id}")
+ public void delete(@PathVariable Long id) {
+ var personIdQuery = personService.findById(id);
+ if (personIdQuery.isEmpty())
+ throw new NotFoundException(Person.class, id);
+
+ personService.delete(personIdQuery.get());
+ }
+}
\ No newline at end of file
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/PersonsException.java b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsException.java
new file mode 100644
index 0000000..781c4f6
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsException.java
@@ -0,0 +1,17 @@
+package com.eureka.persons;
+
+import org.springframework.http.HttpStatus;
+
+public class PersonsException extends RuntimeException{
+ private HttpStatus status;
+
+ public PersonsException(HttpStatus status, String message) {
+ super(message);
+ this.status = status;
+ }
+
+ public PersonsException(HttpStatus status, Throwable cause) {
+ super(cause);
+ this.status = status;
+ }
+}
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/PersonsServer.java b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsServer.java
new file mode 100644
index 0000000..5764a84
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/PersonsServer.java
@@ -0,0 +1,29 @@
+package com.eureka.persons;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.domain.EntityScan;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+
+import java.io.IOException;
+
+@EntityScan(basePackages = "com.eureka.persons")
+@SpringBootApplication
+@EnableEurekaClient
+public class PersonsServer {
+
+ private static final Logger logger = LoggerFactory.getLogger(PersonsServer.class);
+
+ public static void main(String... args) throws IOException {
+ // Look for configuration in persons-server.properties or persons-server.yml
+ System.setProperty("spring.config.name", "persons-server");
+
+ var ctx = SpringApplication.run(PersonsServer.class, args);
+ assert (ctx != null);
+ logger.info("Started ...");
+ System.in.read();
+ ctx.close();
+ }
+}
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/base/AbstractEntity.java b/eureka/persons-server/src/main/java/com/eureka/persons/base/AbstractEntity.java
new file mode 100644
index 0000000..199103b
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/base/AbstractEntity.java
@@ -0,0 +1,70 @@
+package com.eureka.persons.base;
+
+import com.eureka.persons.util.DateProcessor;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.persistence.*;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Comparator;
+import java.util.Objects;
+
+@MappedSuperclass
+@Getter
+@Setter
+public abstract class AbstractEntity implements Serializable {
+
+ public static Comparator COMPARATOR_BY_ID = Comparator.comparing(AbstractEntity::getId);
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.AUTO)
+ @Column(updatable = false)
+ protected Long id;
+
+ @Version
+ protected int version;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateProcessor.DATE_FORMAT)
+ @Column(name = "created_at", nullable = false)
+ @DateTimeFormat(pattern = DateProcessor.DATE_FORMAT)
+ protected LocalDateTime createdAt;
+
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateProcessor.DATE_FORMAT)
+ @Column(name = "modified_at", nullable = false)
+ @DateTimeFormat(pattern = DateProcessor.DATE_FORMAT)
+ protected LocalDateTime modifiedAt;
+
+ /**
+ * This constructor is required by JPA. All subclasses of this class will inherit this constructor.
+ */
+ protected AbstractEntity() {
+ createdAt = LocalDateTime.now();
+ modifiedAt = LocalDateTime.now();
+ }
+
+ // IDE generated methods
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ var that = (AbstractEntity) o;
+ if (!Objects.equals(id, that.id)) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return id != null ? id.hashCode() : 0;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("AbstractEntity[id='%d%n', createdAt='%s', modifiedAt='%s', version='%d%n']",
+ id, DateProcessor.toString(createdAt), DateProcessor.toString(modifiedAt), version);
+ }
+}
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/ex/NotFoundException.java b/eureka/persons-server/src/main/java/com/eureka/persons/ex/NotFoundException.java
new file mode 100644
index 0000000..094ecec
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/ex/NotFoundException.java
@@ -0,0 +1,7 @@
+package com.eureka.persons.ex;
+
+public class NotFoundException extends RuntimeException {
+ public NotFoundException(Class cls, Long id) {
+ super(cls.getSimpleName() + " with id: " + id + " does not exist!");
+ }
+}
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/person/Person.java b/eureka/persons-server/src/main/java/com/eureka/persons/person/Person.java
new file mode 100644
index 0000000..9064df8
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/person/Person.java
@@ -0,0 +1,82 @@
+package com.eureka.persons.person;
+
+import com.eureka.persons.base.AbstractEntity;
+import com.eureka.persons.util.DateProcessor;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+@Entity
+@Getter
+@Setter
+@NoArgsConstructor
+public class Person extends AbstractEntity {
+ interface BasicValidation{}
+
+ @NotNull(groups = BasicValidation.class)
+ @Size(min = 3, max = 30, groups = BasicValidation.class)
+ @Column(nullable = false, unique = true)
+ private String username;
+
+ @NotNull(groups = BasicValidation.class)
+ @Size(min = 3, max = 30, groups = BasicValidation.class)
+ @Column(nullable = false)
+ private String firstName;
+
+ @NotNull(groups = BasicValidation.class)
+ @Size(min = 3, max = 30, groups = BasicValidation.class)
+ @Column(nullable = false)
+ private String lastName;
+
+ @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
+ @NotNull
+ @Size(min = 4, max = 50)
+ @Column(nullable = false)
+ private String password;
+
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = DateProcessor.DATE_FORMAT)
+ @NotNull(groups = BasicValidation.class)
+ @Column(nullable = false)
+ @DateTimeFormat(pattern = DateProcessor.DATE_FORMAT)
+ private LocalDateTime hiringDate;
+
+ @JsonIgnore
+ @Transient
+ private String newPassword;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ var person = (Person) o;
+ if (!Objects.equals(id, person.id)) return false;
+ return Objects.equals(firstName, person.firstName) &&
+ Objects.equals(lastName, person.lastName) &&
+ Objects.equals(hiringDate.toLocalDate(), person.hiringDate.toLocalDate());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), firstName, lastName, hiringDate.toLocalDate());
+ }
+
+ @Override
+ public String toString() {
+ return String.format("Person[username='%s', firstName='%s', lastName='%s', hiringDate='%s']\n",
+ username, firstName, lastName, hiringDate.toString());
+
+ }
+
+}
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/services/Initializer.java b/eureka/persons-server/src/main/java/com/eureka/persons/services/Initializer.java
new file mode 100644
index 0000000..22024a4
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/services/Initializer.java
@@ -0,0 +1,65 @@
+package com.eureka.persons.services;
+
+import com.eureka.persons.person.Person;
+import com.eureka.persons.util.DateProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+
+@Service
+@Transactional
+public class Initializer {
+ private Logger logger = LoggerFactory.getLogger(Initializer.class);
+
+ private PersonService personService;
+
+ public Initializer(PersonService personService) {
+ this.personService = personService;
+ }
+
+ @PostConstruct
+ public void init() {
+ logger.info(" -->> Starting database initialization...");
+ if (personService.findAll().isEmpty()) {
+ createPersons();
+ }
+ logger.info(" -->> Database initialization finished.");
+ }
+
+ private void createPersons() {
+ Person person = new Person();
+ person.setUsername("sherlock.holmes");
+ person.setFirstName("Sherlock");
+ person.setLastName("Holmes");
+ person.setPassword("dudu");
+ person.setHiringDate(DateProcessor.toDate("1983-08-15 00:23"));
+ personService.save(person);
+
+ person = new Person();
+ person.setUsername("jackson.brodie");
+ person.setFirstName("Jackson");
+ person.setLastName("Brodie");
+ person.setPassword("bagy");
+ person.setHiringDate(DateProcessor.toDate("1983-06-22 00:23"));
+ personService.save(person);
+
+ person = new Person();
+ person.setUsername("nancy.drew");
+ person.setFirstName("Nancy");
+ person.setLastName("Drew");
+ person.setPassword("dada45");
+ person.setHiringDate(DateProcessor.toDate("1990-05-21 00:23"));
+ personService.save(person);
+
+ person = new Person();
+ person.setUsername("irene.adler");
+ person.setFirstName("Irene");
+ person.setLastName("Adler");
+ person.setPassword("xxxyy");
+ person.setHiringDate(DateProcessor.toDate("1987-03-11 00:23"));
+ personService.save(person);
+ }
+}
\ No newline at end of file
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/services/PersonService.java b/eureka/persons-server/src/main/java/com/eureka/persons/services/PersonService.java
new file mode 100644
index 0000000..0f86a73
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/services/PersonService.java
@@ -0,0 +1,16 @@
+package com.eureka.persons.services;
+
+import com.eureka.persons.person.Person;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface PersonService {
+ List findAll();
+
+ Optional findById(Long id);
+
+ Person save(Person person);
+
+ void delete(Person person);
+}
\ No newline at end of file
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/services/PersonServiceImpl.java b/eureka/persons-server/src/main/java/com/eureka/persons/services/PersonServiceImpl.java
new file mode 100644
index 0000000..6c4c0c9
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/services/PersonServiceImpl.java
@@ -0,0 +1,42 @@
+package com.eureka.persons.services;
+
+import com.eureka.persons.PersonRepo;
+import com.eureka.persons.person.Person;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.List;
+import java.util.Optional;
+
+@Service
+@Transactional
+public class PersonServiceImpl implements PersonService {
+ private final PersonRepo personRepo;
+
+ public PersonServiceImpl(PersonRepo personRepo) {
+ this.personRepo = personRepo;
+ }
+
+ @Override
+ public List findAll() {
+ return personRepo.findAll();
+ }
+
+ @Override
+ public Optional findById(Long id) {
+ return personRepo.findById(id);
+ }
+
+
+ @Override
+ public Person save(Person person) {
+ personRepo.save(person);
+ return person;
+ }
+
+ @Override
+ public void delete(Person person) {
+ personRepo.delete(person);
+ }
+}
+
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/util/DateProcessor.java b/eureka/persons-server/src/main/java/com/eureka/persons/util/DateProcessor.java
new file mode 100644
index 0000000..0d2f624
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/util/DateProcessor.java
@@ -0,0 +1,17 @@
+package com.eureka.persons.util;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+public class DateProcessor {
+ public static final String DATE_FORMAT= "yyyy-MM-dd HH:mm";
+ private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
+
+ public static LocalDateTime toDate(final String date) {
+ return LocalDateTime.parse(date, formatter);
+ }
+
+ public static String toString(final LocalDateTime date){
+ return date.format(formatter);
+ }
+}
diff --git a/eureka/persons-server/src/main/java/com/eureka/persons/util/NumberGenerator.java b/eureka/persons-server/src/main/java/com/eureka/persons/util/NumberGenerator.java
new file mode 100644
index 0000000..92b1c40
--- /dev/null
+++ b/eureka/persons-server/src/main/java/com/eureka/persons/util/NumberGenerator.java
@@ -0,0 +1,18 @@
+package com.eureka.persons.util;
+
+import java.util.Random;
+
+public final class NumberGenerator {
+ private static final Random RAND = new Random();
+ private static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static final String DIGITS = "0123456789";
+
+ private static Character randomCharacter() {
+ final var all = UPPER.concat(UPPER.toLowerCase()).concat(DIGITS);
+ return all.charAt(RAND.nextInt(all.length() - 1));
+ }
+
+ private NumberGenerator() {
+ // prevent initialization fo this class
+ }
+}
diff --git a/eureka/persons-server/src/main/resources/banner.txt b/eureka/persons-server/src/main/resources/banner.txt
new file mode 100644
index 0000000..be21922
--- /dev/null
+++ b/eureka/persons-server/src/main/resources/banner.txt
@@ -0,0 +1,7 @@
+__________ _________ .__
+\______ \ ___________ __________ ____ ______ / _____/ ______________ _|__| ____ ____
+ | ___// __ \_ __ \/ ___/ _ \ / \ / ___/ \_____ \_/ __ \_ __ \ \/ / |/ ___\/ __ \
+ | | \ ___/| | \/\___ ( <_> ) | \\___ \ / \ ___/| | \/\ /| \ \__\ ___/
+ |____| \___ >__| /____ >____/|___| /____ > /_______ /\___ >__| \_/ |__|\___ >___ >
+ \/ \/ \/ \/ \/ \/ \/ \/
+ :: Spring Boot :: (v2.2.4.RELEASE)
diff --git a/eureka/persons-server/src/main/resources/persons-server.yml b/eureka/persons-server/src/main/resources/persons-server.yml
new file mode 100644
index 0000000..5f367ae
--- /dev/null
+++ b/eureka/persons-server/src/main/resources/persons-server.yml
@@ -0,0 +1,47 @@
+spring:
+ application:
+ name: persons-service # Service registers under this name
+ datasource:
+ driver-class-name: org.h2.Driver
+ jdbc-url: jdbc:h2:mem:personsdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ username: sa
+ password: password
+ maximum-pool-size: 5
+ connection-test-query: "SELECT 1"
+ pool-name: cemsPool
+ connection-timeout: 60000
+ jpa:
+ generate-ddl: true
+ hibernate:
+ ddl-auto: create-drop
+ database-platform: org.hibernate.dialect.H2Dialect
+ h2:
+ console:
+ enabled: true
+# HTTP Server
+server:
+ port: 4001 # HTTP (Tomcat) port
+ address: 0.0.0.0
+
+# Discovery Server Access
+#TODO here you add configurations for eureka client
+eureka:
+ client:
+ service-url:
+ defaultZone: http://localhost:3000/eureka
+ fetch-registry: true
+ register-with-eureka: true
+
+info:
+ app:
+ name: persons-server
+ description: Spring Cloud Application Managing Person Instances
+ version: 1.0-SNAPSHOT
+
+logging:
+ pattern:
+ console: "%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
+ level:
+ root: INFO
+ org.springframework: DEBUG
+ com.apress.cems: DEBUG
diff --git a/eureka/persons-server/src/test/java/com/example/personsserver/PersonsServerApplicationTests.java b/eureka/persons-server/src/test/java/com/example/personsserver/PersonsServerApplicationTests.java
new file mode 100644
index 0000000..2fd298e
--- /dev/null
+++ b/eureka/persons-server/src/test/java/com/example/personsserver/PersonsServerApplicationTests.java
@@ -0,0 +1,17 @@
+package com.example.personsserver;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class PersonsServerApplicationTests {
+
+ //TODO configure discovery-server to be the Eureka's server (on port 3000) and persons-server to be the client server (on port 4001)
+ // hint1: you need to add some configurations in resources -> .yml files
+ // After you start your server and your client you need to create the endpoints from PersonsController, you have more details there
+ // Use postman to test the endpoints. Create a new collection and add all 5 endpoints inside of it.
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/eureka/pom.xml b/eureka/pom.xml
new file mode 100644
index 0000000..1049986
--- /dev/null
+++ b/eureka/pom.xml
@@ -0,0 +1,66 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.4
+
+
+ com.example
+ eureka
+ 0.0.1-SNAPSHOT
+ eureka
+ eureka
+ pom
+
+ 11
+ 2021.0.1
+
+
+ discovery-server
+ persons-server
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-server
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/eureka/src/main/java/com/example/eureka/EurekaApplication.java b/eureka/src/main/java/com/example/eureka/EurekaApplication.java
new file mode 100644
index 0000000..20c67a9
--- /dev/null
+++ b/eureka/src/main/java/com/example/eureka/EurekaApplication.java
@@ -0,0 +1,13 @@
+package com.example.eureka;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class EurekaApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(EurekaApplication.class, args);
+ }
+
+}
diff --git a/eureka/src/main/resources/application.properties b/eureka/src/main/resources/application.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/eureka/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/eureka/src/test/java/com/example/eureka/EurekaApplicationTests.java b/eureka/src/test/java/com/example/eureka/EurekaApplicationTests.java
new file mode 100644
index 0000000..1415105
--- /dev/null
+++ b/eureka/src/test/java/com/example/eureka/EurekaApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.eureka;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class EurekaApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/lab-6-api-gateway/.gitignore b/lab-6-api-gateway/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/lab-6-api-gateway/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/lab-6-api-gateway/api-gateway-project/.gitignore b/lab-6-api-gateway/api-gateway-project/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/lab-6-api-gateway/api-gateway-project/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/lab-6-api-gateway/api-gateway-project/pom.xml b/lab-6-api-gateway/api-gateway-project/pom.xml
new file mode 100644
index 0000000..5eaa00a
--- /dev/null
+++ b/lab-6-api-gateway/api-gateway-project/pom.xml
@@ -0,0 +1,64 @@
+
+
+ 4.0.0
+
+ lab-6-api-gateway
+ com.example
+ 0.0.1-SNAPSHOT
+
+ api-gateway-project
+ 0.0.1-SNAPSHOT
+ api-gateway-project
+ api-gateway-project
+
+ 11
+ 2021.0.1
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+
+
+
+ io.projectreactor
+ reactor-test
+ test
+
+
+ org.springframework.cloud
+ spring-cloud-netflix-eureka-server
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/lab-6-api-gateway/api-gateway-project/src/main/java/com/example/apigatewayproject/ApiGatewayProjectApplication.java b/lab-6-api-gateway/api-gateway-project/src/main/java/com/example/apigatewayproject/ApiGatewayProjectApplication.java
new file mode 100644
index 0000000..e976e83
--- /dev/null
+++ b/lab-6-api-gateway/api-gateway-project/src/main/java/com/example/apigatewayproject/ApiGatewayProjectApplication.java
@@ -0,0 +1,14 @@
+package com.example.apigatewayproject;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
+
+@SpringBootApplication
+public class ApiGatewayProjectApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(ApiGatewayProjectApplication.class, args);
+ }
+
+}
diff --git a/lab-6-api-gateway/api-gateway-project/src/main/resources/application.properties b/lab-6-api-gateway/api-gateway-project/src/main/resources/application.properties
new file mode 100644
index 0000000..66403d2
--- /dev/null
+++ b/lab-6-api-gateway/api-gateway-project/src/main/resources/application.properties
@@ -0,0 +1 @@
+spring.main.web-application-type=reactive
\ No newline at end of file
diff --git a/lab-6-api-gateway/api-gateway-project/src/main/resources/application.yml b/lab-6-api-gateway/api-gateway-project/src/main/resources/application.yml
new file mode 100644
index 0000000..085e160
--- /dev/null
+++ b/lab-6-api-gateway/api-gateway-project/src/main/resources/application.yml
@@ -0,0 +1,33 @@
+server:
+ port: 8080
+
+#TODO use eureka to discover the URL for the service1 and service2
+#TODO configure spring cloud gateway to route the request to downstream services (service1 and service2) based on the paths(/api/greeting, /product)
+#TODO for greeting endpoint add a route to accept requests to /greeting but before calling service1 it must append api before the greeting path (HINT: rewrite path filter)
+#and method types (GET,POST)
+spring:
+ application:
+ name: gateway
+ cloud:
+ gateway:
+ routes:
+ - id: service1
+ uri: http://localhost:8081
+ predicates:
+ - Path=/greeting/**
+ filters:
+ - RewritePath=/greeting, /api/greeting/
+ - id: service2
+ uri: http://localhost:8082
+ predicates:
+ - Path=/product/**
+ - id: persons
+ uri: http://localhost:4001
+ predicates:
+ - Path=/persons/**
+eureka:
+ client:
+ service-url:
+ defaultZone: http://localhost:3000/eureka
+ fetch-registry: true
+ register-with-eureka: true
\ No newline at end of file
diff --git a/lab-6-api-gateway/api-gateway-project/src/test/java/com/example/apigatewayproject/ApiGatewayProjectApplicationTests.java b/lab-6-api-gateway/api-gateway-project/src/test/java/com/example/apigatewayproject/ApiGatewayProjectApplicationTests.java
new file mode 100644
index 0000000..6c58423
--- /dev/null
+++ b/lab-6-api-gateway/api-gateway-project/src/test/java/com/example/apigatewayproject/ApiGatewayProjectApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.apigatewayproject;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class ApiGatewayProjectApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/lab-6-api-gateway/pom.xml b/lab-6-api-gateway/pom.xml
new file mode 100644
index 0000000..491b65e
--- /dev/null
+++ b/lab-6-api-gateway/pom.xml
@@ -0,0 +1,52 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.6.5
+
+
+ com.example
+ lab-6-api-gateway
+ 0.0.1-SNAPSHOT
+ lab-6-api-gateway
+ lab-6-api-gateway
+
+ 11
+
+ pom
+
+ api-gateway-project
+ service1
+ service2
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/lab-6-api-gateway/service1/.gitignore b/lab-6-api-gateway/service1/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/lab-6-api-gateway/service1/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/lab-6-api-gateway/service1/pom.xml b/lab-6-api-gateway/service1/pom.xml
new file mode 100644
index 0000000..89f8966
--- /dev/null
+++ b/lab-6-api-gateway/service1/pom.xml
@@ -0,0 +1,57 @@
+
+
+ 4.0.0
+
+ lab-6-api-gateway
+ com.example
+ 0.0.1-SNAPSHOT
+
+ service1
+ 0.0.1-SNAPSHOT
+ service1
+ service1
+
+ 11
+ 2021.0.1
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/lab-6-api-gateway/service1/src/main/java/com/example/service1/Service1Application.java b/lab-6-api-gateway/service1/src/main/java/com/example/service1/Service1Application.java
new file mode 100644
index 0000000..e89d29f
--- /dev/null
+++ b/lab-6-api-gateway/service1/src/main/java/com/example/service1/Service1Application.java
@@ -0,0 +1,34 @@
+package com.example.service1;
+
+import lombok.extern.java.Log;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Map;
+
+@SpringBootApplication
+@EnableEurekaClient
+@RestController
+public class Service1Application {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Service1Application.class, args);
+ }
+
+ @GetMapping("api/greeting")
+ public String greet(@RequestHeader Map headers, @RequestParam String name) {
+ System.out.println(headers);
+ return "Hello " + name;
+ }
+ // TODO
+ // 1. define a GET endpoint /api/greeting which should accept a query parameter "name"
+ // 2. return should be a string returning a greeting: Hello Brasov
+ // 3. print request headers
+ // 4. register the service in eureka
+
+}
diff --git a/lab-6-api-gateway/service1/src/main/resources/application.yml b/lab-6-api-gateway/service1/src/main/resources/application.yml
new file mode 100644
index 0000000..644b4ea
--- /dev/null
+++ b/lab-6-api-gateway/service1/src/main/resources/application.yml
@@ -0,0 +1,13 @@
+server:
+ port: 8081
+
+spring:
+ application:
+ name: service1
+
+eureka:
+ client:
+ service-url:
+ defaultZone: http://localhost:3000/eureka
+ fetch-registry: true
+ register-with-eureka: true
\ No newline at end of file
diff --git a/lab-6-api-gateway/service1/src/test/java/com/example/service1/Service1ApplicationTests.java b/lab-6-api-gateway/service1/src/test/java/com/example/service1/Service1ApplicationTests.java
new file mode 100644
index 0000000..539fcde
--- /dev/null
+++ b/lab-6-api-gateway/service1/src/test/java/com/example/service1/Service1ApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.service1;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class Service1ApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/lab-6-api-gateway/service2/.gitignore b/lab-6-api-gateway/service2/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/lab-6-api-gateway/service2/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/lab-6-api-gateway/service2/pom.xml b/lab-6-api-gateway/service2/pom.xml
new file mode 100644
index 0000000..b7d3748
--- /dev/null
+++ b/lab-6-api-gateway/service2/pom.xml
@@ -0,0 +1,53 @@
+
+
+ 4.0.0
+
+ lab-6-api-gateway
+ com.example
+ 0.0.1-SNAPSHOT
+
+ service2
+ 0.0.1-SNAPSHOT
+ service2
+ service2
+
+ 11
+ 2021.0.1
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.cloud
+ spring-cloud-starter-netflix-eureka-client
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-dependencies
+ ${spring-cloud.version}
+ pom
+ import
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/lab-6-api-gateway/service2/src/main/java/com/example/service2/Product.java b/lab-6-api-gateway/service2/src/main/java/com/example/service2/Product.java
new file mode 100644
index 0000000..a92ee16
--- /dev/null
+++ b/lab-6-api-gateway/service2/src/main/java/com/example/service2/Product.java
@@ -0,0 +1,13 @@
+package com.example.service2;
+
+import lombok.*;
+
+@Data
+@Setter
+@Getter
+@AllArgsConstructor
+@NoArgsConstructor
+public class Product {
+ String name;
+ int quantity;
+}
diff --git a/lab-6-api-gateway/service2/src/main/java/com/example/service2/Service2Application.java b/lab-6-api-gateway/service2/src/main/java/com/example/service2/Service2Application.java
new file mode 100644
index 0000000..5db7dbc
--- /dev/null
+++ b/lab-6-api-gateway/service2/src/main/java/com/example/service2/Service2Application.java
@@ -0,0 +1,48 @@
+package com.example.service2;
+
+import com.example.service2.repository.ProductRepository;
+import org.apache.http.HttpStatus;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@SpringBootApplication
+@EnableEurekaClient
+@RestController
+public class Service2Application {
+
+ private final ProductRepository productRepository;
+
+ public Service2Application(ProductRepository productRepository) {
+ this.productRepository = productRepository;
+ }
+
+ public static void main(String[] args) {
+ SpringApplication.run(Service2Application.class, args);
+ }
+
+
+ @PostMapping("product")
+ public ResponseEntity> postProduct(@RequestBody Product product) {
+ try {
+ var prod = productRepository.saveProduct(product);
+ return ResponseEntity.ok(prod);
+ } catch (RuntimeException exception) {
+ return ResponseEntity.status(HttpStatus.SC_BAD_REQUEST).body(exception.getMessage());
+ }
+ }
+
+ // TODO
+ // 1. define a POST endpoint /product which should accept a request body containing two properties -product name and quantity
+ //2. save the request body in memory
+ // 3. return 200 if OK
+ // 4. print request headers
+ // 5. register the service in eureka
+ // 6. define a GET endpoint /product to return the saved data using the POST endpoint - return type is List
+}
+
diff --git a/lab-6-api-gateway/service2/src/main/java/com/example/service2/repository/ProductRepository.java b/lab-6-api-gateway/service2/src/main/java/com/example/service2/repository/ProductRepository.java
new file mode 100644
index 0000000..f3202c2
--- /dev/null
+++ b/lab-6-api-gateway/service2/src/main/java/com/example/service2/repository/ProductRepository.java
@@ -0,0 +1,27 @@
+package com.example.service2.repository;
+
+import com.example.service2.Product;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+@Repository
+public class ProductRepository {
+ List products = new ArrayList<>();
+
+ public Optional findProductByName(String name) {
+ return products.stream().filter(product -> product.getName().equals(name)).findFirst();
+ }
+
+ public Product saveProduct(Product product) {
+ findProductByName(product.getName()).ifPresent(r -> {
+ throw new RuntimeException("Product with name " + r.getName() + " already exists!");
+ });
+
+ products.add(product);
+
+ return product;
+ }
+}
diff --git a/lab-6-api-gateway/service2/src/main/resources/application.yml b/lab-6-api-gateway/service2/src/main/resources/application.yml
new file mode 100644
index 0000000..99027f1
--- /dev/null
+++ b/lab-6-api-gateway/service2/src/main/resources/application.yml
@@ -0,0 +1,13 @@
+
+server:
+ port: 8082
+spring:
+ application:
+ name: service2
+
+eureka:
+ client:
+ service-url:
+ defaultZone: http://localhost:3000/eureka
+ fetch-registry: true
+ register-with-eureka: true
\ No newline at end of file
diff --git a/lab-6-api-gateway/service2/src/test/java/com/example/service2/Service2ApplicationTests.java b/lab-6-api-gateway/service2/src/test/java/com/example/service2/Service2ApplicationTests.java
new file mode 100644
index 0000000..3da138b
--- /dev/null
+++ b/lab-6-api-gateway/service2/src/test/java/com/example/service2/Service2ApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.service2;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class Service2ApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/lab-6-api-gateway/src/main/java/com/example/lab6apigateway/Lab6ApiGatewayApplication.java b/lab-6-api-gateway/src/main/java/com/example/lab6apigateway/Lab6ApiGatewayApplication.java
new file mode 100644
index 0000000..eb83cff
--- /dev/null
+++ b/lab-6-api-gateway/src/main/java/com/example/lab6apigateway/Lab6ApiGatewayApplication.java
@@ -0,0 +1,13 @@
+package com.example.lab6apigateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Lab6ApiGatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(Lab6ApiGatewayApplication.class, args);
+ }
+
+}
diff --git a/lab-6-api-gateway/src/main/resources/application.properties b/lab-6-api-gateway/src/main/resources/application.properties
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/lab-6-api-gateway/src/main/resources/application.properties
@@ -0,0 +1 @@
+
diff --git a/lab-6-api-gateway/src/test/java/com/example/lab6apigateway/Lab6ApiGatewayApplicationTests.java b/lab-6-api-gateway/src/test/java/com/example/lab6apigateway/Lab6ApiGatewayApplicationTests.java
new file mode 100644
index 0000000..af4ce01
--- /dev/null
+++ b/lab-6-api-gateway/src/test/java/com/example/lab6apigateway/Lab6ApiGatewayApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.lab6apigateway;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class Lab6ApiGatewayApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}