From ce9a65e51a9dbc6373b2223b9e2b6a86c59cc092 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 26 Jan 2018 12:19:17 +0200 Subject: [PATCH 1/2] Strategy pattern added --- .../ro/ubb/istudent/IStudentApplication.java | 5 + .../ro/ubb/istudent/config/MongoConfig.java | 22 ++ .../controller/GreetingController.java | 8 + .../istudent/converters/CountryConverter.java | 44 ++++ .../istudent/converters/CourseConverter.java | 45 ++++ .../istudent/converters/GenericConverter.java | 26 +++ .../istudent/converters/StudentConverter.java | 56 +++++ .../istudent/converters/TestConverter.java | 41 ++++ .../strategy2/ConverterStrategy.java | 57 +++++ .../converters/strategy2/ConvertersMap.java | 45 ++++ .../ro/ubb/istudent/domain/BaseEntity.java | 15 ++ .../ro/ubb/istudent/domain/CountryEntity.java | 22 ++ .../ro/ubb/istudent/domain/CourseEntity.java | 26 +++ .../ro/ubb/istudent/domain/StudentEntity.java | 34 +++ .../ro/ubb/istudent/domain/TestEntity.java | 17 ++ src/main/java/ro/ubb/istudent/dto/AgeDto.java | 14 ++ .../java/ro/ubb/istudent/dto/BaseDto.java | 16 ++ .../dto/CountryBasedStatisticsDto.java | 16 ++ .../java/ro/ubb/istudent/dto/CountryDto.java | 16 ++ .../java/ro/ubb/istudent/dto/CourseDto.java | 18 ++ .../dto/GenderBasedStatisticsDto.java | 17 ++ .../java/ro/ubb/istudent/dto/StudentDto.java | 25 +++ .../java/ro/ubb/istudent/dto/TestDto.java | 14 ++ .../ro/ubb/istudent/enums/GenderEnum.java | 23 ++ .../exception/GlobalExceptionHandler.java | 2 +- .../java/ro/ubb/istudent/mock/MockData.java | 199 ++++++++++++++++++ .../repository/CountryRepository.java | 13 ++ .../istudent/repository/CourseRepository.java | 13 ++ .../repository/StudentRepository.java | 22 ++ .../istudent/repository/TestRepository.java | 9 + .../ubb/istudent/rest/AgeBasedStatistics.java | 36 ++++ .../istudent/rest/CountryBasedStatistics.java | 36 ++++ .../istudent/rest/GenderBasedStatistics.java | 35 +++ .../service/AgeBasedStatisticsService.java | 15 ++ .../CountryBasedStatisticsService.java | 49 +++++ .../ubb/istudent/service/CountryService.java | 33 +++ .../ubb/istudent/service/CourseService.java | 32 +++ .../service/GenderBasedStatisticsService.java | 52 +++++ .../ubb/istudent/service/StudentService.java | 82 ++++++++ .../ro/ubb/istudent/service/TestService.java | 24 +++ .../ro/ubb/istudent/util/ResponseUtil.java | 9 +- .../mvc/beats/controller/BeatController.java | 22 +- .../messaging/_1_basic/Recv.java | 30 +++ .../messaging/_1_basic/Send.java | 25 +++ .../messaging/_2_worker_queues/NewTask.java | 46 ++++ .../messaging/_2_worker_queues/Worker.java | 51 +++++ .../_3_publish_subscribe/EmitLog.java | 45 ++++ .../_3_publish_subscribe/ReceiveLogs.java | 33 +++ .../messaging/_4_routing/EmitLogDirect.java | 54 +++++ .../_4_routing/ReceiveLogsDirect.java | 41 ++++ .../messaging/_5_topics/EmitLogTopic.java | 67 ++++++ .../messaging/_5_topics/ReceiveLogsTopic.java | 42 ++++ .../_6_remote_procedure_call/RPCClient.java | 79 +++++++ .../_6_remote_procedure_call/RPCServer.java | 91 ++++++++ 54 files changed, 1895 insertions(+), 14 deletions(-) create mode 100644 src/main/java/ro/ubb/istudent/config/MongoConfig.java create mode 100644 src/main/java/ro/ubb/istudent/converters/CountryConverter.java create mode 100644 src/main/java/ro/ubb/istudent/converters/CourseConverter.java create mode 100644 src/main/java/ro/ubb/istudent/converters/GenericConverter.java create mode 100644 src/main/java/ro/ubb/istudent/converters/StudentConverter.java create mode 100644 src/main/java/ro/ubb/istudent/converters/TestConverter.java create mode 100644 src/main/java/ro/ubb/istudent/converters/strategy2/ConverterStrategy.java create mode 100644 src/main/java/ro/ubb/istudent/converters/strategy2/ConvertersMap.java create mode 100644 src/main/java/ro/ubb/istudent/domain/BaseEntity.java create mode 100644 src/main/java/ro/ubb/istudent/domain/CountryEntity.java create mode 100644 src/main/java/ro/ubb/istudent/domain/CourseEntity.java create mode 100644 src/main/java/ro/ubb/istudent/domain/StudentEntity.java create mode 100644 src/main/java/ro/ubb/istudent/domain/TestEntity.java create mode 100644 src/main/java/ro/ubb/istudent/dto/AgeDto.java create mode 100644 src/main/java/ro/ubb/istudent/dto/BaseDto.java create mode 100644 src/main/java/ro/ubb/istudent/dto/CountryBasedStatisticsDto.java create mode 100644 src/main/java/ro/ubb/istudent/dto/CountryDto.java create mode 100644 src/main/java/ro/ubb/istudent/dto/CourseDto.java create mode 100644 src/main/java/ro/ubb/istudent/dto/GenderBasedStatisticsDto.java create mode 100644 src/main/java/ro/ubb/istudent/dto/StudentDto.java create mode 100644 src/main/java/ro/ubb/istudent/dto/TestDto.java create mode 100644 src/main/java/ro/ubb/istudent/enums/GenderEnum.java create mode 100644 src/main/java/ro/ubb/istudent/mock/MockData.java create mode 100644 src/main/java/ro/ubb/istudent/repository/CountryRepository.java create mode 100644 src/main/java/ro/ubb/istudent/repository/CourseRepository.java create mode 100644 src/main/java/ro/ubb/istudent/repository/StudentRepository.java create mode 100644 src/main/java/ro/ubb/istudent/repository/TestRepository.java create mode 100644 src/main/java/ro/ubb/istudent/rest/AgeBasedStatistics.java create mode 100644 src/main/java/ro/ubb/istudent/rest/CountryBasedStatistics.java create mode 100644 src/main/java/ro/ubb/istudent/rest/GenderBasedStatistics.java create mode 100644 src/main/java/ro/ubb/istudent/service/AgeBasedStatisticsService.java create mode 100644 src/main/java/ro/ubb/istudent/service/CountryBasedStatisticsService.java create mode 100644 src/main/java/ro/ubb/istudent/service/CountryService.java create mode 100644 src/main/java/ro/ubb/istudent/service/CourseService.java create mode 100644 src/main/java/ro/ubb/istudent/service/GenderBasedStatisticsService.java create mode 100644 src/main/java/ro/ubb/istudent/service/StudentService.java create mode 100644 src/main/java/ro/ubb/istudent/service/TestService.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_1_basic/Recv.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_1_basic/Send.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_2_worker_queues/NewTask.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_2_worker_queues/Worker.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_3_publish_subscribe/EmitLog.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_3_publish_subscribe/ReceiveLogs.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_4_routing/EmitLogDirect.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_4_routing/ReceiveLogsDirect.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_5_topics/EmitLogTopic.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_5_topics/ReceiveLogsTopic.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_6_remote_procedure_call/RPCClient.java create mode 100644 src/main/java/ro/ubb/samples/enterprise_integration/messaging/_6_remote_procedure_call/RPCServer.java diff --git a/src/main/java/ro/ubb/istudent/IStudentApplication.java b/src/main/java/ro/ubb/istudent/IStudentApplication.java index 62cea69..f428c42 100644 --- a/src/main/java/ro/ubb/istudent/IStudentApplication.java +++ b/src/main/java/ro/ubb/istudent/IStudentApplication.java @@ -1,7 +1,12 @@ package ro.ubb.istudent; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import ro.ubb.istudent.dto.CourseDto; +import ro.ubb.istudent.service.CourseService; +import ro.ubb.istudent.service.StudentService; +import ro.ubb.istudent.service.TestService; @SpringBootApplication public class IStudentApplication { diff --git a/src/main/java/ro/ubb/istudent/config/MongoConfig.java b/src/main/java/ro/ubb/istudent/config/MongoConfig.java new file mode 100644 index 0000000..1983f62 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/config/MongoConfig.java @@ -0,0 +1,22 @@ +package ro.ubb.istudent.config; + +import com.mongodb.Mongo; +import com.mongodb.MongoClient; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.config.AbstractMongoConfiguration; +import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; + +@Configuration +@EnableMongoRepositories(basePackages = "ro.ubb.istudent.repository") +public class MongoConfig extends AbstractMongoConfiguration { + + @Override + protected String getDatabaseName() { + return "istudent"; + } + + @Override + public Mongo mongo() throws Exception { + return new MongoClient("127.0.0.1", 27017); + } +} diff --git a/src/main/java/ro/ubb/istudent/controller/GreetingController.java b/src/main/java/ro/ubb/istudent/controller/GreetingController.java index 5122ab4..f6410f0 100644 --- a/src/main/java/ro/ubb/istudent/controller/GreetingController.java +++ b/src/main/java/ro/ubb/istudent/controller/GreetingController.java @@ -3,6 +3,14 @@ import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import ro.ubb.istudent.dto.CourseDto; +import ro.ubb.istudent.dto.StudentDto; +import ro.ubb.istudent.dto.TestDto; +import ro.ubb.istudent.service.CourseService; +import ro.ubb.istudent.service.StudentService; +import ro.ubb.istudent.service.TestService; + +import java.util.Arrays; @Controller public class GreetingController { diff --git a/src/main/java/ro/ubb/istudent/converters/CountryConverter.java b/src/main/java/ro/ubb/istudent/converters/CountryConverter.java new file mode 100644 index 0000000..388fb28 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/converters/CountryConverter.java @@ -0,0 +1,44 @@ +package ro.ubb.istudent.converters; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import ro.ubb.istudent.domain.CountryEntity; +import ro.ubb.istudent.dto.CountryDto; + +import java.util.Collections; + +@Component +public class CountryConverter extends GenericConverter { + + @Autowired + private StudentConverter studentConverter; + + @Override + public CountryEntity createFromDto(CountryDto dto) { + CountryEntity countryEntity = CountryEntity.builder() + .countryName(dto.getCountryName()) + .build(); + + countryEntity.setId(dto.getId()); + + return countryEntity; + } + + @Override + public CountryDto createFromEntity(CountryEntity entity) { + CountryDto countryDto = CountryDto.builder() + .countryName(entity.getCountryName()) + .build(); + + countryDto.setId(entity.getId()); + + return countryDto; + } + + @Override + public CountryEntity updateEntity(CountryEntity entity, CountryDto dto) { + entity.setCountryName(dto.getCountryName()); + + return entity; + } +} diff --git a/src/main/java/ro/ubb/istudent/converters/CourseConverter.java b/src/main/java/ro/ubb/istudent/converters/CourseConverter.java new file mode 100644 index 0000000..6b1c75a --- /dev/null +++ b/src/main/java/ro/ubb/istudent/converters/CourseConverter.java @@ -0,0 +1,45 @@ +package ro.ubb.istudent.converters; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import ro.ubb.istudent.domain.CourseEntity; +import ro.ubb.istudent.dto.CourseDto; + +import java.util.Collections; + +@Component +public class CourseConverter extends GenericConverter { + + @Autowired + private StudentConverter studentConverter; + + @Override + public CourseEntity createFromDto(CourseDto dto) { + CourseEntity courseEntity = CourseEntity.builder() + .name(dto.getName()) + .minimumGrade(dto.getMinimumGrade()) + .build(); + courseEntity.setId(dto.getId()); + + return courseEntity; + } + + @Override + public CourseDto createFromEntity(CourseEntity entity) { + CourseDto courseDto = CourseDto.builder() + .name(entity.getName()) + .minimumGrade(entity.getMinimumGrade()) + .build(); + courseDto.setId(entity.getId()); + + return courseDto; + } + + @Override + public CourseEntity updateEntity(CourseEntity entity, CourseDto dto) { + entity.setName(dto.getName()); + entity.setMinimumGrade(dto.getMinimumGrade()); + + return entity; + } +} diff --git a/src/main/java/ro/ubb/istudent/converters/GenericConverter.java b/src/main/java/ro/ubb/istudent/converters/GenericConverter.java new file mode 100644 index 0000000..a3af82c --- /dev/null +++ b/src/main/java/ro/ubb/istudent/converters/GenericConverter.java @@ -0,0 +1,26 @@ +package ro.ubb.istudent.converters; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +public abstract class GenericConverter { + + public abstract E createFromDto(D dto); + + public abstract D createFromEntity(E entity); + + public abstract E updateEntity(E entity, D dto); + + public List createFromEntities(final Collection entities) { + return entities.stream() + .map(this::createFromEntity) + .collect(Collectors.toList()); + } + + public List createFromDtos(final Collection dtos) { + return dtos.stream() + .map(this::createFromDto) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/ro/ubb/istudent/converters/StudentConverter.java b/src/main/java/ro/ubb/istudent/converters/StudentConverter.java new file mode 100644 index 0000000..e541faa --- /dev/null +++ b/src/main/java/ro/ubb/istudent/converters/StudentConverter.java @@ -0,0 +1,56 @@ +package ro.ubb.istudent.converters; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import ro.ubb.istudent.domain.StudentEntity; +import ro.ubb.istudent.dto.StudentDto; + +import java.util.Collections; + +@Component +public class StudentConverter extends GenericConverter { + + @Autowired + private TestConverter testConverter; + + @Autowired + private CountryConverter countryConverter; + + @Override + public StudentEntity createFromDto(StudentDto dto) { + StudentEntity studentEntity = StudentEntity.builder() + .age(dto.getAge()) + .gender(dto.getGender()) + .name(dto.getName()) + .country(countryConverter.createFromDto(dto.getCountryDto())) + .tests(testConverter.createFromDtos(dto.getTests() != null ? dto.getTests() : Collections.emptyList())) + .build(); + studentEntity.setId(dto.getId()); + + return studentEntity; + } + + @Override + public StudentDto createFromEntity(StudentEntity entity) { + StudentDto studentDto = StudentDto.builder() + .age(entity.getAge()) + .gender(entity.getGender()) + .name(entity.getName()) + .countryDto(countryConverter.createFromEntity(entity.getCountry())) + .tests(testConverter.createFromEntities(entity.getTests() != null ? entity.getTests() : Collections.emptyList())) + .build(); + studentDto.setId(entity.getId()); + + return studentDto; + } + + @Override + public StudentEntity updateEntity(StudentEntity entity, StudentDto dto) { + entity.setAge(dto.getAge()); + entity.setName(dto.getName()); + entity.setGender(dto.getGender()); + entity.setTests(testConverter.createFromDtos(dto.getTests())); + + return entity; + } +} diff --git a/src/main/java/ro/ubb/istudent/converters/TestConverter.java b/src/main/java/ro/ubb/istudent/converters/TestConverter.java new file mode 100644 index 0000000..a80581f --- /dev/null +++ b/src/main/java/ro/ubb/istudent/converters/TestConverter.java @@ -0,0 +1,41 @@ +package ro.ubb.istudent.converters; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; +import ro.ubb.istudent.domain.CourseEntity; +import ro.ubb.istudent.domain.TestEntity; +import ro.ubb.istudent.dto.TestDto; + +import java.util.List; + +@Component +public class TestConverter extends GenericConverter { + + @Autowired + private CourseConverter courseConverter; + + @Override + public TestEntity createFromDto(TestDto dto) { + return TestEntity.builder() + .grade(dto.getGrade()) + .course(courseConverter.createFromDto(dto.getCourseDto())) + .build(); + } + + @Override + public TestDto createFromEntity(TestEntity entity) { + return TestDto.builder() + .grade(entity.getGrade()) + .courseDto(courseConverter.createFromEntity(entity.getCourse())) + .build(); + } + + @Override + public TestEntity updateEntity(TestEntity entity, TestDto dto) { + entity.setCourse(courseConverter.createFromDto(dto.getCourseDto())); + entity.setGrade(dto.getGrade()); + + return entity; + } +} diff --git a/src/main/java/ro/ubb/istudent/converters/strategy2/ConverterStrategy.java b/src/main/java/ro/ubb/istudent/converters/strategy2/ConverterStrategy.java new file mode 100644 index 0000000..7b97e23 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/converters/strategy2/ConverterStrategy.java @@ -0,0 +1,57 @@ +package ro.ubb.istudent.converters.strategy2; + +import org.springframework.stereotype.Component; +import ro.ubb.istudent.converters.GenericConverter; +import ro.ubb.istudent.domain.BaseEntity; +import ro.ubb.istudent.dto.BaseDto; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +public class ConverterStrategy { + + private Map map; + + private ConverterStrategy(Map map){ + this.map = map; + } + + public BaseEntity createFromDto(BaseDto dto) { + try { + return (BaseEntity) map.get(dto.getClass()).createFromDto(dto); + } catch (Throwable t){ + return null; + } + } + + public BaseDto createFromEntity(BaseEntity entity) { + try { + return (BaseDto) map.get(entity.getClass()).createFromEntity(entity); + } catch (Throwable t){ + return null; + } + } + + public BaseEntity updateEntity(BaseEntity entity, BaseDto dto) { + try { + return (BaseEntity) map.get(entity.getClass()).updateEntity(entity, dto); + } catch (Throwable t){ + return null; + } + } + + public List createFromEntities(final Collection entities) { + return entities.stream() + .map(this::createFromEntity) + .collect(Collectors.toList()); + } + + public List createFromDtos(final Collection dtos) { + return dtos.stream() + .map(this::createFromDto) + .collect(Collectors.toList()); + } +} diff --git a/src/main/java/ro/ubb/istudent/converters/strategy2/ConvertersMap.java b/src/main/java/ro/ubb/istudent/converters/strategy2/ConvertersMap.java new file mode 100644 index 0000000..70f9c8d --- /dev/null +++ b/src/main/java/ro/ubb/istudent/converters/strategy2/ConvertersMap.java @@ -0,0 +1,45 @@ +package ro.ubb.istudent.converters.strategy2; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; +import ro.ubb.istudent.converters.*; +import ro.ubb.istudent.domain.CountryEntity; +import ro.ubb.istudent.domain.CourseEntity; +import ro.ubb.istudent.domain.StudentEntity; +import ro.ubb.istudent.domain.TestEntity; +import ro.ubb.istudent.dto.CountryDto; +import ro.ubb.istudent.dto.CourseDto; +import ro.ubb.istudent.dto.StudentDto; +import ro.ubb.istudent.dto.TestDto; + +import java.util.HashMap; +import java.util.Map; + +@Component +public class ConvertersMap { + + @Autowired + private CountryConverter countryConverter; + @Autowired + private CourseConverter courseConverter; + @Autowired + private StudentConverter studentConverter; + @Autowired + private TestConverter testConverter; + + @Bean + public Map getConverters(){ + Map map = new HashMap(){{ + put(CountryDto.class, countryConverter); + put(CourseDto.class, courseConverter); + put(StudentDto.class, studentConverter); + put(TestDto.class, testConverter); + put(CountryEntity.class, countryConverter); + put(CourseEntity.class, courseConverter); + put(StudentEntity.class, studentConverter); + put(TestEntity.class, testConverter); + }}; + return map; + } +} \ No newline at end of file diff --git a/src/main/java/ro/ubb/istudent/domain/BaseEntity.java b/src/main/java/ro/ubb/istudent/domain/BaseEntity.java new file mode 100644 index 0000000..d7451be --- /dev/null +++ b/src/main/java/ro/ubb/istudent/domain/BaseEntity.java @@ -0,0 +1,15 @@ +package ro.ubb.istudent.domain; + +import lombok.*; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; + +import java.io.Serializable; + +@Getter +@Setter +public abstract class BaseEntity implements Serializable { + @Id + private ObjectId id; + +} diff --git a/src/main/java/ro/ubb/istudent/domain/CountryEntity.java b/src/main/java/ro/ubb/istudent/domain/CountryEntity.java new file mode 100644 index 0000000..c4a5bba --- /dev/null +++ b/src/main/java/ro/ubb/istudent/domain/CountryEntity.java @@ -0,0 +1,22 @@ +package ro.ubb.istudent.domain; + +import lombok.*; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@Document(collection = "countries") +public class CountryEntity extends BaseEntity { + + @Indexed(unique=true) + private String countryName; + +} diff --git a/src/main/java/ro/ubb/istudent/domain/CourseEntity.java b/src/main/java/ro/ubb/istudent/domain/CourseEntity.java new file mode 100644 index 0000000..d7fc351 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/domain/CourseEntity.java @@ -0,0 +1,26 @@ +package ro.ubb.istudent.domain; + +import lombok.*; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@Document(collection = "courses") +public class CourseEntity extends BaseEntity { + + @Indexed(unique=true) + private String name; + + private Integer minimumGrade; + + @DBRef + private List tests = new ArrayList<>(); +} diff --git a/src/main/java/ro/ubb/istudent/domain/StudentEntity.java b/src/main/java/ro/ubb/istudent/domain/StudentEntity.java new file mode 100644 index 0000000..e39b0a8 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/domain/StudentEntity.java @@ -0,0 +1,34 @@ +package ro.ubb.istudent.domain; + +import lombok.*; +import org.springframework.data.mongodb.core.index.Indexed; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; +import ro.ubb.istudent.enums.GenderEnum; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +@Document(collection = "students") +public class StudentEntity extends BaseEntity { + + @Indexed(unique=true) + private String name; + + @Indexed + private GenderEnum gender; + + // We know that every year this value needs to be incremented and one day needs to be stopped + // But as we use this entity as a mock we will assume that age is an Integer for easily manipulation + private Integer age; + + private List tests = new ArrayList<>(); + + @DBRef + private CountryEntity country; +} diff --git a/src/main/java/ro/ubb/istudent/domain/TestEntity.java b/src/main/java/ro/ubb/istudent/domain/TestEntity.java new file mode 100644 index 0000000..208af56 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/domain/TestEntity.java @@ -0,0 +1,17 @@ +package ro.ubb.istudent.domain; + +import lombok.*; +import org.springframework.data.mongodb.core.mapping.DBRef; +import org.springframework.data.mongodb.core.mapping.Document; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +@Document(collection = "tests") +public class TestEntity extends BaseEntity { + @DBRef + private CourseEntity course; + + private Integer grade; +} diff --git a/src/main/java/ro/ubb/istudent/dto/AgeDto.java b/src/main/java/ro/ubb/istudent/dto/AgeDto.java new file mode 100644 index 0000000..f54ff76 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/dto/AgeDto.java @@ -0,0 +1,14 @@ +package ro.ubb.istudent.dto; + +import lombok.*; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class AgeDto extends BaseDto{ + private Integer minAge; + + private Integer maxAge; +} diff --git a/src/main/java/ro/ubb/istudent/dto/BaseDto.java b/src/main/java/ro/ubb/istudent/dto/BaseDto.java new file mode 100644 index 0000000..7cc7309 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/dto/BaseDto.java @@ -0,0 +1,16 @@ +package ro.ubb.istudent.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.bson.types.ObjectId; + +import java.io.Serializable; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public abstract class BaseDto implements Serializable { + private ObjectId id; +} diff --git a/src/main/java/ro/ubb/istudent/dto/CountryBasedStatisticsDto.java b/src/main/java/ro/ubb/istudent/dto/CountryBasedStatisticsDto.java new file mode 100644 index 0000000..fa1e693 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/dto/CountryBasedStatisticsDto.java @@ -0,0 +1,16 @@ +package ro.ubb.istudent.dto; + +import lombok.*; + +import java.util.List; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class CountryBasedStatisticsDto extends BaseDto { + private CountryDto country; + + private List graduatedStudents; +} diff --git a/src/main/java/ro/ubb/istudent/dto/CountryDto.java b/src/main/java/ro/ubb/istudent/dto/CountryDto.java new file mode 100644 index 0000000..032a179 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/dto/CountryDto.java @@ -0,0 +1,16 @@ +package ro.ubb.istudent.dto; + +import lombok.*; + +import java.util.List; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class CountryDto extends BaseDto { + + private String countryName; + +} diff --git a/src/main/java/ro/ubb/istudent/dto/CourseDto.java b/src/main/java/ro/ubb/istudent/dto/CourseDto.java new file mode 100644 index 0000000..c249407 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/dto/CourseDto.java @@ -0,0 +1,18 @@ +package ro.ubb.istudent.dto; + +import lombok.*; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class CourseDto extends BaseDto { + + private String name; + + private Integer minimumGrade; +} diff --git a/src/main/java/ro/ubb/istudent/dto/GenderBasedStatisticsDto.java b/src/main/java/ro/ubb/istudent/dto/GenderBasedStatisticsDto.java new file mode 100644 index 0000000..7e61ca7 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/dto/GenderBasedStatisticsDto.java @@ -0,0 +1,17 @@ +package ro.ubb.istudent.dto; + +import lombok.*; +import ro.ubb.istudent.enums.GenderEnum; + +import java.util.List; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class GenderBasedStatisticsDto extends BaseDto { + private GenderEnum gender; + + private List graduatedStudents; +} diff --git a/src/main/java/ro/ubb/istudent/dto/StudentDto.java b/src/main/java/ro/ubb/istudent/dto/StudentDto.java new file mode 100644 index 0000000..1b9b4d9 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/dto/StudentDto.java @@ -0,0 +1,25 @@ +package ro.ubb.istudent.dto; + +import lombok.*; +import ro.ubb.istudent.enums.GenderEnum; + +import java.util.ArrayList; +import java.util.List; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class StudentDto extends BaseDto { + + private String name; + + private GenderEnum gender; + + private Integer age; + + private List tests = new ArrayList<>(); + + private CountryDto countryDto; +} diff --git a/src/main/java/ro/ubb/istudent/dto/TestDto.java b/src/main/java/ro/ubb/istudent/dto/TestDto.java new file mode 100644 index 0000000..1273e83 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/dto/TestDto.java @@ -0,0 +1,14 @@ +package ro.ubb.istudent.dto; + +import lombok.*; + +@Data +@Builder +@EqualsAndHashCode(callSuper = true) +@AllArgsConstructor +@NoArgsConstructor +public class TestDto extends BaseDto { + private CourseDto courseDto; + + private Integer grade; +} diff --git a/src/main/java/ro/ubb/istudent/enums/GenderEnum.java b/src/main/java/ro/ubb/istudent/enums/GenderEnum.java new file mode 100644 index 0000000..d8898c2 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/enums/GenderEnum.java @@ -0,0 +1,23 @@ +package ro.ubb.istudent.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@AllArgsConstructor +@Getter +public enum GenderEnum { + MALE("male"), + FEMALE("female"); + + private String gender; + + public static GenderEnum fromString(String value) { + return Arrays.stream(GenderEnum.values()) + .filter(gender -> value.equalsIgnoreCase(gender.getGender())) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Illegal gender inserted.")); + } + +} diff --git a/src/main/java/ro/ubb/istudent/exception/GlobalExceptionHandler.java b/src/main/java/ro/ubb/istudent/exception/GlobalExceptionHandler.java index 3e8014d..a9151ef 100644 --- a/src/main/java/ro/ubb/istudent/exception/GlobalExceptionHandler.java +++ b/src/main/java/ro/ubb/istudent/exception/GlobalExceptionHandler.java @@ -15,7 +15,7 @@ public class GlobalExceptionHandler { @ExceptionHandler(EntityNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) public void processEntityNotFoundException(EntityNotFoundException ex) { - LOG.error("Entity not found {}", ex); + LOG.error("BaseEntity not found {}", ex); } @ExceptionHandler(Exception.class) diff --git a/src/main/java/ro/ubb/istudent/mock/MockData.java b/src/main/java/ro/ubb/istudent/mock/MockData.java new file mode 100644 index 0000000..70089f3 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/mock/MockData.java @@ -0,0 +1,199 @@ +package ro.ubb.istudent.mock; + +import com.google.common.collect.ImmutableList; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import ro.ubb.istudent.config.MongoConfig; +import ro.ubb.istudent.dto.CountryDto; +import ro.ubb.istudent.dto.CourseDto; +import ro.ubb.istudent.dto.StudentDto; +import ro.ubb.istudent.dto.TestDto; +import ro.ubb.istudent.enums.GenderEnum; +import ro.ubb.istudent.service.CountryService; +import ro.ubb.istudent.service.CourseService; +import ro.ubb.istudent.service.StudentService; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.stream.IntStream; + +@Component +public class MockData { + + @Autowired + private CourseService courseService; + + @Autowired + private StudentService studentService; + + @Autowired + private CountryService countryService; + + @Autowired + private MongoConfig mongoConfig; + + @PostConstruct + public void init() { + try { + mongoConfig.mongo().dropDatabase("istudent"); + } catch (Exception e) { + e.printStackTrace(); + System.out.println("DB NOT DROPPED!"); + } + + // create countries / nationalities + List countryDtoList = ImmutableList.of( + CountryDto.builder().countryName("Romania").build(), + CountryDto.builder().countryName("Germany").build(), + CountryDto.builder().countryName("England").build() + ); + + // save contries / nationalities + countryDtoList.forEach(countryService::save); + + // create courses + List courseDtoList = ImmutableList.of( + CourseDto.builder().minimumGrade(5).name("Java").build(), + CourseDto.builder().minimumGrade(5).name("C#").build(), + CourseDto.builder().minimumGrade(6).name("Python").build(), + CourseDto.builder().minimumGrade(6).name("C").build(), + CourseDto.builder().minimumGrade(7).name("Assembly").build() + ); + + // save courses + courseDtoList.forEach(courseService::save); + + // get existing countries which we saved before + CountryDto romania = countryService.findByCountryName("Romania").get(); + CountryDto germany = countryService.findByCountryName("Germany").get(); + CountryDto england = countryService.findByCountryName("England").get(); + + // create students + List studentDtoList = ImmutableList.of( + StudentDto.builder().name("Andrei").age(21).gender(GenderEnum.MALE).countryDto(romania).build(), + StudentDto.builder().name("Mihai").age(27).gender(GenderEnum.MALE).countryDto(romania).build(), + StudentDto.builder().name("Elena").age(22).gender(GenderEnum.FEMALE).countryDto(romania).build(), + StudentDto.builder().name("Iliescu").age(100).gender(GenderEnum.MALE).countryDto(romania).build(), + StudentDto.builder().name("Hans").age(28).gender(GenderEnum.MALE).countryDto(germany).build(), + StudentDto.builder().name("Aneta").age(34).gender(GenderEnum.FEMALE).countryDto(germany).build(), + StudentDto.builder().name("Schmitz").age(40).gender(GenderEnum.MALE).countryDto(germany).build(), + StudentDto.builder().name("Beckham").age(45).gender(GenderEnum.MALE).countryDto(england).build(), + StudentDto.builder().name("Rooney").age(39).gender(GenderEnum.MALE).countryDto(england).build(), + StudentDto.builder().name("Abbey").age(23).gender(GenderEnum.FEMALE).countryDto(england).build() + ); + + // save students + studentDtoList.forEach(studentService::save); + + // get existing courses which we saved before + List existingCourses = ImmutableList.of( + courseService.findByName("Java").get(), + courseService.findByName("C#").get(), + courseService.findByName("Python").get(), + courseService.findByName("C").get(), + courseService.findByName("Assembly").get() + ); + + + // create tests + List> testDtoList = ImmutableList.of( + // Andrei tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(4).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(6).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(6).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(7).build()), + + // Mihai tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(5).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(5).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(5).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(5).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(5).build()), + + // Elena tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(3).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(5).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(6).build()), + + // Iliescu tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(10).build()), + + // Hans tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(1).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(5).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(6).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(7).build()), + + // Aneta tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(6).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(6).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(6).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(6).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(6).build()), + + // Schmitz tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(7).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(7).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(7).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(7).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(7).build()), + + // Beckaham tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(8).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(8).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(8).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(8).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(8).build()), + + // Rooney tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(4).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(4).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(4).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(10).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(10).build()), + + // Abbey tests + ImmutableList.of( + TestDto.builder().courseDto(existingCourses.get(0)).grade(5).build(), + TestDto.builder().courseDto(existingCourses.get(1)).grade(6).build(), + TestDto.builder().courseDto(existingCourses.get(2)).grade(7).build(), + TestDto.builder().courseDto(existingCourses.get(3)).grade(8).build(), + TestDto.builder().courseDto(existingCourses.get(4)).grade(9).build()) + ); + + + // get existing students because we want to add some tests to them + List existingStudents = studentService.findAll(); + + + // now we set the list of tests for each students and we update in database + IntStream.range(0, studentDtoList.size()) + .boxed() + .forEach(i -> + { + StudentDto studentDto = existingStudents.get(i); + + studentDto.setTests(testDtoList.get(i)); + studentService.save(studentDto); + }); + + studentService.findByCountry(countryService.findByCountryName("Romania").get()); + } +} diff --git a/src/main/java/ro/ubb/istudent/repository/CountryRepository.java b/src/main/java/ro/ubb/istudent/repository/CountryRepository.java new file mode 100644 index 0000000..b682c26 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/repository/CountryRepository.java @@ -0,0 +1,13 @@ +package ro.ubb.istudent.repository; + +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.repository.MongoRepository; +import ro.ubb.istudent.domain.CountryEntity; +import ro.ubb.istudent.domain.CourseEntity; + +import java.util.Optional; + +public interface CountryRepository extends MongoRepository { + + Optional findByCountryName(String countryName); +} diff --git a/src/main/java/ro/ubb/istudent/repository/CourseRepository.java b/src/main/java/ro/ubb/istudent/repository/CourseRepository.java new file mode 100644 index 0000000..638b4a6 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/repository/CourseRepository.java @@ -0,0 +1,13 @@ +package ro.ubb.istudent.repository; + +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.repository.MongoRepository; +import ro.ubb.istudent.domain.CourseEntity; +import ro.ubb.istudent.domain.StudentEntity; + +import java.util.Optional; + +public interface CourseRepository extends MongoRepository { + + Optional findByName(String name); +} diff --git a/src/main/java/ro/ubb/istudent/repository/StudentRepository.java b/src/main/java/ro/ubb/istudent/repository/StudentRepository.java new file mode 100644 index 0000000..14f32b4 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/repository/StudentRepository.java @@ -0,0 +1,22 @@ +package ro.ubb.istudent.repository; + +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.repository.MongoRepository; +import ro.ubb.istudent.domain.CountryEntity; +import ro.ubb.istudent.domain.StudentEntity; +import ro.ubb.istudent.enums.GenderEnum; + +import java.util.List; +import java.util.Optional; + +public interface StudentRepository extends MongoRepository { + Optional findByName(String name); + + Optional> findAllByCountry(CountryEntity countryEntity); + + Optional> findAllByGender(GenderEnum gender); + + Optional> findAllByAgeBetween(Integer minAge, Integer maxAge); + + Optional> findAllByAgeGreaterThanEqual(Integer age); +} diff --git a/src/main/java/ro/ubb/istudent/repository/TestRepository.java b/src/main/java/ro/ubb/istudent/repository/TestRepository.java new file mode 100644 index 0000000..5a60bb2 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/repository/TestRepository.java @@ -0,0 +1,9 @@ +package ro.ubb.istudent.repository; + +import org.bson.types.ObjectId; +import org.springframework.data.mongodb.repository.MongoRepository; +import ro.ubb.istudent.domain.StudentEntity; +import ro.ubb.istudent.domain.TestEntity; + +public interface TestRepository extends MongoRepository { +} diff --git a/src/main/java/ro/ubb/istudent/rest/AgeBasedStatistics.java b/src/main/java/ro/ubb/istudent/rest/AgeBasedStatistics.java new file mode 100644 index 0000000..5503827 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/rest/AgeBasedStatistics.java @@ -0,0 +1,36 @@ +package ro.ubb.istudent.rest; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +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.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ro.ubb.istudent.dto.AgeDto; +import ro.ubb.istudent.service.StudentService; +import ro.ubb.istudent.util.ResponseUtil; + +import static ro.ubb.istudent.util.ResponseUtil.STATISTICS_URL; + +@RequestMapping("/api") +@RestController +@Slf4j +public class AgeBasedStatistics { + private final String baseUrl; + + private StudentService studentService; + + public AgeBasedStatistics(@Value("${application.base-url}") String baseUrl, StudentService studentService) { + this.baseUrl = baseUrl; + this.studentService = studentService; + } + + @PostMapping(value = STATISTICS_URL + "/age", consumes = "application/json", produces = "application/json") + public ResponseEntity getStudentsBetweenAge(@RequestBody AgeDto ageDto) { + if (null == ageDto.getMaxAge()) { + return ResponseUtil.wrapOrNotFound(studentService.findByAgeGreaterThanOrEqual(ageDto.getMinAge())); + } + return ResponseUtil.wrapOrNotFound(studentService.findByAgeBetween(ageDto)); + } +} diff --git a/src/main/java/ro/ubb/istudent/rest/CountryBasedStatistics.java b/src/main/java/ro/ubb/istudent/rest/CountryBasedStatistics.java new file mode 100644 index 0000000..39c7c88 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/rest/CountryBasedStatistics.java @@ -0,0 +1,36 @@ +package ro.ubb.istudent.rest; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ro.ubb.istudent.service.CountryBasedStatisticsService; +import ro.ubb.istudent.service.CountryService; +import ro.ubb.istudent.util.ResponseUtil; + +import static ro.ubb.istudent.util.ResponseUtil.STATISTICS_URL; + +@RequestMapping("/api") +@RestController +@Slf4j +public class CountryBasedStatistics { + private final String baseUrl; + + private CountryBasedStatisticsService countryBasedStatisticsService; + + private CountryService countryService; + + public CountryBasedStatistics(@Value("${application.base-url}") String baseUrl, CountryBasedStatisticsService countryBasedStatisticsService, CountryService countryService) { + this.baseUrl = baseUrl; + this.countryBasedStatisticsService = countryBasedStatisticsService; + this.countryService = countryService; + } + + @GetMapping(STATISTICS_URL + "/country/{country}") + public ResponseEntity getGraduatedStudentsByCountry(@PathVariable("country") String country) { + return ResponseUtil.wrapOrNotFound(countryBasedStatisticsService.findGraduatedStudentsByCountry(countryService.findByCountryName(country).get())); + } +} diff --git a/src/main/java/ro/ubb/istudent/rest/GenderBasedStatistics.java b/src/main/java/ro/ubb/istudent/rest/GenderBasedStatistics.java new file mode 100644 index 0000000..21d311b --- /dev/null +++ b/src/main/java/ro/ubb/istudent/rest/GenderBasedStatistics.java @@ -0,0 +1,35 @@ +package ro.ubb.istudent.rest; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.EnumUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import ro.ubb.istudent.enums.GenderEnum; +import ro.ubb.istudent.service.GenderBasedStatisticsService; +import ro.ubb.istudent.util.ResponseUtil; + +import static ro.ubb.istudent.util.ResponseUtil.STATISTICS_URL; + +@RequestMapping("/api") +@RestController +@Slf4j +public class GenderBasedStatistics { + + private final String baseUrl; + + private GenderBasedStatisticsService genderBasedStatisticsService; + + public GenderBasedStatistics(@Value("${application.base-url}") String baseUrl, GenderBasedStatisticsService genderBasedStatisticsService) { + this.genderBasedStatisticsService = genderBasedStatisticsService; + this.baseUrl = baseUrl; + } + + @GetMapping(STATISTICS_URL + "/gender/{gender}") + public ResponseEntity getGraduatedStudentsByGender(@PathVariable("gender") String gender) { + return ResponseUtil.wrapOrNotFound(genderBasedStatisticsService.findGraduatedStudentsByGender(EnumUtils.getEnum(GenderEnum.class, gender.toLowerCase()))); + } +} \ No newline at end of file diff --git a/src/main/java/ro/ubb/istudent/service/AgeBasedStatisticsService.java b/src/main/java/ro/ubb/istudent/service/AgeBasedStatisticsService.java new file mode 100644 index 0000000..6647fbe --- /dev/null +++ b/src/main/java/ro/ubb/istudent/service/AgeBasedStatisticsService.java @@ -0,0 +1,15 @@ +package ro.ubb.istudent.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@AllArgsConstructor +@Slf4j +public class AgeBasedStatisticsService { + + private StudentService studentService; + + +} diff --git a/src/main/java/ro/ubb/istudent/service/CountryBasedStatisticsService.java b/src/main/java/ro/ubb/istudent/service/CountryBasedStatisticsService.java new file mode 100644 index 0000000..4ccd672 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/service/CountryBasedStatisticsService.java @@ -0,0 +1,49 @@ +package ro.ubb.istudent.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ro.ubb.istudent.dto.CountryBasedStatisticsDto; +import ro.ubb.istudent.dto.CountryDto; +import ro.ubb.istudent.dto.StudentDto; +import ro.ubb.istudent.dto.TestDto; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Service +@AllArgsConstructor +@Slf4j +public class CountryBasedStatisticsService { + + private StudentService studentService; + + public Optional findGraduatedStudentsByCountry(CountryDto countryDto) { + return studentService.findByCountry(countryDto) + .flatMap(studentDtos -> buildCountryBasedStatisticsDto(studentDtos, countryDto)); + } + + private Optional buildCountryBasedStatisticsDto(List studentList, CountryDto countryDto) { + CountryBasedStatisticsDto countryBasedStatisticsDto = new CountryBasedStatisticsDto(); + + countryBasedStatisticsDto.setCountry(countryDto); + + List graduatedStudents = studentList.stream() + .filter(studentDto -> checkIfAllTestsArePassed(studentDto.getTests())) + .collect(Collectors.toList()); + + if (graduatedStudents.size() == 0) { + return Optional.empty(); + } + + countryBasedStatisticsDto.setGraduatedStudents(graduatedStudents); + + return Optional.of(countryBasedStatisticsDto); + } + + private boolean checkIfAllTestsArePassed(List tests) { + return tests.stream() + .anyMatch(testDto -> testDto.getGrade() < testDto.getCourseDto().getMinimumGrade()); + } +} diff --git a/src/main/java/ro/ubb/istudent/service/CountryService.java b/src/main/java/ro/ubb/istudent/service/CountryService.java new file mode 100644 index 0000000..da5afdd --- /dev/null +++ b/src/main/java/ro/ubb/istudent/service/CountryService.java @@ -0,0 +1,33 @@ +package ro.ubb.istudent.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ro.ubb.istudent.converters.CountryConverter; +import ro.ubb.istudent.converters.strategy2.ConverterStrategy; +import ro.ubb.istudent.domain.BaseEntity; +import ro.ubb.istudent.domain.CountryEntity; +import ro.ubb.istudent.dto.CountryDto; +import ro.ubb.istudent.repository.CountryRepository; + +import java.util.Optional; + +@Service +@AllArgsConstructor +@Slf4j +public class CountryService { + + private CountryRepository repository; + private ConverterStrategy converterStrategy; + + public CountryDto save(CountryDto countryDto) { + return (CountryDto)converterStrategy + .createFromEntity(repository.save((CountryEntity) converterStrategy.createFromDto(countryDto))); + } + + public Optional findByCountryName(String countryName) { + return repository.findByCountryName(countryName) + .map(entity -> (CountryDto) converterStrategy.createFromEntity(entity)); + } +} diff --git a/src/main/java/ro/ubb/istudent/service/CourseService.java b/src/main/java/ro/ubb/istudent/service/CourseService.java new file mode 100644 index 0000000..34c9e48 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/service/CourseService.java @@ -0,0 +1,32 @@ +package ro.ubb.istudent.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ro.ubb.istudent.converters.CourseConverter; +import ro.ubb.istudent.converters.strategy2.ConverterStrategy; +import ro.ubb.istudent.domain.CourseEntity; +import ro.ubb.istudent.dto.CourseDto; +import ro.ubb.istudent.repository.CourseRepository; + +import java.util.Optional; + +@Service +@AllArgsConstructor +@Slf4j +public class CourseService { + + private CourseRepository repository; + private ConverterStrategy converterStrategy; + + public CourseDto save(CourseDto studentDto) { + return (CourseDto) converterStrategy.createFromEntity( + repository.save((CourseEntity) converterStrategy.createFromDto(studentDto)) + ); + } + + public Optional findByName(String name) { + return repository.findByName(name) + .map(courseEntity -> (CourseDto)converterStrategy.createFromEntity(courseEntity)); + } +} diff --git a/src/main/java/ro/ubb/istudent/service/GenderBasedStatisticsService.java b/src/main/java/ro/ubb/istudent/service/GenderBasedStatisticsService.java new file mode 100644 index 0000000..5be33a5 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/service/GenderBasedStatisticsService.java @@ -0,0 +1,52 @@ +package ro.ubb.istudent.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ro.ubb.istudent.dto.GenderBasedStatisticsDto; +import ro.ubb.istudent.dto.StudentDto; +import ro.ubb.istudent.dto.TestDto; +import ro.ubb.istudent.enums.GenderEnum; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +@Service +@AllArgsConstructor +@Slf4j +public class GenderBasedStatisticsService { + + private StudentService studentService; + + /** + * @return List of students which passed all their tests. + */ + public Optional findGraduatedStudentsByGender(GenderEnum gender) { + return studentService.findByGender(gender) + .flatMap(studentDtos -> buildGenderBasedStatisticDto(studentDtos, gender)); + } + + private Optional buildGenderBasedStatisticDto(List studentList, GenderEnum gender) { + GenderBasedStatisticsDto genderBasedStatisticsDto = new GenderBasedStatisticsDto(); + + genderBasedStatisticsDto.setGender(gender); + + List graduatedStudents = studentList.stream() + .filter(studentDto -> checkIfAllTestsArePassed(studentDto.getTests())) + .collect(Collectors.toList()); + + if (graduatedStudents.size() == 0) { + return Optional.empty(); + } + + genderBasedStatisticsDto.setGraduatedStudents(graduatedStudents); + + return Optional.of(genderBasedStatisticsDto); + } + + private boolean checkIfAllTestsArePassed(List tests) { + return tests.stream() + .anyMatch(testDto -> testDto.getGrade() < testDto.getCourseDto().getMinimumGrade()); + } +} diff --git a/src/main/java/ro/ubb/istudent/service/StudentService.java b/src/main/java/ro/ubb/istudent/service/StudentService.java new file mode 100644 index 0000000..8682680 --- /dev/null +++ b/src/main/java/ro/ubb/istudent/service/StudentService.java @@ -0,0 +1,82 @@ +package ro.ubb.istudent.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ro.ubb.istudent.converters.CountryConverter; +import ro.ubb.istudent.converters.StudentConverter; +import ro.ubb.istudent.converters.strategy2.ConverterStrategy; +import ro.ubb.istudent.domain.BaseEntity; +import ro.ubb.istudent.domain.CountryEntity; +import ro.ubb.istudent.domain.StudentEntity; +import ro.ubb.istudent.dto.AgeDto; +import ro.ubb.istudent.dto.BaseDto; +import ro.ubb.istudent.dto.CountryDto; +import ro.ubb.istudent.dto.StudentDto; +import ro.ubb.istudent.enums.GenderEnum; +import ro.ubb.istudent.repository.StudentRepository; +import ro.ubb.samples.architectural.mvc.student.model.Student; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +@Service +@AllArgsConstructor +@Slf4j +public class StudentService { + + private StudentRepository repository; + + private ConverterStrategy converterStrategy; + + public StudentDto save(StudentDto studentDto) { + return (StudentDto) converterStrategy + .createFromEntity(repository.save((StudentEntity) converterStrategy.createFromDto(studentDto))); + } + + public List findAll() { + return converterStrategy.createFromEntities(repository.findAll()) + .stream().map(t -> (StudentDto) t).collect(Collectors.toList()); + } + + public Optional findByName(String name) { + return repository.findByName(name) + .map(s -> (StudentDto) converterStrategy.createFromEntity(s)); + } + + public Optional> findByCountry(CountryDto countryDto) { + return convertStudentEntitiesToDtos( + repository.findAllByCountry((CountryEntity) converterStrategy.createFromDto(countryDto)) + ); + } + + public Optional> findByGender(GenderEnum gender) { + return convertStudentEntitiesToDtos(repository.findAllByGender(gender)); + } + + public Optional> findByAgeBetween(AgeDto ageDto) { + return convertStudentEntitiesToDtos(repository.findAllByAgeBetween(ageDto.getMinAge(), ageDto.getMaxAge())); + } + + public Optional> findByAgeGreaterThanOrEqual(Integer age) { + return convertStudentEntitiesToDtos(repository.findAllByAgeGreaterThanEqual(age)); + } + + public Optional update(StudentDto studentDto) { + return repository.findByName(studentDto.getName()) + .map(studentEntity -> (StudentEntity)converterStrategy.updateEntity(studentEntity, studentDto)) + .map(repository::save) + .map(studentEntity -> (StudentDto) converterStrategy.createFromEntity(studentEntity)); + } + + private Optional> convertStudentEntitiesToDtos(Optional> optional){ + return optional.map(studentEntities -> + studentEntities.stream() + .map(stEntity -> (StudentDto)converterStrategy.createFromEntity(stEntity)) + .collect(Collectors.toList()) + ); + } + +} diff --git a/src/main/java/ro/ubb/istudent/service/TestService.java b/src/main/java/ro/ubb/istudent/service/TestService.java new file mode 100644 index 0000000..8ef362d --- /dev/null +++ b/src/main/java/ro/ubb/istudent/service/TestService.java @@ -0,0 +1,24 @@ +package ro.ubb.istudent.service; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import ro.ubb.istudent.converters.TestConverter; +import ro.ubb.istudent.converters.strategy2.ConverterStrategy; +import ro.ubb.istudent.domain.TestEntity; +import ro.ubb.istudent.dto.TestDto; +import ro.ubb.istudent.repository.TestRepository; + +@Service +@AllArgsConstructor +@Slf4j +public class TestService { + + private TestRepository repository; + private ConverterStrategy converterStrategy; + + public TestDto save(TestDto studentDto) { + return (TestDto) converterStrategy + .createFromEntity(repository.save((TestEntity) converterStrategy.createFromDto(studentDto))); + } +} diff --git a/src/main/java/ro/ubb/istudent/util/ResponseUtil.java b/src/main/java/ro/ubb/istudent/util/ResponseUtil.java index f9fec6d..eeade5b 100644 --- a/src/main/java/ro/ubb/istudent/util/ResponseUtil.java +++ b/src/main/java/ro/ubb/istudent/util/ResponseUtil.java @@ -1,14 +1,19 @@ package ro.ubb.istudent.util; import org.springframework.http.ResponseEntity; -import ro.ubb.istudent.dto.Dto; +import ro.ubb.istudent.dto.BaseDto; import ro.ubb.istudent.exception.EntityNotFoundException; +import java.util.List; import java.util.Optional; public class ResponseUtil { - public static ResponseEntity wrapOrNotFound(Optional dtoOptional) { + + public static final String STATISTICS_URL = "/statistics"; + + public static ResponseEntity wrapOrNotFound(Optional dtoOptional) { return dtoOptional.map(ResponseEntity::ok) .orElseThrow(() -> new EntityNotFoundException("Cannot find entity by id.")); + } } diff --git a/src/main/java/ro/ubb/samples/architectural/mvc/beats/controller/BeatController.java b/src/main/java/ro/ubb/samples/architectural/mvc/beats/controller/BeatController.java index 9b4df45..505ed58 100644 --- a/src/main/java/ro/ubb/samples/architectural/mvc/beats/controller/BeatController.java +++ b/src/main/java/ro/ubb/samples/architectural/mvc/beats/controller/BeatController.java @@ -19,32 +19,32 @@ public BeatController(BeatModelInterface model) { @Override public void start() { -model.on(); -view.disableStartMenuItem(); -view.disableStopMenuItem(); + model.on(); + view.disableStartMenuItem(); + view.disableStopMenuItem(); } @Override public void stop() { -model.off(); -view.disableStopMenuItem(); -view.disableStartMenuItem(); + model.off(); + view.disableStopMenuItem(); + view.disableStartMenuItem(); } @Override public void increaseBPM() { -int bpm = model.getBPM(); -model.setBPM(bpm+1); + int bpm = model.getBPM(); + model.setBPM(bpm + 1); } @Override public void decreaseBPM() { -int bpm = model.getBPM(); -model.setBPM(bpm-1); + int bpm = model.getBPM(); + model.setBPM(bpm - 1); } @Override public void setBPM(int bpm) { -model.setBPM(bpm); + model.setBPM(bpm); } } diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_1_basic/Recv.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_1_basic/Recv.java new file mode 100644 index 0000000..ef85213 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_1_basic/Recv.java @@ -0,0 +1,30 @@ +package ro.ubb.samples.enterprise_integration.messaging._1_basic; + +import com.rabbitmq.client.*; + +import java.io.IOException; + +public class Recv { + + private final static String QUEUE_NAME = "hello"; + + public static void main(String[] argv) throws Exception { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + Connection connection = factory.newConnection(); + Channel channel = connection.createChannel(); + + channel.queueDeclare(QUEUE_NAME, false, false, false, null); + System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); + + Consumer consumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) + throws IOException { + String message = new String(body, "UTF-8"); + System.out.println(" [x] Received '" + message + "'"); + } + }; + channel.basicConsume(QUEUE_NAME, true, consumer); + } +} diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_1_basic/Send.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_1_basic/Send.java new file mode 100644 index 0000000..782cce4 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_1_basic/Send.java @@ -0,0 +1,25 @@ +package ro.ubb.samples.enterprise_integration.messaging._1_basic; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; + +public class Send { + + private final static String QUEUE_NAME = "hello"; + + public static void main(String[] argv) throws Exception { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + Connection connection = factory.newConnection(); + Channel channel = connection.createChannel(); + + channel.queueDeclare(QUEUE_NAME, false, false, false, null); + String message = "Hello World!"; + channel.basicPublish("", QUEUE_NAME, null, message.getBytes("UTF-8")); + System.out.println(" [x] Sent '" + message + "'"); + + channel.close(); + connection.close(); + } +} diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_2_worker_queues/NewTask.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_2_worker_queues/NewTask.java new file mode 100644 index 0000000..a56a000 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_2_worker_queues/NewTask.java @@ -0,0 +1,46 @@ +package ro.ubb.samples.enterprise_integration.messaging._2_worker_queues; + +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.MessageProperties; + +public class NewTask { + + private static final String TASK_QUEUE_NAME = "task_queue"; + + public static void main(String[] argv) throws Exception { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + Connection connection = factory.newConnection(); + Channel channel = connection.createChannel(); + + channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null); + + String message = getMessage(argv); + + channel.basicPublish("", TASK_QUEUE_NAME, + MessageProperties.PERSISTENT_TEXT_PLAIN, + message.getBytes("UTF-8")); + System.out.println(" [x] Sent '" + message + "'"); + + channel.close(); + connection.close(); + } + + private static String getMessage(String[] strings) { + if (strings.length < 1) + return "Hello World!"; + return joinStrings(strings, " "); + } + + private static String joinStrings(String[] strings, String delimiter) { + int length = strings.length; + if (length == 0) return ""; + StringBuilder words = new StringBuilder(strings[0]); + for (int i = 1; i < length; i++) { + words.append(delimiter).append(strings[i]); + } + return words.toString(); + } +} diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_2_worker_queues/Worker.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_2_worker_queues/Worker.java new file mode 100644 index 0000000..5c5161b --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_2_worker_queues/Worker.java @@ -0,0 +1,51 @@ +package ro.ubb.samples.enterprise_integration.messaging._2_worker_queues; + +import com.rabbitmq.client.*; + +import java.io.IOException; + +public class Worker { + + private static final String TASK_QUEUE_NAME = "task_queue"; + + public static void main(String[] argv) throws Exception { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + final Connection connection = factory.newConnection(); + final Channel channel = connection.createChannel(); + + channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null); + System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); + + channel.basicQos(1); + + final Consumer consumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + String message = new String(body, "UTF-8"); + + System.out.println(" [x] Received '" + message + "'"); + try { + doWork(message); + } finally { + System.out.println(" [x] Done"); + channel.basicAck(envelope.getDeliveryTag(), false); + } + } + }; + channel.basicConsume(TASK_QUEUE_NAME, false, consumer); + } + + private static void doWork(String task) { + for (char ch : task.toCharArray()) { + if (ch == '.') { + try { + Thread.sleep(1000); + } catch (InterruptedException _ignored) { + Thread.currentThread().interrupt(); + } + } + } + } +} + diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_3_publish_subscribe/EmitLog.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_3_publish_subscribe/EmitLog.java new file mode 100644 index 0000000..ada529c --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_3_publish_subscribe/EmitLog.java @@ -0,0 +1,45 @@ +package ro.ubb.samples.enterprise_integration.messaging._3_publish_subscribe; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.Channel; + +public class EmitLog { + + private static final String EXCHANGE_NAME = "logs"; + + public static void main(String[] argv) throws Exception { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + Connection connection = factory.newConnection(); + Channel channel = connection.createChannel(); + + channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT); + + String message = getMessage(argv); + + channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes("UTF-8")); + System.out.println(" [x] Sent '" + message + "'"); + + channel.close(); + connection.close(); + } + + private static String getMessage(String[] strings){ + if (strings.length < 1) + return "info: Hello World!"; + return joinStrings(strings, " "); + } + + private static String joinStrings(String[] strings, String delimiter) { + int length = strings.length; + if (length == 0) return ""; + StringBuilder words = new StringBuilder(strings[0]); + for (int i = 1; i < length; i++) { + words.append(delimiter).append(strings[i]); + } + return words.toString(); + } +} + diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_3_publish_subscribe/ReceiveLogs.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_3_publish_subscribe/ReceiveLogs.java new file mode 100644 index 0000000..e1ec938 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_3_publish_subscribe/ReceiveLogs.java @@ -0,0 +1,33 @@ +package ro.ubb.samples.enterprise_integration.messaging._3_publish_subscribe; + +import com.rabbitmq.client.*; + +import java.io.IOException; + +public class ReceiveLogs { + private static final String EXCHANGE_NAME = "logs"; + + public static void main(String[] argv) throws Exception { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + Connection connection = factory.newConnection(); + Channel channel = connection.createChannel(); + + channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT); + String queueName = channel.queueDeclare().getQueue(); + channel.queueBind(queueName, EXCHANGE_NAME, ""); + + System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); + + Consumer consumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, + AMQP.BasicProperties properties, byte[] body) throws IOException { + String message = new String(body, "UTF-8"); + System.out.println(" [x] Received '" + message + "'"); + } + }; + channel.basicConsume(queueName, true, consumer); + } +} + diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_4_routing/EmitLogDirect.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_4_routing/EmitLogDirect.java new file mode 100644 index 0000000..10186b5 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_4_routing/EmitLogDirect.java @@ -0,0 +1,54 @@ +package ro.ubb.samples.enterprise_integration.messaging._4_routing; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.Channel; + +public class EmitLogDirect { + + private static final String EXCHANGE_NAME = "direct_logs"; + + public static void main(String[] argv) throws Exception { + + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + Connection connection = factory.newConnection(); + Channel channel = connection.createChannel(); + + channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); + + String severity = getSeverity(argv); + String message = getMessage(argv); + + channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes("UTF-8")); + System.out.println(" [x] Sent '" + severity + "':'" + message + "'"); + + channel.close(); + connection.close(); + } + + private static String getSeverity(String[] strings){ + if (strings.length < 1) + return "info"; + return strings[0]; + } + + private static String getMessage(String[] strings){ + if (strings.length < 2) + return "Hello World!"; + return joinStrings(strings, " ", 1); + } + + private static String joinStrings(String[] strings, String delimiter, int startIndex) { + int length = strings.length; + if (length == 0 ) return ""; + if (length < startIndex ) return ""; + StringBuilder words = new StringBuilder(strings[startIndex]); + for (int i = startIndex + 1; i < length; i++) { + words.append(delimiter).append(strings[i]); + } + return words.toString(); + } +} + diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_4_routing/ReceiveLogsDirect.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_4_routing/ReceiveLogsDirect.java new file mode 100644 index 0000000..d719dff --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_4_routing/ReceiveLogsDirect.java @@ -0,0 +1,41 @@ +package ro.ubb.samples.enterprise_integration.messaging._4_routing; + +import com.rabbitmq.client.*; + +import java.io.IOException; + +public class ReceiveLogsDirect { + + private static final String EXCHANGE_NAME = "direct_logs"; + + public static void main(String[] argv) throws Exception { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + Connection connection = factory.newConnection(); + Channel channel = connection.createChannel(); + + channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); + String queueName = channel.queueDeclare().getQueue(); + + if (argv.length < 1){ + System.err.println("Usage: ReceiveLogsDirect [info] [warning] [error]"); + System.exit(1); + } + + for(String severity : argv){ + channel.queueBind(queueName, EXCHANGE_NAME, severity); + } + System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); + + Consumer consumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, + AMQP.BasicProperties properties, byte[] body) throws IOException { + String message = new String(body, "UTF-8"); + System.out.println(" [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'"); + } + }; + channel.basicConsume(queueName, true, consumer); + } +} + diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_5_topics/EmitLogTopic.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_5_topics/EmitLogTopic.java new file mode 100644 index 0000000..0ce3d29 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_5_topics/EmitLogTopic.java @@ -0,0 +1,67 @@ +package ro.ubb.samples.enterprise_integration.messaging._5_topics; + +import com.rabbitmq.client.BuiltinExchangeType; +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.Channel; + +public class EmitLogTopic { + + private static final String EXCHANGE_NAME = "topic_logs"; + + public static void main(String[] argv) { + Connection connection = null; + Channel channel = null; + try { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + + connection = factory.newConnection(); + channel = connection.createChannel(); + + channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC); + + String routingKey = getRouting(argv); + String message = getMessage(argv); + + channel.basicPublish(EXCHANGE_NAME, routingKey, null, message.getBytes("UTF-8")); + System.out.println(" [x] Sent '" + routingKey + "':'" + message + "'"); + + } + catch (Exception e) { + e.printStackTrace(); + } + finally { + if (connection != null) { + try { + connection.close(); + } + catch (Exception ignore) {} + } + } + } + + private static String getRouting(String[] strings){ + if (strings.length < 1) + return "anonymous.info"; + return strings[0]; + } + + private static String getMessage(String[] strings){ + if (strings.length < 2) + return "Hello World!"; + return joinStrings(strings, " ", 1); + } + + private static String joinStrings(String[] strings, String delimiter, int startIndex) { + int length = strings.length; + if (length == 0 ) return ""; + if (length < startIndex ) return ""; + StringBuilder words = new StringBuilder(strings[startIndex]); + for (int i = startIndex + 1; i < length; i++) { + words.append(delimiter).append(strings[i]); + } + return words.toString(); + } +} + diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_5_topics/ReceiveLogsTopic.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_5_topics/ReceiveLogsTopic.java new file mode 100644 index 0000000..b972342 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_5_topics/ReceiveLogsTopic.java @@ -0,0 +1,42 @@ +package ro.ubb.samples.enterprise_integration.messaging._5_topics; + +import com.rabbitmq.client.*; + +import java.io.IOException; + +public class ReceiveLogsTopic { + + private static final String EXCHANGE_NAME = "topic_logs"; + + public static void main(String[] argv) throws Exception { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + Connection connection = factory.newConnection(); + Channel channel = connection.createChannel(); + + channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC); + String queueName = channel.queueDeclare().getQueue(); + + if (argv.length < 1) { + System.err.println("Usage: ReceiveLogsTopic [binding_key]..."); + System.exit(1); + } + + for (String bindingKey : argv) { + channel.queueBind(queueName, EXCHANGE_NAME, bindingKey); + } + + System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); + + Consumer consumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, + AMQP.BasicProperties properties, byte[] body) throws IOException { + String message = new String(body, "UTF-8"); + System.out.println(" [x] Received '" + envelope.getRoutingKey() + "':'" + message + "'"); + } + }; + channel.basicConsume(queueName, true, consumer); + } +} + diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_6_remote_procedure_call/RPCClient.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_6_remote_procedure_call/RPCClient.java new file mode 100644 index 0000000..0402ef1 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_6_remote_procedure_call/RPCClient.java @@ -0,0 +1,79 @@ +package ro.ubb.samples.enterprise_integration.messaging._6_remote_procedure_call; + +import com.rabbitmq.client.*; + +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeoutException; + +public class RPCClient { + + private Connection connection; + private Channel channel; + private String requestQueueName = "rpc_queue"; + private String replyQueueName; + + public RPCClient() throws IOException, TimeoutException { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + + connection = factory.newConnection(); + channel = connection.createChannel(); + + replyQueueName = channel.queueDeclare().getQueue(); + } + + public String call(String message) throws IOException, InterruptedException { + String corrId = UUID.randomUUID().toString(); + + AMQP.BasicProperties props = new AMQP.BasicProperties + .Builder() + .correlationId(corrId) + .replyTo(replyQueueName) + .build(); + + channel.basicPublish("", requestQueueName, props, message.getBytes("UTF-8")); + + final BlockingQueue response = new ArrayBlockingQueue(1); + + channel.basicConsume(replyQueueName, true, new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + if (properties.getCorrelationId().equals(corrId)) { + response.offer(new String(body, "UTF-8")); + } + } + }); + + return response.take(); + } + + public void close() throws IOException { + connection.close(); + } + + public static void main(String[] argv) { + RPCClient fibonacciRpc = null; + String response = null; + try { + fibonacciRpc = new RPCClient(); + + String fibReq = "40"; + System.out.println(" [x] Requesting fib(" + fibReq + ")"); + response = fibonacciRpc.call(fibReq); + System.out.println(" [.] Got '" + response + "'"); + } catch (IOException | TimeoutException | InterruptedException e) { + e.printStackTrace(); + } finally { + if (fibonacciRpc != null) { + try { + fibonacciRpc.close(); + } catch (IOException _ignore) { + } + } + } + } +} + diff --git a/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_6_remote_procedure_call/RPCServer.java b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_6_remote_procedure_call/RPCServer.java new file mode 100644 index 0000000..579b6e6 --- /dev/null +++ b/src/main/java/ro/ubb/samples/enterprise_integration/messaging/_6_remote_procedure_call/RPCServer.java @@ -0,0 +1,91 @@ +package ro.ubb.samples.enterprise_integration.messaging._6_remote_procedure_call; + +import com.rabbitmq.client.ConnectionFactory; +import com.rabbitmq.client.Connection; +import com.rabbitmq.client.Channel; +import com.rabbitmq.client.Consumer; +import com.rabbitmq.client.DefaultConsumer; +import com.rabbitmq.client.AMQP; +import com.rabbitmq.client.Envelope; + +import java.io.IOException; +import java.util.concurrent.TimeoutException; + +public class RPCServer { + + private static final String RPC_QUEUE_NAME = "rpc_queue"; + + private static int fib(int n) { + if (n ==0) return 0; + if (n == 1) return 1; + return fib(n-1) + fib(n-2); + } + + public static void main(String[] argv) { + ConnectionFactory factory = new ConnectionFactory(); + factory.setHost("localhost"); + + Connection connection = null; + try { + connection = factory.newConnection(); + final Channel channel = connection.createChannel(); + + channel.queueDeclare(RPC_QUEUE_NAME, false, false, false, null); + + channel.basicQos(1); + + System.out.println(" [x] Awaiting RPC requests"); + + Consumer consumer = new DefaultConsumer(channel) { + @Override + public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException { + AMQP.BasicProperties replyProps = new AMQP.BasicProperties + .Builder() + .correlationId(properties.getCorrelationId()) + .build(); + + String response = ""; + + try { + String message = new String(body,"UTF-8"); + int n = Integer.parseInt(message); + + System.out.println(" [.] fib(" + message + ")"); + response += fib(n); + } + catch (RuntimeException e){ + System.out.println(" [.] " + e.toString()); + } + finally { + channel.basicPublish( "", properties.getReplyTo(), replyProps, response.getBytes("UTF-8")); + channel.basicAck(envelope.getDeliveryTag(), false); + // RabbitMq consumer worker thread notifies the RPC server owner thread + synchronized(this) { + this.notify(); + } + } + } + }; + + channel.basicConsume(RPC_QUEUE_NAME, false, consumer); + // Wait and be prepared to consume the message from RPC client. + while (true) { + synchronized(consumer) { + try { + consumer.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } catch (IOException | TimeoutException e) { + e.printStackTrace(); + } + finally { + if (connection != null) + try { + connection.close(); + } catch (IOException _ignore) {} + } + } +} \ No newline at end of file From ab0e38493cdb5e628ed705ef0c36058d9adfad22 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 26 Jan 2018 12:28:57 +0200 Subject: [PATCH 2/2] Fix --- README.md | 33 ++----- build.gradle | 11 ++- gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 6 +- .../ubb/istudent/domain/GreetingEntity.java | 56 ----------- src/main/java/ro/ubb/istudent/dto/Dto.java | 6 -- .../java/ro/ubb/istudent/dto/GreetingDto.java | 23 ----- .../repository/GreetingRepository.java | 12 --- .../ubb/istudent/rest/GreetingResource.java | 55 ----------- .../ubb/istudent/service/GreetingService.java | 61 ------------ .../istudent/service/GreetingServiceTest.java | 94 ------------------- 11 files changed, 23 insertions(+), 337 deletions(-) delete mode 100644 src/main/java/ro/ubb/istudent/domain/GreetingEntity.java delete mode 100644 src/main/java/ro/ubb/istudent/dto/Dto.java delete mode 100644 src/main/java/ro/ubb/istudent/dto/GreetingDto.java delete mode 100644 src/main/java/ro/ubb/istudent/repository/GreetingRepository.java delete mode 100644 src/main/java/ro/ubb/istudent/rest/GreetingResource.java delete mode 100644 src/main/java/ro/ubb/istudent/service/GreetingService.java delete mode 100644 src/test/java/ro/ubb/istudent/service/GreetingServiceTest.java diff --git a/README.md b/README.md index f6d1147..7b2d88f 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ # iStudent -Design Patterns Course UBB 2017-2018 +Analytics and Reporting - Course related analytics #7 -1. User management & Course subscriptions -2. Assignments, tests and gradings/ & Test/Assignment design -3. Analytics & Reporting -4. University Blog - push notifications etc. +Statistics based on number of students that graduated the course compared to total number of students +Statistics based on graduation of students broken down to student country of residence +Statistics based on age groups and graduation (18-29, 30-39,40-60, 60+) +Statistics based on graduation and gender -# Build Status -[![wercker status](https://app.wercker.com/status/158f0fee4804c3da09b80f23ca8f29d6/m/master "wercker status")](https://app.wercker.com/project/byKey/158f0fee4804c3da09b80f23ca8f29d6) -# Project Details -## Prerequisites -- __[JDK 1.8](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)__ ## How to build and run the project? + +-> first install mongodb +-> before running the application, start mongo instance. Make sure the port corresponds with the one from Mongo Config +-> I recommend to install also a native MongoDB management tool like Robo 3T + ### Windows ```java step 1: @@ -36,16 +36,3 @@ http://localhost:8080 step 4: Enjoy coding :) ``` - -# Logistics -## __[Slack channel](https://ubbdesignpatterns2017.slack.com/)__ ([Invitation link](https://join.slack.com/t/ubbdesignpatterns2017/shared_invite/enQtMjU4ODcyMDc3MjcwLWQ3ZmFmMDIzYmU4YmYwZGRkMWQxMTU1YjUyYTE3YmJlMWExMTAzY2JiYzY0MDdiN2VkMzVlMzc4ZGVjMGJhY2M)) - -## Courses -- __[Course 1](https://docs.google.com/presentation/d/1vQ-MAlstyvX_rapYVQ4uLOabJwdJ7010YurVI_bQYpM): Solid Principles and Creational Patterns (Factory, Builder, Prototype, Singleton)__ -- __[Course 2](https://docs.google.com/presentation/d/1xZhmu2bT6TYEeAyY02-e5vRRglJ_5G-UnXmGUIlpNPg): Structural Patterns (Adapter, Bridge, Composite, Decorator, Facade, Proxy)__ -- __[Course 3](https://docs.google.com/presentation/d/1udyA-FaIrRZ9EQUn-biKbpMH8yDvkEsIEr1CbYGMW7s): Behavioral Patterns (Chain of Responsibility, Command, Iterator, Mediator, Observer)__ -- __[Course 4](https://docs.google.com/presentation/d/1fzrjC-HwMg7WEsOtEXUHubnNU1c8CU1OaFyv4UXRJfA): Behavioral Patterns (State, Strategy, Template)__ - -## __[Attendance status](https://docs.google.com/spreadsheets/d/1lzO3BhkjEk6xRPxoFb3Yq5RtlE43MPsmJ1ofIl_kk9M/edit?usp=sheets_home&ths=true)__ of students - -## __[Self-scheduling for labs](https://docs.google.com/spreadsheets/d/16gnOL0lQRFnXmxHOGag_XkTWqVXekKKYTLMFK_mtWec/edit#gid=0)__, for a more balanced number of students at each laboratory diff --git a/build.gradle b/build.gradle index 60a43b6..689b136 100644 --- a/build.gradle +++ b/build.gradle @@ -14,9 +14,11 @@ buildscript { dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") classpath 'org.junit.platform:junit-platform-gradle-plugin:1.0.0' + classpath "io.franzbecker:gradle-lombok:1.11" } } +apply plugin: "io.franzbecker.gradle-lombok" apply plugin: 'java' apply plugin: 'org.springframework.boot' apply plugin: 'war' @@ -37,19 +39,24 @@ repositories { maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } maven { url 'http://repo.maven.apache.org/maven2' } maven { url 'https://jitpack.io' } + maven { url 'https://repo.spring.io/libs-release' } } configurations { providedRuntime } + dependencies { compile('org.springframework.boot:spring-boot-starter-thymeleaf') compile('org.springframework.boot:spring-boot-starter-web') compile('org.springframework.boot:spring-boot-starter-data-mongodb') compile("de.flapdoodle.embed:de.flapdoodle.embed.mongo") - runtime('com.h2database:h2') - runtime('mysql:mysql-connector-java') + compile group: 'com.rabbitmq', name: 'amqp-client', version: '5.0.0' + compile 'org.mongodb:mongodb-driver:3.5.0' + // https://mvnrepository.com/artifact/com.google.guava/guava + compile group: 'com.google.guava', name: 'guava', version: '23.5-jre' + providedRuntime('org.springframework.boot:spring-boot-starter-tomcat') testCompile('org.springframework.boot:spring-boot-starter-test') diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0f0ea20..933b647 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,5 @@ -#Sun Oct 01 18:38:57 EEST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip diff --git a/gradlew b/gradlew index 4453cce..cccdd3d 100755 --- a/gradlew +++ b/gradlew @@ -33,11 +33,11 @@ DEFAULT_JVM_OPTS="" # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -155,7 +155,7 @@ if $cygwin ; then fi # Escape application args -save ( ) { +save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } diff --git a/src/main/java/ro/ubb/istudent/domain/GreetingEntity.java b/src/main/java/ro/ubb/istudent/domain/GreetingEntity.java deleted file mode 100644 index 5a58b3b..0000000 --- a/src/main/java/ro/ubb/istudent/domain/GreetingEntity.java +++ /dev/null @@ -1,56 +0,0 @@ -package ro.ubb.istudent.domain; - -import org.bson.types.ObjectId; -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.mapping.Document; - -import java.io.Serializable; -import java.util.Objects; - -@Document(collection = "greeting") -public class GreetingEntity implements Serializable { - - @Id - private ObjectId id; - - private String message; - - public ObjectId getId() { - return id; - } - - public void setId(ObjectId id) { - this.id = id; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - GreetingEntity that = (GreetingEntity) o; - return Objects.equals(id, that.id) && - Objects.equals(message, that.message); - } - - @Override - public int hashCode() { - - return Objects.hash(id, message); - } - - @Override - public String toString() { - return "GreetingEntity{" + - "id=" + id + - ", message='" + message + '\'' + - '}'; - } -} diff --git a/src/main/java/ro/ubb/istudent/dto/Dto.java b/src/main/java/ro/ubb/istudent/dto/Dto.java deleted file mode 100644 index 4ce6bc1..0000000 --- a/src/main/java/ro/ubb/istudent/dto/Dto.java +++ /dev/null @@ -1,6 +0,0 @@ -package ro.ubb.istudent.dto; - -import java.io.Serializable; - -public interface Dto extends Serializable { -} diff --git a/src/main/java/ro/ubb/istudent/dto/GreetingDto.java b/src/main/java/ro/ubb/istudent/dto/GreetingDto.java deleted file mode 100644 index 2650502..0000000 --- a/src/main/java/ro/ubb/istudent/dto/GreetingDto.java +++ /dev/null @@ -1,23 +0,0 @@ -package ro.ubb.istudent.dto; - -public class GreetingDto implements Dto { - - private String id; - private String message; - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/src/main/java/ro/ubb/istudent/repository/GreetingRepository.java b/src/main/java/ro/ubb/istudent/repository/GreetingRepository.java deleted file mode 100644 index 34d6f8e..0000000 --- a/src/main/java/ro/ubb/istudent/repository/GreetingRepository.java +++ /dev/null @@ -1,12 +0,0 @@ -package ro.ubb.istudent.repository; - -import org.bson.types.ObjectId; -import org.springframework.data.mongodb.repository.MongoRepository; -import ro.ubb.istudent.domain.GreetingEntity; - -import java.util.Optional; - -public interface GreetingRepository extends MongoRepository { - - Optional findGreetingEntityById(String greetingId); -} diff --git a/src/main/java/ro/ubb/istudent/rest/GreetingResource.java b/src/main/java/ro/ubb/istudent/rest/GreetingResource.java deleted file mode 100644 index 54f3ba0..0000000 --- a/src/main/java/ro/ubb/istudent/rest/GreetingResource.java +++ /dev/null @@ -1,55 +0,0 @@ -package ro.ubb.istudent.rest; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import ro.ubb.istudent.dto.GreetingDto; -import ro.ubb.istudent.service.GreetingService; -import ro.ubb.istudent.util.ResponseUtil; - -import java.net.URI; -import java.net.URISyntaxException; - -@RequestMapping("/api") -@RestController -public class GreetingResource { - - private static final String GREETING_CONTROLLER_MAPPING = "/greeting"; - private static final Logger LOG = LoggerFactory.getLogger(GreetingResource.class); - private final GreetingService service; - private final String baseUrl; - - public GreetingResource(GreetingService service, @Value("${application.base-url}") String baseUrl) { - this.service = service; - this.baseUrl = baseUrl; - } - - @GetMapping("/greeting/{greetingId}") - public ResponseEntity getHelloWorldGreeting(@PathVariable("greetingId") String greetingId) { - return ResponseUtil.wrapOrNotFound(service.findGreetingById(greetingId)); - } - - @PutMapping("/greeting/{greetingId}") - public ResponseEntity updateHelloWorldGreeting(@PathVariable("greetingId") String greetingId, @RequestBody GreetingDto greeting) { - LOG.debug("Updating greeting with id: " + greetingId + " and new greeting value:" + greeting); - service.updateGreetingWithId(greetingId, greeting); - return ResponseEntity.ok().build(); - } - - @DeleteMapping(GREETING_CONTROLLER_MAPPING + "/{greetingId}") - public ResponseEntity deleteGreeting(@PathVariable("greetingId") String greetingId) { - LOG.debug("Deleting greeting with id: " + greetingId); - service.deleteGreetingById(greetingId); - return ResponseEntity.ok().build(); - } - - @PostMapping(GREETING_CONTROLLER_MAPPING) - public ResponseEntity createGreeting(@RequestBody GreetingDto greeting) throws URISyntaxException { - LOG.debug("Creating greeting with value: " + greeting); - GreetingDto savedGreeting = service.createGreeting(greeting); - return ResponseEntity.created(new URI(baseUrl + GREETING_CONTROLLER_MAPPING + "/" + savedGreeting.getId())).build(); - } - -} diff --git a/src/main/java/ro/ubb/istudent/service/GreetingService.java b/src/main/java/ro/ubb/istudent/service/GreetingService.java deleted file mode 100644 index 5d68cda..0000000 --- a/src/main/java/ro/ubb/istudent/service/GreetingService.java +++ /dev/null @@ -1,61 +0,0 @@ -package ro.ubb.istudent.service; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.stereotype.Service; -import ro.ubb.istudent.domain.GreetingEntity; -import ro.ubb.istudent.dto.GreetingDto; -import ro.ubb.istudent.repository.GreetingRepository; - -import java.util.Optional; - -@Service -public class GreetingService { - - private static final Logger LOG = LoggerFactory.getLogger(GreetingService.class); - private final GreetingRepository repository; - - public GreetingService(GreetingRepository repository) { - this.repository = repository; - } - - public Optional findGreetingById(String greetingId) { - return repository.findGreetingEntityById(greetingId) - .map(this::greetingToGreetingDTO); - } - - public void updateGreetingWithId(String greetingId, GreetingDto request) { - Optional optionalGreetingEntity = repository.findGreetingEntityById(greetingId); - if (optionalGreetingEntity.isPresent()) { - optionalGreetingEntity.get().setMessage(request.getMessage()); - } else { - LOG.error("Greeting with id {} not found", greetingId); - } - } - - public void deleteGreetingById(String greetingId) { - Optional optionalGreetingEntity = repository.findGreetingEntityById(greetingId); - if (optionalGreetingEntity.isPresent()) { - repository.delete(optionalGreetingEntity.get()); - } else { - LOG.error("Greeting with id {} not found", greetingId); - } - } - - public GreetingDto createGreeting(GreetingDto greeting) { - return greetingToGreetingDTO(repository.save(greetingDTOToEntity(greeting))); - } - - private GreetingDto greetingToGreetingDTO(GreetingEntity entity) { - GreetingDto dto = new GreetingDto(); - dto.setId(entity.getId().toHexString()); - dto.setMessage(entity.getMessage()); - return dto; - } - - private GreetingEntity greetingDTOToEntity(GreetingDto dto) { - GreetingEntity entity = new GreetingEntity(); - entity.setMessage(dto.getMessage()); - return entity; - } -} diff --git a/src/test/java/ro/ubb/istudent/service/GreetingServiceTest.java b/src/test/java/ro/ubb/istudent/service/GreetingServiceTest.java deleted file mode 100644 index 57d244a..0000000 --- a/src/test/java/ro/ubb/istudent/service/GreetingServiceTest.java +++ /dev/null @@ -1,94 +0,0 @@ -package ro.ubb.istudent.service; - - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Assumptions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.transaction.annotation.Transactional; -import ro.ubb.istudent.IStudentApplication; -import ro.ubb.istudent.dto.GreetingDto; - -import java.util.Optional; - -import static org.junit.jupiter.api.Assertions.*; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(classes = IStudentApplication.class) -@DisplayName("Greeting service integration tests") -class GreetingServiceTest { - - @Autowired - private GreetingService service; - - @Test - @DisplayName("Saving a greeting should work") - void saveGreeting() { - GreetingDto savedGreeting = service.createGreeting(createGreetingDto("We come in peace!")); - Assertions.assertAll("Saving greetings should work", - () -> assertNotNull(savedGreeting, "Greeting creation failed"), - () -> assertNotNull(savedGreeting.getId(), "Greeting is not saved"), - () -> assertEquals("We come in peace!", savedGreeting.getMessage(), "Invalid greeting message")); - } - - @Test - @DisplayName("Retrieving a greeting by id should work") - void findGreetingById() { - // Given we have a greeting already saved - GreetingDto savedGreeting = service.createGreeting(createGreetingDto("We come in peace!")); - Assumptions.assumeTrue(savedGreeting != null); - // When we try to retrieve it - Optional greetingByIdOptional = service.findGreetingById(savedGreeting.getId()); - // Then it should be there - Assertions.assertAll("Retrieving a greeting by id should work", - () -> assertTrue(greetingByIdOptional.isPresent(), "Could not find greeting by id"), - () -> assertEquals(savedGreeting.getId(), greetingByIdOptional.get().getId(), "Retrieved greeting has invalid id"), - () -> assertEquals(savedGreeting.getMessage(), greetingByIdOptional.get().getMessage(), "Retrieved greeting has different message from the saved one")); - - } - - @Test - @DisplayName("Removing a greeting by id should work") - void deleteGreetingById() { - // Given we have a greeting already saved - GreetingDto savedGreeting = service.createGreeting(createGreetingDto("We come in peace!")); - Assumptions.assumeTrue(savedGreeting != null); - // When we delete it - service.deleteGreetingById(savedGreeting.getId()); - // Then it should be removed - Optional deletedGreetingOptional = service.findGreetingById(savedGreeting.getId()); - Assertions.assertAll("Removing a greeting by id should work", - () -> assertFalse(deletedGreetingOptional.isPresent(), "Found greeting by id when it should be deleted")); - - } - - - @Test - @DisplayName("Updating a greeting should work") - void updateGreeting() { - // Given we have a greeting already saved - GreetingDto savedGreeting = service.createGreeting(createGreetingDto("We come in peace!")); - Assumptions.assumeTrue(savedGreeting != null); - // When we update it - savedGreeting.setMessage("Updated message"); - service.updateGreetingWithId(savedGreeting.getId(), savedGreeting); - // Then it should be updated - Optional updatedGreetingOptional = service.findGreetingById(savedGreeting.getId()); - Assertions.assertAll("Updating a greeting by id should work", - () -> assertTrue(updatedGreetingOptional.isPresent(), "Could not find greeting by id"), - () -> assertEquals(savedGreeting.getId(), updatedGreetingOptional.get().getId(), "Updated greeting has invalid id"), - () -> assertEquals("Updated message", updatedGreetingOptional.get().getMessage(), "Updated greeting has different message from the expected updated one")); - - } - - - private GreetingDto createGreetingDto(String message) { - GreetingDto greetingDto = new GreetingDto(); - greetingDto.setMessage(message); - return greetingDto; - } -}