diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..490f145
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,4 @@
+FROM public.ecr.aws/amazoncorretto/amazoncorretto:11
+EXPOSE 81
+ADD target/dorotech_teste-1.0-SNAPSHOT.jar dorotech_teste-1.0-SNAPSHOT.jar
+ENTRYPOINT ["java","-jar","/dorotech_teste-1.0-SNAPSHOT.jar"]
\ No newline at end of file
diff --git a/README.md b/README.md
index d171857..c0c6ec2 100644
--- a/README.md
+++ b/README.md
@@ -1,76 +1,61 @@
# Desafio Back End Java na DoroTech
-Somos uma empresa com clientes que atuam em vários segmentos do mercado, com diferentes tecnologias, culturas e desafios.
+### Documentação
+```
-Gostamos de compor nossos times com profissionais multidisciplinares, que tenham alta capacidade de aprendizado, sejam detalhistas, resilientes, questionadores e curiosos. Você, como Java Developer, será o responsável por implementar, dar manutenção, aplicar correções e propor soluções em projetos de software.
+1. Desenvolvido aplicação CRUD para cadastro, recuperação, update e delete de produtos.
-## Requisitos do desafio:
-```
-1. Criar um código que execute um CRUD(Create, Read, Update, Delete) em uma tabela para gerenciar produtos eletrônicos.
-2. Use um banco NoSQL(DynamoDB é um diferencial).
-3. Utilizar Spring como framework(Quarkus é um diferencial).
-4. Dados da tabela a ser criada no banco:
- - Products:
- name,
- description,
- price,
- amount.
+2. Foi utilizado o Framework SpringBoot para desenvolvimento, java 11, Maven, Swagger e Lombok.
+3. Os dados estão sendo persistidos no Banco de dados NOSQl DynamoDB, tambem estou utilizando Docker, ECR, ECS, fargate, CodeBuild e CodePipeline para deploy da aplicação.
-Seja criativo! fazer o melhor não é ser complexo.
-```
+4. Utilizei processamento assincrono para criação de um novo produto, utilizando o SQS da AWS
-## Dicas e Informações Valiosas
-```
-O que gostaríamos de ver em seu teste:
+5. As variaveis de ambiente com as credenciais da AWS para testar a aplicação serão enviadas ao avaliador
+
+6. A aplicação foi configurada para rodar na porta 8081, assim como a porta do container que esta sendo exposta é a porta 81
+
+7. É possivil testar e verificar parte da documentação gerada pelo swagger no link gerado pelo mesmo quando rodando local: http://localhost:8081/swagger-ui.html#/
+
+8. Como rodar manualmente:
+ - va ao diretorio raiz do projeto e acesse a pasta target
+ - em seguida abra no terminal a localização e entre com o seguinte comando
+ - mvn spring-boot:run
+ Obs: atente-se as variaveis de ambiente
- Convenção de nome em classes, objetos, variáveis, métodos e etc.
- Faça commits regulares. Eles são melhores do que um commit gigantesco. Gostaríamos de ver commits organizados e padronizados, então capriche neles!
- Bônus 1 Quarkus & AWS, implementação de uma lambda AWS utilizando framework Quarkus
- Bônus 2 Testes automatizados
- Observação: Nenhum dos itens acima é obrigatório.
-
-O que o seu Teste não deve ter:
- Saber que não foi você quem implementou o projeto.
- Várias bibliotecas instaladas sem uso.
- Falta de organização de código.
- Falta de documentação.
- Nome de variáveis sem sentido ou sem padrão de nomes.
- Histórico de commits desorganizado e despadronizado.
-
-Boa Sorte!!
-```
+9. Acesso através da API publica : http://54.237.216.243:8081/ + rotas
+ Acesso atraǘes da API publica + Swagger : http://54.237.216.243:8081/swagger-ui.html#/
+
+9. Caso deseje rodar via IDE recomendo fortemente o uso do Intellij, porem caso use outra IDE não deve encontrar grandes problemas pois todo o gerenciamento
+de dependencias esta sendo feito pelo maven, basta apenas ter atenção ao detalhe do anotation processor do lombok e tambem adicionar as variaveis de ambiente
+
-## Itens obrigatórios
-```
-1. Possibilitar a criação de um novo produto
-2. Possibilitar consulta de todos os produtos no banco de dados.
-3. Possibilitar consultar um produto específico pelo id.
-4. Permitir a exclusão de um produto.
-5. Persistir os dados na base.
```
-## Itens desejáveis
+### Métodos HTTP
```
-1. Criação de Testes unitários.
-2. Utilização de alguma ferramenta AWS(API Gateway, Lambda, SQS, SNS, EC2,..).
-3. Docker.
-4. Utilização de algum padrão de projeto.
+--->>>Local
+ - Busca todos os produtos - GET : http://localhost:8081/products/getAllProducts
+ - Cria produto - POST : http://localhost:8081/products/createProduct
+ - Encontra produto por ID - GET : GET http://localhost:8081/products/getProductById/{{id}}
+ - Deleta produto por ID - DELETE : http://localhost:8081/products/deleteProduct/{{id}}
+ - Atualiza produto por ID - UPDATE : http://localhost:8081/products/updateProduct/{{id}}
+
```
-### Instruções para entrega
+### Funcionamento do programa
```
-1. Fazer um fork desse repositório
-
-2. Criar um branch com o seu primeiro e último nome
-git checkout -b joao-silva
-3. Escreva a documentação da sua aplicação
-Você deve, substituir o conteúdo do arquivo README.md e escrever a documentação da sua aplicação, com os seguintes tópicos:
- - Projeto: Descreva o projeto e como você o executou. Seja objetivo.
- - Tecnologias: Descreva quais tecnologias foram utilizadas, enumerando versões (se necessário) e os links para suas documentações, quais bibliotecas instalou e porque.
-Como compilar e rodar: Descreva como compilar e rodar sua aplicação.
+ OBS: Recomendo a utilização do Swagger para fins de testes manuais. Link Segue Acima
-4. Faça uma Pull Request
-Após implementada a solução, crie uma pull request com o seu projeto para esse repositório, avise o recrutador.
+ - Ao iniciar o programa localmente o mesmo ira rodar na porta local 8081 e necessitará das variaveis de ambiente para se conectar a AWS
+ e por fim se conectar ao DynamoDB e ao sistema de filas SQS
+ - Ja existe uma carga de dados no Banco então se ao iniciar o software e acessar o metodo GET /getAllProducts esse por sua vez deverá retornar os produtos do banco
+ - Para criar um produto isso deverá ser feito através do metodo POST /createProduct, a criação de produtos ocorrerá em background com o DTO do produto sendo enviado
+ para uma fila SQS, e só após a fila ser consumida esse novo produto será persistido no banco.
+ - Para fazer um update, primeiro deve-se saber o ID do produto em seguida atualizar as informação e então enviar a requisição.
+ - Para se fazer um delete também é necessário saber o ID do produto que se deseja excluir.
+
```
+
+
diff --git a/buildspec.yml b/buildspec.yml
new file mode 100644
index 0000000..19cc8a5
--- /dev/null
+++ b/buildspec.yml
@@ -0,0 +1,31 @@
+version: 0.2
+
+
+phases:
+ pre_build:
+ commands:
+ - mvn clean install
+ - echo Logging in to Amazon ECR...
+ - aws --version
+ - aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin 237601488461.dkr.ecr.us-east-1.amazonaws.com
+ - REPOSITORY_URI=237601488461.dkr.ecr.us-east-1.amazonaws.com/myrepository
+ - COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
+ - IMAGE_TAG=build-$(echo $CODEBUILD_BUILD_ID | awk -F":" '{print $2}')
+ build:
+ commands:
+ - echo Build started on `date`
+ - echo Building the Docker image...
+ - docker build -t myrepository .
+ - docker tag myrepository:latest 237601488461.dkr.ecr.us-east-1.amazonaws.com/myrepository:latest
+ post_build:
+ commands:
+ - echo Build completed on `date`
+ - echo Pushing the Docker images...
+ - docker push 237601488461.dkr.ecr.us-east-1.amazonaws.com/myrepository:latest
+ - echo Writing image definitions file...
+ - printf '[{"name":"container","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
+ - cat imagedefinitions.json
+artifacts:
+ files:
+ - imagedefinitions.json
+ - target/dorotech_teste-1.0-SNAPSHOT.jar
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..fa9deb9
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,107 @@
+
+
+ 4.0.0
+
+ groupId
+ dorotech_teste
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.4
+
+
+
+
+ 11
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ io.springfox
+ springfox-swagger-ui
+ 2.9.2
+
+
+
+ io.springfox
+ springfox-swagger2
+ 2.9.2
+
+
+
+ com.amazonaws
+ aws-java-sdk-dynamodb
+ 1.12.198
+
+
+
+ com.github.derjust
+ spring-data-dynamodb
+ 5.1.0
+
+
+
+ com.amazonaws
+ amazon-sqs-java-messaging-lib
+ 1.0.8
+
+
+
+ org.springframework
+ spring-jms
+
+
+
+ commons-io
+ commons-io
+ 2.4
+
+
+
+ com.amazonaws
+ aws-java-sdk-sqs
+ 1.12.198
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/br/dorotech/app/DorotechApp.java b/src/main/java/com/br/dorotech/app/DorotechApp.java
new file mode 100644
index 0000000..c125db7
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/DorotechApp.java
@@ -0,0 +1,15 @@
+package com.br.dorotech.app;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@SpringBootApplication
+@EnableSwagger2
+public class DorotechApp {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DorotechApp.class, args);
+ }
+
+}
diff --git a/src/main/java/com/br/dorotech/app/configs/DynamoDbConfig.java b/src/main/java/com/br/dorotech/app/configs/DynamoDbConfig.java
new file mode 100644
index 0000000..7b45529
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/configs/DynamoDbConfig.java
@@ -0,0 +1,44 @@
+package com.br.dorotech.app.configs;
+
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
+import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
+import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.StringUtils;
+
+
+@Configuration
+@EnableDynamoDBRepositories(basePackages = "com.br.dorotech.app.repositories")
+public class DynamoDbConfig {
+
+ @Value("${amazon.dynamodb.endpoint}")
+ private String amazonDynamoDBEndpoint;
+
+ @Value("${amazon.aws.accesskey}")
+ private String amazonAWSAccessKey;
+
+ @Value("${amazon.aws.secretkey}")
+ private String amazonAWSSecretKey;
+
+ @Bean
+ public AmazonDynamoDB amazonDynamoDB() {
+ AmazonDynamoDB amazonDynamoDB
+ = new AmazonDynamoDBClient(amazonAWSCredentials());
+
+ if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
+ amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
+ }
+
+ return amazonDynamoDB;
+ }
+
+ @Bean
+ public AWSCredentials amazonAWSCredentials() {
+ return new BasicAWSCredentials(
+ amazonAWSAccessKey, amazonAWSSecretKey);
+ }
+}
diff --git a/src/main/java/com/br/dorotech/app/configs/SQSJmsConsumerConfiguration.java b/src/main/java/com/br/dorotech/app/configs/SQSJmsConsumerConfiguration.java
new file mode 100644
index 0000000..399072b
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/configs/SQSJmsConsumerConfiguration.java
@@ -0,0 +1,62 @@
+package com.br.dorotech.app.configs;
+
+import com.amazon.sqs.javamessaging.ProviderConfiguration;
+import com.amazon.sqs.javamessaging.SQSConnectionFactory;
+import com.amazonaws.services.sqs.AmazonSQS;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.DependsOn;
+import org.springframework.jms.annotation.EnableJms;
+import org.springframework.jms.config.DefaultJmsListenerContainerFactory;
+import org.springframework.jms.core.JmsTemplate;
+import org.springframework.util.ErrorHandler;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * Configuration class for connection with SQS queues (consumer)
+ */
+@Configuration
+@EnableJms
+@DependsOn("SQSProviderConfiguration")
+@Slf4j
+public class SQSJmsConsumerConfiguration implements ErrorHandler {
+
+ private SQSConnectionFactory connectionFactory;
+
+ private AmazonSQS amazonSQS;
+
+ public SQSJmsConsumerConfiguration(AmazonSQS amazonSQS) {
+ this.amazonSQS = amazonSQS;
+ }
+
+ @PostConstruct
+ public void init() {
+ connectionFactory = createSQSConnectionFactory();
+ }
+
+ private SQSConnectionFactory createSQSConnectionFactory() {
+ return new SQSConnectionFactory(new ProviderConfiguration(), amazonSQS);
+ }
+
+ @Bean
+ public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
+ final DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
+ factory.setConnectionFactory(connectionFactory);
+ factory.setErrorHandler(this);
+ return factory;
+ }
+
+ @Bean
+ public JmsTemplate defaultJmsTemplate() {
+ return new JmsTemplate(connectionFactory);
+ }
+
+ @Override
+ public void handleError(Throwable t) {
+ log.error("Listener SQS error has been thrown");
+ log.error("SQS_ERROR_LOCAL_MESSAGE: {}", t.getLocalizedMessage());
+ log.error("SQS_ERROR_MESSAGE: {}", t.getMessage());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/br/dorotech/app/configs/SQSProviderConfiguration.java b/src/main/java/com/br/dorotech/app/configs/SQSProviderConfiguration.java
new file mode 100644
index 0000000..3002a64
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/configs/SQSProviderConfiguration.java
@@ -0,0 +1,33 @@
+package com.br.dorotech.app.configs;
+
+import com.amazonaws.auth.AWSStaticCredentialsProvider;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.sqs.AmazonSQS;
+import com.amazonaws.services.sqs.AmazonSQSClientBuilder;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SQSProviderConfiguration {
+
+ @Value("${amazon.region}")
+ private String region;
+
+ @Value("${amazon.aws.accesskey}")
+ private String accessKey;
+
+ @Value("${amazon.aws.secretkey}")
+ private String secretKey;
+
+ @Bean
+ public AmazonSQS createSQSClient() {
+ return AmazonSQSClientBuilder
+ .standard()
+ .withCredentials(new AWSStaticCredentialsProvider(
+ new BasicAWSCredentials(accessKey,secretKey)
+ ))
+ .withRegion(region)
+ .build();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/br/dorotech/app/configs/SwaggerConfig.java b/src/main/java/com/br/dorotech/app/configs/SwaggerConfig.java
new file mode 100644
index 0000000..f2d0a9d
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/configs/SwaggerConfig.java
@@ -0,0 +1,47 @@
+package com.br.dorotech.app.configs;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig extends WebMvcConfigurationSupport {
+
+ @Bean
+ public Docket DorotechApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .select()
+ .apis(RequestHandlerSelectors.any())
+ .paths(PathSelectors.any())
+ .build()
+ .apiInfo(metaData());
+ }
+
+ private ApiInfo metaData() {
+ return new ApiInfoBuilder()
+ .title("Spring Boot REST API - Dorotech")
+ .description("\"Spring Boot REST API Dorotech App\"")
+ .version("1.0.0")
+ .license("Apache License Version 2.0")
+ .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0\"")
+ .build();
+ }
+
+ @Override
+ protected void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry.addResourceHandler("swagger-ui.html")
+ .addResourceLocations("classpath:/META-INF/resources/");
+
+ registry.addResourceHandler("/webjars/**")
+ .addResourceLocations("classpath:/META-INF/resources/webjars/");
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/br/dorotech/app/controllers/ProductController.java b/src/main/java/com/br/dorotech/app/controllers/ProductController.java
new file mode 100644
index 0000000..aed6514
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/controllers/ProductController.java
@@ -0,0 +1,58 @@
+package com.br.dorotech.app.controllers;
+
+import com.br.dorotech.app.models.dtos.ProductDTO;
+import com.br.dorotech.app.models.entities.Product;
+import com.br.dorotech.app.services.ProductService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequestMapping(value = "/products")
+@RequiredArgsConstructor
+public class ProductController {
+
+ private final ProductService productService;
+
+ @GetMapping(value = "/getAllProducts")
+ public ResponseEntity> getAllProducts() {
+ final List product = productService.findAllProducts();
+ return new ResponseEntity<>(product, HttpStatus.OK);
+ }
+
+ @PostMapping(value = "/createProduct")
+ public ResponseEntity createProduct(@RequestBody ProductDTO productDTO) {
+ final ProductDTO createProductDTO = productService.startProductCreation(productDTO);
+ return new ResponseEntity<>(createProductDTO, HttpStatus.CREATED);
+ }
+
+ @GetMapping(value = "/getProductById/{id}")
+ public ResponseEntity getProductById(@PathVariable String id){
+ final ProductDTO productDTO = productService.findProductById(id);
+ return new ResponseEntity<>(productDTO, HttpStatus.OK);
+ }
+
+ @DeleteMapping(value = "/deleteProduct/{id}")
+ public ResponseEntity deleteProduct(@PathVariable String id) {
+ final String msg = "Product Id " + id + " deleted!";
+ productService.deleteProduct(id);
+ return new ResponseEntity<>(msg, HttpStatus.OK);
+ }
+
+ @PutMapping(value = "/updateProduct/{id}")
+ public ResponseEntity updateProduct(@PathVariable String id, @RequestBody ProductDTO productDTO) {
+ final ProductDTO productUpdateDTO = productService.updateProduct(id, productDTO);
+ return new ResponseEntity<>(productUpdateDTO, HttpStatus.OK);
+ }
+
+}
diff --git a/src/main/java/com/br/dorotech/app/exceptions/ResourceNotFoundException.java b/src/main/java/com/br/dorotech/app/exceptions/ResourceNotFoundException.java
new file mode 100644
index 0000000..ac9faa0
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/exceptions/ResourceNotFoundException.java
@@ -0,0 +1,11 @@
+package com.br.dorotech.app.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.server.ResponseStatusException;
+
+public class ResourceNotFoundException extends ResponseStatusException {
+
+ public ResourceNotFoundException(HttpStatus status, String reason) {
+ super(status, reason);
+ }
+}
diff --git a/src/main/java/com/br/dorotech/app/exceptions/RestBusinessException.java b/src/main/java/com/br/dorotech/app/exceptions/RestBusinessException.java
new file mode 100644
index 0000000..0ace4b4
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/exceptions/RestBusinessException.java
@@ -0,0 +1,11 @@
+package com.br.dorotech.app.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.server.ResponseStatusException;
+
+public class RestBusinessException extends ResponseStatusException {
+
+ public RestBusinessException(HttpStatus status, String reason) {
+ super(status, reason);
+ }
+}
diff --git a/src/main/java/com/br/dorotech/app/helper/ProductHelper.java b/src/main/java/com/br/dorotech/app/helper/ProductHelper.java
new file mode 100644
index 0000000..082f3a2
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/helper/ProductHelper.java
@@ -0,0 +1,36 @@
+package com.br.dorotech.app.helper;
+
+import com.br.dorotech.app.models.dtos.ProductDTO;
+import com.br.dorotech.app.models.entities.Product;
+
+public class ProductHelper {
+
+ public static ProductDTO productsDTOBuilder(Product product){
+ return ProductDTO.builder()
+ .amount(product.getAmount())
+ .price(product.getPrice())
+ .name(product.getName())
+ .description(product.getDescription())
+ .build();
+ }
+
+ public static Product productsBuilder(ProductDTO productDTO){
+ return Product.builder()
+ .amount(productDTO.getAmount())
+ .price(productDTO.getPrice())
+ .name(productDTO.getName())
+ .description(productDTO.getDescription())
+ .build();
+ }
+
+ public static Product productsUpdateBuilder(Product product, ProductDTO productDTO){
+ return Product.builder()
+ .id(product.getId())
+ .amount(productDTO.getAmount())
+ .price(productDTO.getPrice())
+ .name(productDTO.getName())
+ .description(productDTO.getDescription())
+ .build();
+ }
+
+}
diff --git a/src/main/java/com/br/dorotech/app/models/dtos/ProductDTO.java b/src/main/java/com/br/dorotech/app/models/dtos/ProductDTO.java
new file mode 100644
index 0000000..3a5c8b8
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/models/dtos/ProductDTO.java
@@ -0,0 +1,19 @@
+package com.br.dorotech.app.models.dtos;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Builder
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProductDTO {
+
+ private String name;
+ private String description;
+ private Double price;
+ private Double amount;
+
+}
diff --git a/src/main/java/com/br/dorotech/app/models/entities/Product.java b/src/main/java/com/br/dorotech/app/models/entities/Product.java
new file mode 100644
index 0000000..fd738d7
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/models/entities/Product.java
@@ -0,0 +1,39 @@
+package com.br.dorotech.app.models.entities;
+
+import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
+import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAutoGeneratedKey;
+import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
+import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@DynamoDBTable(tableName = "products")
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class Product implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @DynamoDBHashKey(attributeName = "productId")
+ @DynamoDBAutoGeneratedKey
+ private String id;
+
+ @DynamoDBAttribute
+ private String name;
+
+ @DynamoDBAttribute
+ private String description;
+
+ @DynamoDBAttribute
+ private Double price;
+
+ @DynamoDBAttribute
+ private Double amount;
+
+}
diff --git a/src/main/java/com/br/dorotech/app/repositories/ProductRepository.java b/src/main/java/com/br/dorotech/app/repositories/ProductRepository.java
new file mode 100644
index 0000000..c6dbf1e
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/repositories/ProductRepository.java
@@ -0,0 +1,13 @@
+package com.br.dorotech.app.repositories;
+
+import com.br.dorotech.app.models.entities.Product;
+import org.socialsignin.spring.data.dynamodb.repository.DynamoDBCrudRepository;
+import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
+import org.springframework.stereotype.Repository;
+
+@Repository
+@EnableScan
+public interface ProductRepository extends DynamoDBCrudRepository {
+
+
+}
diff --git a/src/main/java/com/br/dorotech/app/services/ProductService.java b/src/main/java/com/br/dorotech/app/services/ProductService.java
new file mode 100644
index 0000000..9e58c6d
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/services/ProductService.java
@@ -0,0 +1,22 @@
+package com.br.dorotech.app.services;
+
+import com.br.dorotech.app.models.dtos.ProductDTO;
+import com.br.dorotech.app.models.entities.Product;
+
+import java.util.List;
+
+public interface ProductService {
+
+ ProductDTO startProductCreation(ProductDTO productDTO);
+
+ void finishProductCreation(ProductDTO productDTO);
+
+ List findAllProducts();
+
+ ProductDTO findProductById(String id);
+
+ void deleteProduct(String id);
+
+ ProductDTO updateProduct(String id, ProductDTO productDTO);
+
+}
diff --git a/src/main/java/com/br/dorotech/app/services/impl/ProductServiceImpl.java b/src/main/java/com/br/dorotech/app/services/impl/ProductServiceImpl.java
new file mode 100644
index 0000000..932473f
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/services/impl/ProductServiceImpl.java
@@ -0,0 +1,72 @@
+package com.br.dorotech.app.services.impl;
+
+import com.br.dorotech.app.exceptions.ResourceNotFoundException;
+import com.br.dorotech.app.models.dtos.ProductDTO;
+import com.br.dorotech.app.models.entities.Product;
+import com.br.dorotech.app.repositories.ProductRepository;
+import com.br.dorotech.app.services.ProductService;
+import com.br.dorotech.app.sqs.ProductMessageProducer;
+import com.br.dorotech.app.util.JsonUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+import static com.br.dorotech.app.helper.ProductHelper.productsBuilder;
+import static com.br.dorotech.app.helper.ProductHelper.productsDTOBuilder;
+import static com.br.dorotech.app.helper.ProductHelper.productsUpdateBuilder;
+
+@Service
+@RequiredArgsConstructor
+@Slf4j
+public class ProductServiceImpl implements ProductService {
+
+ private final ProductRepository productRepository;
+
+ private final ProductMessageProducer productMessageProducer;
+
+ @Value("${amazon.queue.product-creation}")
+ private String queueName;
+
+ @Override
+ public ProductDTO startProductCreation(ProductDTO productDTO) {
+ productMessageProducer.sentToQueue(queueName, JsonUtil.writeValueAsString(productDTO));
+ log.info("***** PRODUCT CREATION DATA SENT TO QUEUE: " + queueName + ", PRODUCT NAME: " + productDTO.getName()
+ + ", PRODUCT DESCRIPTION: " + productDTO.getDescription());
+ return productDTO;
+ }
+
+ @Override
+ public void finishProductCreation(ProductDTO productDTO){
+ productRepository.save(productsBuilder(productDTO));
+ }
+
+ @Override
+ public List findAllProducts() {
+ return (List) productRepository.findAll();
+ }
+
+ @Override
+ public ProductDTO findProductById(String id) {
+ Product product = productRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(HttpStatus.NOT_FOUND, "Id not found!"));
+ return productsDTOBuilder(product);
+ }
+
+ @Override
+ public void deleteProduct(String id) {
+ Product product = productRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(HttpStatus.NOT_FOUND, "Id not found!"));
+ productRepository.delete(product);
+ }
+
+ @Override
+ public ProductDTO updateProduct(String id, ProductDTO productDTO) {
+ Product product = productRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException(HttpStatus.NOT_FOUND, "Id not found!"));
+ Product productUpdated = productsUpdateBuilder(product, productDTO);
+ productRepository.save(productUpdated);
+ return productDTO;
+ }
+
+}
diff --git a/src/main/java/com/br/dorotech/app/sqs/ProductMessageConsumer.java b/src/main/java/com/br/dorotech/app/sqs/ProductMessageConsumer.java
new file mode 100644
index 0000000..1f3bc89
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/sqs/ProductMessageConsumer.java
@@ -0,0 +1,33 @@
+package com.br.dorotech.app.sqs;
+
+import com.br.dorotech.app.models.dtos.ProductDTO;
+import com.br.dorotech.app.services.ProductService;
+import com.br.dorotech.app.util.JsonUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.jms.annotation.JmsListener;
+import org.springframework.messaging.handler.annotation.Payload;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+public class ProductMessageConsumer {
+
+ private final ProductService productService;
+
+ @Value("${amazon.queue.product-creation}")
+ private String queueName;
+
+ @JmsListener(destination = "${amazon.queue.product-creation}")
+ public void messageConsumer(@Payload String message) {
+ ProductDTO productDTO = JsonUtil.readValue(message, ProductDTO.class);
+
+ log.info("***** PRODUCT CREATED: " + queueName + ", PRODUCT NAME: " + productDTO.getName()
+ + ", PRODUCT DESCRIPTION: " + productDTO.getDescription());
+
+ productService.finishProductCreation(productDTO);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/br/dorotech/app/sqs/ProductMessageProducer.java b/src/main/java/com/br/dorotech/app/sqs/ProductMessageProducer.java
new file mode 100644
index 0000000..a7e2bf0
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/sqs/ProductMessageProducer.java
@@ -0,0 +1,22 @@
+package com.br.dorotech.app.sqs;
+
+import com.amazonaws.services.sqs.AmazonSQS;
+import com.amazonaws.services.sqs.model.SendMessageRequest;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class ProductMessageProducer {
+
+ private final AmazonSQS amazonSQS;
+
+ public void sentToQueue(final String queueName, final String message) {
+ amazonSQS.sendMessage(new SendMessageRequest()
+ .withQueueUrl(queueName)
+ .withMessageBody(message)
+ );
+ }
+
+}
+
diff --git a/src/main/java/com/br/dorotech/app/util/JsonUtil.java b/src/main/java/com/br/dorotech/app/util/JsonUtil.java
new file mode 100644
index 0000000..ea6102a
--- /dev/null
+++ b/src/main/java/com/br/dorotech/app/util/JsonUtil.java
@@ -0,0 +1,54 @@
+package com.br.dorotech.app.util;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JsonUtil {
+ private static final Logger LOG = LoggerFactory.getLogger(JsonUtil.class);
+
+ private static final ObjectMapper OBJECT_MAPPER = createObjectMapper();
+
+ private static final ObjectMapper createObjectMapper() {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
+ objectMapper.registerModule(new JavaTimeModule());
+ objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ return objectMapper;
+ }
+
+
+ public static String writeValueAsString(Object value) {
+ try {
+ String json = OBJECT_MAPPER.writeValueAsString(value);
+ json = (json.equals("\"\"")) ? "{}" : json;
+
+ return json;
+ } catch (JsonProcessingException e) {
+ LOG.error("Erro ao gerar json : " + value, e);
+ }
+
+ return "";
+ }
+
+ public static T readValue(String json, Class valueType) {
+ try {
+ if (JsonNode.class.isAssignableFrom(valueType)) {
+ return (T) (OBJECT_MAPPER.readTree(json));
+ } else {
+ return OBJECT_MAPPER.readValue(json, valueType);
+ }
+ } catch (Exception e) {
+ LOG.error("Erro ao gerar objeto a partir do JSON : " + json, e);
+ }
+
+ return null;
+ }
+
+}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..572f4a9
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,20 @@
+server:
+ port: 8081
+ error:
+ include-message: always
+ include-binding-errors: always
+
+amazon:
+ aws:
+ accesskey: ${access.key}
+ secretkey: ${secret.key}
+ dynamodb:
+ endpoint: http://dynamodb.us-east-1.amazonaws.com
+
+ queue:
+ product-creation: product-creation
+
+ region: us-east-1
+
+
+