diff --git a/.mvn/wrapper/MavenWrapperDownloader.java b/.mvn/wrapper/MavenWrapperDownloader.java index a45eb6b..65e6aae 100644 --- a/.mvn/wrapper/MavenWrapperDownloader.java +++ b/.mvn/wrapper/MavenWrapperDownloader.java @@ -21,98 +21,99 @@ import java.util.Properties; public class MavenWrapperDownloader { - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + private static final String WRAPPER_VERSION = "0.5.6"; + /** Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + + "/maven-wrapper-" + + WRAPPER_VERSION + + ".jar"; - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use + * instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; + /** Path where the maven-wrapper.jar will be saved to. */ + private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar"; - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... } + } } + System.out.println("- Downloading from: " + url); - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + + outputFile.getParentFile().getAbsolutePath() + + "'"); + } } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault( + new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } } diff --git a/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/CustomerDao.java b/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/CustomerDao.java index 327fa71..de0e13a 100644 --- a/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/CustomerDao.java +++ b/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/CustomerDao.java @@ -1,6 +1,7 @@ package de.strasser.peter.hexagonal.persistence; import de.strasser.peter.hexagonal.application.customer.domain.Customer; +import de.strasser.peter.hexagonal.application.customer.port.in.QueryAllCustomersCRUD; import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerAdapter; import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerAdapter; import de.strasser.peter.hexagonal.persistence.mapper.CustomerMapper; @@ -13,12 +14,13 @@ import org.springframework.stereotype.Repository; import java.math.BigInteger; import java.time.LocalDate; import java.util.HashMap; +import java.util.List; import java.util.Optional; @Slf4j @Repository @RequiredArgsConstructor -public class CustomerDao implements SaveCustomerAdapter, LoadCustomerAdapter { +public class CustomerDao implements SaveCustomerAdapter, LoadCustomerAdapter, QueryAllCustomersCRUD { private final CustomerRepository customerRepository; private final CustomerMapper customerMapper; @@ -38,4 +40,9 @@ public class CustomerDao implements SaveCustomerAdapter, LoadCustomerAdapter { new HashMap<>(), true); } + + @Override + public List getAll() { + return customerMapper.toDomain(customerRepository.findAll()); + } } diff --git a/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/mapper/CustomerMapper.java b/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/mapper/CustomerMapper.java index 38b449b..24132d0 100644 --- a/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/mapper/CustomerMapper.java +++ b/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/mapper/CustomerMapper.java @@ -3,84 +3,90 @@ package de.strasser.peter.hexagonal.persistence.mapper; import de.strasser.peter.hexagonal.application.customer.domain.Address; import de.strasser.peter.hexagonal.application.customer.domain.Customer; import de.strasser.peter.hexagonal.persistence.model.CustomerEntity; +import org.mapstruct.Mapper; import org.springframework.core.convert.converter.Converter; -import org.springframework.stereotype.Component; import java.util.HashMap; +import java.util.List; import java.util.Map; -@Component -public class CustomerMapper { - public Customer toDomain(CustomerEntity customerEntity) { - final HashMap addresses = createAddressMap(customerEntity); - return Customer.createCustomer( - customerEntity.getId(), - customerEntity.getName(), - customerEntity.getHashedPassword(), - customerEntity.getBirthday(), - addresses, - customerEntity.isActive()); - } +@Mapper +public interface CustomerMapper { + List toDomain(List customerEntityList); + default Customer toDomain(CustomerEntity customerEntity) { + final HashMap addresses = createAddressMap(customerEntity); + return Customer.createCustomer( + customerEntity.getId(), + customerEntity.getName(), + customerEntity.getHashedPassword(), + customerEntity.getBirthday(), + addresses, + customerEntity.isActive()); + } - public CustomerEntity toDbEntity(Customer customer) { - return new CustomerEntity( - customer.getId(), - customer.getName(), - customer.getHashedPassword(), - customer.getBirthday(), - customer.isActive(), - getAddressAttribute(customer, Address.AddressType.DEFAULT, Address::getStreet), - getAddressAttribute(customer, Address.AddressType.DEFAULT, Address::getHouseNumber), - getAddressAttribute(customer, Address.AddressType.DEFAULT, Address::getZipCode), - getAddressAttribute(customer, Address.AddressType.DEFAULT, Address::getCountry), - getAddressAttribute(customer, Address.AddressType.SHIPPING, Address::getStreet), - getAddressAttribute(customer, Address.AddressType.SHIPPING, Address::getHouseNumber), - getAddressAttribute(customer, Address.AddressType.SHIPPING, Address::getZipCode), - getAddressAttribute(customer, Address.AddressType.SHIPPING, Address::getCountry), - getAddressAttribute(customer, Address.AddressType.BILLING, Address::getStreet), - getAddressAttribute(customer, Address.AddressType.BILLING, Address::getHouseNumber), - getAddressAttribute(customer, Address.AddressType.BILLING, Address::getZipCode), - getAddressAttribute(customer, Address.AddressType.BILLING, Address::getCountry)); - } + default CustomerEntity toDbEntity(Customer customer) { + return new CustomerEntity( + customer.getId(), + customer.getName(), + customer.getHashedPassword(), + customer.getBirthday(), + customer.isActive(), + getAddressAttribute(customer, Address.AddressType.DEFAULT, Address::getStreet), + getAddressAttribute(customer, Address.AddressType.DEFAULT, Address::getHouseNumber), + getAddressAttribute(customer, Address.AddressType.DEFAULT, Address::getZipCode), + getAddressAttribute(customer, Address.AddressType.DEFAULT, Address::getCountry), + getAddressAttribute(customer, Address.AddressType.SHIPPING, Address::getStreet), + getAddressAttribute(customer, Address.AddressType.SHIPPING, Address::getHouseNumber), + getAddressAttribute(customer, Address.AddressType.SHIPPING, Address::getZipCode), + getAddressAttribute(customer, Address.AddressType.SHIPPING, Address::getCountry), + getAddressAttribute(customer, Address.AddressType.BILLING, Address::getStreet), + getAddressAttribute(customer, Address.AddressType.BILLING, Address::getHouseNumber), + getAddressAttribute(customer, Address.AddressType.BILLING, Address::getZipCode), + getAddressAttribute(customer, Address.AddressType.BILLING, Address::getCountry)); + } - private T getAddressAttribute(Customer customer, Address.AddressType type, Converter getter) { - final Map addresses = customer.getAddresses(); - if (addresses != null) { - final Address address = addresses.get(type); - if (address != null) { - return getter.convert(address); - } - } - return null; + private T getAddressAttribute( + Customer customer, Address.AddressType type, Converter getter) { + final Map addresses = customer.getAddresses(); + if (addresses != null) { + final Address address = addresses.get(type); + if (address != null) { + return getter.convert(address); + } } + return null; + } - private HashMap createAddressMap(CustomerEntity customerEntity) { - final HashMap addresses = new HashMap<>(); - if (customerEntity.getStreet() != null) { - addresses.put(Address.AddressType.DEFAULT, - new Address( - customerEntity.getStreet(), - customerEntity.getHouseNumber(), - customerEntity.getZipCode(), - customerEntity.getCountry())); - } - if (customerEntity.getBillingStreet() != null) { - addresses.put(Address.AddressType.SHIPPING, - new Address( - customerEntity.getShippingStreet(), - customerEntity.getShippingHouseNumber(), - customerEntity.getShippingZipCode(), - customerEntity.getShippingCountry())); - } - if (customerEntity.getBillingStreet() != null) { - addresses.put(Address.AddressType.BILLING, - new Address( - customerEntity.getBillingStreet(), - customerEntity.getBillingHouseNumber(), - customerEntity.getBillingZipCode(), - customerEntity.getBillingCountry())); - } - return addresses; + private HashMap createAddressMap(CustomerEntity customerEntity) { + final HashMap addresses = new HashMap<>(); + if (customerEntity.getStreet() != null) { + addresses.put( + Address.AddressType.DEFAULT, + new Address( + customerEntity.getStreet(), + customerEntity.getHouseNumber(), + customerEntity.getZipCode(), + customerEntity.getCountry())); } + if (customerEntity.getBillingStreet() != null) { + addresses.put( + Address.AddressType.SHIPPING, + new Address( + customerEntity.getShippingStreet(), + customerEntity.getShippingHouseNumber(), + customerEntity.getShippingZipCode(), + customerEntity.getShippingCountry())); + } + if (customerEntity.getBillingStreet() != null) { + addresses.put( + Address.AddressType.BILLING, + new Address( + customerEntity.getBillingStreet(), + customerEntity.getBillingHouseNumber(), + customerEntity.getBillingZipCode(), + customerEntity.getBillingCountry())); + } + return addresses; + } } diff --git a/adapter/persistence/src/test/java/de/strasser/peter/hexagonal/persistence/CustomerDaoTest.java b/adapter/persistence/src/test/java/de/strasser/peter/hexagonal/persistence/CustomerDaoTest.java index 96f0b4f..f929489 100644 --- a/adapter/persistence/src/test/java/de/strasser/peter/hexagonal/persistence/CustomerDaoTest.java +++ b/adapter/persistence/src/test/java/de/strasser/peter/hexagonal/persistence/CustomerDaoTest.java @@ -2,6 +2,7 @@ package de.strasser.peter.hexagonal.persistence; import de.strasser.peter.hexagonal.application.customer.domain.Customer; import de.strasser.peter.hexagonal.persistence.mapper.CustomerMapper; +import de.strasser.peter.hexagonal.persistence.mapper.CustomerMapperImpl; import de.strasser.peter.hexagonal.persistence.repository.CustomerRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; @@ -15,7 +16,7 @@ import java.time.LocalDate; import static org.junit.jupiter.api.Assertions.assertEquals; @DataMongoTest -@Import({CustomerDao.class, CustomerMapper.class}) +@Import({CustomerDao.class, CustomerMapperImpl.class}) class CustomerDaoTest { @Autowired private CustomerDao customerDao; diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/AddAddressController.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/AddAddressController.java index 64e6606..ac8889e 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/AddAddressController.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/AddAddressController.java @@ -2,8 +2,8 @@ package de.strasser.peter.hexagonal.web; import de.strasser.peter.hexagonal.application.customer.port.in.AddAddressUseCase; import de.strasser.peter.hexagonal.application.customer.port.in.commands.AddAddressCommand; -import de.strasser.peter.hexagonal.web.mapper.AddAddressRequestMapper; -import de.strasser.peter.hexagonal.web.model.AddAddressRequest; +import de.strasser.peter.hexagonal.web.mapper.AddAddressWebMapper; +import de.strasser.peter.hexagonal.web.dto.request.AddAddressRequest; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -17,8 +17,7 @@ import java.util.List; @RequiredArgsConstructor public class AddAddressController { private final AddAddressUseCase addAddressUseCase; - private final AddAddressRequestMapper addAddressMapper; - + private final AddAddressWebMapper addAddressMapper; @PostMapping("/v1/address") public void addAddress(@RequestParam BigInteger customerId, @RequestBody AddAddressRequest addAddressRequest) { diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/CustomerCRUDController.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/CustomerCRUDController.java new file mode 100644 index 0000000..ff76b26 --- /dev/null +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/CustomerCRUDController.java @@ -0,0 +1,17 @@ +package de.strasser.peter.hexagonal.web; + +import de.strasser.peter.hexagonal.application.customer.port.in.QueryAllCustomersCRUD; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class CustomerCRUDController { + private final QueryAllCustomersCRUD queryAllCustomersCRUD; + + @GetMapping("/v1/customers") + public Object getAllCustomers() { + return this.queryAllCustomersCRUD.getAll(); + } +} diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/RegisterCustomerController.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/RegisterCustomerController.java index 2d8ae9e..6f73890 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/RegisterCustomerController.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/RegisterCustomerController.java @@ -1,8 +1,8 @@ package de.strasser.peter.hexagonal.web; import de.strasser.peter.hexagonal.application.customer.port.in.RegisterCustomerUseCase; -import de.strasser.peter.hexagonal.web.mapper.RegisterCustomerRequestMapper; -import de.strasser.peter.hexagonal.web.model.RegisterCustomerRequest; +import de.strasser.peter.hexagonal.web.mapper.RegisterCustomerWebMapper; +import de.strasser.peter.hexagonal.web.dto.request.RegisterCustomerRequest; import lombok.AllArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RestController; @AllArgsConstructor public class RegisterCustomerController { private final RegisterCustomerUseCase registerCustomerUseCase; - private final RegisterCustomerRequestMapper registerCustomerMapper; + private final RegisterCustomerWebMapper registerCustomerMapper; @PostMapping("/v1/register") public void registerCustomer(@RequestBody RegisterCustomerRequest registerCustomerRequest) { diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/model/AddAddressRequest.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/AddAddressRequest.java similarity index 84% rename from adapter/web/src/main/java/de/strasser/peter/hexagonal/web/model/AddAddressRequest.java rename to adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/AddAddressRequest.java index bde6bf7..c9db45a 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/model/AddAddressRequest.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/AddAddressRequest.java @@ -1,4 +1,4 @@ -package de.strasser.peter.hexagonal.web.model; +package de.strasser.peter.hexagonal.web.dto.request; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/model/RegisterCustomerRequest.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/RegisterCustomerRequest.java similarity index 84% rename from adapter/web/src/main/java/de/strasser/peter/hexagonal/web/model/RegisterCustomerRequest.java rename to adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/RegisterCustomerRequest.java index 50edead..ee76867 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/model/RegisterCustomerRequest.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/request/RegisterCustomerRequest.java @@ -1,4 +1,4 @@ -package de.strasser.peter.hexagonal.web.model; +package de.strasser.peter.hexagonal.web.dto.request; import lombok.AllArgsConstructor; import lombok.Data; diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java new file mode 100644 index 0000000..225256d --- /dev/null +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java @@ -0,0 +1,4 @@ +package de.strasser.peter.hexagonal.web.dto.response; + +public class CustomerResponse { +} diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/errors/ErrorHandling.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/errors/ErrorHandling.java index 548fcde..cae9ab9 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/errors/ErrorHandling.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/errors/ErrorHandling.java @@ -36,7 +36,7 @@ public class ErrorHandling { final ErrorResponse errResponse = new ErrorResponse( LocalDateTime.now().toString(), code.value(), - e.getClass().getName(), + e.getClass().getSimpleName(), e.getMessage(), req.getRequestURI()); return ResponseEntity.status(code).body(errResponse); diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddAddressRequestMapper.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddAddressWebMapper.java similarity index 69% rename from adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddAddressRequestMapper.java rename to adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddAddressWebMapper.java index 7d3881d..55e8492 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddAddressRequestMapper.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddAddressWebMapper.java @@ -1,10 +1,10 @@ package de.strasser.peter.hexagonal.web.mapper; import de.strasser.peter.hexagonal.application.customer.port.in.commands.AddAddressCommand; -import de.strasser.peter.hexagonal.web.model.AddAddressRequest; +import de.strasser.peter.hexagonal.web.dto.request.AddAddressRequest; import org.mapstruct.Mapper; @Mapper -public interface AddAddressRequestMapper { +public interface AddAddressWebMapper { AddAddressCommand toCmd(AddAddressRequest addAddressRequest); } diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/CustomerWebMapper.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/CustomerWebMapper.java new file mode 100644 index 0000000..ff63998 --- /dev/null +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/CustomerWebMapper.java @@ -0,0 +1,14 @@ +package de.strasser.peter.hexagonal.web.mapper; + +import de.strasser.peter.hexagonal.application.customer.domain.Customer; +import de.strasser.peter.hexagonal.web.dto.response.CustomerResponse; +import org.mapstruct.Mapper; + +import java.util.List; + +@Mapper +public interface CustomerWebMapper { + CustomerResponse toResponse(Customer customer); + + List toResponse(List customer); +} diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/RegisterCustomerRequestMapper.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/RegisterCustomerWebMapper.java similarity index 74% rename from adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/RegisterCustomerRequestMapper.java rename to adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/RegisterCustomerWebMapper.java index 3e1dfa7..05f0106 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/RegisterCustomerRequestMapper.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/RegisterCustomerWebMapper.java @@ -1,12 +1,12 @@ package de.strasser.peter.hexagonal.web.mapper; import de.strasser.peter.hexagonal.application.customer.port.in.commands.RegisterCustomerCommand; -import de.strasser.peter.hexagonal.web.model.RegisterCustomerRequest; +import de.strasser.peter.hexagonal.web.dto.request.RegisterCustomerRequest; import org.mapstruct.Mapper; import org.mapstruct.Mapping; @Mapper -public interface RegisterCustomerRequestMapper { +public interface RegisterCustomerWebMapper { @Mapping(source = "password", target = "clearPassword") RegisterCustomerCommand toCmd(RegisterCustomerRequest registerCustomerRequest); } diff --git a/adapter/web/src/test/java/de/strasser/peter/hexagonal/web/RegisterCustomerControllerTest.java b/adapter/web/src/test/java/de/strasser/peter/hexagonal/web/RegisterCustomerControllerTest.java new file mode 100644 index 0000000..eda1cc6 --- /dev/null +++ b/adapter/web/src/test/java/de/strasser/peter/hexagonal/web/RegisterCustomerControllerTest.java @@ -0,0 +1,53 @@ +package de.strasser.peter.hexagonal.web; + +import de.strasser.peter.hexagonal.application.customer.port.in.RegisterCustomerUseCase; +import de.strasser.peter.hexagonal.application.customer.port.in.commands.RegisterCustomerCommand; +import de.strasser.peter.hexagonal.common.validators.TestUtils; +import de.strasser.peter.hexagonal.web.mapper.RegisterCustomerWebMapperImpl; +import lombok.extern.slf4j.Slf4j; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import java.time.LocalDate; + +import static org.mockito.BDDMockito.eq; +import static org.mockito.BDDMockito.then; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@Slf4j +@WebMvcTest(controllers = RegisterCustomerController.class) +@Import(RegisterCustomerWebMapperImpl.class) +class RegisterCustomerControllerTest { + @Autowired private MockMvc mockMvc; + + @MockBean private RegisterCustomerUseCase registerCustomerUseCase; + + @Test + public void should_RegisterUser_When_SendingValidRequest() throws Exception { + final String body = TestUtils.readStringFromResource("valid_register_customer.json"); + mockMvc + .perform(post("/v1/register").contentType(MediaType.APPLICATION_JSON).content(body)) + .andExpect(status().isOk()) + .andReturn(); + + var registerCmd = new RegisterCustomerCommand("meier", LocalDate.of(2010, 1, 1), "Ha11OMaMa!"); + + then(registerCustomerUseCase).should().register(eq(registerCmd)); + } + + @Test + public void should_DenyRequest_When_SendingInvalidDateFormat() throws Exception { + final String body = TestUtils.readStringFromResource("invalid_date_register_customer.json"); + + mockMvc + .perform(post("/v1/register").contentType(MediaType.APPLICATION_JSON).content(body)) + .andExpect(status().is4xxClientError()) + .andReturn(); + } +} diff --git a/adapter/web/src/test/java/de/strasser/peter/hexagonal/web/TestConfiguration.java b/adapter/web/src/test/java/de/strasser/peter/hexagonal/web/TestConfiguration.java new file mode 100644 index 0000000..125d241 --- /dev/null +++ b/adapter/web/src/test/java/de/strasser/peter/hexagonal/web/TestConfiguration.java @@ -0,0 +1,12 @@ +package de.strasser.peter.hexagonal.web; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@Slf4j +@SpringBootApplication +public class TestConfiguration { + + +} diff --git a/adapter/web/src/test/resources/invalid_date_register_customer.json b/adapter/web/src/test/resources/invalid_date_register_customer.json new file mode 100644 index 0000000..27e8328 --- /dev/null +++ b/adapter/web/src/test/resources/invalid_date_register_customer.json @@ -0,0 +1,5 @@ +{ + "name": "meier", + "birthDay": "200-01-01", + "password": "Ha11OMaMa!" +} diff --git a/adapter/web/src/test/resources/valid_register_customer.json b/adapter/web/src/test/resources/valid_register_customer.json new file mode 100644 index 0000000..4216d6b --- /dev/null +++ b/adapter/web/src/test/resources/valid_register_customer.json @@ -0,0 +1,5 @@ +{ + "name": "meier", + "birthDay": "2010-01-01", + "password": "Ha11OMaMa!" +} diff --git a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/in/QueryAllCustomersCRUD.java b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/in/QueryAllCustomersCRUD.java new file mode 100644 index 0000000..3a9f2d7 --- /dev/null +++ b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/in/QueryAllCustomersCRUD.java @@ -0,0 +1,9 @@ +package de.strasser.peter.hexagonal.application.customer.port.in; + +import de.strasser.peter.hexagonal.application.customer.domain.Customer; + +import java.util.List; + +public interface QueryAllCustomersCRUD { + List getAll(); +} diff --git a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerService.java b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerService.java index 720c3ed..b3f7163 100644 --- a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerService.java +++ b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerService.java @@ -20,13 +20,13 @@ class RegisterCustomerService implements RegisterCustomerUseCase { @Override public void register(@Valid RegisterCustomerCommand registerCmd) { - var encryptedPw = this.secureHashingAlgorithm(registerCmd.getClearPassword()); + var encryptedPw = this.superSecureHashingAlgorithm(registerCmd.getClearPassword()); var newCustomer = Customer.newCustomer(registerCmd.getName(), encryptedPw, registerCmd.getBirthDay()); saveUser.upsert(newCustomer); } - private String secureHashingAlgorithm(String s) { + private String superSecureHashingAlgorithm(String s) { return new StringBuilder(s).reverse().toString(); } } diff --git a/common/.mvn/wrapper/MavenWrapperDownloader.java b/common/.mvn/wrapper/MavenWrapperDownloader.java index a45eb6b..65e6aae 100644 --- a/common/.mvn/wrapper/MavenWrapperDownloader.java +++ b/common/.mvn/wrapper/MavenWrapperDownloader.java @@ -21,98 +21,99 @@ import java.util.Properties; public class MavenWrapperDownloader { - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + private static final String WRAPPER_VERSION = "0.5.6"; + /** Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. */ + private static final String DEFAULT_DOWNLOAD_URL = + "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + + "/maven-wrapper-" + + WRAPPER_VERSION + + ".jar"; - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to use + * instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; + /** Path where the maven-wrapper.jar will be saved to. */ + private static final String MAVEN_WRAPPER_JAR_PATH = ".mvn/wrapper/maven-wrapper.jar"; - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if (mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if (mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if (!outputFile.getParentFile().exists()) { - if (!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if (mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); + if (mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... } + } } + System.out.println("- Downloading from: " + url); - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if (!outputFile.getParentFile().exists()) { + if (!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + + outputFile.getParentFile().getAbsolutePath() + + "'"); + } } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault( + new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } } diff --git a/common/mvnw b/common/mvnw index 3c8a553..8ae6456 100644 --- a/common/mvnw +++ b/common/mvnw @@ -316,7 +316,7 @@ export MAVEN_CMD_LINE_ARGS WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +$MAVEN_OPTS \ +-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ +"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ +${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/common/src/main/java/de/strasser/peter/hexagonal/common/validators/SecurePassword.java b/common/src/main/java/de/strasser/peter/hexagonal/common/validators/SecurePassword.java index 6e3290c..a2be987 100644 --- a/common/src/main/java/de/strasser/peter/hexagonal/common/validators/SecurePassword.java +++ b/common/src/main/java/de/strasser/peter/hexagonal/common/validators/SecurePassword.java @@ -17,23 +17,25 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; @Constraint(validatedBy = SecurePassword.PasswordValidator.class) public @interface SecurePassword { - String message() default - "# a digit must occur at least once\n" + - "# a lower case letter must occur at least once\n" + - "# an upper case letter must occur at least once\n" + - "# a special character must occur at least once ( one of !@#$%^&*(),.?\":{}|<>) \n" + - "# no whitespace allowed in the entire string\n" + - "# anything, at least eight places though"; + String message() default + "# a digit must occur at least once\n" + + "# a lower case letter must occur at least once\n" + + "# an upper case letter must occur at least once\n" + + "# a special character must occur at least once ( one of !@#$%^&*(),.?\":{}|<>) \n" + + "# no whitespace allowed in the entire string\n" + + "# anything, at least eight places though"; - Class[] groups() default {}; + Class[] groups() default {}; - Class[] payload() default {}; + Class[] payload() default {}; - class PasswordValidator implements ConstraintValidator { + class PasswordValidator implements ConstraintValidator { - @Override - public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { - return s != null && s.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*(),.?\":{}|<>])(?=\\S+$).{8,}$"); - } + @Override + public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { + return s != null + && s.matches( + "^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*(),.?\":{}|<>])(?=\\S+$).{8,}$"); } + } } diff --git a/common/src/main/java/de/strasser/peter/hexagonal/common/validators/TestUtils.java b/common/src/main/java/de/strasser/peter/hexagonal/common/validators/TestUtils.java new file mode 100644 index 0000000..bc92d5e --- /dev/null +++ b/common/src/main/java/de/strasser/peter/hexagonal/common/validators/TestUtils.java @@ -0,0 +1,15 @@ +package de.strasser.peter.hexagonal.common.validators; + +import org.springframework.util.ResourceUtils; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +public class TestUtils { + + public static String readStringFromResource(String filename) throws IOException { + final File file = ResourceUtils.getFile("classpath:" + filename); + return Files.readString(file.toPath()); + } +} diff --git a/mvnw b/mvnw index 3c8a553..8ae6456 100644 --- a/mvnw +++ b/mvnw @@ -316,7 +316,7 @@ export MAVEN_CMD_LINE_ARGS WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" +$MAVEN_OPTS \ +-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ +"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ +${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"