[JAVA-14174] Renamed paterns to paterns-module (#12718)

* [JAVA-14174] Renamed paterns to paterns-module

* [JAVA-14174] naming fixes

Co-authored-by: panagiotiskakos <panagiotis.kakos@libra-is.com>
This commit is contained in:
panos-kakos
2022-09-19 07:44:14 +01:00
committed by GitHub
parent 74dcaa0935
commit 63a9bfbad9
518 changed files with 32 additions and 32 deletions
+1
View File
@@ -0,0 +1 @@
/product-service/
+3
View File
@@ -0,0 +1,3 @@
## Patterns Modules
This module contains articles about design patterns.
@@ -0,0 +1,3 @@
### Relevant Articles:
- [Clean Architecture with Spring Boot](https://www.baeldung.com/spring-boot-clean-architecture)
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>clean-architecture</artifactId>
<version>1.0</version>
<name>clean-architecture</name>
<description>Project for clean architecture in java</description>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>parent-boot-2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>../../parent-boot-2</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-engine</artifactId>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-runner</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,40 @@
package com.baeldung.pattern.cleanarchitecture;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
@SpringBootApplication
public class CleanArchitectureApplication {
public static void main(String[] args) {
SpringApplication.run(CleanArchitectureApplication.class);
}
@Bean
BeanFactoryPostProcessor beanFactoryPostProcessor(ApplicationContext beanRegistry) {
return beanFactory -> {
genericApplicationContext((BeanDefinitionRegistry) ((AnnotationConfigServletWebServerApplicationContext) beanRegistry).getBeanFactory());
};
}
void genericApplicationContext(BeanDefinitionRegistry beanRegistry) {
ClassPathBeanDefinitionScanner beanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanRegistry);
beanDefinitionScanner.addIncludeFilter(removeModelAndEntitiesFilter());
beanDefinitionScanner.scan("com.baeldung.pattern.cleanarchitecture");
}
static TypeFilter removeModelAndEntitiesFilter() {
return (MetadataReader mr, MetadataReaderFactory mrf) -> !mr.getClassMetadata()
.getClassName()
.endsWith("Model");
}
}
@@ -0,0 +1,30 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
class CommonUser implements User {
String name;
String password;
CommonUser(String name, String password) {
this.name = name;
this.password = password;
}
CommonUser() {
}
@Override
public boolean passwordIsValid() {
return password != null && password.length() > 5;
}
@Override
public String getName() {
return name;
}
@Override
public String getPassword() {
return password;
}
}
@@ -0,0 +1,8 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
class CommonUserFactory implements UserFactory {
@Override
public User create(String name, String password) {
return new CommonUser(name, password);
}
}
@@ -0,0 +1,21 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
class JpaUser implements UserRegisterDsGateway {
final JpaUserRepository repository;
JpaUser(JpaUserRepository repository) {
this.repository = repository;
}
@Override
public boolean existsByName(String name) {
return repository.existsById(name);
}
@Override
public void save(UserDsRequestModel requestModel) {
UserDataMapper accountDataMapper = new UserDataMapper(requestModel.getName(), requestModel.getPassword(), requestModel.getCreationTime());
repository.save(accountDataMapper);
}
}
@@ -0,0 +1,8 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
interface JpaUserRepository extends JpaRepository<UserDataMapper, String> {
}
@@ -0,0 +1,9 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
interface User {
boolean passwordIsValid();
String getName();
String getPassword();
}
@@ -0,0 +1,53 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
import java.time.LocalDateTime;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "user")
class UserDataMapper {
@Id
String name;
String password;
LocalDateTime creationTime;
public UserDataMapper() {
}
public UserDataMapper(String name, String password, LocalDateTime creationTime) {
super();
this.name = name;
this.password = password;
this.creationTime = creationTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public LocalDateTime getCreationTime() {
return creationTime;
}
public void setCreationTime(LocalDateTime creationTime) {
this.creationTime = creationTime;
}
}
@@ -0,0 +1,41 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
import java.time.LocalDateTime;
class UserDsRequestModel {
String name;
String password;
LocalDateTime creationTime;
public UserDsRequestModel(String name, String password, LocalDateTime creationTime) {
this.name = name;
this.password = password;
this.creationTime = creationTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public LocalDateTime getCreationTime() {
return creationTime;
}
public void setCreationTime(LocalDateTime creationTime) {
this.creationTime = creationTime;
}
}
@@ -0,0 +1,5 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
interface UserFactory {
User create(String name, String password);
}
@@ -0,0 +1,5 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
public interface UserInputBoundary {
UserResponseModel create(UserRequestModel requestModel);
}
@@ -0,0 +1,7 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
interface UserPresenter {
UserResponseModel prepareSuccessView(UserResponseModel user);
UserResponseModel prepareFailView(String error);
}
@@ -0,0 +1,20 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
class UserRegisterController {
final UserInputBoundary userInput;
UserRegisterController(UserInputBoundary accountGateway) {
this.userInput = accountGateway;
}
@PostMapping("/user")
UserResponseModel create(@RequestBody UserRequestModel requestModel) {
return userInput.create(requestModel);
}
}
@@ -0,0 +1,7 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
interface UserRegisterDsGateway {
boolean existsByName(String identifier);
void save(UserDsRequestModel requestModel);
}
@@ -0,0 +1,35 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
import java.time.LocalDateTime;
class UserRegisterInteractor implements UserInputBoundary {
final UserRegisterDsGateway userDsGateway;
final UserPresenter userPresenter;
final UserFactory userFactory;
UserRegisterInteractor(UserRegisterDsGateway userRegisterDfGateway, UserPresenter userPresenter,
UserFactory userFactory) {
this.userDsGateway = userRegisterDfGateway;
this.userPresenter = userPresenter;
this.userFactory = userFactory;
}
@Override
public UserResponseModel create(UserRequestModel requestModel) {
if (userDsGateway.existsByName(requestModel.getName())) {
return userPresenter.prepareFailView("User already exists.");
}
User user = userFactory.create(requestModel.getName(), requestModel.getPassword());
if (!user.passwordIsValid()) {
return userPresenter.prepareFailView("User password must have more than 5 characters.");
}
LocalDateTime now = LocalDateTime.now();
UserDsRequestModel userDsModel = new UserDsRequestModel(user.getName(), user.getPassword(), now);
userDsGateway.save(userDsModel);
UserResponseModel accountResponseModel = new UserResponseModel(user.getName(), now.toString());
return userPresenter.prepareSuccessView(accountResponseModel);
}
}
@@ -0,0 +1,33 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
class UserRequestModel {
String name;
String password;
public UserRequestModel() {
super();
}
UserRequestModel(String name, String password) {
super();
this.name = name;
this.password = password;
}
String getName() {
return name;
}
void setName(String name) {
this.name = name;
}
String getPassword() {
return password;
}
void setPassword(String password) {
this.password = password;
}
}
@@ -0,0 +1,22 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ResponseStatusException;
class UserResponseFormatter implements UserPresenter {
@Override
public UserResponseModel prepareSuccessView(UserResponseModel response) {
LocalDateTime responseTime = LocalDateTime.parse(response.getCreationTime());
response.setCreationTime(responseTime.format(DateTimeFormatter.ofPattern("hh:mm:ss")));
return response;
}
@Override
public UserResponseModel prepareFailView(String error) {
throw new ResponseStatusException(HttpStatus.CONFLICT, error);
}
}
@@ -0,0 +1,29 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
public class UserResponseModel {
String login;
String creationTime;
public UserResponseModel(String login, String creationTime) {
this.login = login;
this.creationTime = creationTime;
}
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
public String getCreationTime() {
return creationTime;
}
public void setCreationTime(String creationTime) {
this.creationTime = creationTime;
}
}
@@ -0,0 +1,2 @@
server.port=8080
server.error.include-message=always
@@ -0,0 +1,29 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import org.junit.jupiter.api.Test;
import org.springframework.web.server.ResponseStatusException;
import com.baeldung.pattern.cleanarchitecture.usercreation.UserResponseFormatter;
import com.baeldung.pattern.cleanarchitecture.usercreation.UserResponseModel;
class UserResponseFormatterUnitTest {
UserResponseFormatter userResponseFormatter = new UserResponseFormatter();
@Test
void givenDateAnd3HourTime_whenPrepareSuccessView_thenReturnOnly3HourTime() {
UserResponseModel modelResponse = new UserResponseModel("baeldung", "2020-12-20T03:00:00.000");
UserResponseModel formattedResponse = userResponseFormatter.prepareSuccessView(modelResponse);
assertThat(formattedResponse.getCreationTime()).isEqualTo("03:00:00");
}
@Test
void whenPrepareFailView_thenThrowHttpConflictException() {
assertThatThrownBy(() -> userResponseFormatter.prepareFailView("Invalid password"))
.isInstanceOf(ResponseStatusException.class);
}
}
@@ -0,0 +1,15 @@
package com.baeldung.pattern.cleanarchitecture.usercreation;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.Test;
class UserUnitTest {
@Test
void given123Password_whenPasswordIsNotValid_thenIsFalse() {
User user = new CommonUser("Baeldung", "123");
assertThat(user.passwordIsValid()).isFalse();
}
}
+5
View File
@@ -0,0 +1,5 @@
This module contains articles about composing together CQRS and Event Sourcing
## Relevant Articles
- [CQRS and Event Sourcing in Java](https://www.baeldung.com/cqrs-event-sourcing-java)
+28
View File
@@ -0,0 +1,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cqrs-es</artifactId>
<version>1.0-SNAPSHOT</version>
<name>cqrs-es</name>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>patterns-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,30 @@
package com.baeldung.patterns.cqrs.aggregates;
import com.baeldung.patterns.cqrs.commands.CreateUserCommand;
import com.baeldung.patterns.cqrs.commands.UpdateUserCommand;
import com.baeldung.patterns.cqrs.repository.UserWriteRepository;
import com.baeldung.patterns.domain.User;
public class UserAggregate {
private UserWriteRepository writeRepository;
public UserAggregate(UserWriteRepository repository) {
this.writeRepository = repository;
}
public User handleCreateUserCommand(CreateUserCommand command) {
User user = new User(command.getUserId(), command.getFirstName(), command.getLastName());
writeRepository.addUser(user.getUserid(), user);
return user;
}
public User handleUpdateUserCommand(UpdateUserCommand command) {
User user = writeRepository.getUser(command.getUserId());
user.setAddresses(command.getAddresses());
user.setContacts(command.getContacts());
writeRepository.addUser(user.getUserid(), user);
return user;
}
}
@@ -0,0 +1,14 @@
package com.baeldung.patterns.cqrs.commands;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class CreateUserCommand {
private String userId;
private String firstName;
private String lastName;
}
@@ -0,0 +1,20 @@
package com.baeldung.patterns.cqrs.commands;
import java.util.HashSet;
import java.util.Set;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class UpdateUserCommand {
private String userId;
private Set<Address> addresses = new HashSet<>();
private Set<Contact> contacts = new HashSet<>();
}
@@ -0,0 +1,37 @@
package com.baeldung.patterns.cqrs.projections;
import java.util.Set;
import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery;
import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.UserAddress;
import com.baeldung.patterns.domain.UserContact;
public class UserProjection {
private UserReadRepository repository;
public UserProjection(UserReadRepository repository) {
this.repository = repository;
}
public Set<Contact> handle(ContactByTypeQuery query) throws Exception {
UserContact userContact = repository.getUserContact(query.getUserId());
if (userContact == null)
throw new Exception("User does not exist.");
return userContact.getContactByType()
.get(query.getContactType());
}
public Set<Address> handle(AddressByRegionQuery query) throws Exception {
UserAddress userAddress = repository.getUserAddress(query.getUserId());
if (userAddress == null)
throw new Exception("User does not exist.");
return userAddress.getAddressByRegion()
.get(query.getState());
}
}
@@ -0,0 +1,49 @@
package com.baeldung.patterns.cqrs.projectors;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
import com.baeldung.patterns.domain.UserAddress;
import com.baeldung.patterns.domain.UserContact;
public class UserProjector {
UserReadRepository readRepository = new UserReadRepository();
public UserProjector(UserReadRepository readRepository) {
this.readRepository = readRepository;
}
public void project(User user) {
UserContact userContact = Optional.ofNullable(readRepository.getUserContact(user.getUserid()))
.orElse(new UserContact());
Map<String, Set<Contact>> contactByType = new HashMap<>();
for (Contact contact : user.getContacts()) {
Set<Contact> contacts = Optional.ofNullable(contactByType.get(contact.getType()))
.orElse(new HashSet<>());
contacts.add(contact);
contactByType.put(contact.getType(), contacts);
}
userContact.setContactByType(contactByType);
readRepository.addUserContact(user.getUserid(), userContact);
UserAddress userAddress = Optional.ofNullable(readRepository.getUserAddress(user.getUserid()))
.orElse(new UserAddress());
Map<String, Set<Address>> addressByRegion = new HashMap<>();
for (Address address : user.getAddresses()) {
Set<Address> addresses = Optional.ofNullable(addressByRegion.get(address.getState()))
.orElse(new HashSet<>());
addresses.add(address);
addressByRegion.put(address.getState(), addresses);
}
userAddress.setAddressByRegion(addressByRegion);
readRepository.addUserAddress(user.getUserid(), userAddress);
}
}
@@ -0,0 +1,12 @@
package com.baeldung.patterns.cqrs.queries;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class AddressByRegionQuery {
private String userId;
private String state;
}
@@ -0,0 +1,12 @@
package com.baeldung.patterns.cqrs.queries;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class ContactByTypeQuery {
private String userId;
private String contactType;
}
@@ -0,0 +1,31 @@
package com.baeldung.patterns.cqrs.repository;
import java.util.HashMap;
import java.util.Map;
import com.baeldung.patterns.domain.UserAddress;
import com.baeldung.patterns.domain.UserContact;
public class UserReadRepository {
private Map<String, UserAddress> userAddress = new HashMap<>();
private Map<String, UserContact> userContact = new HashMap<>();
public void addUserAddress(String id, UserAddress user) {
userAddress.put(id, user);
}
public UserAddress getUserAddress(String id) {
return userAddress.get(id);
}
public void addUserContact(String id, UserContact user) {
userContact.put(id, user);
}
public UserContact getUserContact(String id) {
return userContact.get(id);
}
}
@@ -0,0 +1,20 @@
package com.baeldung.patterns.cqrs.repository;
import java.util.HashMap;
import java.util.Map;
import com.baeldung.patterns.domain.User;
public class UserWriteRepository {
private Map<String, User> store = new HashMap<>();
public void addUser(String id, User user) {
store.put(id, user);
}
public User getUser(String id) {
return store.get(id);
}
}
@@ -0,0 +1,20 @@
package com.baeldung.patterns.crud.repository;
import java.util.HashMap;
import java.util.Map;
import com.baeldung.patterns.domain.User;
public class UserRepository {
private Map<String, User> store = new HashMap<>();
public void addUser(String id, User user) {
store.put(id, user);
}
public User getUser(String id) {
return store.get(id);
}
}
@@ -0,0 +1,55 @@
package com.baeldung.patterns.crud.service;
import java.util.Set;
import java.util.stream.Collectors;
import com.baeldung.patterns.crud.repository.UserRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
public class UserService {
private UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public void createUser(String userId, String firstName, String lastName) {
User user = new User(userId, firstName, lastName);
repository.addUser(userId, user);
}
public void updateUser(String userId, Set<Contact> contacts, Set<Address> addresses) throws Exception {
User user = repository.getUser(userId);
if (user == null)
throw new Exception("User does not exist.");
user.setContacts(contacts);
user.setAddresses(addresses);
repository.addUser(userId, user);
}
public Set<Contact> getContactByType(String userId, String contactType) throws Exception {
User user = repository.getUser(userId);
if (user == null)
throw new Exception("User does not exit.");
Set<Contact> contacts = user.getContacts();
return contacts.stream()
.filter(c -> c.getType()
.equals(contactType))
.collect(Collectors.toSet());
}
public Set<Address> getAddressByRegion(String userId, String state) throws Exception {
User user = repository.getUser(userId);
if (user == null)
throw new Exception("User does not exist.");
Set<Address> addresses = user.getAddresses();
return addresses.stream()
.filter(a -> a.getState()
.equals(state))
.collect(Collectors.toSet());
}
}
@@ -0,0 +1,14 @@
package com.baeldung.patterns.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Address {
private String city;
private String state;
private String postcode;
}
@@ -0,0 +1,13 @@
package com.baeldung.patterns.domain;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Contact {
private String type;
private String detail;
}
@@ -0,0 +1,22 @@
package com.baeldung.patterns.domain;
import java.util.HashSet;
import java.util.Set;
import lombok.Data;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
@Data
@RequiredArgsConstructor
public class User {
@NonNull
private String userid;
@NonNull
private String firstname;
@NonNull
private String lastname;
private Set<Contact> contacts = new HashSet<>();
private Set<Address> addresses = new HashSet<>();
}
@@ -0,0 +1,14 @@
package com.baeldung.patterns.domain;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.Data;
@Data
public class UserAddress {
private Map<String, Set<Address>> addressByRegion = new HashMap<>();
}
@@ -0,0 +1,14 @@
package com.baeldung.patterns.domain;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import lombok.Data;
@Data
public class UserContact {
private Map<String, Set<Contact>> contactByType = new HashMap<>();
}
@@ -0,0 +1,15 @@
package com.baeldung.patterns.es.events;
import java.util.Date;
import java.util.UUID;
import lombok.ToString;
@ToString
public abstract class Event {
public final UUID id = UUID.randomUUID();
public final Date created = new Date();
}
@@ -0,0 +1,16 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserAddressAddedEvent extends Event {
private String city;
private String state;
private String postCode;
}
@@ -0,0 +1,16 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserAddressRemovedEvent extends Event {
private String city;
private String state;
private String postCode;
}
@@ -0,0 +1,15 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserContactAddedEvent extends Event {
private String contactType;
private String contactDetails;
}
@@ -0,0 +1,15 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserContactRemovedEvent extends Event {
private String contactType;
private String contactDetails;
}
@@ -0,0 +1,16 @@
package com.baeldung.patterns.es.events;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class UserCreatedEvent extends Event {
private String userId;
private String firstName;
private String lastName;
}
@@ -0,0 +1,29 @@
package com.baeldung.patterns.es.repository;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.baeldung.patterns.es.events.Event;
public class EventStore {
private Map<String, List<Event>> store = new HashMap<>();
public void addEvent(String id, Event event) {
List<Event> events = store.get(id);
if (events == null) {
events = new ArrayList<Event>();
events.add(event);
store.put(id, events);
} else {
events.add(event);
}
}
public List<Event> getEvents(String id) {
return store.get(id);
}
}
@@ -0,0 +1,72 @@
package com.baeldung.patterns.es.service;
import java.util.Set;
import java.util.stream.Collectors;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
import com.baeldung.patterns.es.events.UserAddressAddedEvent;
import com.baeldung.patterns.es.events.UserAddressRemovedEvent;
import com.baeldung.patterns.es.events.UserContactAddedEvent;
import com.baeldung.patterns.es.events.UserContactRemovedEvent;
import com.baeldung.patterns.es.events.UserCreatedEvent;
import com.baeldung.patterns.es.repository.EventStore;
public class UserService {
private EventStore repository;
public UserService(EventStore repository) {
this.repository = repository;
}
public void createUser(String userId, String firstName, String lastName) {
repository.addEvent(userId, new UserCreatedEvent(userId, firstName, lastName));
}
public void updateUser(String userId, Set<Contact> contacts, Set<Address> addresses) throws Exception {
User user = UserUtility.recreateUserState(repository, userId);
if (user == null)
throw new Exception("User does not exist.");
user.getContacts()
.stream()
.filter(c -> !contacts.contains(c))
.forEach(c -> repository.addEvent(userId, new UserContactRemovedEvent(c.getType(), c.getDetail())));
contacts.stream()
.filter(c -> !user.getContacts()
.contains(c))
.forEach(c -> repository.addEvent(userId, new UserContactAddedEvent(c.getType(), c.getDetail())));
user.getAddresses()
.stream()
.filter(a -> !addresses.contains(a))
.forEach(a -> repository.addEvent(userId, new UserAddressRemovedEvent(a.getCity(), a.getState(), a.getPostcode())));
addresses.stream()
.filter(a -> !user.getAddresses()
.contains(a))
.forEach(a -> repository.addEvent(userId, new UserAddressAddedEvent(a.getCity(), a.getState(), a.getPostcode())));
}
public Set<Contact> getContactByType(String userId, String contactType) throws Exception {
User user = UserUtility.recreateUserState(repository, userId);
if (user == null)
throw new Exception("User does not exist.");
return user.getContacts()
.stream()
.filter(c -> c.getType()
.equals(contactType))
.collect(Collectors.toSet());
}
public Set<Address> getAddressByRegion(String userId, String state) throws Exception {
User user = UserUtility.recreateUserState(repository, userId);
if (user == null)
throw new Exception("User does not exist.");
return user.getAddresses()
.stream()
.filter(a -> a.getState()
.equals(state))
.collect(Collectors.toSet());
}
}
@@ -0,0 +1,62 @@
package com.baeldung.patterns.es.service;
import java.util.List;
import java.util.UUID;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
import com.baeldung.patterns.es.events.Event;
import com.baeldung.patterns.es.events.UserAddressAddedEvent;
import com.baeldung.patterns.es.events.UserAddressRemovedEvent;
import com.baeldung.patterns.es.events.UserContactAddedEvent;
import com.baeldung.patterns.es.events.UserContactRemovedEvent;
import com.baeldung.patterns.es.events.UserCreatedEvent;
import com.baeldung.patterns.es.repository.EventStore;
public class UserUtility {
public static User recreateUserState(EventStore store, String userId) {
User user = null;
List<Event> events = store.getEvents(userId);
for (Event event : events) {
if (event instanceof UserCreatedEvent) {
UserCreatedEvent e = (UserCreatedEvent) event;
user = new User(UUID.randomUUID()
.toString(), e.getFirstName(), e.getLastName());
}
if (event instanceof UserAddressAddedEvent) {
UserAddressAddedEvent e = (UserAddressAddedEvent) event;
Address address = new Address(e.getCity(), e.getState(), e.getPostCode());
if (user != null)
user.getAddresses()
.add(address);
}
if (event instanceof UserAddressRemovedEvent) {
UserAddressRemovedEvent e = (UserAddressRemovedEvent) event;
Address address = new Address(e.getCity(), e.getState(), e.getPostCode());
if (user != null)
user.getAddresses()
.remove(address);
}
if (event instanceof UserContactAddedEvent) {
UserContactAddedEvent e = (UserContactAddedEvent) event;
Contact contact = new Contact(e.getContactType(), e.getContactDetails());
if (user != null)
user.getContacts()
.add(contact);
}
if (event instanceof UserContactRemovedEvent) {
UserContactRemovedEvent e = (UserContactRemovedEvent) event;
Contact contact = new Contact(e.getContactType(), e.getContactDetails());
if (user != null)
user.getContacts()
.remove(contact);
}
}
return user;
}
}
@@ -0,0 +1,87 @@
package com.baeldung.patterns.escqrs.aggregates;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import com.baeldung.patterns.cqrs.commands.CreateUserCommand;
import com.baeldung.patterns.cqrs.commands.UpdateUserCommand;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
import com.baeldung.patterns.es.events.Event;
import com.baeldung.patterns.es.events.UserAddressAddedEvent;
import com.baeldung.patterns.es.events.UserAddressRemovedEvent;
import com.baeldung.patterns.es.events.UserContactAddedEvent;
import com.baeldung.patterns.es.events.UserContactRemovedEvent;
import com.baeldung.patterns.es.events.UserCreatedEvent;
import com.baeldung.patterns.es.repository.EventStore;
import com.baeldung.patterns.es.service.UserUtility;
public class UserAggregate {
private EventStore writeRepository;
public UserAggregate(EventStore repository) {
this.writeRepository = repository;
}
public List<Event> handleCreateUserCommand(CreateUserCommand command) {
UserCreatedEvent event = new UserCreatedEvent(command.getUserId(), command.getFirstName(), command.getLastName());
writeRepository.addEvent(command.getUserId(), event);
return Arrays.asList(event);
}
public List<Event> handleUpdateUserCommand(UpdateUserCommand command) {
User user = UserUtility.recreateUserState(writeRepository, command.getUserId());
List<Event> events = new ArrayList<>();
List<Contact> contactsToRemove = user.getContacts()
.stream()
.filter(c -> !command.getContacts()
.contains(c))
.collect(Collectors.toList());
for (Contact contact : contactsToRemove) {
UserContactRemovedEvent contactRemovedEvent = new UserContactRemovedEvent(contact.getType(), contact.getDetail());
events.add(contactRemovedEvent);
writeRepository.addEvent(command.getUserId(), contactRemovedEvent);
}
List<Contact> contactsToAdd = command.getContacts()
.stream()
.filter(c -> !user.getContacts()
.contains(c))
.collect(Collectors.toList());
for (Contact contact : contactsToAdd) {
UserContactAddedEvent contactAddedEvent = new UserContactAddedEvent(contact.getType(), contact.getDetail());
events.add(contactAddedEvent);
writeRepository.addEvent(command.getUserId(), contactAddedEvent);
}
List<Address> addressesToRemove = user.getAddresses()
.stream()
.filter(a -> !command.getAddresses()
.contains(a))
.collect(Collectors.toList());
for (Address address : addressesToRemove) {
UserAddressRemovedEvent addressRemovedEvent = new UserAddressRemovedEvent(address.getCity(), address.getState(), address.getPostcode());
events.add(addressRemovedEvent);
writeRepository.addEvent(command.getUserId(), addressRemovedEvent);
}
List<Address> addressesToAdd = command.getAddresses()
.stream()
.filter(a -> !user.getAddresses()
.contains(a))
.collect(Collectors.toList());
for (Address address : addressesToAdd) {
UserAddressAddedEvent addressAddedEvent = new UserAddressAddedEvent(address.getCity(), address.getState(), address.getPostcode());
events.add(addressAddedEvent);
writeRepository.addEvent(command.getUserId(), addressAddedEvent);
}
return events;
}
}
@@ -0,0 +1,91 @@
package com.baeldung.patterns.escqrs.projectors;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.UserAddress;
import com.baeldung.patterns.domain.UserContact;
import com.baeldung.patterns.es.events.Event;
import com.baeldung.patterns.es.events.UserAddressAddedEvent;
import com.baeldung.patterns.es.events.UserAddressRemovedEvent;
import com.baeldung.patterns.es.events.UserContactAddedEvent;
import com.baeldung.patterns.es.events.UserContactRemovedEvent;
public class UserProjector {
UserReadRepository readRepository = new UserReadRepository();
public UserProjector(UserReadRepository readRepository) {
this.readRepository = readRepository;
}
public void project(String userId, List<Event> events) {
for (Event event : events) {
if (event instanceof UserAddressAddedEvent)
apply(userId, (UserAddressAddedEvent) event);
if (event instanceof UserAddressRemovedEvent)
apply(userId, (UserAddressRemovedEvent) event);
if (event instanceof UserContactAddedEvent)
apply(userId, (UserContactAddedEvent) event);
if (event instanceof UserContactRemovedEvent)
apply(userId, (UserContactRemovedEvent) event);
}
}
public void apply(String userId, UserAddressAddedEvent event) {
Address address = new Address(event.getCity(), event.getState(), event.getPostCode());
UserAddress userAddress = Optional.ofNullable(readRepository.getUserAddress(userId))
.orElse(new UserAddress());
Set<Address> addresses = Optional.ofNullable(userAddress.getAddressByRegion()
.get(address.getState()))
.orElse(new HashSet<>());
addresses.add(address);
userAddress.getAddressByRegion()
.put(address.getState(), addresses);
readRepository.addUserAddress(userId, userAddress);
}
public void apply(String userId, UserAddressRemovedEvent event) {
Address address = new Address(event.getCity(), event.getState(), event.getPostCode());
UserAddress userAddress = readRepository.getUserAddress(userId);
if (userAddress != null) {
Set<Address> addresses = userAddress.getAddressByRegion()
.get(address.getState());
if (addresses != null)
addresses.remove(address);
readRepository.addUserAddress(userId, userAddress);
}
}
public void apply(String userId, UserContactAddedEvent event) {
Contact contact = new Contact(event.getContactType(), event.getContactDetails());
UserContact userContact = Optional.ofNullable(readRepository.getUserContact(userId))
.orElse(new UserContact());
Set<Contact> contacts = Optional.ofNullable(userContact.getContactByType()
.get(contact.getType()))
.orElse(new HashSet<>());
contacts.add(contact);
userContact.getContactByType()
.put(contact.getType(), contacts);
readRepository.addUserContact(userId, userContact);
}
public void apply(String userId, UserContactRemovedEvent event) {
Contact contact = new Contact(event.getContactType(), event.getContactDetails());
UserContact userContact = readRepository.getUserContact(userId);
if (userContact != null) {
Set<Contact> contacts = userContact.getContactByType()
.get(contact.getType());
if (contacts != null)
contacts.remove(contact);
readRepository.addUserContact(userId, userContact);
}
}
}
@@ -0,0 +1,74 @@
package com.baeldung.patterns.cqrs;
import static org.junit.Assert.assertEquals;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.patterns.cqrs.aggregates.UserAggregate;
import com.baeldung.patterns.cqrs.commands.CreateUserCommand;
import com.baeldung.patterns.cqrs.commands.UpdateUserCommand;
import com.baeldung.patterns.cqrs.projections.UserProjection;
import com.baeldung.patterns.cqrs.projectors.UserProjector;
import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery;
import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.cqrs.repository.UserWriteRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.domain.User;
public class ApplicationUnitTest {
private UserWriteRepository writeRepository;
private UserReadRepository readRepository;
private UserProjector projector;
private UserAggregate userAggregate;
private UserProjection userProjection;
@Before
public void setUp() {
writeRepository = new UserWriteRepository();
readRepository = new UserReadRepository();
projector = new UserProjector(readRepository);
userAggregate = new UserAggregate(writeRepository);
userProjection = new UserProjection(readRepository);
}
@Test
public void givenCQRSApplication_whenCommandRun_thenQueryShouldReturnResult() throws Exception {
String userId = UUID.randomUUID()
.toString();
User user = null;
CreateUserCommand createUserCommand = new CreateUserCommand(userId, "Tom", "Sawyer");
user = userAggregate.handleCreateUserCommand(createUserCommand);
projector.project(user);
UpdateUserCommand updateUserCommand = new UpdateUserCommand(user.getUserid(), Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"))
.collect(Collectors.toSet()),
Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"))
.collect(Collectors.toSet()));
user = userAggregate.handleUpdateUserCommand(updateUserCommand);
projector.project(user);
updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()),
Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()));
user = userAggregate.handleUpdateUserCommand(updateUserCommand);
projector.project(user);
ContactByTypeQuery contactByTypeQuery = new ContactByTypeQuery(userId, "EMAIL");
assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"))
.collect(Collectors.toSet()), userProjection.handle(contactByTypeQuery));
AddressByRegionQuery addressByRegionQuery = new AddressByRegionQuery(userId, "NY");
assertEquals(Stream.of(new Address("New York", "NY", "10001"))
.collect(Collectors.toSet()), userProjection.handle(addressByRegionQuery));
}
}
@@ -0,0 +1,48 @@
package com.baeldung.patterns.crud;
import static org.junit.Assert.assertEquals;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.patterns.crud.repository.UserRepository;
import com.baeldung.patterns.crud.service.UserService;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
public class ApplicationUnitTest {
private UserRepository repository;
@Before
public void setUp() {
repository = new UserRepository();
}
@Test
public void givenCRUDApplication_whenDataCreated_thenDataCanBeFetched() throws Exception {
UserService service = new UserService(repository);
String userId = UUID.randomUUID()
.toString();
service.createUser(userId, "Tom", "Sawyer");
service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()),
Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()));
service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()),
Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()));
assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"))
.collect(Collectors.toSet()), service.getContactByType(userId, "EMAIL"));
assertEquals(Stream.of(new Address("New York", "NY", "10001"))
.collect(Collectors.toSet()), service.getAddressByRegion(userId, "NY"));
}
}
@@ -0,0 +1,50 @@
package com.baeldung.patterns.es;
import static org.junit.Assert.assertEquals;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.es.repository.EventStore;
import com.baeldung.patterns.es.service.UserService;
public class ApplicationUnitTest {
private EventStore repository;
private UserService service;
@Before
public void setUp() {
repository = new EventStore();
service = new UserService(repository);
}
@Test
public void givenCRUDApplication_whenDataCreated_thenDataCanBeFetched() throws Exception {
String userId = UUID.randomUUID()
.toString();
service.createUser(userId, "Tom", "Sawyer");
service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()),
Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()));
service.updateUser(userId, Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()),
Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()));
assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"))
.collect(Collectors.toSet()), service.getContactByType(userId, "EMAIL"));
assertEquals(Stream.of(new Address("New York", "NY", "10001"))
.collect(Collectors.toSet()), service.getAddressByRegion(userId, "NY"));
}
}
@@ -0,0 +1,76 @@
package com.baeldung.patterns.escqrs;
import static org.junit.Assert.assertEquals;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
import com.baeldung.patterns.cqrs.commands.CreateUserCommand;
import com.baeldung.patterns.cqrs.commands.UpdateUserCommand;
import com.baeldung.patterns.cqrs.projections.UserProjection;
import com.baeldung.patterns.cqrs.queries.AddressByRegionQuery;
import com.baeldung.patterns.cqrs.queries.ContactByTypeQuery;
import com.baeldung.patterns.cqrs.repository.UserReadRepository;
import com.baeldung.patterns.domain.Address;
import com.baeldung.patterns.domain.Contact;
import com.baeldung.patterns.es.events.Event;
import com.baeldung.patterns.es.repository.EventStore;
import com.baeldung.patterns.escqrs.aggregates.UserAggregate;
import com.baeldung.patterns.escqrs.projectors.UserProjector;
public class ApplicationUnitTest {
private EventStore writeRepository;
private UserReadRepository readRepository;
private UserProjector projector;
private UserAggregate userAggregate;
private UserProjection userProjection;
@Before
public void setUp() {
writeRepository = new EventStore();
readRepository = new UserReadRepository();
projector = new UserProjector(readRepository);
userAggregate = new UserAggregate(writeRepository);
userProjection = new UserProjection(readRepository);
}
@Test
public void givenCQRSApplication_whenCommandRun_thenQueryShouldReturnResult() throws Exception {
String userId = UUID.randomUUID()
.toString();
List<Event> events = null;
CreateUserCommand createUserCommand = new CreateUserCommand(userId, "Kumar", "Chandrakant");
events = userAggregate.handleCreateUserCommand(createUserCommand);
projector.project(userId, events);
UpdateUserCommand updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Los Angeles", "CA", "90001"))
.collect(Collectors.toSet()),
Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("EMAIL", "tom.sawyer@rediff.com"))
.collect(Collectors.toSet()));
events = userAggregate.handleUpdateUserCommand(updateUserCommand);
projector.project(userId, events);
updateUserCommand = new UpdateUserCommand(userId, Stream.of(new Address("New York", "NY", "10001"), new Address("Housten", "TX", "77001"))
.collect(Collectors.toSet()),
Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"), new Contact("PHONE", "700-000-0001"))
.collect(Collectors.toSet()));
events = userAggregate.handleUpdateUserCommand(updateUserCommand);
projector.project(userId, events);
ContactByTypeQuery contactByTypeQuery = new ContactByTypeQuery(userId, "EMAIL");
assertEquals(Stream.of(new Contact("EMAIL", "tom.sawyer@gmail.com"))
.collect(Collectors.toSet()), userProjection.handle(contactByTypeQuery));
AddressByRegionQuery addressByRegionQuery = new AddressByRegionQuery(userId, "NY");
assertEquals(Stream.of(new Address("New York", "NY", "10001"))
.collect(Collectors.toSet()), userProjection.handle(addressByRegionQuery));
}
}
@@ -0,0 +1,6 @@
### Relevant Articles:
- [Service Locator Pattern and Java Implementation](https://www.baeldung.com/java-service-locator-pattern)
- [The DAO Pattern in Java](https://www.baeldung.com/java-dao-pattern)
- [DAO vs Repository Patterns](https://www.baeldung.com/java-dao-vs-repository)
- [Difference Between MVC and MVP Patterns](https://www.baeldung.com/mvc-vs-mvp-pattern)
- [The DTO Pattern (Data Transfer Object)](https://www.baeldung.com/java-dto-pattern)
@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>design-patterns-architectural</artifactId>
<version>1.0</version>
<name>design-patterns-architectural</name>
<packaging>jar</packaging>
<parent>
<groupId>com.baeldung</groupId>
<artifactId>patterns-modules</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>${rest-assured.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-core.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql-connector.version}</version>
<type>jar</type>
</dependency>
</dependencies>
<properties>
<hibernate-core.version>5.2.16.Final</hibernate-core.version>
<mysql-connector.version>6.0.6</mysql-connector.version>
<spring-boot.version>2.5.3</spring-boot.version>
<rest-assured.version>3.3.0</rest-assured.version>
</properties>
</project>
@@ -0,0 +1,53 @@
package com.baeldung.daopattern.application;
import com.baeldung.daopattern.config.JpaEntityManagerFactory;
import com.baeldung.daopattern.daos.Dao;
import com.baeldung.daopattern.daos.JpaUserDao;
import com.baeldung.daopattern.entities.User;
import java.util.List;
import java.util.Optional;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
public class UserApplication {
private static JpaUserDao jpaUserDao;
public static void main(String[] args) {
User user1 = getUser(1);
System.out.println(user1);
updateUser(user1, new String[]{"John", "john@domain.com"});
saveUser(new User("Monica", "monica@domain.com"));
deleteUser(getUser(2));
getAllUsers().forEach(user -> System.out.println(user.getName()));
}
private static class JpaUserDaoHolder {
private static final JpaUserDao jpaUserDao = new JpaUserDao(new JpaEntityManagerFactory().getEntityManager());
}
public static Dao getJpaUserDao() {
return JpaUserDaoHolder.jpaUserDao;
}
public static User getUser(long id) {
Optional<User> user = getJpaUserDao().get(id);
return user.orElseGet(()-> {return new User("non-existing user", "no-email");});
}
public static List<User> getAllUsers() {
return getJpaUserDao().getAll();
}
public static void updateUser(User user, String[] params){
getJpaUserDao().update(user, params);
}
public static void saveUser(User user) {
getJpaUserDao().save(user);
}
public static void deleteUser(User user) {
getJpaUserDao().delete(user);
}
}
@@ -0,0 +1,65 @@
package com.baeldung.daopattern.config;
import com.baeldung.daopattern.entities.User;
import com.mysql.cj.jdbc.MysqlDataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceUnitInfo;
import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl;
import org.hibernate.jpa.boot.internal.PersistenceUnitInfoDescriptor;
public class JpaEntityManagerFactory {
private final String DB_URL = "jdbc:mysql://databaseurl";
private final String DB_USER_NAME = "username";
private final String DB_PASSWORD = "password";
public EntityManager getEntityManager() {
return getEntityManagerFactory().createEntityManager();
}
protected EntityManagerFactory getEntityManagerFactory() {
PersistenceUnitInfo persistenceUnitInfo = getPersistenceUnitInfo(getClass().getSimpleName());
Map<String, Object> configuration = new HashMap<>();
return new EntityManagerFactoryBuilderImpl(new PersistenceUnitInfoDescriptor(persistenceUnitInfo), configuration)
.build();
}
protected PersistenceUnitInfoImpl getPersistenceUnitInfo(String name) {
return new PersistenceUnitInfoImpl(name, getEntityClassNames(), getProperties());
}
protected List<String> getEntityClassNames() {
return Arrays.asList(getEntities())
.stream()
.map(Class::getName)
.collect(Collectors.toList());
}
protected Properties getProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.id.new_generator_mappings", false);
properties.put("hibernate.connection.datasource", getMysqlDataSource());
return properties;
}
protected Class[] getEntities() {
return new Class[]{User.class};
}
protected DataSource getMysqlDataSource() {
MysqlDataSource mysqlDataSource = new MysqlDataSource();
mysqlDataSource.setURL(DB_URL);
mysqlDataSource.setUser(DB_USER_NAME);
mysqlDataSource.setPassword(DB_PASSWORD);
return mysqlDataSource;
}
}
@@ -0,0 +1,130 @@
package com.baeldung.daopattern.config;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import javax.sql.DataSource;
import javax.persistence.SharedCacheMode;
import javax.persistence.ValidationMode;
import javax.persistence.spi.ClassTransformer;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.persistence.spi.PersistenceUnitTransactionType;
import org.hibernate.jpa.HibernatePersistenceProvider;
public class PersistenceUnitInfoImpl implements PersistenceUnitInfo {
public static final String JPA_VERSION = "2.1";
private final String persistenceUnitName;
private PersistenceUnitTransactionType transactionType = PersistenceUnitTransactionType.RESOURCE_LOCAL;
private final List<String> managedClassNames;
private final List<String> mappingFileNames = new ArrayList<>();
private final Properties properties;
private DataSource jtaDataSource;
private DataSource nonJtaDataSource;
public PersistenceUnitInfoImpl(String persistenceUnitName, List<String> managedClassNames, Properties properties) {
this.persistenceUnitName = persistenceUnitName;
this.managedClassNames = managedClassNames;
this.properties = properties;
}
@Override
public String getPersistenceUnitName() {
return persistenceUnitName;
}
@Override
public String getPersistenceProviderClassName() {
return HibernatePersistenceProvider.class.getName();
}
@Override
public PersistenceUnitTransactionType getTransactionType() {
return transactionType;
}
@Override
public DataSource getJtaDataSource() {
return jtaDataSource;
}
public PersistenceUnitInfoImpl setJtaDataSource(DataSource jtaDataSource) {
this.jtaDataSource = jtaDataSource;
this.nonJtaDataSource = null;
transactionType = PersistenceUnitTransactionType.JTA;
return this;
}
@Override
public DataSource getNonJtaDataSource() {
return nonJtaDataSource;
}
public PersistenceUnitInfoImpl setNonJtaDataSource(DataSource nonJtaDataSource) {
this.nonJtaDataSource = nonJtaDataSource;
this.jtaDataSource = null;
transactionType = PersistenceUnitTransactionType.RESOURCE_LOCAL;
return this;
}
@Override
public List<String> getMappingFileNames() {
return mappingFileNames;
}
@Override
public List<URL> getJarFileUrls() {
return Collections.emptyList();
}
@Override
public URL getPersistenceUnitRootUrl() {
return null;
}
@Override
public List<String> getManagedClassNames() {
return managedClassNames;
}
@Override
public boolean excludeUnlistedClasses() {
return false;
}
@Override
public SharedCacheMode getSharedCacheMode() {
return SharedCacheMode.UNSPECIFIED;
}
@Override
public ValidationMode getValidationMode() {
return ValidationMode.AUTO;
}
public Properties getProperties() {
return properties;
}
@Override
public String getPersistenceXMLSchemaVersion() {
return JPA_VERSION;
}
@Override
public ClassLoader getClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
@Override
public void addTransformer(ClassTransformer transformer) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public ClassLoader getNewTempClassLoader() {
return null;
}
}
@@ -0,0 +1,17 @@
package com.baeldung.daopattern.daos;
import java.util.List;
import java.util.Optional;
public interface Dao<T> {
Optional<T> get(long id);
List<T> getAll();
void save(T t);
void update(T t, String[] params);
void delete(T t);
}
@@ -0,0 +1,60 @@
package com.baeldung.daopattern.daos;
import com.baeldung.daopattern.entities.User;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
public class JpaUserDao implements Dao<User> {
private final EntityManager entityManager;
public JpaUserDao(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public Optional<User> get(long id) {
return Optional.ofNullable(entityManager.find(User.class, id));
}
@Override
public List<User> getAll() {
Query query = entityManager.createQuery("SELECT e FROM User e");
return query.getResultList();
}
@Override
public void save(User user) {
executeInsideTransaction(entityManager -> entityManager.persist(user));
}
@Override
public void update(User user, String[] params) {
user.setName(Objects.requireNonNull(params[0], "Name cannot be null"));
user.setEmail(Objects.requireNonNull(params[1], "Email cannot be null"));
executeInsideTransaction(entityManager -> entityManager.merge(user));
}
@Override
public void delete(User user) {
executeInsideTransaction(entityManager -> entityManager.remove(user));
}
private void executeInsideTransaction(Consumer<EntityManager> action) {
final EntityTransaction tx = entityManager.getTransaction();
try {
tx.begin();
action.accept(entityManager);
tx.commit();
}
catch (RuntimeException e) {
tx.rollback();
throw e;
}
}
}
@@ -0,0 +1,44 @@
package com.baeldung.daopattern.daos;
import com.baeldung.daopattern.entities.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
public class UserDao implements Dao<User> {
private List<User> users = new ArrayList<>();
public UserDao() {
users.add(new User("John", "john@domain.com"));
users.add(new User("Susan", "susan@domain.com"));
}
@Override
public Optional<User> get(long id) {
return Optional.ofNullable(users.get((int) id));
}
@Override
public List<User> getAll() {
return users;
}
@Override
public void save(User user) {
users.add(user);
}
@Override
public void update(User user, String[] params) {
user.setName(Objects.requireNonNull(params[0], "Name cannot be null"));
user.setEmail(Objects.requireNonNull(params[1], "Email cannot be null"));
users.add(user);
}
@Override
public void delete(User user) {
users.remove(user);
}
}
@@ -0,0 +1,45 @@
package com.baeldung.daopattern.entities;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String name;
private String email;
public User(){}
public User(String name, String email) {
this.name = name;
this.email = email;
}
public void setName(String name) {
this.name = name;
}
public void setEmail(String email) {
this.email = email;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
}
@@ -0,0 +1,12 @@
package com.baeldung.dtopattern;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
@@ -0,0 +1,28 @@
package com.baeldung.dtopattern.api;
import com.baeldung.dtopattern.domain.Role;
import com.baeldung.dtopattern.domain.User;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import static java.util.stream.Collectors.toList;
@Component
class Mapper {
public UserDTO toDto(User user) {
String name = user.getName();
List<String> roles = user
.getRoles()
.stream()
.map(Role::getName)
.collect(toList());
return new UserDTO(name, roles);
}
public User toUser(UserCreationDTO userDTO) {
return new User(userDTO.getName(), userDTO.getPassword(), new ArrayList<>());
}
}
@@ -0,0 +1,51 @@
package com.baeldung.dtopattern.api;
import com.baeldung.dtopattern.domain.RoleService;
import com.baeldung.dtopattern.domain.User;
import com.baeldung.dtopattern.domain.UserService;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import static java.util.stream.Collectors.toList;
@RestController
@RequestMapping("/users")
class UserController {
private UserService userService;
private RoleService roleService;
private Mapper mapper;
public UserController(UserService userService, RoleService roleService, Mapper mapper) {
this.userService = userService;
this.roleService = roleService;
this.mapper = mapper;
}
@GetMapping
@ResponseBody
public List<UserDTO> getUsers() {
return userService.getAll()
.stream()
.map(mapper::toDto)
.collect(toList());
}
@PostMapping
@ResponseBody
public UserIdDTO create(@RequestBody UserCreationDTO userDTO) {
User user = mapper.toUser(userDTO);
userDTO.getRoles()
.stream()
.map(role -> roleService.getOrCreate(role))
.forEach(user::addRole);
userService.save(user);
return new UserIdDTO(user.getId());
}
}
@@ -0,0 +1,36 @@
package com.baeldung.dtopattern.api;
import java.util.List;
public class UserCreationDTO {
private String name;
private String password;
private List<String> roles;
UserCreationDTO() {}
public String getName() {
return name;
}
public String getPassword() {
return password;
}
public List<String> getRoles() {
return roles;
}
void setName(String name) {
this.name = name;
}
void setPassword(String password) {
this.password = password;
}
void setRoles(List<String> roles) {
this.roles = roles;
}
}
@@ -0,0 +1,22 @@
package com.baeldung.dtopattern.api;
import java.util.List;
public class UserDTO {
private String name;
private List<String> roles;
public UserDTO(String name, List<String> roles) {
this.name = name;
this.roles = roles;
}
public String getName() {
return name;
}
public List<String> getRoles() {
return roles;
}
}
@@ -0,0 +1,14 @@
package com.baeldung.dtopattern.api;
public class UserIdDTO {
private String id;
public UserIdDTO(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
@@ -0,0 +1,49 @@
package com.baeldung.dtopattern.domain;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
class InMemoryRepository implements UserRepository, RoleRepository {
private Map<String, User> users = new LinkedHashMap<>();
private Map<String, Role> roles = new LinkedHashMap<>();
@Override
public List<User> getAll() {
return new ArrayList<>(users.values());
}
@Override
public void save(User user) {
user.setId(UUID.randomUUID().toString());
users.put(user.getId(), user);
}
@Override
public void save(Role role) {
role.setId(UUID.randomUUID().toString());
roles.put(role.getId(), role);
}
@Override
public Role getRoleById(String id) {
return roles.get(id);
}
@Override
public Role getRoleByName(String name) {
return roles.values()
.stream()
.filter(role -> role.getName().equalsIgnoreCase(name))
.findFirst()
.orElse(null);
}
@Override
public void deleteAll() {
users.clear();
roles.clear();
}
}
@@ -0,0 +1,28 @@
package com.baeldung.dtopattern.domain;
import java.util.Objects;
public class Role {
private String id;
private String name;
public Role(String name) {
this.name = Objects.requireNonNull(name);
}
public String getId() {
return id;
}
void setId(String id) {
this.id = Objects.requireNonNull(id);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = Objects.requireNonNull(name);
}
}
@@ -0,0 +1,7 @@
package com.baeldung.dtopattern.domain;
public interface RoleRepository {
Role getRoleById(String id);
Role getRoleByName(String name);
void save(Role role);
}
@@ -0,0 +1,32 @@
package com.baeldung.dtopattern.domain;
import org.springframework.stereotype.Service;
import java.util.Objects;
@Service
public class RoleService {
private RoleRepository repository;
public RoleService(RoleRepository repository) {
this.repository = repository;
}
public Role getOrCreate(String name) {
Role role = repository.getRoleByName(name);
if (role == null) {
role = new Role(name);
repository.save(role);
}
return role;
}
public void save(Role role) {
Objects.requireNonNull(role);
repository.save(role);
}
}
@@ -0,0 +1,80 @@
package com.baeldung.dtopattern.domain;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class User {
private static SecretKeySpec KEY = initKey();
static SecretKeySpec initKey(){
try {
SecretKey secretKey = KeyGenerator.getInstance("AES").generateKey();
return new SecretKeySpec(secretKey.getEncoded(), "AES");
} catch (NoSuchAlgorithmException ex) {
return null;
}
}
private String id;
private String name;
private String password;
private List<Role> roles;
public User(String name, String password, List<Role> roles) {
this.name = Objects.requireNonNull(name);
this.password = this.encrypt(password);
this.roles = Objects.requireNonNull(roles);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void addRole(Role role) {
roles.add(role);
}
public List<Role> getRoles() {
return Collections.unmodifiableList(roles);
}
public String getId() {
return id;
}
void setId(String id) {
this.id = id;
}
String encrypt(String password) {
Objects.requireNonNull(password);
try {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, KEY);
final byte[] encryptedBytes = cipher.doFinal(password.getBytes(StandardCharsets.UTF_8));
return new String(encryptedBytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
// do nothing
return "";
}
}
}
@@ -0,0 +1,9 @@
package com.baeldung.dtopattern.domain;
import java.util.List;
public interface UserRepository {
List<User> getAll();
void save(User user);
void deleteAll();
}
@@ -0,0 +1,25 @@
package com.baeldung.dtopattern.domain;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Objects;
@Service
public class UserService {
private UserRepository repository;
public UserService(UserRepository repository) {
this.repository = repository;
}
public List<User> getAll() {
return repository.getAll();
}
public void save(User user) {
Objects.requireNonNull(user);
repository.save(user);
}
}
@@ -0,0 +1,24 @@
package com.baeldung.mvc_mvp.mvc;
public class MvcMainClass {
public static void main(String[] args) {
Product model = retrieveProductFromDatabase();
ProductView view = new ProductView();
model.setView(view);
model.showProduct();
ProductController controller = new ProductController(model);
controller.setName("SmartPhone");
model.showProduct();
}
private static Product retrieveProductFromDatabase() {
Product product = new Product();
product.setName("Mobile");
product.setDescription("New Brand");
product.setPrice(1000.0);
return product;
}
}
@@ -0,0 +1,45 @@
package com.baeldung.mvc_mvp.mvc;
public class Product {
private String name;
private String description;
private Double price;
private ProductView view;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
public ProductView getView() {
return view;
}
public void setView(ProductView view) {
this.view = view;
}
public void showProduct() {
view.printProductDetails(name, description, price);
}
}
@@ -0,0 +1,34 @@
package com.baeldung.mvc_mvp.mvc;
public class ProductController {
private final Product product;
public ProductController(Product product) {
this.product = product;
}
public String getName() {
return product.getName();
}
public void setName(String name) {
product.setName(name);
}
public String getDescription() {
return product.getDescription();
}
public void setDescription(String description) {
product.setDescription(description);
}
public Double getPrice() {
return product.getPrice();
}
public void setPrice(Double price) {
product.setPrice(price);
}
}
@@ -0,0 +1,15 @@
package com.baeldung.mvc_mvp.mvc;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProductView {
private static Logger log = LoggerFactory.getLogger(ProductView.class);
public void printProductDetails(String name, String description, Double price) {
log.info("Product details:");
log.info("product Name: " + name);
log.info("product Description: " + description);
log.info("product price: " + price);
}
}
@@ -0,0 +1,22 @@
package com.baeldung.mvc_mvp.mvp;
public class MvpMainClass {
public static void main(String[] args) {
Product model = retrieveProductFromDatabase();
ProductView view = new ProductView();
ProductPresenter presenter = new ProductPresenter(model, view);
presenter.showProduct();
presenter.setName("SmartPhone");
presenter.showProduct();
}
private static Product retrieveProductFromDatabase() {
Product product = new Product();
product.setName("Mobile");
product.setDescription("New Brand");
product.setPrice(1000.0);
return product;
}
}
@@ -0,0 +1,32 @@
package com.baeldung.mvc_mvp.mvp;
public class Product {
private String name;
private String description;
private Double price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
}
@@ -0,0 +1,40 @@
package com.baeldung.mvc_mvp.mvp;
public class ProductPresenter {
private final Product product;
private final ProductView view;
public ProductPresenter(Product product, ProductView view) {
this.product = product;
this.view = view;
}
public String getName() {
return product.getName();
}
public void setName(String name) {
product.setName(name);
}
public String getDescription() {
return product.getDescription();
}
public void setDescription(String description) {
product.setDescription(description);
}
public Double getProductPrice() {
return product.getPrice();
}
public void setPrice(Double price) {
product.setPrice(price);
}
public void showProduct() {
view.printProductDetails(product.getName(), product.getDescription(), product.getPrice());
}
}
@@ -0,0 +1,15 @@
package com.baeldung.mvc_mvp.mvp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProductView {
private static Logger log = LoggerFactory.getLogger(ProductView.class);
public void printProductDetails(String name, String description, Double price) {
log.info("Product details:");
log.info("product Name: " + name);
log.info("product Description: " + description);
log.info("product price: " + price);
}
}
@@ -0,0 +1,37 @@
package com.baeldung.repositoryvsdaopattern;
import java.util.Date;
public class Tweet {
private String email;
private String tweetText;
private Date dateCreated;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getTweetText() {
return tweetText;
}
public void setTweetText(String tweetText) {
this.tweetText = tweetText;
}
public Date getDateCreated() {
return dateCreated;
}
public void setDateCreated(Date dateCreated) {
this.dateCreated = dateCreated;
}
}
@@ -0,0 +1,9 @@
package com.baeldung.repositoryvsdaopattern;
import java.util.List;
public interface TweetDao {
List<Tweet> fetchTweets(String email);
}
@@ -0,0 +1,17 @@
package com.baeldung.repositoryvsdaopattern;
import java.util.ArrayList;
import java.util.List;
public class TweetDaoImpl implements TweetDao {
@Override
public List<Tweet> fetchTweets(String email) {
List<Tweet> tweets = new ArrayList<Tweet>();
//call Twitter API and prepare Tweet object
return tweets;
}
}
@@ -0,0 +1,51 @@
package com.baeldung.repositoryvsdaopattern;
public class User {
private Long id;
private String userName;
private String firstName;
private String lastName;
private String email;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
@@ -0,0 +1,13 @@
package com.baeldung.repositoryvsdaopattern;
public interface UserDao {
void create(User user);
User read(Long id);
void update(User user);
void delete(String userName);
}
@@ -0,0 +1,33 @@
package com.baeldung.repositoryvsdaopattern;
import javax.persistence.EntityManager;
public class UserDaoImpl implements UserDao {
private final EntityManager entityManager;
public UserDaoImpl(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Override
public void create(User user) {
entityManager.persist(user);
}
@Override
public User read(Long id) {
return entityManager.find(User.class, id);
}
@Override
public void update(User user) {
}
@Override
public void delete(String userName) {
}
}
@@ -0,0 +1,21 @@
package com.baeldung.repositoryvsdaopattern;
import java.util.List;
public interface UserRepository {
User get(Long id);
void add(User user);
void update(User user);
void remove(User user);
User findByUserName(String userName);
User findByEmail(String email);
List<Tweet> fetchTweets(User user);
}
@@ -0,0 +1,51 @@
package com.baeldung.repositoryvsdaopattern;
import java.util.List;
public class UserRepositoryImpl implements UserRepository {
private UserDaoImpl userDaoImpl;
private TweetDaoImpl tweetDaoImpl;
@Override
public User get(Long id) {
UserSocialMedia user = (UserSocialMedia) userDaoImpl.read(id);
List<Tweet> tweets = tweetDaoImpl.fetchTweets(user.getEmail());
user.setTweets(tweets);
return user;
}
@Override
public void add(User user) {
userDaoImpl.create(user);
}
@Override
public void remove(User user) {
}
@Override
public void update(User user) {
}
@Override
public List<Tweet> fetchTweets(User user) {
return tweetDaoImpl.fetchTweets(user.getEmail());
}
@Override
public User findByUserName(String userName) {
return null;
}
@Override
public User findByEmail(String email) {
return null;
}
}
@@ -0,0 +1,17 @@
package com.baeldung.repositoryvsdaopattern;
import java.util.List;
public class UserSocialMedia extends User {
private List<Tweet> tweets;
public List<Tweet> getTweets() {
return tweets;
}
public void setTweets(List<Tweet> tweets) {
this.tweets = tweets;
}
}
@@ -0,0 +1,39 @@
package com.baeldung.service.locator;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Gebruiker on 4/20/2018.
*/
public class Cache {
private List<MessagingService> services;
public Cache(){
services = new ArrayList<MessagingService>();
}
public MessagingService getService(String serviceName){
for (MessagingService service : services) {
if(service.getServiceName().equalsIgnoreCase(serviceName)){
System.out.println("Returning cached " + serviceName + " object");
return service;
}
}
return null;
}
public void addService(MessagingService newService){
boolean exists = false;
for (MessagingService service : services) {
if(service.getServiceName().equalsIgnoreCase(newService.getServiceName())){
exists = true;
}
}
if(!exists){
services.add(newService);
}
}
}
@@ -0,0 +1,15 @@
package com.baeldung.service.locator;
/**
* Created by Gebruiker on 4/20/2018.
*/
public class EmailService implements MessagingService {
public String getMessageBody() {
return "email message";
}
public String getServiceName() {
return "EmailService";
}
}
@@ -0,0 +1,17 @@
package com.baeldung.service.locator;
/**
* Created by Gebruiker on 4/20/2018.
*/
public class InitialContext {
public Object lookup(String serviceName) {
if (serviceName.equalsIgnoreCase("EmailService")) {
return new EmailService();
} else if (serviceName.equalsIgnoreCase("SMSService")) {
return new SMSService();
}
return null;
}
}
@@ -0,0 +1,22 @@
package com.baeldung.service.locator;
/**
* Created by Gebruiker on 4/20/2018.
*/
public class Main {
public static void main(String[] args) {
MessagingService service = ServiceLocator.getService("EmailService");
String email = service.getMessageBody();
System.out.println(email);
service = ServiceLocator.getService("SMSService");
String sms = service.getMessageBody();
System.out.println(sms);
service = ServiceLocator.getService("EmailService");
String newEmail = service.getMessageBody();
System.out.println(newEmail);
}
}

Some files were not shown because too many files have changed in this diff Show More