├── .github └── FUNDING.yml ├── .gitignore ├── Jenkinsfile ├── LICENSE ├── README.md ├── admin-server ├── Jenkinsfile ├── README ├── pom.xml └── src │ └── main │ ├── java │ └── de │ │ └── codecentric │ │ └── boot │ │ └── admin │ │ └── SpringBootAdminApplication.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ ├── docker │ ├── Dockerfile │ ├── filebeat.yml │ ├── logstash-beats.crt │ └── start.sh │ └── logback-spring.xml ├── api-gateway ├── Jenkinsfile ├── README ├── nbactions.xml ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── apssouza │ │ ├── BasicApplication.java │ │ ├── clients │ │ ├── TodoClient.java │ │ └── UserClient.java │ │ ├── configuration │ │ ├── JwtConfiguration.java │ │ ├── OAuth2ResourceServerConfiguration.java │ │ └── ServiceDiscoveryConfiguration.java │ │ ├── controllers │ │ ├── TodoController.java │ │ └── UserController.java │ │ ├── exceptions │ │ └── DataNotFoundException.java │ │ ├── pojos │ │ ├── Todo.java │ │ └── User.java │ │ └── services │ │ ├── TodoService.java │ │ ├── TodoServiceImpl.java │ │ ├── UserService.java │ │ └── UserServiceImpl.java │ └── resources │ ├── application.properties │ ├── bootstrap.yml │ ├── docker │ ├── Dockerfile │ ├── filebeat.yml │ ├── logstash-beats.crt │ └── start.sh │ └── public.cert ├── assets ├── event-docker-compose.yml ├── infra-docker-compose.yml ├── logging-docker-compose.yml ├── microservices-arch.jpg ├── microservices-arch.xml ├── oauth-docker-compose.yml └── proxy-docker-compose.yml ├── aws-compose.yml ├── aws-deploy.sh ├── config-server ├── .gitignore ├── Jenkinsfile ├── README ├── nbactions.xml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apssouza │ │ │ └── config │ │ │ └── Application.java │ └── resources │ │ ├── application.yml │ │ ├── docker │ │ ├── Dockerfile │ │ ├── filebeat.yml │ │ ├── logstash-beats.crt │ │ └── start.sh │ │ └── offline-repository │ │ ├── admin.yml │ │ ├── api-gateway.properties │ │ ├── eureka-server.yml │ │ ├── mailer.properties │ │ ├── oauth.properties │ │ ├── reminder.properties │ │ └── user.properties │ └── test │ ├── java │ └── demo │ │ └── OutOfContainerTest.java │ └── resources │ └── offline-repository │ ├── application.yml │ └── testConfig.yml ├── docker-compose.yml ├── docker-orchestrate.sh ├── eureka-server ├── .gitignore ├── Jenkinsfile ├── README ├── nbactions.xml ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── apssouza │ │ └── discovery │ │ └── Application.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ └── docker │ ├── Dockerfile │ ├── filebeat.yml │ ├── logstash-beats.crt │ └── start.sh ├── jmx-monitoring ├── README ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── apssouza │ └── monitoring │ ├── CallMonitoringAspect.java │ ├── Monitored.java │ ├── MonitoringConfig.java │ └── MonitoringInvokedEvent.java ├── mail-service ├── .gitignore ├── Jenkinsfile ├── README ├── nbactions.xml ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apssouza │ │ │ ├── eventsourcing │ │ │ ├── EventsourcingApplication.java │ │ │ ├── aggregates │ │ │ │ ├── AbstractAggregate.java │ │ │ │ ├── Aggregate.java │ │ │ │ ├── EmailAggregate.java │ │ │ │ ├── EmailState.java │ │ │ │ └── ObjectState.java │ │ │ ├── commands │ │ │ │ ├── EmailCommandHandler.java │ │ │ │ ├── EmailCreateCommand.java │ │ │ │ ├── EmailDeleteCommand.java │ │ │ │ ├── EmailDeliveryCommand.java │ │ │ │ └── EmailSendCommand.java │ │ │ ├── entities │ │ │ │ └── Email.java │ │ │ ├── events │ │ │ │ ├── EmailCreatedEvent.java │ │ │ │ ├── EmailDeletedEvent.java │ │ │ │ ├── EmailDeliveredEvent.java │ │ │ │ ├── EmailEvent.java │ │ │ │ └── EmailSentEvent.java │ │ │ ├── eventstore │ │ │ │ ├── EventDescriptor.java │ │ │ │ ├── EventSerializer.java │ │ │ │ ├── EventStoreRepository.java │ │ │ │ └── EventStream.java │ │ │ ├── queries │ │ │ │ └── EmailQueryObject.java │ │ │ └── services │ │ │ │ ├── EventSourcingService.java │ │ │ │ └── EventSourcingServiceImpl.java │ │ │ └── mailservice │ │ │ ├── MailserviceApplication.java │ │ │ ├── configurations │ │ │ └── EventSourcingConfig.java │ │ │ ├── controllers │ │ │ ├── EmailController.java │ │ │ └── NotifyController.java │ │ │ ├── integration │ │ │ └── reminder │ │ │ │ ├── EventInput.java │ │ │ │ ├── ToDoDto.java │ │ │ │ └── TodoCreatedEvent.java │ │ │ └── repository │ │ │ └── EmailRepository.java │ └── resources │ │ ├── application.properties │ │ ├── bootstrap.yml │ │ └── docker │ │ ├── Dockerfile │ │ ├── filebeat.yml │ │ ├── logstash-beats.crt │ │ └── start.sh │ └── test │ └── java │ └── com │ └── apssouza │ └── eventsourcing │ ├── aggregates │ └── EmailAggregateTest.java │ └── commands │ └── EmailCommandHandlerTest.java ├── oauth-server ├── Jenkinsfile ├── README ├── pom.xml └── src │ └── main │ ├── java │ └── com │ │ └── apssouza │ │ ├── BasicApplication.java │ │ ├── auth │ │ └── CustomTokenEnhancer.java │ │ ├── clients │ │ └── UserClient.java │ │ ├── configuration │ │ ├── AuthenticationConfiguration.java │ │ ├── JwtServerConfiguration.java │ │ ├── OAuth2ServerConfiguration.java │ │ └── ServiceDiscoveryConfiguration.java │ │ ├── pojos │ │ └── User.java │ │ └── services │ │ ├── UserService.java │ │ └── UserServiceImpl.java │ └── resources │ ├── application.properties │ ├── bootstrap.yml │ ├── docker │ ├── Dockerfile │ ├── filebeat.yml │ ├── logstash-beats.crt │ └── start.sh │ └── jwt.jks ├── package-projects.sh ├── pom.xml ├── private.cert ├── proxy ├── Dockerfile ├── README ├── default.conf ├── filebeat.yml ├── logstash-beats.crt └── start.sh ├── public.cert ├── remainder-service ├── Jenkinsfile ├── README ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apssouza │ │ │ ├── BasicApplication.java │ │ │ ├── annotations │ │ │ └── ChangeEvent.java │ │ │ ├── bootstrap │ │ │ └── TodoLoader.java │ │ │ ├── configuration │ │ │ ├── H2DbConfiguration.java │ │ │ ├── ServiceDiscoveryConfiguration.java │ │ │ └── WebSocketConfig.java │ │ │ ├── controllers │ │ │ ├── TodoChangesController.java │ │ │ ├── TodoController.java │ │ │ └── TodoServiceStatisticsController.java │ │ │ ├── entities │ │ │ ├── Attachment.java │ │ │ ├── Category.java │ │ │ └── ToDo.java │ │ │ ├── events │ │ │ ├── TodoChangedEvent.java │ │ │ ├── TodoCreatedEvent.java │ │ │ ├── TodoServiceMethodInvokedEvent.java │ │ │ └── TodoUpdatedEvent.java │ │ │ ├── exceptions │ │ │ └── DataNotFoundException.java │ │ │ ├── helpers │ │ │ └── AutowireHelper.java │ │ │ ├── integrations │ │ │ └── socket │ │ │ │ ├── TodoChangeSocketNotify.java │ │ │ │ └── TodoSocketController.java │ │ │ ├── listeners │ │ │ ├── TodoChangedListener.java │ │ │ └── TodoServiceMethodListener.java │ │ │ ├── monitors │ │ │ ├── ToDoEntityListener.java │ │ │ ├── TodoServiceMethodInvokedStore.java │ │ │ └── TodoStoreEventChanges.java │ │ │ ├── pojos │ │ │ └── SocketOutputMessage.java │ │ │ ├── repositories │ │ │ ├── AttachmentRepository.java │ │ │ ├── CategoryRepository.java │ │ │ └── TodoRepository.java │ │ │ ├── services │ │ │ ├── TodoService.java │ │ │ └── TodoServiceImpl.java │ │ │ └── validation │ │ │ ├── CheckIsValid.java │ │ │ ├── CrossCheckConstraintValidator.java │ │ │ └── ValidEntity.java │ └── resources │ │ ├── application.properties │ │ ├── bootstrap.yml │ │ └── docker │ │ ├── Dockerfile │ │ ├── filebeat.yml │ │ ├── logstash-beats.crt │ │ └── start.sh │ └── test │ └── java │ └── com │ └── apssouza │ ├── configuration │ └── RepositoryConfiguration.java │ ├── controllers │ └── TodoControllerTest.java │ └── entities │ └── TodoIT.java ├── todo-infra ├── README ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── apssouza │ └── infra │ ├── AbstractDomainEvent.java │ ├── AppEvent.java │ └── EventPublisher.java └── user-service ├── Jenkinsfile ├── README ├── nb-configuration.xml ├── nbactions-release-profile.xml ├── nbactions.xml ├── pom.xml └── src └── main ├── java └── com │ └── apssouza │ ├── BasicApplication.java │ ├── bootstrap │ └── UserLoader.java │ ├── configuration │ ├── H2DbConfiguration.java │ └── ServiceDiscoveryConfiguration.java │ ├── controllers │ └── AccountController.java │ ├── entities │ └── Account.java │ ├── exceptions │ └── DataNotFoundException.java │ ├── repositories │ └── AccountRepository.java │ └── services │ ├── AccountService.java │ └── AccountServiceImpl.java └── resources ├── application.properties ├── bootstrap.yml └── docker ├── Dockerfile ├── filebeat.yml ├── logstash-beats.crt └── start.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | patreon: apssouza 4 | custom: ["https://www.buymeacoffee.com/apssouza"] 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source # 2 | ################### 3 | *.com 4 | *.class 5 | *.dll 6 | *.exe 7 | *.o 8 | *.so 9 | 10 | # Packages # 11 | ############ 12 | # it's better to unpack these files and commit the raw source 13 | # git has its own built in compression methods 14 | *.7z 15 | *.dmg 16 | *.gz 17 | *.iso 18 | *.rar 19 | *.tar 20 | *.zip 21 | 22 | # Logs and databases # 23 | ###################### 24 | *.log 25 | *.sqlite 26 | 27 | # OS generated files # 28 | ###################### 29 | .DS_Store 30 | .DS_Store? 31 | ._* 32 | .Spotlight-V100 33 | .Trashes 34 | ehthumbs.db 35 | Thumbs.db 36 | .cache 37 | .settings 38 | .tmproj 39 | .idea 40 | *nbprojects 41 | *nbproject 42 | *nbactions.xml 43 | *nb-configuration.xml 44 | *.svn 45 | nb_jr_remoting.cfg 46 | 47 | .project 48 | .classpath 49 | .idea 50 | *.iml 51 | atlassian-ide-plugin.xml 52 | target 53 | *rebel* 54 | *mvn* -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build images') { 6 | sh "./package-projects.sh" 7 | } 8 | stage('Deploy ECS') { 9 | sh "./aws-deploy.sh" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Alexsandro Souza 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /admin-server/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build image') { 6 | // Run the maven build 7 | if (isUnix()) { 8 | sh "mvn -f ./admin-server/pom.xml -Pdockerimage docker:build " 9 | } else { 10 | echo "Not ready for windows" 11 | } 12 | } 13 | stage('Deploy ECS') { 14 | echo "TODO deploy on AWS" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /admin-server/README: -------------------------------------------------------------------------------- 1 | # Admin server 2 | 3 | This is a simple admin interface for Spring Boot applications. 4 | 5 | Have a look at the project to get a better Idea fo it. https://github.com/codecentric/spring-boot-admin 6 | -------------------------------------------------------------------------------- /admin-server/src/main/java/de/codecentric/boot/admin/SpringBootAdminApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package de.codecentric.boot.admin; 17 | 18 | import org.springframework.boot.SpringApplication; 19 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 20 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 21 | import org.springframework.context.annotation.Configuration; 22 | 23 | import de.codecentric.boot.admin.config.EnableAdminServer; 24 | 25 | 26 | // tag::application-eureka[] 27 | @Configuration 28 | @EnableAutoConfiguration 29 | @EnableDiscoveryClient 30 | @EnableAdminServer 31 | public class SpringBootAdminApplication { 32 | public static void main(String[] args) { 33 | SpringApplication.run(SpringBootAdminApplication.class, args); 34 | } 35 | } 36 | // end::application-eureka[] 37 | -------------------------------------------------------------------------------- /admin-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: admin 4 | -------------------------------------------------------------------------------- /admin-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | cloud: 4 | config: 5 | uri: http://config:8888 6 | -------------------------------------------------------------------------------- /admin-server/src/main/resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | 4 | MAINTAINER Alexsandro 5 | ENV REFRESHED_AT 2017-09-17 6 | 7 | ENV TERM xterm 8 | ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom 9 | 10 | RUN apt-get update -qq \ 11 | && apt-get install -qqy curl wget \ 12 | && apt-get clean \ 13 | \ 14 | && touch /var/log/todo.log \ 15 | && chmod 666 /var/log/todo.log 16 | 17 | ADD application/lib/springboot-webapp.jar /app.jar 18 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 19 | RUN bash -c 'chmod +x wait-for-it.sh' 20 | 21 | # install Filebeat 22 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 23 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 24 | && dpkg -i ${FILEBEAT_VERSION} \ 25 | && rm ${FILEBEAT_VERSION} 26 | 27 | # configure Filebeat 28 | ADD filebeat.yml /etc/filebeat/filebeat.yml 29 | 30 | # CA cert 31 | RUN mkdir -p /etc/pki/tls/certs 32 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 33 | 34 | # start Filebeat 35 | ADD ./start.sh /usr/local/bin/start.sh 36 | RUN chmod +x /usr/local/bin/start.sh 37 | CMD [ "/usr/local/bin/start.sh" ] -------------------------------------------------------------------------------- /admin-server/src/main/resources/docker/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - /var/log/spring-music.log 21 | document_type: log4j 22 | multiline: 23 | pattern: '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}' 24 | negate: true 25 | match: after 26 | - 27 | paths: 28 | - /usr/local/tomcat/logs/*.out 29 | - /usr/local/tomcat/logs/*.log 30 | document_type: tomcat 31 | -------------------------------------------------------------------------------- /admin-server/src/main/resources/docker/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /admin-server/src/main/resources/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 6 | -------------------------------------------------------------------------------- /admin-server/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /api-gateway/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build image') { 6 | // Run the maven build 7 | if (isUnix()) { 8 | sh "mvn -f ./api-gateway/pom.xml -Pdockerimage docker:build" 9 | } else { 10 | echo "Not ready for windows" 11 | } 12 | } 13 | stage('Deploy ECS') { 14 | echo "TODO deploy on AWS" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /api-gateway/README: -------------------------------------------------------------------------------- 1 | # API Gateway 2 | 3 | We are implementing an API gateway pattern to our project. 4 | 5 | This is the single entry point for all clients. The API gateway handles the requests. 6 | At the moment we have in this layer only the authentication using JWT then the requests are simply proxied/routed to the appropriate service. 7 | 8 | ## To-do 9 | 10 | * Add cache handling 11 | 12 | -------------------------------------------------------------------------------- /api-gateway/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | debug 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 11 | 12 | 13 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath com.apssouza.BasicApplication 14 | java 15 | true 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/BasicApplication.java: -------------------------------------------------------------------------------- 1 | package com.apssouza; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.feign.EnableFeignClients; 6 | import org.springframework.cloud.netflix.hystrix.EnableHystrix; 7 | 8 | @SpringBootApplication 9 | @EnableFeignClients 10 | @EnableHystrix 11 | public class BasicApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(BasicApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/clients/TodoClient.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.clients; 2 | 3 | import com.apssouza.pojos.Todo; 4 | import com.apssouza.pojos.User; 5 | import java.util.List; 6 | import org.springframework.cloud.netflix.feign.FeignClient; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | 11 | /** 12 | * Declarative To do REST client 13 | * 14 | * @author apssouza 15 | */ 16 | @FeignClient("todo") 17 | public interface TodoClient { 18 | 19 | @RequestMapping(value = "/todos", method = RequestMethod.GET) 20 | public List getAll(); 21 | 22 | @RequestMapping(value = "/todos/search", method = RequestMethod.GET) 23 | public List getTodoByUserEmaill(@RequestParam("email") String email); 24 | 25 | @RequestMapping( 26 | value = "/todos", 27 | method = RequestMethod.POST 28 | ) 29 | Todo createTodo(Todo todo); 30 | } 31 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/clients/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.clients; 2 | 3 | import com.apssouza.pojos.Todo; 4 | import com.apssouza.pojos.User; 5 | import java.util.List; 6 | import org.springframework.cloud.netflix.feign.FeignClient; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | 11 | /** 12 | * Declarative User REST client 13 | * 14 | * @author apssouza 15 | */ 16 | @FeignClient("user") 17 | public interface UserClient { 18 | 19 | @RequestMapping(value = "/accounts", method = RequestMethod.GET) 20 | public List getAll(); 21 | 22 | @RequestMapping(value = "/accounts/search", method = RequestMethod.GET) 23 | public User getUserByEmail(@RequestParam("email") String email); 24 | 25 | @RequestMapping(value = "/users", method = RequestMethod.POST) 26 | Todo createUser(User user); 27 | } 28 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/configuration/JwtConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import java.io.IOException; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.beans.factory.annotation.Qualifier; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.core.io.ClassPathResource; 9 | import org.springframework.core.io.Resource; 10 | import org.springframework.security.oauth2.provider.token.TokenStore; 11 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 12 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 13 | import org.springframework.util.FileCopyUtils; 14 | 15 | /** 16 | * Json web token configuration 17 | * 18 | * @author apssouza 19 | */ 20 | @Configuration 21 | public class JwtConfiguration { 22 | 23 | @Autowired 24 | JwtAccessTokenConverter jwtAccessTokenConverter; 25 | 26 | @Bean 27 | @Qualifier("tokenStore") 28 | public TokenStore tokenStore() { 29 | return new JwtTokenStore(jwtAccessTokenConverter); 30 | } 31 | 32 | @Bean 33 | protected JwtAccessTokenConverter jwtTokenEnhancer() { 34 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 35 | Resource resource = new ClassPathResource("public.cert"); 36 | String publicKey = null; 37 | try { 38 | publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream())); 39 | } catch (IOException e) { 40 | throw new RuntimeException(e); 41 | } 42 | converter.setVerifierKey(publicKey); 43 | return converter; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/configuration/OAuth2ResourceServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.http.HttpMethod; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 9 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 10 | import org.springframework.security.oauth2.provider.token.TokenStore; 11 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 12 | 13 | /** 14 | * OAuth2 resource server configuration 15 | * 16 | * @author apssouza 17 | */ 18 | @Configuration 19 | @EnableResourceServer 20 | public class OAuth2ResourceServerConfiguration extends ResourceServerConfigurerAdapter { 21 | 22 | @Override 23 | public void configure(HttpSecurity http) throws Exception { 24 | http 25 | .csrf().disable() 26 | .authorizeRequests() 27 | .antMatchers("/hystrix.stream").permitAll() 28 | .antMatchers("/**").authenticated() 29 | .antMatchers(HttpMethod.GET, "/todos").hasAuthority("USER_READ"); 30 | //.antMatchers(HttpMethod.POST, "/foo").hasAuthority("FOO_WRITE"); 31 | //you can implement it like this, but I show method invocation security on write 32 | } 33 | 34 | @Override 35 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 36 | resources.resourceId("todo").tokenStore(tokenStore); 37 | } 38 | 39 | @Autowired 40 | TokenStore tokenStore; 41 | 42 | @Autowired 43 | JwtAccessTokenConverter tokenConverter; 44 | } 45 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/configuration/ServiceDiscoveryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * Eureka client configuration 8 | * 9 | * @author apssouza 10 | */ 11 | @Configuration 12 | @EnableDiscoveryClient 13 | public class ServiceDiscoveryConfiguration { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/controllers/TodoController.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.controllers; 2 | 3 | import com.apssouza.clients.TodoClient; 4 | import com.apssouza.pojos.User; 5 | import com.apssouza.services.TodoService; 6 | import java.util.List; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.web.bind.annotation.GetMapping; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | /** 14 | * To Do entry point 15 | * 16 | * @author apssouza 17 | */ 18 | @RequestMapping("/todos") 19 | @RestController 20 | public class TodoController { 21 | 22 | @Autowired 23 | TodoService todoService; 24 | 25 | @GetMapping 26 | public List all() { 27 | return this.todoService.getAll(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/controllers/UserController.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.controllers; 2 | 3 | import com.apssouza.clients.TodoClient; 4 | import com.apssouza.clients.UserClient; 5 | import com.apssouza.pojos.Todo; 6 | import com.apssouza.pojos.User; 7 | import com.apssouza.services.TodoService; 8 | import com.apssouza.services.UserService; 9 | import java.util.List; 10 | 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 13 | import org.springframework.web.bind.annotation.GetMapping; 14 | import org.springframework.web.bind.annotation.PostMapping; 15 | import org.springframework.web.bind.annotation.RequestBody; 16 | import org.springframework.web.bind.annotation.RequestMapping; 17 | import org.springframework.web.bind.annotation.RestController; 18 | 19 | /** 20 | * User entry point 21 | * 22 | * @author apssouza 23 | */ 24 | @RequestMapping("/accounts") 25 | @RestController 26 | public class UserController { 27 | 28 | @Autowired 29 | UserService userService; 30 | 31 | @Autowired 32 | TodoService todoService; 33 | 34 | @GetMapping 35 | public List all() { 36 | return this.userService.getAll(); 37 | } 38 | 39 | @GetMapping("/me") 40 | public User me(OAuth2Authentication auth) { 41 | return this.userService.getUserByEmail(auth.getName()); 42 | } 43 | 44 | @GetMapping("/me/todos") 45 | public List todos(OAuth2Authentication auth) { 46 | return this.todoService.getTodoByUserEmaill(auth.getName()); 47 | } 48 | 49 | @PostMapping("/me/todos") 50 | public Todo create(@RequestBody Todo todo) { 51 | return this.todoService.createTodo(todo); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/exceptions/DataNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.exceptions; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.bind.annotation.ResponseStatus; 5 | 6 | /** 7 | * Data not found exception. It will return the Not found HTTP status code 8 | * 9 | * @author Apssouza 10 | */ 11 | @ResponseStatus(HttpStatus.NOT_FOUND) 12 | public class DataNotFoundException extends RuntimeException { 13 | 14 | public DataNotFoundException(String msg) { 15 | super(msg); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/pojos/Todo.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.pojos; 2 | 3 | /** 4 | * To do PoJo 5 | * 6 | * @author apssouza 7 | */ 8 | public class Todo { 9 | 10 | private long id; 11 | 12 | private String caption; 13 | 14 | private String userEmail; 15 | 16 | private String description; 17 | 18 | private int priority; 19 | 20 | public int getPriority() { 21 | return priority; 22 | } 23 | 24 | public void setPriority(int priority) { 25 | this.priority = priority; 26 | } 27 | 28 | public long getId() { 29 | return id; 30 | } 31 | 32 | public void setId(long id) { 33 | this.id = id; 34 | } 35 | 36 | public String getCaption() { 37 | return caption; 38 | } 39 | 40 | public void setCaption(String caption) { 41 | this.caption = caption; 42 | } 43 | 44 | public String getUserEmail() { 45 | return userEmail; 46 | } 47 | 48 | public void setUserEmail(String userEmail) { 49 | this.userEmail = userEmail; 50 | } 51 | 52 | public String getDescription() { 53 | return description; 54 | } 55 | 56 | public void setDescription(String description) { 57 | this.description = description; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/pojos/User.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.pojos; 2 | 3 | /** 4 | * User Pojo 5 | * 6 | * @author apssouza 7 | */ 8 | public class User { 9 | 10 | private long id; 11 | 12 | private long authId; 13 | 14 | private String name; 15 | 16 | private String email; 17 | 18 | public User() { 19 | } 20 | 21 | public User(String name, String email, long authId) { 22 | this.name = name; 23 | this.email = email; 24 | this.authId = authId; 25 | } 26 | 27 | public long getId() { 28 | return id; 29 | } 30 | 31 | public void setId(long id) { 32 | this.id = id; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | public String getEmail() { 44 | return email; 45 | } 46 | 47 | public void setEmail(String email) { 48 | this.email = email; 49 | } 50 | 51 | public long getAuthId() { 52 | return authId; 53 | } 54 | 55 | public void setAuthId(long authId) { 56 | this.authId = authId; 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/services/TodoService.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.pojos.Todo; 4 | import com.apssouza.pojos.User; 5 | import java.util.List; 6 | 7 | /** 8 | * 9 | * @author apssouza 10 | */ 11 | public interface TodoService { 12 | 13 | public List getAll(); 14 | 15 | public List getTodoByUserEmaill(String email); 16 | 17 | Todo createTodo(Todo todo); 18 | } 19 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/services/TodoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.clients.TodoClient; 4 | import com.apssouza.pojos.Todo; 5 | import com.apssouza.pojos.User; 6 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * ToDo service 14 | * @author apssouza 15 | */ 16 | @Component 17 | public class TodoServiceImpl implements TodoService { 18 | 19 | @Autowired 20 | TodoClient todoClient; 21 | 22 | @Override 23 | public List getAll() { 24 | return todoClient.getAll(); 25 | } 26 | 27 | @Override 28 | @HystrixCommand(fallbackMethod = "getFallbackTodos") 29 | public List getTodoByUserEmaill(String email) { 30 | return todoClient.getTodoByUserEmaill(email); 31 | } 32 | 33 | @Override 34 | public Todo createTodo(Todo todo) { 35 | return todoClient.createTodo(todo); 36 | } 37 | 38 | public List getFallbackTodos(String email) { 39 | return Collections.emptyList(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/services/UserService.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.pojos.Todo; 4 | import com.apssouza.pojos.User; 5 | import java.util.List; 6 | 7 | /** 8 | * 9 | * @author apssouza 10 | */ 11 | public interface UserService { 12 | 13 | List getAll(); 14 | 15 | User getUserByEmail(String email); 16 | 17 | Todo createUser(User user); 18 | } 19 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/apssouza/services/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.clients.UserClient; 4 | import com.apssouza.pojos.Todo; 5 | import com.apssouza.pojos.User; 6 | import java.util.List; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | 10 | /** 11 | * User Service 12 | * 13 | * @author apssouza 14 | */ 15 | @Component 16 | public class UserServiceImpl implements UserService { 17 | 18 | @Autowired 19 | UserClient userClient; 20 | 21 | @Override 22 | public List getAll() { 23 | return userClient.getAll(); 24 | } 25 | 26 | @Override 27 | public User getUserByEmail(String email) { 28 | return userClient.getUserByEmail(email); 29 | } 30 | 31 | @Override 32 | public Todo createUser(User user) { 33 | return userClient.createUser(user); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /api-gateway/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name = api-gateway -------------------------------------------------------------------------------- /api-gateway/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | cloud: 4 | config: 5 | uri: http://config:8888 6 | -------------------------------------------------------------------------------- /api-gateway/src/main/resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | 4 | MAINTAINER Alexsandro 5 | ENV REFRESHED_AT 2017-09-17 6 | 7 | ENV TERM xterm 8 | ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom 9 | 10 | RUN apt-get update -qq \ 11 | && apt-get install -qqy curl wget \ 12 | && apt-get clean \ 13 | \ 14 | && touch /var/log/todo.log \ 15 | && chmod 666 /var/log/todo.log 16 | 17 | ADD application/lib/springboot-webapp.jar /app.jar 18 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 19 | RUN bash -c 'chmod +x wait-for-it.sh' 20 | 21 | 22 | # install Filebeat 23 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 24 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 25 | && dpkg -i ${FILEBEAT_VERSION} \ 26 | && rm ${FILEBEAT_VERSION} 27 | 28 | # configure Filebeat 29 | ADD filebeat.yml /etc/filebeat/filebeat.yml 30 | 31 | # CA cert 32 | RUN mkdir -p /etc/pki/tls/certs 33 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 34 | 35 | # start Filebeat 36 | ADD ./start.sh /usr/local/bin/start.sh 37 | RUN chmod +x /usr/local/bin/start.sh 38 | CMD [ "/usr/local/bin/start.sh" ] -------------------------------------------------------------------------------- /api-gateway/src/main/resources/docker/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - /var/log/spring-music.log 21 | document_type: log4j 22 | multiline: 23 | pattern: '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}' 24 | negate: true 25 | match: after 26 | - 27 | paths: 28 | - /usr/local/tomcat/logs/*.out 29 | - /usr/local/tomcat/logs/*.log 30 | document_type: tomcat 31 | -------------------------------------------------------------------------------- /api-gateway/src/main/resources/docker/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /api-gateway/src/main/resources/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 6 | -------------------------------------------------------------------------------- /api-gateway/src/main/resources/public.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAybh3MPztT363c041gifD 3 | B1JKb7M/N6doCBIVJmbS1nVrCQRiVq4vcsMfTI/C6yNp4a2VF/UMuJTyy3c4iKe7 4 | A1jNn2dd4EBBN6ljavhQSZ6ImiSDqUF40BHs54b5ffZfzBIsNcvRPZVCt6Fs/OuX 5 | EaMkIesyaQxQS1xKH3gHFhWSS74MShqXDZwG/tc4CojSFTkhBPFh1/7x8XB+0UVK 6 | QYElIdMrSUZfNMJ+DIzphogwDbqzDoVxC1nqHDAju7x2FENtHg5Xs0UXeKFuDLfO 7 | WHG5z9HBSooEQnKrz/9G/Uvd6NNcXJYCgI/6MjRGlQ3MPSKMDpVHkBiK/XYw0Vs7 8 | DQIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /assets/event-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | 5 | zookeeper: 6 | image: wurstmeister/zookeeper 7 | ports: 8 | - 2181:2181 9 | networks: 10 | - net 11 | 12 | kafka: 13 | image: wurstmeister/kafka 14 | ports: 15 | - 9092:9092 16 | depends_on: 17 | - zookeeper 18 | environment: 19 | KAFKA_ADVERTISED_HOST_NAME: 172.19.0.1 20 | KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" 21 | KAFKA_CREATE_TOPICS: "todo-mail:1:1" 22 | KAFKA_ADVERTISED_HOST_NAME: "kafka" 23 | volumes: 24 | - /var/run/docker.sock:/var/run/docker.sock 25 | hostname: kafka 26 | container_name: kafka 27 | networks: 28 | - net 29 | reminder: 30 | image: todo/reminder-service 31 | ports: 32 | - 8015:8015 33 | - 8001:8001 34 | networks: 35 | - net 36 | depends_on: 37 | - kafka 38 | hostname: reminder 39 | command: ["./wait-for-it.sh","kafka:8010","--timeout=150","--","/usr/local/bin/start.sh"] 40 | 41 | mail: 42 | image: todo/mail-service 43 | ports: 44 | - 8020:8020 45 | - 8000:8000 46 | networks: 47 | - net 48 | depends_on: 49 | - kafka 50 | hostname: mail 51 | container_name: mail 52 | command: ["./wait-for-it.sh","kafka:8010","--timeout=150","--","/usr/local/bin/start.sh"] 53 | 54 | config: 55 | image: todo/config-server 56 | ports: 57 | - 8888:8888 58 | networks: 59 | - net 60 | hostname: config 61 | container_name: config 62 | external_links: 63 | - elk 64 | 65 | eureka: 66 | image: todo/eureka-server 67 | ports: 68 | - 8010:8010 69 | networks: 70 | - net 71 | depends_on: 72 | - config 73 | hostname: eureka 74 | container_name: eureka 75 | command: ["./wait-for-it.sh","config:8888","--timeout=100","--","/usr/local/bin/start.sh"] 76 | external_links: 77 | - elk 78 | 79 | 80 | volumes: 81 | todo_data: 82 | external: true 83 | todo_elk: 84 | external: true 85 | 86 | networks: 87 | net: 88 | driver: bridge 89 | -------------------------------------------------------------------------------- /assets/infra-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | elk: 5 | image: sebp/elk:latest 6 | ports: 7 | - 5601:5601 8 | - 9200:9200 9 | - 5044:5044 10 | - 5001:5000 11 | networks: 12 | - net 13 | volumes: 14 | - todo_elk:/var/lib/elasticsearch 15 | hostname: elk 16 | container_name: elk 17 | mem_limit: 4925288000 18 | cpu_shares: 500 19 | 20 | zookeeper: 21 | image: wurstmeister/zookeeper 22 | ports: 23 | - 2181:2181 24 | networks: 25 | - net 26 | mem_limit: 925288000 27 | cpu_shares: 100 28 | 29 | kafka: 30 | image: wurstmeister/kafka 31 | ports: 32 | - 9092 33 | depends_on: 34 | - zookeeper 35 | environment: 36 | KAFKA_ADVERTISED_HOST_NAME: 172.19.0.1 37 | KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" 38 | KAFKA_CREATE_TOPICS: "todo-mail:1:1" 39 | volumes: 40 | - /var/run/docker.sock:/var/run/docker.sock 41 | hostname: kafka 42 | container_name: kafka 43 | networks: 44 | - net 45 | mem_limit: 925288000 46 | cpu_shares: 100 47 | 48 | volumes: 49 | todo_data: 50 | external: true 51 | todo_elk: 52 | external: true 53 | 54 | networks: 55 | net: 56 | driver: bridge 57 | -------------------------------------------------------------------------------- /assets/logging-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | config: 5 | image: todo/config-server 6 | ports: 7 | - 8888:8888 8 | networks: 9 | - net 10 | hostname: config 11 | container_name: config 12 | external_links: 13 | - elk 14 | command: ["./wait-for-it.sh","elk:5601","--timeout=90","--","/usr/local/bin/start.sh"] 15 | 16 | user: 17 | image: todo/user-service 18 | ports: 19 | - 8016:8016 20 | networks: 21 | - net 22 | hostname: user 23 | container_name: user 24 | command: ["./wait-for-it.sh","elk:5601","--timeout=90","--","/usr/local/bin/start.sh"] 25 | external_links: 26 | - elk 27 | - kafka 28 | 29 | elk: 30 | image: sebp/elk:latest 31 | ports: 32 | - 5601:5601 33 | - 9200:9200 34 | - 5044:5044 35 | - 5000:5000 36 | networks: 37 | - net 38 | volumes: 39 | - todo_data:/var/lib/elasticsearch 40 | hostname: elk 41 | container_name: elk 42 | mem_limit: 4925288000 43 | cpu_shares: 500 44 | 45 | volumes: 46 | todo_data: 47 | external: true 48 | todo_elk: 49 | external: true 50 | 51 | networks: 52 | net: 53 | driver: bridge 54 | -------------------------------------------------------------------------------- /assets/microservices-arch.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apssouza22/java-microservice/9172a9004dd92434fbec4712cb45650a611185c3/assets/microservices-arch.jpg -------------------------------------------------------------------------------- /assets/oauth-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | config: 5 | image: todo/config-server 6 | ports: 7 | - 8888:8888 8 | networks: 9 | - net 10 | hostname: config 11 | container_name: config 12 | external_links: 13 | - elk 14 | - kafka 15 | 16 | oauth: 17 | image: todo/oauth-server 18 | ports: 19 | - 8017:8017 20 | networks: 21 | - net 22 | depends_on: 23 | - user 24 | hostname: oauth 25 | container_name: oauth 26 | command: ["./wait-for-it.sh","eureka:8010","--timeout=150","--","/usr/local/bin/start.sh"] 27 | external_links: 28 | - elk 29 | 30 | eureka: 31 | image: todo/eureka-server 32 | ports: 33 | - 8010:8010 34 | networks: 35 | - net 36 | depends_on: 37 | - config 38 | hostname: eureka 39 | container_name: eureka 40 | command: ["./wait-for-it.sh","config:8888","--timeout=100","--","/usr/local/bin/start.sh"] 41 | external_links: 42 | - elk 43 | 44 | gateway: 45 | image: todo/api-gateway 46 | ports: 47 | - 8018:8018 48 | networks: 49 | - net 50 | hostname: gateway 51 | command: ["./wait-for-it.sh","eureka:8010","--timeout=150","--","/usr/local/bin/start.sh"] 52 | external_links: 53 | - elk 54 | 55 | user: 56 | image: todo/user-service 57 | ports: 58 | - 8016:8016 59 | networks: 60 | - net 61 | hostname: user 62 | container_name: user 63 | command: ["./wait-for-it.sh","eureka:8010","--timeout=150","--","/usr/local/bin/start.sh"] 64 | external_links: 65 | - elk 66 | - kafka 67 | 68 | volumes: 69 | todo_data: 70 | external: true 71 | todo_elk: 72 | external: true 73 | 74 | networks: 75 | net: 76 | driver: bridge 77 | -------------------------------------------------------------------------------- /assets/proxy-docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | config: 5 | image: todo/config-server 6 | ports: 7 | - 8888:8888 8 | networks: 9 | - net 10 | hostname: config 11 | container_name: config 12 | external_links: 13 | - elk 14 | - kafka 15 | 16 | gateway: 17 | image: todo/api-gateway 18 | ports: 19 | - 8018 20 | networks: 21 | - net 22 | hostname: gateway 23 | command: ["./wait-for-it.sh","config:8888","--timeout=50","--","/usr/local/bin/start.sh"] 24 | external_links: 25 | - elk 26 | 27 | proxy: 28 | build: proxy/ 29 | ports: 30 | - 8055:80 31 | networks: 32 | - net 33 | depends_on: 34 | - gateway 35 | hostname: proxy 36 | container_name: proxy 37 | command: ["./wait-for-it.sh","gateway:8018","--timeout=50","--","/usr/local/bin/start.sh"] 38 | 39 | volumes: 40 | todo_data: 41 | external: true 42 | todo_elk: 43 | external: true 44 | 45 | networks: 46 | net: 47 | driver: bridge 48 | -------------------------------------------------------------------------------- /aws-deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | loginString="$(aws ecr get-login)" 5 | ${loginString/-e none/ } 6 | REPOSITORY_URI=${REPOSITORY_URI} 7 | 8 | docker tag todo/oauth-server:latest ${REPOSITORY_URI}:oauth-server 9 | docker push ${REPOSITORY_URI}:oauth-server 10 | 11 | docker tag todo/user-service:latest ${REPOSITORY_URI}:user-service 12 | docker push ${REPOSITORY_URI}:user-service 13 | 14 | docker tag todo/api-gateway:latest ${REPOSITORY_URI}:api-gateway 15 | docker push ${REPOSITORY_URI}:api-gateway 16 | 17 | docker tag todo/config-server:latest ${REPOSITORY_URI}:config-server 18 | docker push ${REPOSITORY_URI}:config-server 19 | 20 | 21 | docker tag todo/eureka-server:latest ${REPOSITORY_URI}:eureka-server 22 | docker push ${REPOSITORY_URI}:eureka-server 23 | 24 | docker tag todo/reminder-service:latest ${REPOSITORY_URI}:reminder-service 25 | docker push ${REPOSITORY_URI}:reminder-service 26 | 27 | docker tag todo/admin-server:latest ${REPOSITORY_URI}:admin-server 28 | docker push ${REPOSITORY_URI}:admin-server 29 | 30 | 31 | docker tag todo/mail-service:latest ${REPOSITORY_URI}:mail-service 32 | docker push ${REPOSITORY_URI}:mail-service 33 | 34 | ecs-cli compose --verbose --file ./aws-compose.yml up 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /config-server/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /config-server/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build image') { 6 | // Run the maven build 7 | if (isUnix()) { 8 | sh "mvn -f ./config-server/pom.xml -Pdockerimage docker:build" 9 | } else { 10 | echo "Not ready for windows" 11 | } 12 | } 13 | stage('Deploy ECS') { 14 | echo "TODO deploy on AWS" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /config-server/README: -------------------------------------------------------------------------------- 1 | # Config server 2 | 3 | In the Config Server we have a central place to manage external properties for applications across all environments. 4 | We are using Spring config to deal with configuration of our services. 5 | 6 | -------------------------------------------------------------------------------- /config-server/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 11 | 12 | 13 | -classpath %classpath com.apssouza.config.Application 14 | java 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | process-classes 24 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 25 | 26 | 27 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath com.apssouza.config.Application 28 | java 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.apssouza.config.Application 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /config-server/src/main/java/com/apssouza/config/Application.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.config; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | @SpringBootApplication 8 | @EnableConfigServer 9 | public class Application { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(Application.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /config-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring.profiles.active: native 3 | spring.application.name: config-server 4 | server.port: 8888 5 | eureka.client.serviceUrl.defaultZone : http://eureka:8010/eureka/,http://localhost:8011/eureka/ 6 | 7 | spring: 8 | cloud: 9 | config: 10 | server: 11 | git: 12 | uri: https://github.com/apssouza22/java-microservice 13 | searchPaths: config-data 14 | # "native" is used when the native profile is active, for local tests with a classpath repo: 15 | native: 16 | searchLocations: classpath:offline-repository/ 17 | 18 | 19 | -------------------------------------------------------------------------------- /config-server/src/main/resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | 4 | MAINTAINER Alexsandro 5 | ENV REFRESHED_AT 2017-09-17 6 | 7 | ENV TERM xterm 8 | ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom 9 | 10 | RUN apt-get update -qq \ 11 | && apt-get install -qqy curl wget \ 12 | && apt-get clean \ 13 | \ 14 | && touch /var/log/todo.log \ 15 | && chmod 666 /var/log/todo.log 16 | 17 | ADD application/lib/springboot-webapp.jar /app.jar 18 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 19 | RUN bash -c 'chmod +x wait-for-it.sh' 20 | 21 | # install Filebeat 22 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 23 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 24 | && dpkg -i ${FILEBEAT_VERSION} \ 25 | && rm ${FILEBEAT_VERSION} 26 | 27 | # configure Filebeat 28 | ADD filebeat.yml /etc/filebeat/filebeat.yml 29 | 30 | # CA cert 31 | RUN mkdir -p /etc/pki/tls/certs 32 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 33 | 34 | # start Filebeat 35 | ADD ./start.sh /usr/local/bin/start.sh 36 | RUN chmod +x /usr/local/bin/start.sh 37 | CMD [ "/usr/local/bin/start.sh" ] -------------------------------------------------------------------------------- /config-server/src/main/resources/docker/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - /var/log/spring-music.log 21 | document_type: log4j 22 | multiline: 23 | pattern: '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}' 24 | negate: true 25 | match: after 26 | - 27 | paths: 28 | - /usr/local/tomcat/logs/*.out 29 | - /usr/local/tomcat/logs/*.log 30 | document_type: tomcat 31 | -------------------------------------------------------------------------------- /config-server/src/main/resources/docker/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /config-server/src/main/resources/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 6 | -------------------------------------------------------------------------------- /config-server/src/main/resources/offline-repository/admin.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8026 3 | 4 | spring: 5 | application: 6 | name: admin 7 | cloud: 8 | config: 9 | enabled: false 10 | # tag::configuration-eureka[] 11 | eureka: #<1> 12 | instance: 13 | leaseRenewalIntervalInSeconds: 10 14 | client: 15 | registryFetchIntervalSeconds: 5 16 | serviceUrl: 17 | defaultZone: ${EUREKA_SERVICE_URL:http://localhost:8010}/eureka/ 18 | 19 | management.security.enabled: false #<2> 20 | # end::configuration-eureka[] 21 | 22 | # tag::configuration-ui-hystrix[] 23 | spring.boot.admin.routes.endpoints: env,metrics,dump,jolokia,info,configprops,trace,logfile,refresh,flyway,liquibase,heapdump,loggers,auditevents,hystrix.stream,turbine.stream,activiti 24 | # end::configuration-ui-hystrix[] 25 | 26 | # tag::configuration-ui-turbine[] 27 | spring.boot.admin.turbine: 28 | clusters: default 29 | location: turbine #<1> 30 | # end::configuration-ui-turbine[] 31 | 32 | logging.file: /var/log/todo.log 33 | 34 | -------------------------------------------------------------------------------- /config-server/src/main/resources/offline-repository/api-gateway.properties: -------------------------------------------------------------------------------- 1 | server.port = 8018 2 | spring.application.name = api-gateway 3 | eureka.client.serviceUrl.defaultZone = http://eureka:8010/eureka/ 4 | 5 | #database 6 | spring.jpa.properties.hibernate.show_sql=true 7 | spring.jpa.properties.hibernate.use_sql_comments=true 8 | spring.jpa.properties.hibernate.format_sql=true 9 | spring.jpa.properties.hibernate.type=trace 10 | 11 | logging.level.org.hibernate.SQL=DEBUG 12 | logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE 13 | 14 | #spring admin 15 | spring.boot.admin.url=http://admin:8026,http://localhost:8026 16 | management.security.enabled= false -------------------------------------------------------------------------------- /config-server/src/main/resources/offline-repository/eureka-server.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # This default profile is used when running a single instance completely standalone: 3 | spring: 4 | boot: 5 | admin: 6 | url: http://admin:8026,http://localhost:8026 7 | profiles: default 8 | 9 | server: 10 | port: 8010 11 | 12 | eureka: 13 | instance: 14 | hostname: localhost 15 | preferIpAddress: true 16 | # ipAddress: 52.50.116.215 17 | client: 18 | registerWithEureka: false 19 | fetchRegistry: false 20 | serviceUrl: 21 | defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 22 | 23 | # primary, secondary, and tertiary illustrate running 3 intercommunicating instances. This example has them running 24 | # side-by-side on localhost -- which is unrealistic in production -- but does illustrate how multiple instances collaborate. 25 | # Run by opening 3 separate command prompts: 26 | # java -jar -Dspring.profiles.active=primary target/commmon-eureka-server-1.jar 27 | # java -jar -Dspring.profiles.active=secondary target/commmon-eureka-server-1.jar 28 | # java -jar -Dspring.profiles.active=tertiary target/commmon-eureka-server-1.jar 29 | 30 | --- 31 | spring: 32 | profiles: primary 33 | server: 34 | port: 8011 35 | eureka: 36 | client: 37 | serviceUrl: 38 | defaultZone: http://localhost:8012/eureka, http://localhost:8013/eureka/ 39 | 40 | --- 41 | spring: 42 | profiles: secondary 43 | server: 44 | port: 8012 45 | eureka: 46 | client: 47 | serviceUrl: 48 | defaultZone: http://localhost:8013/eureka/,http://localhost:8011/eureka/ 49 | 50 | --- 51 | spring: 52 | profiles: tertiary 53 | server: 54 | port: 8013 55 | eureka: 56 | client: 57 | serviceUrl: 58 | defaultZone: http://localhost:8011/eureka/,http://localhost:8012/eureka/ 59 | 60 | logging.file: /var/log/todo.log -------------------------------------------------------------------------------- /config-server/src/main/resources/offline-repository/mailer.properties: -------------------------------------------------------------------------------- 1 | server.port=8020 2 | 3 | spring.application.name=mailer 4 | 5 | eureka.client.serviceUrl.defaultZone = http://eureka:8010/eureka/,http://localhost:8011/eureka/ 6 | 7 | #spring admin 8 | spring.boot.admin.url=http://admin:8026,http://localhost:8026 9 | management.security.enabled= false 10 | 11 | logging.file= /var/log/todo.log 12 | 13 | #spring stream 14 | spring.cloud.stream.default.contentType=application/json 15 | spring.cloud.stream.bindings.output.destination=todo-mail 16 | spring.cloud.stream.bindings.input.destination=todo-mail 17 | spring.cloud.stream.bindings.input.group=todo-mail 18 | spring.cloud.stream.kafka.binder.headers = type 19 | spring.cloud.stream.kafka.binder.brokers=kafka 20 | spring.cloud.stream.kafka.binder.zkNodes=zookeeper 21 | spring.cloud.stream.kafka.binder.defaultZkPort=2181 22 | spring.cloud.stream.kafka.binder.defaultBrokerPort=9092 23 | -------------------------------------------------------------------------------- /config-server/src/main/resources/offline-repository/oauth.properties: -------------------------------------------------------------------------------- 1 | server.port = 8017 2 | spring.application.name = oauth 3 | eureka.client.serviceUrl.defaultZone = http://eureka:8010/eureka/,http://localhost:8010/eureka/ 4 | 5 | #database 6 | spring.jpa.properties.hibernate.show_sql=true 7 | spring.jpa.properties.hibernate.use_sql_comments=true 8 | spring.jpa.properties.hibernate.format_sql=true 9 | spring.jpa.properties.hibernate.type=trace 10 | 11 | logging.level.org.hibernate.SQL=DEBUG 12 | logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE 13 | 14 | #spring admin 15 | spring.boot.admin.url=http://admin:8026,http://localhost:8026 16 | management.security.enabled: false 17 | 18 | logging.file= /var/log/todo.log 19 | -------------------------------------------------------------------------------- /config-server/src/main/resources/offline-repository/reminder.properties: -------------------------------------------------------------------------------- 1 | server.port = 8015 2 | eureka.client.serviceUrl.defaultZone = http://eureka:8010/eureka/,http://localhost:8010/eureka/ 3 | 4 | #database 5 | spring.jpa.properties.hibernate.show_sql=true 6 | spring.jpa.properties.hibernate.use_sql_comments=true 7 | spring.jpa.properties.hibernate.format_sql=true 8 | spring.jpa.properties.hibernate.type=trace 9 | 10 | logging.level.org.hibernate.SQL=DEBUG 11 | logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE 12 | 13 | #spring admin 14 | spring.boot.admin.url=http://admin:8026,http://localhost:8026 15 | management.security.enabled= false 16 | 17 | logging.file= /var/log/todo.log 18 | 19 | #spring stream 20 | spring.cloud.stream.default.contentType=application/json 21 | spring.cloud.stream.bindings.output.destination=todo-mail 22 | spring.cloud.stream.bindings.input.destination=todo-mail 23 | spring.cloud.stream.bindings.input.group=todo-mail 24 | spring.cloud.stream.kafka.binder.headers = type 25 | spring.cloud.stream.kafka.binder.brokers=kafka 26 | spring.cloud.stream.kafka.binder.zkNodes=zookeeper 27 | spring.cloud.stream.kafka.binder.defaultZkPort=2181 28 | spring.cloud.stream.kafka.binder.defaultBrokerPort=9092 -------------------------------------------------------------------------------- /config-server/src/main/resources/offline-repository/user.properties: -------------------------------------------------------------------------------- 1 | server.port = 8016 2 | spring.application.name = user 3 | eureka.client.serviceUrl.defaultZone = http://eureka:8010/eureka/,http://localhost:8011/eureka/ 4 | 5 | #database 6 | spring.jpa.properties.hibernate.show_sql=true 7 | spring.jpa.properties.hibernate.use_sql_comments=true 8 | spring.jpa.properties.hibernate.format_sql=true 9 | spring.jpa.properties.hibernate.type=trace 10 | 11 | logging.level.org.hibernate.SQL=DEBUG 12 | logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE 13 | 14 | #spring admin 15 | spring.boot.admin.url=http://admin:8026,http://localhost:8026 16 | management.security.enabled= false 17 | 18 | logging.file=/var/log/todo.log 19 | -------------------------------------------------------------------------------- /config-server/src/test/java/demo/OutOfContainerTest.java: -------------------------------------------------------------------------------- 1 | package demo; 2 | 3 | import com.apssouza.config.Application; 4 | import static org.junit.Assert.assertTrue; 5 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 6 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 7 | 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.test.context.ActiveProfiles; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | import org.springframework.test.context.web.WebAppConfiguration; 16 | import org.springframework.test.web.servlet.MockMvc; 17 | import org.springframework.test.web.servlet.MvcResult; 18 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 19 | import org.springframework.web.context.WebApplicationContext; 20 | 21 | /** 22 | * Out-of-container test for the config server. 23 | * Verifies that the server serves up configuration when asked. 24 | * Uses "native" profile to obtain properties from local file system rather than GitHub. 25 | * 26 | * @author ken krueger 27 | */ 28 | @RunWith(SpringRunner.class) 29 | @SpringBootTest(classes = Application.class) 30 | @WebAppConfiguration 31 | @ActiveProfiles("native") // "native" means use local classpath location rather than GitHub. 32 | public class OutOfContainerTest { 33 | 34 | @Autowired WebApplicationContext spring; 35 | MockMvc mockMvc; 36 | 37 | @Before 38 | public void setup() { 39 | mockMvc = MockMvcBuilders.webAppContextSetup(spring).build(); 40 | } 41 | 42 | @Test 43 | public void propertyLoadTest() throws Exception { 44 | 45 | // To test if this config server is working, we will simulate a "testConfig" client 46 | // calling to get properties for its default profile. These configuration files 47 | // (application.yml and testConfig.yml) are on the classpath as the server is 48 | // running the 'native' profile: 49 | MvcResult result = 50 | mockMvc.perform(get("/eureka-server.properties")) 51 | .andExpect(status().isOk()) 52 | .andReturn() 53 | ; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /config-server/src/test/resources/offline-repository/application.yml: -------------------------------------------------------------------------------- 1 | fromApplication: applicationValue -------------------------------------------------------------------------------- /config-server/src/test/resources/offline-repository/testConfig.yml: -------------------------------------------------------------------------------- 1 | fromTestConfig: testConfigValue -------------------------------------------------------------------------------- /docker-orchestrate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ######################################################################## 4 | # title: Build Complete Project 5 | # author: Alexsandro souza (https://apssouza.com.br) 6 | # url: https://github.com/apssouza22 7 | # description: Build complete Java microservice project 8 | # usage: sh ./build_project.sh 9 | ######################################################################## 10 | 11 | set -ex 12 | 13 | 14 | # mount a named volume on host to store mongo and elk data 15 | # ** assumes your project folder is 'todo' ** 16 | docker volume create --name todo_data 17 | docker volume create --name todo_elk 18 | 19 | # create bridge network for project 20 | # ** assumes your project folder is 'todo' ** 21 | docker network create -d bridge todo_net 22 | 23 | # build images and orchestrate start-up of containers (in this order) 24 | # -p = --project-name 25 | docker-compose -p todo up 26 | 27 | -------------------------------------------------------------------------------- /eureka-server/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /eureka-server/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build image') { 6 | // Run the maven build 7 | if (isUnix()) { 8 | sh "mvn -f ./eureka-server/pom.xml -Pdockerimage docker:build " 9 | } else { 10 | echo "Not ready for windows" 11 | } 12 | } 13 | stage('Deploy ECS') { 14 | echo "TODO deploy on AWS" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /eureka-server/README: -------------------------------------------------------------------------------- 1 | # Eureka server 2 | 3 | Server-side service discovery allows services to find and communicate with each other without hard coding hostname and port. 4 | The only ‘fixed point’ in such an architecture consists of a service registry with which each service has to register. -------------------------------------------------------------------------------- /eureka-server/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 11 | 12 | 13 | -classpath %classpath demo.Application 14 | java 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /eureka-server/src/main/java/com/apssouza/discovery/Application.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.discovery; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class Application { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(Application.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /eureka-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | application: 4 | name: eureka-server 5 | -------------------------------------------------------------------------------- /eureka-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | cloud: 4 | config: 5 | uri: http://config:8888 6 | -------------------------------------------------------------------------------- /eureka-server/src/main/resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | 4 | MAINTAINER Alexsandro 5 | ENV REFRESHED_AT 2017-09-17 6 | 7 | ENV TERM xterm 8 | ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom 9 | 10 | RUN apt-get update -qq \ 11 | && apt-get install -qqy curl wget \ 12 | && apt-get clean \ 13 | \ 14 | && touch /var/log/todo.log \ 15 | && chmod 666 /var/log/todo.log 16 | 17 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 18 | RUN bash -c 'chmod +x wait-for-it.sh' 19 | 20 | ADD application/lib/springboot-webapp.jar /app.jar 21 | 22 | 23 | # install Filebeat 24 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 25 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 26 | && dpkg -i ${FILEBEAT_VERSION} \ 27 | && rm ${FILEBEAT_VERSION} 28 | 29 | # configure Filebeat 30 | ADD filebeat.yml /etc/filebeat/filebeat.yml 31 | 32 | # CA cert 33 | RUN mkdir -p /etc/pki/tls/certs 34 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 35 | 36 | # start Filebeat 37 | ADD ./start.sh /usr/local/bin/start.sh 38 | RUN chmod +x /usr/local/bin/start.sh 39 | CMD [ "/usr/local/bin/start.sh" ] -------------------------------------------------------------------------------- /eureka-server/src/main/resources/docker/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - /var/log/spring-music.log 21 | document_type: log4j 22 | multiline: 23 | pattern: '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}' 24 | negate: true 25 | match: after 26 | - 27 | paths: 28 | - /usr/local/tomcat/logs/*.out 29 | - /usr/local/tomcat/logs/*.log 30 | document_type: tomcat 31 | -------------------------------------------------------------------------------- /eureka-server/src/main/resources/docker/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /eureka-server/src/main/resources/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 6 | -------------------------------------------------------------------------------- /jmx-monitoring/README: -------------------------------------------------------------------------------- 1 | # JMX monitoring module 2 | 3 | On this module we show how to export managed been easily using JMX. We implemented 4 | a monitoring functionality using Aspect, Annotation and JMX, with the possibility of 5 | enable /disable and check the values real time using any JMX client. 6 | -------------------------------------------------------------------------------- /jmx-monitoring/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | jmx-monitoring 8 | 0.0.1-SNAPSHOT 9 | jar 10 | Jmx monitoring utilities 11 | 12 | 13 | parent-todo-ms 14 | com.apssouza 15 | 0.0.1-SNAPSHOT 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-aop 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /jmx-monitoring/src/main/java/com/apssouza/monitoring/Monitored.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.apssouza.monitoring; 17 | 18 | import java.lang.annotation.ElementType; 19 | import java.lang.annotation.Retention; 20 | import java.lang.annotation.RetentionPolicy; 21 | import java.lang.annotation.Target; 22 | 23 | /** 24 | * @author Maciej Szarlinski 25 | */ 26 | @Retention(RetentionPolicy.RUNTIME) 27 | @Target(ElementType.METHOD) 28 | public @interface Monitored { 29 | } 30 | -------------------------------------------------------------------------------- /jmx-monitoring/src/main/java/com/apssouza/monitoring/MonitoringConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.apssouza.monitoring; 17 | 18 | import org.springframework.context.annotation.Configuration; 19 | import org.springframework.context.annotation.EnableAspectJAutoProxy; 20 | 21 | /** 22 | * @author Maciej Szarlinski 23 | */ 24 | @Configuration 25 | @EnableAspectJAutoProxy 26 | public class MonitoringConfig { 27 | 28 | } 29 | -------------------------------------------------------------------------------- /jmx-monitoring/src/main/java/com/apssouza/monitoring/MonitoringInvokedEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.monitoring; 2 | 3 | /** 4 | * 5 | * @author apssouza 6 | */ 7 | public class MonitoringInvokedEvent { 8 | 9 | private final long duration; 10 | 11 | private final String methodName; 12 | 13 | public MonitoringInvokedEvent(String methodName, long duration) { 14 | this.methodName = methodName; 15 | this.duration = duration; 16 | } 17 | 18 | public long getDuration() { 19 | return duration; 20 | } 21 | 22 | public String getMethodName() { 23 | return methodName; 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /mail-service/.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /mail-service/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build image') { 6 | // Run the maven build 7 | if (isUnix()) { 8 | sh "mvn -f ./mail-service/pom.xml -Pdockerimage docker:build" 9 | } else { 10 | echo "Not ready for windows" 11 | } 12 | } 13 | stage('Deploy ECS') { 14 | echo "TODO deploy on AWS" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /mail-service/README: -------------------------------------------------------------------------------- 1 | # Mail service 2 | 3 | This is a service responsible for sending emails. 4 | 5 | On this services we are using the concept of event centric. We show how to use 6 | Command-Query Responsibility Separation (CQRS), eventsourcing, ditributed events with 7 | Kafka and more. 8 | -------------------------------------------------------------------------------- /mail-service/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 11 | 12 | 13 | -classpath %classpath com.apssouza.mailservice.MailserviceApplication 14 | java 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | process-classes 24 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 25 | 26 | 27 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath com.apssouza.mailservice.MailserviceApplication 28 | java 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.apssouza.mailservice.MailserviceApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/EventsourcingApplication.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing; 2 | 3 | import java.time.Instant; 4 | import java.util.UUID; 5 | import java.util.logging.Level; 6 | import java.util.logging.Logger; 7 | import org.springframework.boot.SpringApplication; 8 | import org.springframework.boot.autoconfigure.SpringBootApplication; 9 | import org.springframework.context.ConfigurableApplicationContext; 10 | 11 | /** 12 | * 13 | * @author apssouza 14 | */ 15 | @SpringBootApplication 16 | public class EventsourcingApplication { 17 | 18 | public static void main(String[] args) { 19 | ConfigurableApplicationContext context = SpringApplication.run(EventsourcingApplication.class, args); 20 | // EmailCommandHandler commandHandler = context.getBean(EmailCommandHandler.class); 21 | // 22 | // UUID randomUUID = UUID.randomUUID(); 23 | // 24 | // EmailCreateCommand commandCreate = new EmailCreateCommand(randomUUID, "Alex", "apssouza22@gmail.com"); 25 | // EmailSendCommand send = new EmailSendCommand(randomUUID, Instant.now()); 26 | // EmailDeliveryCommand delivery = new EmailDeliveryCommand(randomUUID, Instant.now()); 27 | // EmailDeleteCommand delete = new EmailDeleteCommand(randomUUID); 28 | // try { 29 | // commandHandler.create(commandCreate); 30 | // commandHandler.send(send); 31 | // commandHandler.delivery(delivery); 32 | // commandHandler.delete(delete); 33 | // } catch (Exception ex) { 34 | // Logger.getLogger(EventsourcingApplication.class.getName()).log(Level.SEVERE, null, ex); 35 | // } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/aggregates/AbstractAggregate.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.apssouza.eventsourcing.aggregates; 7 | 8 | import com.apssouza.infra.AppEvent; 9 | import java.util.List; 10 | import java.util.concurrent.CopyOnWriteArrayList; 11 | 12 | /** 13 | * 14 | * @author apssouza 15 | */ 16 | public abstract class AbstractAggregate implements Aggregate { 17 | 18 | protected String uuid; 19 | 20 | protected List changes = new CopyOnWriteArrayList(); 21 | 22 | protected CopyOnWriteArrayList appendChange(AppEvent event) { 23 | CopyOnWriteArrayList listChanges = new CopyOnWriteArrayList(changes); 24 | listChanges.add(event); 25 | return listChanges; 26 | } 27 | 28 | @Override 29 | public List getUncommittedChanges() { 30 | return changes; 31 | } 32 | 33 | @Override 34 | public String getUuid() { 35 | return uuid; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/aggregates/Aggregate.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.aggregates; 2 | 3 | import com.apssouza.infra.AppEvent; 4 | import java.util.List; 5 | 6 | /** 7 | * The aggregate interface 8 | * 9 | * @author apssouza 10 | */ 11 | public interface Aggregate { 12 | 13 | String getUuid(); 14 | 15 | List getUncommittedChanges(); 16 | 17 | Aggregate markChangesAsCommitted(); 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/aggregates/EmailState.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.aggregates; 2 | 3 | /** 4 | * Email state 5 | * 6 | * @author apssouza 7 | */ 8 | public enum EmailState implements ObjectState { 9 | CREATED, 10 | SENT, 11 | DELIVERED, 12 | READ, 13 | FAILED, 14 | REPLIED, 15 | DELETED 16 | } 17 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/aggregates/ObjectState.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.aggregates; 2 | 3 | /** 4 | * State object interface 5 | * 6 | * @author apssouza 7 | */ 8 | public interface ObjectState { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/commands/EmailCommandHandler.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.commands; 2 | 3 | import com.apssouza.eventsourcing.aggregates.EmailAggregate; 4 | import com.apssouza.eventsourcing.services.EventSourcingService; 5 | import com.apssouza.infra.AppEvent; 6 | import com.apssouza.infra.EventPublisher; 7 | import java.util.List; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | /** 12 | * Email command service handler. Deal with the business requirements before 13 | * send the command 14 | * 15 | * @author apssouza 16 | */ 17 | @Service 18 | @Transactional 19 | public class EmailCommandHandler { 20 | 21 | private final EventSourcingService eventSourcingService; 22 | 23 | private final EventPublisher eventPublisher; 24 | 25 | public EmailCommandHandler( 26 | EventSourcingService eventSourcingService, 27 | EventPublisher eventPublisher 28 | ) { 29 | this.eventSourcingService = eventSourcingService; 30 | this.eventPublisher = eventPublisher; 31 | } 32 | 33 | 34 | public void create(EmailCreateCommand command) throws Exception { 35 | EmailAggregate emailAggregate = getByUUID(command.getUuid()); 36 | emailAggregate = emailAggregate.create(command); 37 | List pendingEvents = emailAggregate.getUncommittedChanges(); 38 | eventSourcingService.save(emailAggregate); 39 | 40 | pendingEvents.forEach(eventPublisher::publish); 41 | pendingEvents.forEach(eventPublisher::stream); 42 | } 43 | 44 | public void send(EmailSendCommand command) throws Exception { 45 | EmailAggregate emailAggregate = getByUUID(command.getUuid()); 46 | emailAggregate = emailAggregate.send(command); 47 | 48 | List pendingEvents = emailAggregate.getUncommittedChanges(); 49 | pendingEvents.forEach(eventPublisher::stream); 50 | 51 | eventSourcingService.save(emailAggregate); 52 | } 53 | 54 | public void delivery(EmailDeliveryCommand command) throws Exception { 55 | EmailAggregate emailAggregate = getByUUID(command.getUuid()); 56 | emailAggregate = emailAggregate.delivery(command); 57 | 58 | List pendingEvents = emailAggregate.getUncommittedChanges(); 59 | pendingEvents.forEach(eventPublisher::stream); 60 | 61 | eventSourcingService.save(emailAggregate); 62 | } 63 | 64 | public void delete(EmailDeleteCommand command) throws Exception { 65 | EmailAggregate emailAggregate = getByUUID(command.getUuid()); 66 | emailAggregate.delete(command); 67 | 68 | List pendingEvents = emailAggregate.getUncommittedChanges(); 69 | pendingEvents.forEach(eventPublisher::stream); 70 | 71 | eventSourcingService.save(emailAggregate); 72 | } 73 | 74 | public EmailAggregate getByUUID(String uuid) { 75 | return EmailAggregate.from(uuid, eventSourcingService.getRelatedEvents(uuid)); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/commands/EmailCreateCommand.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.commands; 2 | 3 | import com.apssouza.eventsourcing.entities.Email; 4 | 5 | /** 6 | * Email create command 7 | * 8 | * @author apssouza 9 | */ 10 | public class EmailCreateCommand { 11 | 12 | private final String uuid; 13 | 14 | private final Email email; 15 | 16 | public EmailCreateCommand(String uuid, Email email) { 17 | this.uuid = uuid; 18 | this.email = email; 19 | } 20 | 21 | public Email getEmail() { 22 | return email; 23 | } 24 | 25 | public String getUuid() { 26 | return uuid; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/commands/EmailDeleteCommand.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.commands; 2 | 3 | /** 4 | * Email delete command 5 | * 6 | * @author apssouza 7 | */ 8 | public class EmailDeleteCommand { 9 | 10 | private String uuid; 11 | 12 | public EmailDeleteCommand(String id) { 13 | this.uuid = id; 14 | } 15 | 16 | public String getUuid() { 17 | return uuid; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/commands/EmailDeliveryCommand.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.commands; 2 | 3 | import java.time.Instant; 4 | 5 | /** 6 | * Email delivery command 7 | * 8 | * @author apssouza 9 | */ 10 | public class EmailDeliveryCommand { 11 | 12 | private final String uuid; 13 | private final Instant instant; 14 | 15 | public EmailDeliveryCommand(String uuid, Instant instant) { 16 | this.uuid = uuid; 17 | this.instant = instant; 18 | } 19 | 20 | public String getUuid() { 21 | return uuid; 22 | } 23 | 24 | public Instant getInstant() { 25 | return instant; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/commands/EmailSendCommand.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.apssouza.eventsourcing.commands; 7 | 8 | import java.time.Instant; 9 | import java.util.UUID; 10 | 11 | /** 12 | * Email send command 13 | * 14 | * @author apssouza 15 | */ 16 | public class EmailSendCommand { 17 | 18 | private final String uuid; 19 | private final Instant instant; 20 | 21 | public EmailSendCommand(String uuid, Instant instant) { 22 | this.uuid = uuid; 23 | this.instant = instant; 24 | } 25 | 26 | public String getUuid() { 27 | return uuid; 28 | } 29 | 30 | public Instant getInstant() { 31 | return instant; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/entities/Email.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.entities; 2 | 3 | import com.apssouza.eventsourcing.aggregates.EmailState; 4 | import javax.persistence.Column; 5 | import javax.persistence.Entity; 6 | import javax.persistence.GeneratedValue; 7 | import javax.persistence.Id; 8 | import javax.persistence.Version; 9 | import javax.validation.constraints.NotNull; 10 | import javax.validation.constraints.Size; 11 | 12 | /** 13 | * Email entity 14 | * 15 | * @author apssouza 16 | */ 17 | @Entity 18 | public class Email { 19 | 20 | @Id 21 | @GeneratedValue 22 | private long id; 23 | 24 | @NotNull 25 | private long authId; 26 | 27 | @NotNull 28 | @Size(min = 2, max = 256) 29 | private String name; 30 | 31 | @org.hibernate.validator.constraints.Email 32 | @NotNull 33 | @Column(unique = true) 34 | private String email; 35 | 36 | private EmailState state; 37 | 38 | @Version 39 | private long version; 40 | 41 | public Email() { 42 | } 43 | 44 | public Email(String name, String email, EmailState state) { 45 | this.name = name; 46 | this.email = email; 47 | this.state = state; 48 | } 49 | 50 | public Email(long id, String name, String email, EmailState state) { 51 | this(name, email,state); 52 | this.id = id; 53 | } 54 | 55 | public EmailState getState() { 56 | return state; 57 | } 58 | 59 | 60 | public long getId() { 61 | return id; 62 | } 63 | 64 | public void setId(long id) { 65 | this.id = id; 66 | } 67 | 68 | public String getName() { 69 | return name; 70 | } 71 | 72 | public void setName(String name) { 73 | this.name = name; 74 | } 75 | 76 | public String getEmail() { 77 | return email; 78 | } 79 | 80 | public void setEmail(String email) { 81 | this.email = email; 82 | } 83 | 84 | public long getAuthId() { 85 | return authId; 86 | } 87 | 88 | public void setAuthId(long authId) { 89 | this.authId = authId; 90 | } 91 | 92 | public long getVersion() { 93 | return version; 94 | } 95 | 96 | public void setVersion(long version) { 97 | this.version = version; 98 | } 99 | 100 | @Override 101 | public String toString() { 102 | return "Email{" + "id=" + id + ", authId=" + authId + ", name=" + name + ", email=" + email + ", version=" + version + '}'; 103 | } 104 | 105 | public Email setState(EmailState emailState) { 106 | state = emailState; 107 | return this; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/events/EmailCreatedEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.events; 2 | 3 | import com.apssouza.eventsourcing.entities.Email; 4 | import java.time.Instant; 5 | 6 | /** 7 | * Email created event 8 | * 9 | * @author apssouza 10 | */ 11 | public class EmailCreatedEvent implements EmailEvent { 12 | 13 | private Email email; 14 | 15 | public EmailCreatedEvent(String uuid) { 16 | } 17 | 18 | protected String uuid; 19 | 20 | protected Instant when = Instant.now(); 21 | 22 | @Override 23 | public String uuid() { 24 | return uuid; 25 | } 26 | 27 | @Override 28 | public Instant when() { 29 | return when; 30 | } 31 | 32 | public EmailCreatedEvent(String uuid, Email account) { 33 | this.email = account; 34 | this.uuid = uuid; 35 | } 36 | 37 | @Override 38 | public Email getEmail() { 39 | return email; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/events/EmailDeletedEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.events; 2 | 3 | import com.apssouza.eventsourcing.commands.EmailDeleteCommand; 4 | import com.apssouza.eventsourcing.entities.Email; 5 | import com.apssouza.infra.AbstractDomainEvent; 6 | import com.apssouza.infra.AppEvent; 7 | import java.time.Instant; 8 | 9 | /** 10 | * Email deleted event 11 | * 12 | * @author apssouza 13 | */ 14 | public class EmailDeletedEvent extends AbstractDomainEvent implements EmailEvent { 15 | 16 | private final String uuid; 17 | private final String type = "Deleted"; 18 | private final Instant when = Instant.now(); 19 | 20 | private Email email; 21 | 22 | /** 23 | * 24 | * @param uuid 25 | * @param email 26 | */ 27 | public EmailDeletedEvent(String uuid, Email email) { 28 | this.uuid = uuid; 29 | this.email = email; 30 | } 31 | 32 | @Override 33 | public String uuid() { 34 | return uuid; 35 | } 36 | 37 | public String type() { 38 | return type; 39 | } 40 | 41 | @Override 42 | public Instant when() { 43 | return when; 44 | } 45 | 46 | public Email getEmail() { 47 | return email; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/events/EmailDeliveredEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.events; 2 | 3 | import com.apssouza.eventsourcing.entities.Email; 4 | import com.apssouza.infra.AbstractDomainEvent; 5 | import java.time.Instant; 6 | 7 | /** 8 | * Email delivered event 9 | * 10 | * @author apssouza 11 | */ 12 | public class EmailDeliveredEvent extends AbstractDomainEvent implements EmailEvent { 13 | 14 | private final String uuid; 15 | private final Instant when = Instant.now(); 16 | private final String type = "sent"; 17 | 18 | private final Email email; 19 | 20 | public EmailDeliveredEvent(String uuid, Email email) { 21 | this.uuid = uuid; 22 | this.email = email; 23 | } 24 | 25 | @Override 26 | public String uuid() { 27 | return uuid; 28 | } 29 | 30 | public String type() { 31 | return type; 32 | } 33 | 34 | @Override 35 | public Instant when() { 36 | return when; 37 | } 38 | 39 | @Override 40 | public Email getEmail() { 41 | return email; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/events/EmailEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.apssouza.eventsourcing.events; 7 | 8 | import com.apssouza.eventsourcing.entities.Email; 9 | import com.apssouza.infra.AppEvent; 10 | 11 | /** 12 | * 13 | * @author apssouza 14 | */ 15 | public interface EmailEvent extends AppEvent{ 16 | 17 | Email getEmail(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/events/EmailSentEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.events; 2 | 3 | import com.apssouza.eventsourcing.entities.Email; 4 | import com.apssouza.infra.AbstractDomainEvent; 5 | 6 | /** 7 | * Email sent event 8 | * 9 | * @author apssouza 10 | */ 11 | public class EmailSentEvent extends AbstractDomainEvent implements EmailEvent { 12 | 13 | private final String type = "sent"; 14 | 15 | private Email email; 16 | 17 | public EmailSentEvent(String uuid, Email email) { 18 | this.uuid = uuid; 19 | this.email = email; 20 | } 21 | 22 | @Override 23 | public Email getEmail() { 24 | return email; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/eventstore/EventDescriptor.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.eventstore; 2 | 3 | 4 | import javax.persistence.*; 5 | import java.time.Instant; 6 | 7 | @Entity(name = "event_descriptors") 8 | public class EventDescriptor { 9 | 10 | @Id 11 | @GeneratedValue(generator = "event_descriptors_seq", strategy = GenerationType.SEQUENCE) 12 | @SequenceGenerator(name = "event_descriptors_seq", sequenceName = "event_descriptors_seq", allocationSize = 1) 13 | private Long id; 14 | 15 | @Column(nullable = false, length = 600) 16 | private String body; 17 | 18 | @Column(nullable = false, name = "occurred_at") 19 | private Instant occurredAt = Instant.now(); 20 | 21 | @Column(nullable = false, length = 60) 22 | private String type; 23 | 24 | @ManyToOne 25 | private EventStream eventStream; 26 | 27 | EventDescriptor(String body, Instant occurredAt, String type) { 28 | this.body = body; 29 | this.occurredAt = occurredAt; 30 | this.type = type; 31 | } 32 | 33 | private EventDescriptor() { 34 | } 35 | 36 | public Long getId() { 37 | return id; 38 | } 39 | 40 | public String getBody() { 41 | return body; 42 | } 43 | 44 | public Instant getOccurredAt() { 45 | return occurredAt; 46 | } 47 | 48 | public String getType() { 49 | return type; 50 | } 51 | 52 | public EventStream getEventStream() { 53 | return eventStream; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/eventstore/EventSerializer.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.eventstore; 2 | 3 | import com.apssouza.infra.AppEvent; 4 | import com.fasterxml.jackson.core.JsonProcessingException; 5 | import com.fasterxml.jackson.databind.ObjectMapper; 6 | import com.fasterxml.jackson.databind.SerializationFeature; 7 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 8 | import org.springframework.stereotype.Component; 9 | 10 | import java.io.IOException; 11 | 12 | import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; 13 | 14 | @Component 15 | public class EventSerializer { 16 | 17 | private final ObjectMapper objectMapper; 18 | 19 | public EventSerializer() { 20 | this.objectMapper = new ObjectMapper(); 21 | objectMapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false); 22 | objectMapper.registerModule(new JavaTimeModule()); 23 | objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); 24 | } 25 | 26 | public EventDescriptor serialize(AppEvent event) { 27 | try { 28 | return new EventDescriptor(objectMapper.writeValueAsString(event), event.when(), AppEvent.class.getCanonicalName()); 29 | } catch (JsonProcessingException e) { 30 | throw new RuntimeException(e); 31 | } 32 | } 33 | 34 | public AppEvent deserialize(EventDescriptor eventDescriptor) { 35 | try { 36 | return objectMapper.readValue(eventDescriptor.getBody(), AppEvent.class); 37 | } catch (IOException e) { 38 | throw new RuntimeException(e); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/eventstore/EventStoreRepository.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.eventstore; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | import java.util.List; 6 | import java.util.Optional; 7 | 8 | import static java.util.Collections.emptyList; 9 | 10 | public interface EventStoreRepository extends JpaRepository { 11 | 12 | Optional findByAggregateUUID(String uuid); 13 | 14 | default EventStream saveEvents(String aggregateId, List events) { 15 | final EventStream eventStream = findByAggregateUUID(aggregateId) 16 | .orElseGet(() -> new EventStream(aggregateId)); 17 | eventStream.addEvents(events); 18 | return save(eventStream); 19 | } 20 | 21 | default List getEventsForAggregate(String aggregateId) { 22 | return findByAggregateUUID(aggregateId) 23 | .map(EventStream::getEvents) 24 | .orElse(emptyList()); 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/eventstore/EventStream.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.eventstore; 2 | 3 | 4 | import java.io.Serializable; 5 | import javax.persistence.*; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import static java.util.Comparator.comparing; 10 | import static java.util.stream.Collectors.toList; 11 | import static javax.persistence.FetchType.EAGER; 12 | 13 | @Entity(name = "event_streams") 14 | public class EventStream implements Serializable { 15 | 16 | @Id 17 | @GeneratedValue(generator = "event_stream_seq", strategy = GenerationType.SEQUENCE) 18 | @SequenceGenerator(name = "event_stream_seq", sequenceName = "event_stream_seq", allocationSize = 1) 19 | private Long id; 20 | 21 | @Column(unique = true, nullable = false, name = "aggregate_uuid", length = 36) 22 | private String aggregateUUID; 23 | 24 | @Version 25 | @Column(nullable = false) 26 | private long version; 27 | 28 | @OneToMany( 29 | cascade = CascadeType.ALL, 30 | orphanRemoval = true, 31 | fetch = EAGER 32 | ) 33 | private List events; 34 | 35 | public EventStream() { 36 | this.events = new ArrayList<>(); 37 | } 38 | 39 | EventStream(String aggregateUUID) { 40 | this.events = new ArrayList<>(); 41 | this.aggregateUUID = aggregateUUID; 42 | } 43 | 44 | public Long getId() { 45 | return id; 46 | } 47 | 48 | public String getAggregateUUID() { 49 | return aggregateUUID; 50 | } 51 | 52 | public long getVersion() { 53 | return version; 54 | } 55 | 56 | void addEvents(List events) { 57 | this.events.addAll(events); 58 | } 59 | 60 | List getEvents() { 61 | return events 62 | .stream() 63 | .sorted(comparing(EventDescriptor::getOccurredAt)) 64 | .collect(toList()); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/queries/EmailQueryObject.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.queries; 2 | 3 | import com.apssouza.eventsourcing.entities.Email; 4 | import com.apssouza.eventsourcing.events.EmailCreatedEvent; 5 | import com.apssouza.eventsourcing.events.EmailDeletedEvent; 6 | import com.apssouza.mailservice.repository.EmailRepository; 7 | import java.util.List; 8 | import org.springframework.context.event.EventListener; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Email query service, read data from the read data source This can be 13 | * separated in a new service 14 | * 15 | * @author apssouza 16 | */ 17 | @Component 18 | public class EmailQueryObject { 19 | 20 | private final EmailRepository emailRepository; 21 | 22 | public EmailQueryObject(EmailRepository emailRepository) { 23 | this.emailRepository = emailRepository; 24 | } 25 | 26 | public List all() { 27 | return emailRepository.findAll(); 28 | } 29 | 30 | @EventListener 31 | public void updateEmail(EmailCreatedEvent event) { 32 | System.out.println("event= "+ event.getEmail()); 33 | emailRepository.save(event.getEmail()); 34 | } 35 | 36 | @EventListener 37 | public void updateEmail(EmailDeletedEvent event) { 38 | emailRepository.delete(event.getEmail()); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/services/EventSourcingService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.apssouza.eventsourcing.services; 7 | 8 | import com.apssouza.eventsourcing.aggregates.Aggregate; 9 | import com.apssouza.eventsourcing.eventstore.EventStream; 10 | import com.apssouza.infra.AppEvent; 11 | import java.util.List; 12 | 13 | /** 14 | * 15 | * @author apssouza 16 | */ 17 | public interface EventSourcingService { 18 | 19 | Aggregate save(Aggregate aggregate) ; 20 | 21 | List getRelatedEvents(String uuid); 22 | 23 | EventStream getAggregate(String uuid); 24 | } 25 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/eventsourcing/services/EventSourcingServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.services; 2 | 3 | import com.apssouza.eventsourcing.aggregates.Aggregate; 4 | import com.apssouza.eventsourcing.eventstore.EventSerializer; 5 | import com.apssouza.eventsourcing.eventstore.EventStoreRepository; 6 | import com.apssouza.eventsourcing.eventstore.EventStream; 7 | import com.apssouza.infra.AppEvent; 8 | import java.util.List; 9 | import java.util.UUID; 10 | import static java.util.stream.Collectors.toList; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.context.ApplicationEventPublisher; 13 | import org.springframework.stereotype.Service; 14 | import org.springframework.transaction.annotation.Transactional; 15 | 16 | /** 17 | * 18 | * @author apssouza 19 | */ 20 | @Service 21 | @Transactional(readOnly = true) 22 | public class EventSourcingServiceImpl implements EventSourcingService{ 23 | 24 | private final EventSerializer eventSerializer; 25 | private final EventStoreRepository eventStoreRepository; 26 | 27 | @Autowired 28 | public EventSourcingServiceImpl( 29 | EventStoreRepository eventStore, 30 | EventSerializer eventSerializer, 31 | ApplicationEventPublisher eventPublisher 32 | ) { 33 | this.eventStoreRepository = eventStore; 34 | this.eventSerializer = eventSerializer; 35 | } 36 | 37 | @Override 38 | @Transactional 39 | public Aggregate save(Aggregate aggregate) { 40 | final List pendingEvents = aggregate.getUncommittedChanges(); 41 | eventStoreRepository.saveEvents( 42 | aggregate.getUuid(), 43 | pendingEvents 44 | .stream() 45 | .map(eventSerializer::serialize) 46 | .collect(toList()) 47 | ); 48 | return aggregate.markChangesAsCommitted(); 49 | } 50 | 51 | @Override 52 | public List getRelatedEvents(String uuid) { 53 | return eventStoreRepository.getEventsForAggregate(uuid) 54 | .stream() 55 | .map(eventSerializer::deserialize) 56 | .collect(toList()); 57 | } 58 | 59 | @Override 60 | public EventStream getAggregate(String uuid) { 61 | return eventStoreRepository.findByAggregateUUID(uuid) 62 | .orElseGet( () -> new EventStream()); 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/mailservice/MailserviceApplication.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.mailservice; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.ComponentScan; 6 | 7 | @SpringBootApplication 8 | @ComponentScan(basePackages = { 9 | "com.apssouza.infra", 10 | "com.apssouza.eventsourcing", 11 | "com.apssouza.mailservice" 12 | }) 13 | public class MailserviceApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(MailserviceApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/mailservice/configurations/EventSourcingConfig.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.mailservice.configurations; 2 | 3 | import org.springframework.context.annotation.ComponentScan; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * Event sourcing module configuration 8 | * 9 | * @author apssouza 10 | */ 11 | @ComponentScan({"com.apssouza.eventsourcing"}) 12 | @Configuration 13 | public class EventSourcingConfig { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/mailservice/controllers/EmailController.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.mailservice.controllers; 2 | 3 | import com.apssouza.eventsourcing.entities.Email; 4 | import com.apssouza.mailservice.repository.EmailRepository; 5 | import java.util.List; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * 13 | * @author apssouza 14 | */ 15 | @RestController 16 | @RequestMapping("/emails") 17 | public class EmailController { 18 | 19 | @Autowired 20 | EmailRepository repository; 21 | 22 | @GetMapping 23 | public List list() { 24 | return repository.findAll(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/mailservice/controllers/NotifyController.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.mailservice.controllers; 2 | 3 | import com.apssouza.eventsourcing.aggregates.EmailState; 4 | import com.apssouza.eventsourcing.commands.EmailCommandHandler; 5 | import com.apssouza.eventsourcing.commands.EmailCreateCommand; 6 | import com.apssouza.eventsourcing.entities.Email; 7 | import java.util.UUID; 8 | import java.util.concurrent.CompletableFuture; 9 | import java.util.concurrent.Executors; 10 | import java.util.concurrent.Future; 11 | import java.util.function.Supplier; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.util.ReflectionUtils; 14 | import org.springframework.web.bind.annotation.GetMapping; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.ResponseBody; 17 | import org.springframework.web.bind.annotation.RestController; 18 | 19 | /** 20 | * 21 | * @author apssouza 22 | */ 23 | @RestController 24 | @RequestMapping("/send") 25 | public class NotifyController { 26 | 27 | @Autowired 28 | EmailCommandHandler emailCommandHandler; 29 | 30 | @GetMapping("email") 31 | public @ResponseBody Future sendEmail() { 32 | Supplier supplier = () -> { 33 | String uuid = UUID.randomUUID().toString(); 34 | EmailCreateCommand command = new EmailCreateCommand( 35 | uuid, 36 | new Email("Alexsandro", "apssouza22@gmail.com", EmailState.CREATED) 37 | ); 38 | Executors.newCachedThreadPool().submit(() -> { 39 | try { 40 | emailCommandHandler.create(command); 41 | } catch (Exception ex) { 42 | ReflectionUtils.rethrowRuntimeException(ex); 43 | } 44 | }); 45 | return "Email sent successfully. - code= " + uuid; 46 | }; 47 | 48 | return CompletableFuture.supplyAsync(supplier, Executors.newCachedThreadPool()); 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/mailservice/integration/reminder/EventInput.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.mailservice.integration.reminder; 2 | 3 | import com.apssouza.eventsourcing.aggregates.EmailState; 4 | import com.apssouza.eventsourcing.commands.EmailCommandHandler; 5 | import com.apssouza.eventsourcing.commands.EmailCreateCommand; 6 | import com.apssouza.eventsourcing.entities.Email; 7 | import java.time.Instant; 8 | import java.util.UUID; 9 | import org.apache.log4j.Logger; 10 | import org.springframework.cloud.stream.annotation.EnableBinding; 11 | import org.springframework.cloud.stream.annotation.StreamListener; 12 | import org.springframework.cloud.stream.messaging.Sink; 13 | import org.springframework.messaging.handler.annotation.Payload; 14 | 15 | /** 16 | * 17 | * The Stream Kafka event input 18 | * 19 | * @author apssouza 20 | */ 21 | @EnableBinding(Sink.class) 22 | public class EventInput { 23 | 24 | Logger LOG = Logger.getLogger(EventInput.class); 25 | 26 | private final EmailCommandHandler commanderHandler; 27 | 28 | public EventInput(EmailCommandHandler commander) { 29 | this.commanderHandler = commander; 30 | } 31 | 32 | 33 | @StreamListener( 34 | target = Sink.INPUT, 35 | condition = "headers['type']=='TodoCreatedEvent'" 36 | ) 37 | public void todoCreated(@Payload TodoCreatedEvent event) throws Exception { 38 | LOG.info("Todo created"); 39 | LOG.info("when = " + event.when()); 40 | LOG.info("todo = " + event.getTodo().toString()); 41 | 42 | String uuid = UUID.randomUUID().toString(); 43 | Email email = new Email("Alexsandro", "test"+Instant.now().getEpochSecond()+"@gmail.com", EmailState.CREATED); 44 | EmailCreateCommand command = new EmailCreateCommand(uuid, email); 45 | commanderHandler.create(command); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/mailservice/integration/reminder/ToDoDto.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.mailservice.integration.reminder; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * To Do entity 7 | * 8 | * @author apssouza 9 | */ 10 | public class ToDoDto implements Cloneable { 11 | 12 | public enum TodoStatus { 13 | DONE, PENDING 14 | } 15 | 16 | private long id; 17 | 18 | private String caption; 19 | 20 | private String userEmail; 21 | 22 | private String description; 23 | 24 | private Date createdat; 25 | 26 | private int priority; 27 | 28 | private TodoStatus status = TodoStatus.PENDING; 29 | 30 | private long version; 31 | 32 | public ToDoDto() { 33 | } 34 | 35 | public ToDoDto(String email, String caption, String description, int priority) { 36 | this.caption = caption; 37 | this.description = description; 38 | this.priority = priority; 39 | this.userEmail = email; 40 | } 41 | 42 | public String getUserEmail() { 43 | return userEmail; 44 | } 45 | 46 | public void setUserEmail(String userEmail) { 47 | this.userEmail = userEmail; 48 | } 49 | 50 | public void setId(long id) { 51 | this.id = id; 52 | } 53 | 54 | public void setCaption(String caption) { 55 | this.caption = caption; 56 | } 57 | 58 | public void setDescription(String description) { 59 | this.description = description; 60 | } 61 | 62 | public void setPriority(int priority) { 63 | this.priority = priority; 64 | } 65 | 66 | public void setVersion(long version) { 67 | this.version = version; 68 | } 69 | 70 | public void setStatus(TodoStatus status) { 71 | this.status = status; 72 | } 73 | 74 | public TodoStatus getStatus() { 75 | return status; 76 | } 77 | 78 | public Long getId() { 79 | return id; 80 | } 81 | 82 | public void setId(Long id) { 83 | this.id = id; 84 | } 85 | 86 | public String getCaption() { 87 | return caption; 88 | } 89 | 90 | public String getDescription() { 91 | return description; 92 | } 93 | 94 | public int getPriority() { 95 | return priority; 96 | } 97 | 98 | public long getVersion() { 99 | return version; 100 | } 101 | 102 | public Date getCreatedat() { 103 | return createdat; 104 | } 105 | 106 | public void setCreatedat(Date createdat) { 107 | this.createdat = createdat; 108 | } 109 | 110 | @Override 111 | public String toString() { 112 | return "ToDo{" + "id=" + id + ", caption=" + caption + ", description=" + description + ", priority=" + priority + ", done=" + status + ", version=" + version + '}'; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/mailservice/integration/reminder/TodoCreatedEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.mailservice.integration.reminder; 2 | 3 | import com.apssouza.infra.AbstractDomainEvent; 4 | 5 | /** 6 | * To Do created event 7 | * 8 | * @author apssouza 9 | */ 10 | public class TodoCreatedEvent extends AbstractDomainEvent { 11 | 12 | private ToDoDto todo; 13 | 14 | public TodoCreatedEvent(ToDoDto todo) { 15 | this.todo = todo; 16 | } 17 | 18 | public TodoCreatedEvent() { 19 | } 20 | 21 | public ToDoDto getTodo() { 22 | return todo; 23 | } 24 | 25 | public void setTodo(ToDoDto todo) { 26 | this.todo = todo; 27 | } 28 | 29 | public int getPriority() { 30 | return this.todo.getPriority(); 31 | } 32 | 33 | @Override 34 | public String toString() { 35 | return "TodoChangeEvent{" + "todo=" + todo.getDescription() + '}'; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /mail-service/src/main/java/com/apssouza/mailservice/repository/EmailRepository.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.mailservice.repository; 2 | 3 | import com.apssouza.eventsourcing.entities.Email; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | /** 8 | * 9 | * @author apssouza 10 | */ 11 | @Repository 12 | public interface EmailRepository extends JpaRepository{ 13 | 14 | } 15 | -------------------------------------------------------------------------------- /mail-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=mailer 2 | -------------------------------------------------------------------------------- /mail-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | cloud: 4 | config: 5 | uri: http://config:8888 6 | -------------------------------------------------------------------------------- /mail-service/src/main/resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | 4 | MAINTAINER Alexsandro 5 | ENV REFRESHED_AT 2017-09-17 6 | 7 | ENV TERM xterm 8 | ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom 9 | 10 | RUN apt-get update -qq \ 11 | && apt-get install -qqy curl wget \ 12 | && apt-get clean \ 13 | \ 14 | && touch /var/log/todo.log \ 15 | && chmod 666 /var/log/todo.log 16 | 17 | ADD application/lib/springboot-webapp.jar /app.jar 18 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 19 | RUN bash -c 'chmod +x wait-for-it.sh' 20 | 21 | # install Filebeat 22 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 23 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 24 | && dpkg -i ${FILEBEAT_VERSION} \ 25 | && rm ${FILEBEAT_VERSION} 26 | 27 | # configure Filebeat 28 | ADD filebeat.yml /etc/filebeat/filebeat.yml 29 | 30 | # CA cert 31 | RUN mkdir -p /etc/pki/tls/certs 32 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 33 | 34 | # start Filebeat 35 | ADD ./start.sh /usr/local/bin/start.sh 36 | RUN chmod +x /usr/local/bin/start.sh 37 | CMD [ "/usr/local/bin/start.sh" ] -------------------------------------------------------------------------------- /mail-service/src/main/resources/docker/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - /var/log/spring-music.log 21 | document_type: log4j 22 | multiline: 23 | pattern: '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}' 24 | negate: true 25 | match: after 26 | - 27 | paths: 28 | - /usr/local/tomcat/logs/*.out 29 | - /usr/local/tomcat/logs/*.log 30 | document_type: tomcat 31 | -------------------------------------------------------------------------------- /mail-service/src/main/resources/docker/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /mail-service/src/main/resources/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | java -Djava.security.egd=file:/dev/./urandom -jar -Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n /app.jar 6 | -------------------------------------------------------------------------------- /mail-service/src/test/java/com/apssouza/eventsourcing/commands/EmailCommandHandlerTest.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.eventsourcing.commands; 2 | 3 | import com.apssouza.eventsourcing.aggregates.Aggregate; 4 | import com.apssouza.eventsourcing.aggregates.EmailAggregate; 5 | import com.apssouza.eventsourcing.aggregates.EmailState; 6 | import com.apssouza.eventsourcing.entities.Email; 7 | import com.apssouza.eventsourcing.eventstore.EventStream; 8 | import com.apssouza.eventsourcing.services.EventSourcingService; 9 | import com.apssouza.infra.EventPublisher; 10 | import java.time.Instant; 11 | import java.util.UUID; 12 | import org.junit.Assert; 13 | import org.junit.Before; 14 | import org.junit.Test; 15 | import org.mockito.Mockito; 16 | import static org.mockito.Mockito.verify; 17 | 18 | public class EmailCommandHandlerTest { 19 | 20 | private EventSourcingService eventSourcingService; 21 | 22 | private EventPublisher eventPublisher; 23 | 24 | private EmailCommandHandler commandHandler; 25 | 26 | @Before 27 | public void setUp() { 28 | eventSourcingService = Mockito.mock(EventSourcingService.class); 29 | eventPublisher = Mockito.mock(EventPublisher.class); 30 | commandHandler = new EmailCommandHandler(eventSourcingService, eventPublisher); 31 | } 32 | 33 | @Test 34 | public void create() throws Exception { 35 | String uuid = UUID.randomUUID().toString(); 36 | EmailCreateCommand command = new EmailCreateCommand( 37 | uuid, 38 | new Email("Alexsandro", "apssouza22@gmail.com", EmailState.CREATED) 39 | ); 40 | commandHandler.create(command); 41 | verify(eventPublisher, Mockito.times(1)).publish(Mockito.anyObject()); 42 | verify(eventPublisher, Mockito.times(1)).stream(Mockito.anyObject()); 43 | } 44 | 45 | @Test 46 | public void send() throws Exception { 47 | String uuid = UUID.randomUUID().toString(); 48 | EmailSendCommand command = new EmailSendCommand(uuid, Instant.now()); 49 | commandHandler.send(command); 50 | verify(eventSourcingService, Mockito.times(1)).save(Mockito.any(Aggregate.class)); 51 | verify(eventPublisher, Mockito.times(1)).stream(Mockito.anyObject()); 52 | } 53 | 54 | @Test 55 | public void getByUUID() { 56 | String uuid = "123"; 57 | Mockito.when(eventSourcingService.getAggregate(Mockito.anyString())) 58 | .thenReturn(new EventStream()); 59 | EmailAggregate byUUID = commandHandler.getByUUID(uuid); 60 | Assert.assertTrue(byUUID.getState().getEmail() == null); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /oauth-server/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build image') { 6 | // Run the maven build 7 | if (isUnix()) { 8 | sh "mvn -f ./oauth-server/pom.xml -Pdockerimage docker:build" 9 | } else { 10 | echo "Not ready for windows" 11 | } 12 | } 13 | stage('Deploy ECS') { 14 | echo "TODO deploy on AWS" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /oauth-server/README: -------------------------------------------------------------------------------- 1 | # Oauth server 2 | 3 | The OAuth server enables a third-party app to obtain limited access to an HTTP service. 4 | Instead of using the resource owner's credentials to access a protected resource, 5 | the client obtains an access token issued by this authorization server. 6 | 7 | We are issuing a token of JWT (JSON Web Token) format that defines a compact and 8 | self-contained way for securely transmitting information between parties as a JSON object. 9 | 10 | 11 | To authenticate: 12 | curl -X POST -vu todo-app:123456 http://localhost:8017/oauth/token -H "Accept: application/json" -d "password=1234&username=apssouza22@gmail.com&grant_type=password&scope=write&client_secret=123456&client_id=todo-app" -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/BasicApplication.java: -------------------------------------------------------------------------------- 1 | package com.apssouza; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.feign.EnableFeignClients; 6 | import org.springframework.cloud.netflix.hystrix.EnableHystrix; 7 | 8 | @SpringBootApplication 9 | @EnableHystrix 10 | @EnableFeignClients 11 | public class BasicApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(BasicApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/auth/CustomTokenEnhancer.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.auth; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; 6 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 7 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 8 | import org.springframework.security.oauth2.provider.token.TokenEnhancer; 9 | 10 | /** 11 | * 12 | * @author apssouza 13 | */ 14 | public class CustomTokenEnhancer implements TokenEnhancer { 15 | 16 | @Override 17 | public OAuth2AccessToken enhance( 18 | OAuth2AccessToken accessToken, 19 | OAuth2Authentication authentication 20 | ) { 21 | Map additionalInfo = new HashMap<>(); 22 | additionalInfo.put("name", authentication.getName()); 23 | ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); 24 | return accessToken; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/clients/UserClient.java: -------------------------------------------------------------------------------- 1 | 2 | package com.apssouza.clients; 3 | 4 | import com.apssouza.pojos.User; 5 | import org.springframework.cloud.netflix.feign.FeignClient; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | 11 | /** 12 | * 13 | * @author apssouza 14 | */ 15 | @FeignClient("user") 16 | @Component 17 | public interface UserClient { 18 | 19 | @RequestMapping(value = "/accounts/search", method = RequestMethod.GET) 20 | public User getUserByEmail(@RequestParam("email") String email); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/configuration/AuthenticationConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import com.apssouza.services.UserService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 8 | import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; 9 | import org.springframework.security.core.authority.AuthorityUtils; 10 | import org.springframework.security.core.userdetails.User; 11 | import org.springframework.security.core.userdetails.UserDetailsService; 12 | 13 | /** 14 | * @author apssouza 15 | */ 16 | @Configuration 17 | class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter { 18 | 19 | @Autowired 20 | UserService userService; 21 | 22 | @Override 23 | public void init(AuthenticationManagerBuilder auth) throws Exception { 24 | auth.userDetailsService(userDetailsService()); 25 | } 26 | 27 | @Bean 28 | protected UserDetailsService userDetailsService() { 29 | return (email) -> { 30 | com.apssouza.pojos.User user = userService.getUserByEmail(email); 31 | return new User( 32 | user.getEmail(), 33 | user.getPassword(), 34 | true, true, true, true, 35 | AuthorityUtils.createAuthorityList("USER", "write") 36 | ); 37 | }; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/configuration/JwtServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.io.ClassPathResource; 6 | import org.springframework.security.oauth2.provider.token.TokenStore; 7 | import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 8 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 9 | import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory; 10 | 11 | /** 12 | * Json Web token configuration. 13 | * 14 | * @author apssouza 15 | */ 16 | @Configuration 17 | public class JwtServerConfiguration { 18 | 19 | private static final String ENC_PASSWORD = "58347105"; 20 | 21 | @Bean 22 | public TokenStore tokenStore() { 23 | return new JwtTokenStore(jwtTokenEnhancer()); 24 | } 25 | 26 | @Bean 27 | protected JwtAccessTokenConverter jwtTokenEnhancer() { 28 | KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory( 29 | new ClassPathResource("jwt.jks"), 30 | ENC_PASSWORD.toCharArray() 31 | ); 32 | JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 33 | converter.setKeyPair(keyStoreKeyFactory.getKeyPair("jwt")); 34 | return converter; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/configuration/ServiceDiscoveryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * 8 | * @author apssouza 9 | */ 10 | @Configuration 11 | @EnableDiscoveryClient 12 | public class ServiceDiscoveryConfiguration { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/pojos/User.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.pojos; 2 | 3 | /** 4 | * 5 | * @author apssouza 6 | */ 7 | public class User { 8 | 9 | private long id; 10 | 11 | private String email; 12 | 13 | private String password; 14 | 15 | public User() { 16 | } 17 | 18 | public User(long id, String email, String password) { 19 | this.id = id; 20 | this.email = email; 21 | this.password = password; 22 | } 23 | 24 | public long getId() { 25 | return id; 26 | } 27 | 28 | public void setId(long id) { 29 | this.id = id; 30 | } 31 | 32 | public String getEmail() { 33 | return email; 34 | } 35 | 36 | public void setEmail(String email) { 37 | this.email = email; 38 | } 39 | 40 | public String getPassword() { 41 | return password; 42 | } 43 | 44 | public void setPassword(String password) { 45 | this.password = password; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/services/UserService.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.pojos.User; 4 | 5 | /** 6 | * User service. 7 | * 8 | * @author apssouza 9 | */ 10 | public interface UserService { 11 | 12 | User getUserByEmail(String email); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /oauth-server/src/main/java/com/apssouza/services/UserServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.clients.UserClient; 4 | import com.apssouza.pojos.User; 5 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * 11 | * @author apssouza 12 | */ 13 | @Component 14 | public class UserServiceImpl implements UserService { 15 | 16 | @Autowired 17 | UserClient userClient; 18 | 19 | @Override 20 | @HystrixCommand(fallbackMethod = "getFallbackUserByEmail") 21 | public User getUserByEmail(String email) { 22 | return userClient.getUserByEmail(email); 23 | } 24 | 25 | public User getFallbackUserByEmail(String email) { 26 | return new User(); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /oauth-server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name = oauth -------------------------------------------------------------------------------- /oauth-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | cloud: 4 | config: 5 | uri: http://config:8888 6 | -------------------------------------------------------------------------------- /oauth-server/src/main/resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | 4 | MAINTAINER Alexsandro 5 | ENV REFRESHED_AT 2017-09-17 6 | 7 | ENV TERM xterm 8 | ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom 9 | 10 | RUN apt-get update -qq \ 11 | && apt-get install -qqy curl wget \ 12 | && apt-get clean \ 13 | \ 14 | && touch /var/log/todo.log \ 15 | && chmod 666 /var/log/todo.log 16 | 17 | ADD application/lib/springboot-webapp.jar /app.jar 18 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 19 | RUN bash -c 'chmod +x wait-for-it.sh' 20 | 21 | # install Filebeat 22 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 23 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 24 | && dpkg -i ${FILEBEAT_VERSION} \ 25 | && rm ${FILEBEAT_VERSION} 26 | 27 | # configure Filebeat 28 | ADD filebeat.yml /etc/filebeat/filebeat.yml 29 | 30 | # CA cert 31 | RUN mkdir -p /etc/pki/tls/certs 32 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 33 | 34 | # start Filebeat 35 | ADD ./start.sh /usr/local/bin/start.sh 36 | RUN chmod +x /usr/local/bin/start.sh 37 | CMD [ "/usr/local/bin/start.sh" ] -------------------------------------------------------------------------------- /oauth-server/src/main/resources/docker/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - /var/log/spring-music.log 21 | document_type: log4j 22 | multiline: 23 | pattern: '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}' 24 | negate: true 25 | match: after 26 | - 27 | paths: 28 | - /usr/local/tomcat/logs/*.out 29 | - /usr/local/tomcat/logs/*.log 30 | document_type: tomcat 31 | -------------------------------------------------------------------------------- /oauth-server/src/main/resources/docker/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /oauth-server/src/main/resources/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 6 | -------------------------------------------------------------------------------- /oauth-server/src/main/resources/jwt.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apssouza22/java-microservice/9172a9004dd92434fbec4712cb45650a611185c3/oauth-server/src/main/resources/jwt.jks -------------------------------------------------------------------------------- /package-projects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | mvn clean install 6 | mvn -f ./remainder-service/pom.xml -Pdockerimage docker:build 7 | mvn -f ./eureka-server/pom.xml -Pdockerimage docker:build 8 | mvn -f ./config-server/pom.xml -Pdockerimage docker:build 9 | mvn -f ./oauth-server/pom.xml -Pdockerimage docker:build 10 | mvn -f ./user-service/pom.xml -Pdockerimage docker:build 11 | mvn -f ./api-gateway/pom.xml -Pdockerimage docker:build 12 | mvn -f ./admin-server/pom.xml -Pdockerimage docker:build 13 | mvn -f ./mail-service/pom.xml -Pdockerimage docker:build 14 | -------------------------------------------------------------------------------- /private.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDGTCCAgGgAwIBAgIECjQ1nzANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQGEwJE 3 | RTEPMA0GA1UECBMGQmVybGluMQ8wDQYDVQQHEwZCZXJsaW4xDDAKBgNVBAMTA2p3 4 | dDAeFw0xNzA0MDUyMDUxMzJaFw0xNzA3MDQyMDUxMzJaMD0xCzAJBgNVBAYTAkRF 5 | MQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEMMAoGA1UEAxMDand0 6 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAybh3MPztT363c041gifD 7 | B1JKb7M/N6doCBIVJmbS1nVrCQRiVq4vcsMfTI/C6yNp4a2VF/UMuJTyy3c4iKe7 8 | A1jNn2dd4EBBN6ljavhQSZ6ImiSDqUF40BHs54b5ffZfzBIsNcvRPZVCt6Fs/OuX 9 | EaMkIesyaQxQS1xKH3gHFhWSS74MShqXDZwG/tc4CojSFTkhBPFh1/7x8XB+0UVK 10 | QYElIdMrSUZfNMJ+DIzphogwDbqzDoVxC1nqHDAju7x2FENtHg5Xs0UXeKFuDLfO 11 | WHG5z9HBSooEQnKrz/9G/Uvd6NNcXJYCgI/6MjRGlQ3MPSKMDpVHkBiK/XYw0Vs7 12 | DQIDAQABoyEwHzAdBgNVHQ4EFgQUFUTAZMq6dpZd54AqO3Q61a4FhsswDQYJKoZI 13 | hvcNAQELBQADggEBADbIFIK3QKj7zcnL3ufBg2sVEL9Jm6/HZ2j75TV0/C5G5FqF 14 | B86kYO6xhNBIw1NGO9kckLsgCfIaqkpE8UYhskHHQFIofMMQV2dcYCu1K6bKjFU9 15 | IgTELi+m10mW1nb97f30NhPREvuH/JDttCRq+EjMb9V6bETuuTUTzkOLBaJweRqW 16 | bIdGtWxxpx8xv9iuqeLfvWyN2c08VfdgVMR8QXLE6vh/KZOqixuVdKEScqkkC4NC 17 | dXc6G5tarmSDAQnHzsEXI1o9whJ4y5c37l/hRWE+UmHSdztOjZi38Duw7j8o7Irn 18 | i9529XjL+xAYmGeaRJxA8ql6L8GerXUTIWmWdBA= 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /proxy/Dockerfile: -------------------------------------------------------------------------------- 1 | # NGINX image with build artifact 2 | 3 | FROM nginx:latest 4 | 5 | MAINTAINER Gary A. Stafford 6 | ENV REFRESHED_AT 2016-09-17 7 | 8 | ENV GITHUB_REPO https://github.com/garystafford/spring-music/raw/build-artifacts 9 | ENV STATIC_FILE spring-music-static.zip 10 | 11 | RUN apt-get update -qq \ 12 | && apt-get install -qqy curl wget unzip nano \ 13 | && apt-get clean \ 14 | \ 15 | && wget -O /tmp/${STATIC_FILE} ${GITHUB_REPO}/${STATIC_FILE} \ 16 | && unzip /tmp/${STATIC_FILE} -d /usr/share/nginx/assets/ 17 | 18 | COPY default.conf /etc/nginx/conf.d/default.conf 19 | 20 | # tweak nginx image set-up, remove log symlinks 21 | RUN rm /var/log/nginx/access.log /var/log/nginx/error.log 22 | 23 | # install Filebeat 24 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 25 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 26 | && dpkg -i ${FILEBEAT_VERSION} \ 27 | && rm ${FILEBEAT_VERSION} 28 | 29 | # configure Filebeat 30 | ADD filebeat.yml /etc/filebeat/filebeat.yml 31 | 32 | # CA cert 33 | RUN mkdir -p /etc/pki/tls/certs 34 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 35 | 36 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 37 | RUN bash -c 'chmod +x wait-for-it.sh' 38 | 39 | # start Filebeat 40 | ADD ./start.sh /usr/local/bin/start.sh 41 | RUN chmod +x /usr/local/bin/start.sh 42 | CMD [ "/usr/local/bin/start.sh" ] 43 | -------------------------------------------------------------------------------- /proxy/README: -------------------------------------------------------------------------------- 1 | # Proxy server 2 | 3 | This is a Nginx proxy/ Load balance server placed in front our API Gateway in order to have a 4 | load balance and be able of scaling our API Gateway as much as we need. -------------------------------------------------------------------------------- /proxy/default.conf: -------------------------------------------------------------------------------- 1 | # Based on http://nginx.org/en/docs/http/load_balancing.html 2 | upstream backend { 3 | #ip_hash; 4 | server gateway:8018; 5 | } 6 | 7 | server { 8 | listen 80; 9 | server_name proxy; 10 | 11 | location ~* \/assets\/(css|images|js|template)\/* { 12 | root /usr/share/nginx/; 13 | expires max; 14 | add_header Pragma public; 15 | add_header Cache-Control "public, must-revalidate, proxy-revalidate"; 16 | add_header Vary Accept-Encoding; 17 | access_log off; 18 | } 19 | 20 | location / { 21 | proxy_set_header Host $host; 22 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 23 | proxy_set_header X-Real-IP $remote_addr; 24 | proxy_set_header Host $proxy_host; 25 | add_header Request-Time $request_time; 26 | add_header Upstream-Address $upstream_addr; 27 | add_header Upstream-Response-Time $upstream_response_time; 28 | proxy_pass http://backend; 29 | } 30 | 31 | error_page 404 /404.html; 32 | 33 | # redirect server error pages to the static page /50x.html 34 | error_page 500 502 503 504 /50x.html; 35 | location = /50x.html { 36 | root /usr/share/nginx/html; 37 | } 38 | 39 | location /nginx_status { 40 | stub_status on; 41 | access_log off; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /proxy/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - "/var/log/nginx/*.log" 21 | document_type: nginx-access 22 | -------------------------------------------------------------------------------- /proxy/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /proxy/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | nginx 6 | tail -f /var/log/nginx/access.log -f /var/log/nginx/error.log 7 | -------------------------------------------------------------------------------- /public.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAybh3MPztT363c041gifD 3 | B1JKb7M/N6doCBIVJmbS1nVrCQRiVq4vcsMfTI/C6yNp4a2VF/UMuJTyy3c4iKe7 4 | A1jNn2dd4EBBN6ljavhQSZ6ImiSDqUF40BHs54b5ffZfzBIsNcvRPZVCt6Fs/OuX 5 | EaMkIesyaQxQS1xKH3gHFhWSS74MShqXDZwG/tc4CojSFTkhBPFh1/7x8XB+0UVK 6 | QYElIdMrSUZfNMJ+DIzphogwDbqzDoVxC1nqHDAju7x2FENtHg5Xs0UXeKFuDLfO 7 | WHG5z9HBSooEQnKrz/9G/Uvd6NNcXJYCgI/6MjRGlQ3MPSKMDpVHkBiK/XYw0Vs7 8 | DQIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /remainder-service/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build image') { 6 | // Run the maven build 7 | if (isUnix()) { 8 | sh "mvn -f ./remainder-service/pom.xml -Pdockerimage docker:build" 9 | } else { 10 | echo "Not ready for windows" 11 | } 12 | } 13 | stage('Deploy ECS') { 14 | echo "TODO deploy on AWS" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /remainder-service/README: -------------------------------------------------------------------------------- 1 | # Reminder service 2 | 3 | This is the core of our To-Do project, here we have all functionality related to the To-do. 4 | On this server we tried to add many cool Java things in order to make the project nicer. 5 | 6 | Here we are working with: 7 | Events 8 | EntityListeners 9 | AOP 10 | Optional, extensively 11 | Monitoring 12 | Defensive copying 13 | Maven Multimodules 14 | External messages 15 | Socket 16 | Hibernate 17 | Spring data 18 | Custom Annotations 19 | 20 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/BasicApplication.java: -------------------------------------------------------------------------------- 1 | package com.apssouza; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Import; 6 | import com.apssouza.monitoring.MonitoringConfig; 7 | 8 | @SpringBootApplication 9 | @Import(MonitoringConfig.class) 10 | public class BasicApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(BasicApplication.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/annotations/ChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.annotations; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import org.springframework.beans.factory.annotation.Qualifier; 8 | 9 | @Qualifier 10 | @Retention(RetentionPolicy.RUNTIME) 11 | @Target({ElementType.FIELD, ElementType.TYPE}) 12 | public @interface ChangeEvent { 13 | 14 | Type value(); 15 | 16 | enum Type { 17 | CREATION, UPDATE; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/bootstrap/TodoLoader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.apssouza.bootstrap; 7 | 8 | import com.apssouza.repositories.TodoRepository; 9 | import org.apache.log4j.Logger; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.context.ApplicationListener; 12 | import org.springframework.context.event.ContextRefreshedEvent; 13 | import com.apssouza.entities.ToDo; 14 | import org.springframework.stereotype.Component; 15 | 16 | /** 17 | * 18 | * @author apssouza 19 | */ 20 | @Component 21 | public class TodoLoader implements ApplicationListener { 22 | 23 | private final TodoRepository todoRepository; 24 | private final Logger log = Logger.getLogger(this.getClass().getCanonicalName()); 25 | 26 | @Autowired 27 | public TodoLoader(TodoRepository todoRepository) { 28 | this.todoRepository = todoRepository; 29 | } 30 | 31 | 32 | @Override 33 | public void onApplicationEvent(ContextRefreshedEvent e) { 34 | ToDo todo1 = new ToDo("apssouza22@gmail.com","Test caption", "description 1", 2); 35 | ToDo todo2 = new ToDo("gael@gmail.com","Test caption 2", "description 2", 3); 36 | ToDo todo3 = new ToDo("marcia@gmail.com","Test caption 3", "description 3", 2); 37 | 38 | todoRepository.save(todo1); 39 | todoRepository.save(todo2); 40 | todoRepository.save(todo3); 41 | 42 | log.info("Created the to-dos."); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/configuration/H2DbConfiguration.java: -------------------------------------------------------------------------------- 1 | 2 | package com.apssouza.configuration; 3 | 4 | 5 | import org.h2.server.web.WebServlet; 6 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * Configuration to enable access to the h2db console 12 | * @author apssouza 13 | */ 14 | @Configuration 15 | public class H2DbConfiguration { 16 | @Bean 17 | ServletRegistrationBean h2servletRegistration(){ 18 | ServletRegistrationBean registrationBean = new ServletRegistrationBean( new WebServlet()); 19 | registrationBean.addUrlMappings("/console/*"); 20 | return registrationBean; 21 | } 22 | } 23 | 24 | /** 25 | * If using spring security, we need to add this configuration to the 26 | * Spring security configuration 27 | */ 28 | 29 | /* 30 | package guru.springframework.configuration; 31 | 32 | import org.springframework.context.annotation.Configuration; 33 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 34 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 35 | 36 | @Configuration 37 | public class SecurityConfiguration extends WebSecurityConfigurerAdapter { 38 | 39 | @Override 40 | protected void configure(HttpSecurity httpSecurity) throws Exception { 41 | httpSecurity.authorizeRequests().antMatchers("/").permitAll().and() 42 | .authorizeRequests().antMatchers("/console/**").permitAll(); 43 | 44 | httpSecurity.csrf().disable(); //disable csrf, not recommeded to production 45 | httpSecurity.headers().frameOptions().disable(); //disable X-Frame-Options 46 | } 47 | 48 | } 49 | */ -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/configuration/ServiceDiscoveryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * Enabling Eureka Client 8 | * 9 | * @author apssouza 10 | */ 11 | @Configuration 12 | @EnableDiscoveryClient 13 | public class ServiceDiscoveryConfiguration { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/configuration/WebSocketConfig.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.messaging.simp.config.MessageBrokerRegistry; 5 | import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer; 6 | import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; 7 | import org.springframework.web.socket.config.annotation.StompEndpointRegistry; 8 | 9 | /** 10 | * Web socket configuration. 11 | * 12 | * @author apssouza 13 | */ 14 | @Configuration 15 | @EnableWebSocketMessageBroker 16 | public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { 17 | 18 | @Override 19 | public void configureMessageBroker(MessageBrokerRegistry config) { 20 | config.enableSimpleBroker("/topic"); 21 | config.setApplicationDestinationPrefixes("/app"); 22 | } 23 | 24 | @Override 25 | public void registerStompEndpoints(StompEndpointRegistry registry) { 26 | //no withSockJS() if not working with js 27 | registry.addEndpoint("/socket-todos").setAllowedOrigins("*").withSockJS(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/controllers/TodoChangesController.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.controllers; 2 | 3 | import com.apssouza.events.TodoChangedEvent; 4 | import com.apssouza.monitors.TodoStoreEventChanges; 5 | import java.util.List; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | /** 12 | * Controller to get the To do changes 13 | * 14 | * @author apssouza 15 | */ 16 | @RequestMapping("/todo-changes") 17 | @RestController 18 | public class TodoChangesController { 19 | 20 | @Autowired 21 | TodoStoreEventChanges monitor; 22 | 23 | @GetMapping 24 | public List expose() { 25 | return this.monitor.getRecentEvents(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/controllers/TodoServiceStatisticsController.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.controllers; 2 | 3 | import com.apssouza.monitors.TodoServiceMethodInvokedStore; 4 | import com.fasterxml.jackson.databind.node.JsonNodeFactory; 5 | import com.fasterxml.jackson.databind.node.ObjectNode; 6 | import java.util.LongSummaryStatistics; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RequestMapping("/todo-statistics") 13 | @RestController 14 | public class TodoServiceStatisticsController { 15 | 16 | @Autowired 17 | TodoServiceMethodInvokedStore monitor; 18 | 19 | @GetMapping 20 | public ObjectNode get() { 21 | LongSummaryStatistics statistics = monitor.getStatistics(); 22 | return JsonNodeFactory.instance.objectNode(). 23 | put("average-duration", statistics.getAverage()). 24 | put("invocation-count", statistics.getCount()). 25 | put("min-duration", statistics.getMin()). 26 | put("max-duration", statistics.getMax()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/entities/Attachment.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.entities; 2 | 3 | import java.util.Objects; 4 | import javax.persistence.Entity; 5 | import javax.persistence.GeneratedValue; 6 | import javax.persistence.Id; 7 | import javax.persistence.ManyToOne; 8 | 9 | /** 10 | * To Do's Attachment entity 11 | * 12 | * @author apssouza 13 | */ 14 | @Entity 15 | public class Attachment { 16 | 17 | @Id 18 | @GeneratedValue 19 | private Long id; 20 | 21 | private String name; 22 | 23 | private String type; 24 | 25 | @ManyToOne 26 | private ToDo todo; 27 | 28 | public Attachment() { 29 | } 30 | 31 | 32 | public Attachment(String name, String type) { 33 | this.name = name; 34 | this.type = type; 35 | } 36 | 37 | public Long getId() { 38 | return id; 39 | } 40 | 41 | public void setId(Long id) { 42 | this.id = id; 43 | } 44 | 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | 53 | public String getType() { 54 | return type; 55 | } 56 | 57 | public void setType(String type) { 58 | this.type = type; 59 | } 60 | 61 | public ToDo getTodo() { 62 | return todo; 63 | } 64 | 65 | public void setTodo(ToDo todo) { 66 | this.todo = todo; 67 | } 68 | 69 | @Override 70 | public int hashCode() { 71 | int hash = 7; 72 | hash = 61 * hash + Objects.hashCode(this.id); 73 | return hash; 74 | } 75 | 76 | @Override 77 | public boolean equals(Object obj) { 78 | if (this == obj) { 79 | return true; 80 | } 81 | if (obj == null) { 82 | return false; 83 | } 84 | if (getClass() != obj.getClass()) { 85 | return false; 86 | } 87 | final Attachment other = (Attachment) obj; 88 | if (!Objects.equals(this.id, other.id)) { 89 | return false; 90 | } 91 | return true; 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/entities/Category.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.entities; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import javax.persistence.CascadeType; 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.Id; 9 | import javax.persistence.ManyToMany; 10 | 11 | /** 12 | * To Do's Category entity 13 | * 14 | * @author apssouza 15 | */ 16 | @Entity 17 | public class Category { 18 | 19 | @Id 20 | @GeneratedValue 21 | private Long id; 22 | 23 | private String name; 24 | 25 | @ManyToMany( 26 | mappedBy = "categories", 27 | cascade = {CascadeType.PERSIST, CascadeType.MERGE} 28 | ) 29 | private List todos = new ArrayList<>(); 30 | 31 | ; 32 | 33 | public Category(Long id, String name) { 34 | this.name = name; 35 | this.id = id; 36 | } 37 | 38 | public Category(String name) { 39 | this.name = name; 40 | } 41 | 42 | public Category() { 43 | } 44 | 45 | /** 46 | * Defensive copying Provide an attractive alternative to the rather 47 | * pathological clone method 48 | * 49 | * @param category 50 | * @return Category 51 | */ 52 | public static Category newInstance(Category category) { 53 | return new Category( 54 | category.getId(), 55 | category.getName() 56 | ); 57 | } 58 | 59 | public Long getId() { 60 | return id; 61 | } 62 | 63 | public void setId(Long id) { 64 | this.id = id; 65 | } 66 | 67 | public String getName() { 68 | return name; 69 | } 70 | 71 | public void setName(String name) { 72 | this.name = name; 73 | } 74 | 75 | public List getTodos() { 76 | return todos; 77 | } 78 | 79 | public void setTodos(List todos) { 80 | this.todos = todos; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/events/TodoChangedEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.events; 2 | 3 | import com.apssouza.entities.ToDo; 4 | import com.fasterxml.jackson.annotation.JsonIgnore; 5 | 6 | /** 7 | * Interface To Do changed event 8 | * 9 | * @author apssouza 10 | */ 11 | public interface TodoChangedEvent { 12 | 13 | @JsonIgnore 14 | int getPriority(); 15 | 16 | ToDo getTodo(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/events/TodoCreatedEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.events; 2 | 3 | import com.apssouza.annotations.ChangeEvent; 4 | import com.apssouza.entities.ToDo; 5 | import com.apssouza.infra.AbstractDomainEvent; 6 | 7 | /** 8 | * To Do created event 9 | * 10 | * @author apssouza 11 | */ 12 | @ChangeEvent(ChangeEvent.Type.CREATION) 13 | public class TodoCreatedEvent extends AbstractDomainEvent implements TodoChangedEvent { 14 | 15 | private ToDo todo; 16 | 17 | public TodoCreatedEvent(ToDo todo) { 18 | this.todo = todo; 19 | } 20 | 21 | public TodoCreatedEvent() { 22 | } 23 | 24 | public ToDo getTodo() { 25 | return todo; 26 | } 27 | 28 | public void setTodo(ToDo todo) { 29 | this.todo = todo; 30 | } 31 | 32 | @Override 33 | public int getPriority() { 34 | return this.todo.getPriority(); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | return "TodoChangeEvent{" + "todo=" + todo.getDescription() + '}'; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/events/TodoServiceMethodInvokedEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.events; 2 | 3 | /** 4 | * To Do service method invoked event 5 | * 6 | * @author apssouza 7 | */ 8 | public class TodoServiceMethodInvokedEvent { 9 | 10 | private String methodName; 11 | private long duration; 12 | 13 | public TodoServiceMethodInvokedEvent(String methodName, long duration) { 14 | this.methodName = methodName; 15 | this.duration = duration; 16 | } 17 | 18 | public TodoServiceMethodInvokedEvent() { 19 | } 20 | 21 | public String getMethodName() { 22 | return methodName; 23 | } 24 | 25 | public long getDuration() { 26 | return duration; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "CallEvent{" + "methodName=" + methodName + ", duration=" + duration + '}'; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/events/TodoUpdatedEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.events; 2 | 3 | import com.apssouza.annotations.ChangeEvent; 4 | import com.apssouza.entities.ToDo; 5 | import com.apssouza.infra.AbstractDomainEvent; 6 | 7 | /** 8 | * To Do updated event 9 | * 10 | * @author apssouza 11 | */ 12 | @ChangeEvent(ChangeEvent.Type.UPDATE) 13 | public class TodoUpdatedEvent extends AbstractDomainEvent implements TodoChangedEvent { 14 | 15 | private ToDo todo; 16 | 17 | public TodoUpdatedEvent(ToDo todo) { 18 | this.todo = todo; 19 | } 20 | 21 | public TodoUpdatedEvent() { 22 | } 23 | 24 | public ToDo getTodo() { 25 | return todo; 26 | } 27 | 28 | public void setTodo(ToDo todo) { 29 | this.todo = todo; 30 | } 31 | 32 | public int getPriority() { 33 | return this.todo.getPriority(); 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return "TodoChangeEvent{" + "todo=" + todo.getDescription() + '}'; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/exceptions/DataNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.exceptions; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.bind.annotation.ResponseStatus; 5 | 6 | /** 7 | * Data not found exception response 404 http status to the client 8 | * 9 | * @author Apssouza 10 | */ 11 | @ResponseStatus(HttpStatus.NOT_FOUND) 12 | public class DataNotFoundException extends RuntimeException { 13 | 14 | public DataNotFoundException(String msg) { 15 | super(msg); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/helpers/AutowireHelper.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.helpers; 2 | 3 | import org.springframework.context.ApplicationContextAware; 4 | import org.springframework.context.ApplicationContext; 5 | import org.springframework.stereotype.Component; 6 | 7 | /** 8 | * 9 | * @author apssouza 10 | */ 11 | /** 12 | * Helper class which is able to autowire a specified class. It holds a static 13 | * reference to the {@link org 14 | * .springframework.context.ApplicationContext}. 15 | */ 16 | @Component 17 | public final class AutowireHelper implements ApplicationContextAware { 18 | 19 | private static final AutowireHelper INSTANCE = new AutowireHelper(); 20 | 21 | private static ApplicationContext applicationContext; 22 | 23 | private AutowireHelper() { 24 | } 25 | 26 | /** 27 | * Tries to autowire the specified instance of the class if one of the 28 | * specified beans which need to be autowired are null. 29 | * 30 | * @param classToAutowire the instance of the class which holds @Autowire 31 | * annotations 32 | * @param beansToAutowireInClass the beans which have the @Autowire 33 | * annotation in the specified {#classToAutowire} 34 | */ 35 | public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) { 36 | for (Object bean : beansToAutowireInClass) { 37 | if (bean == null) { 38 | applicationContext.getAutowireCapableBeanFactory().autowireBean(classToAutowire); 39 | return; 40 | } 41 | } 42 | } 43 | 44 | @Override 45 | public void setApplicationContext(final ApplicationContext applicationContext) { 46 | AutowireHelper.applicationContext = applicationContext; 47 | } 48 | 49 | /** 50 | * @return the singleton instance. 51 | */ 52 | public static AutowireHelper getInstance() { 53 | return INSTANCE; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/integrations/socket/TodoChangeSocketNotify.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.integrations.socket; 2 | 3 | import com.apssouza.annotations.ChangeEvent; 4 | import com.apssouza.entities.ToDo; 5 | import com.apssouza.events.TodoChangedEvent; 6 | import com.apssouza.pojos.SocketOutputMessage; 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | import javax.websocket.EncodeException; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.messaging.simp.SimpMessagingTemplate; 13 | import org.springframework.stereotype.Component; 14 | 15 | /** 16 | * Component responsible to notify socket clients. 17 | * 18 | * @author apssouza 19 | */ 20 | @Component 21 | public class TodoChangeSocketNotify { 22 | 23 | @Autowired 24 | private SimpMessagingTemplate template; 25 | 26 | public void notify(TodoChangedEvent e) throws EncodeException { 27 | ToDo todo = e.getTodo(); 28 | String time = new SimpleDateFormat("HH:mm").format(new Date()); 29 | Class aClass = e.getClass(); 30 | 31 | ChangeEvent annotation = aClass.getAnnotation(ChangeEvent.class); 32 | ChangeEvent.Type value = annotation.value(); 33 | SocketOutputMessage socketOutputMessage = new SocketOutputMessage(todo, value.toString(), time); 34 | template.convertAndSend("/topic/todos", socketOutputMessage); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/integrations/socket/TodoSocketController.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.integrations.socket; 2 | 3 | import com.apssouza.pojos.SocketOutputMessage; 4 | import org.springframework.messaging.handler.annotation.MessageMapping; 5 | import org.springframework.messaging.handler.annotation.SendTo; 6 | import org.springframework.stereotype.Controller; 7 | 8 | /** 9 | * A socket endpoint controller 10 | * 11 | * @author apssouza 12 | */ 13 | @Controller 14 | public class TodoSocketController { 15 | 16 | @MessageMapping("/socket-todos") 17 | @SendTo("/topic/todos") 18 | public SocketOutputMessage send(SocketOutputMessage message) throws Exception { 19 | return message; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/listeners/TodoChangedListener.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.listeners; 2 | 3 | import com.apssouza.events.TodoChangedEvent; 4 | import com.apssouza.integrations.socket.TodoChangeSocketNotify; 5 | import com.apssouza.monitors.TodoStoreEventChanges; 6 | import javax.websocket.EncodeException; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.context.event.EventListener; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * ToDo Changed listener. 13 | * 14 | * @author apssouza 15 | */ 16 | @Component 17 | public class TodoChangedListener { 18 | 19 | @Autowired 20 | TodoStoreEventChanges changesMonitor; 21 | 22 | @Autowired 23 | TodoChangeSocketNotify socketNotify; 24 | 25 | @EventListener 26 | public void onTodoChange(TodoChangedEvent event) throws EncodeException { 27 | changesMonitor.addNewEvent(event); 28 | socketNotify.notify(event); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/listeners/TodoServiceMethodListener.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.listeners; 2 | 3 | import com.apssouza.events.TodoServiceMethodInvokedEvent; 4 | import com.apssouza.monitors.TodoServiceMethodInvokedStore; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.event.EventListener; 7 | import org.springframework.stereotype.Component; 8 | 9 | /** 10 | * TodoService method invoked listener 11 | * 12 | * @author apssouza 13 | */ 14 | @Component 15 | public class TodoServiceMethodListener { 16 | 17 | @Autowired 18 | private TodoServiceMethodInvokedStore methodMonitor; 19 | 20 | @EventListener 21 | public void onMethodCalled(TodoServiceMethodInvokedEvent event){ 22 | methodMonitor.addNewEvent(event); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/monitors/ToDoEntityListener.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.monitors; 2 | 3 | import com.apssouza.entities.ToDo; 4 | import com.apssouza.events.TodoCreatedEvent; 5 | import com.apssouza.events.TodoUpdatedEvent; 6 | import com.apssouza.helpers.AutowireHelper; 7 | import com.apssouza.infra.EventPublisher; 8 | import javax.persistence.PostPersist; 9 | import javax.persistence.PostUpdate; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | /** 13 | * ToDo's entity listener 14 | * 15 | * @author apssouza 16 | */ 17 | public class ToDoEntityListener { 18 | 19 | @Autowired 20 | private EventPublisher publisher; 21 | 22 | @PostPersist 23 | public void onPersist(ToDo todo) { 24 | //ToDoPersistenceMonitor is not a spring managed been, so we need to inject 25 | // publisher using this simple helper 26 | AutowireHelper.autowire(this, this.publisher); 27 | this.publisher.publish(new TodoCreatedEvent(todo)); 28 | } 29 | 30 | @PostUpdate 31 | public void onUpdate(ToDo todo) { 32 | AutowireHelper.autowire(this, this.publisher); 33 | this.publisher.publish(new TodoUpdatedEvent(todo)); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/monitors/TodoServiceMethodInvokedStore.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.monitors; 2 | 3 | import com.apssouza.events.TodoServiceMethodInvokedEvent; 4 | import java.util.List; 5 | import java.util.LongSummaryStatistics; 6 | import java.util.concurrent.CopyOnWriteArrayList; 7 | import java.util.stream.Collectors; 8 | import javax.annotation.PostConstruct; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Store TodoService method invoked. 13 | * 14 | * @author apssouza 15 | */ 16 | @Component 17 | public class TodoServiceMethodInvokedStore { 18 | 19 | private CopyOnWriteArrayList events; 20 | 21 | @PostConstruct 22 | public void init() { 23 | this.events = new CopyOnWriteArrayList<>(); 24 | } 25 | 26 | public void addNewEvent(TodoServiceMethodInvokedEvent event) { 27 | this.events.add(event); 28 | } 29 | 30 | public List getRecentChanges() { 31 | return this.events; 32 | } 33 | 34 | public LongSummaryStatistics getStatistics() { 35 | return this.events.stream(). 36 | collect(Collectors.summarizingLong(TodoServiceMethodInvokedEvent::getDuration)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/monitors/TodoStoreEventChanges.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.monitors; 2 | 3 | import com.apssouza.events.TodoChangedEvent; 4 | import java.util.List; 5 | import java.util.LongSummaryStatistics; 6 | import java.util.concurrent.CopyOnWriteArrayList; 7 | import java.util.stream.Collectors; 8 | import javax.annotation.PostConstruct; 9 | import org.springframework.stereotype.Component; 10 | 11 | /** 12 | * Store ToDo event changes. 13 | * 14 | * @author apssouza 15 | */ 16 | @Component 17 | public class TodoStoreEventChanges { 18 | 19 | private CopyOnWriteArrayList events; 20 | 21 | @PostConstruct 22 | public void init() { 23 | this.events = new CopyOnWriteArrayList<>(); 24 | } 25 | 26 | public void addNewEvent(TodoChangedEvent event) { 27 | this.events.add(event); 28 | } 29 | 30 | public List getRecentEvents() { 31 | return this.events; 32 | } 33 | 34 | public LongSummaryStatistics getStatistics() { 35 | return this.events.stream(). 36 | collect(Collectors.summarizingLong(TodoChangedEvent::getPriority)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/pojos/SocketOutputMessage.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.pojos; 2 | 3 | import com.apssouza.entities.ToDo; 4 | 5 | /** 6 | * Socket message output. 7 | * 8 | * @author apssouza 9 | */ 10 | public class SocketOutputMessage { 11 | 12 | private final ToDo todo; 13 | private final String state; 14 | private final String time; 15 | 16 | public SocketOutputMessage(ToDo todo, String state, String time) { 17 | this.todo = todo; 18 | this.state = state; 19 | this.time = time; 20 | } 21 | 22 | public ToDo getTodo() { 23 | return todo; 24 | } 25 | 26 | public String getState() { 27 | return state; 28 | } 29 | 30 | public String getTime() { 31 | return time; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/repositories/AttachmentRepository.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.repositories; 2 | 3 | 4 | import com.apssouza.entities.Attachment; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | /** 9 | * @author apssouza 10 | */ 11 | @Repository 12 | public interface AttachmentRepository extends JpaRepository { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/repositories/CategoryRepository.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.repositories; 2 | 3 | 4 | import com.apssouza.entities.Category; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | /** 9 | * @author apssouza 10 | */ 11 | @Repository 12 | public interface CategoryRepository extends JpaRepository { 13 | 14 | } 15 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/repositories/TodoRepository.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.repositories; 2 | 3 | 4 | import com.apssouza.entities.ToDo; 5 | import java.util.List; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.stereotype.Repository; 8 | 9 | /** 10 | * @author apssouza 11 | */ 12 | @Repository 13 | public interface TodoRepository extends JpaRepository { 14 | 15 | boolean deleteById(Long id); 16 | 17 | List findByUserEmail(String email); 18 | } 19 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/services/TodoService.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.entities.ToDo; 4 | import com.apssouza.exceptions.DataNotFoundException; 5 | import java.util.List; 6 | import java.util.Optional; 7 | 8 | /** 9 | * 10 | * @author apssouza 11 | */ 12 | public interface TodoService { 13 | 14 | Optional findById(long id); 15 | 16 | Boolean delete(long id) throws DataNotFoundException; 17 | 18 | List all(); 19 | 20 | ToDo save(ToDo todo); 21 | 22 | ToDo updateStatus(long id, ToDo.TodoStatus status) throws DataNotFoundException; 23 | 24 | ToDo update(Long id, ToDo toDo) throws DataNotFoundException; 25 | 26 | List getByUserEmail(String email); 27 | } 28 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/services/TodoServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.repositories.TodoRepository; 4 | import com.apssouza.entities.ToDo; 5 | import com.apssouza.events.TodoCreatedEvent; 6 | import com.apssouza.exceptions.DataNotFoundException; 7 | import com.apssouza.infra.EventPublisher; 8 | import com.apssouza.monitoring.CallMonitoringAspect; 9 | import com.apssouza.monitoring.Monitored; 10 | import java.util.List; 11 | import java.util.Optional; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Service; 14 | 15 | @Service 16 | public class TodoServiceImpl implements TodoService { 17 | 18 | @Autowired 19 | private TodoRepository todoRepository; 20 | 21 | @Autowired 22 | private EventPublisher publisher; 23 | 24 | @Override 25 | @Monitored 26 | public Optional findById(long id) { 27 | return Optional.ofNullable(this.todoRepository.findOne(id)); 28 | } 29 | 30 | @Override 31 | @Monitored 32 | public Boolean delete(long id) throws DataNotFoundException { 33 | this.findById(id) 34 | .orElseThrow(() -> new DataNotFoundException("Not found ToDo id " + id)); 35 | 36 | return this.todoRepository.deleteById(id); 37 | } 38 | 39 | @Override 40 | @Monitored 41 | public List all() { 42 | return this.todoRepository.findAll(); 43 | } 44 | 45 | @Override 46 | @Monitored 47 | public ToDo save(ToDo todo) { 48 | ToDo savedTodo = this.todoRepository.save(todo); 49 | this.publisher.stream(new TodoCreatedEvent(savedTodo)); 50 | return savedTodo; 51 | 52 | } 53 | 54 | @Override 55 | @Monitored 56 | public ToDo updateStatus(long id, ToDo.TodoStatus status) throws DataNotFoundException { 57 | return this.findById(id) 58 | .map((t) -> { 59 | t.setStatus(status); 60 | return todoRepository.save(t); 61 | }).orElseThrow(() -> new DataNotFoundException("Not found ToDo id " + id)); 62 | } 63 | 64 | @Override 65 | @Monitored 66 | public ToDo update(Long id, ToDo toDo) throws DataNotFoundException { 67 | return this.findById(id) 68 | .map(todo -> { 69 | todo.setCaption(toDo.getCaption()); 70 | todo.setDescription(toDo.getDescription()); 71 | todo.setPriority(toDo.getPriority()); 72 | return save(todo); 73 | }).orElseThrow(() -> new DataNotFoundException("User not found")); 74 | } 75 | 76 | @Override 77 | @Monitored 78 | public List getByUserEmail(String email) { 79 | return this.todoRepository.findByUserEmail(email); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/validation/CheckIsValid.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.validation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | import javax.validation.Constraint; 9 | import javax.validation.Payload; 10 | 11 | /** 12 | * Check if the instance is valid. 13 | * @author apssouza 14 | */ 15 | @Documented 16 | @Constraint(validatedBy = CrossCheckConstraintValidator.class) 17 | @Target({ElementType.TYPE}) 18 | @Retention(RetentionPolicy.RUNTIME) 19 | public @interface CheckIsValid { 20 | 21 | String message() default "Cross check failed!"; 22 | 23 | Class[] groups() default {}; 24 | 25 | Class[] payload() default {}; 26 | } 27 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/validation/CrossCheckConstraintValidator.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.validation; 2 | 3 | import javax.validation.ConstraintValidator; 4 | import javax.validation.ConstraintValidatorContext; 5 | 6 | /** 7 | * A constraint ToDo validator 8 | * 9 | * @author apssouza 10 | */ 11 | public class CrossCheckConstraintValidator implements ConstraintValidator { 12 | 13 | @Override 14 | public void initialize(CheckIsValid constraintAnnotation) { 15 | } 16 | 17 | @Override 18 | public boolean isValid(ValidEntity entity, ConstraintValidatorContext context) { 19 | return entity.isValid(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /remainder-service/src/main/java/com/apssouza/validation/ValidEntity.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.validation; 2 | 3 | /** 4 | * Valid entity interface 5 | * 6 | * @author apssouza 7 | */ 8 | public interface ValidEntity { 9 | 10 | boolean isValid(); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /remainder-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name = reminder 2 | logging.file=/var/log/todo.log 3 | -------------------------------------------------------------------------------- /remainder-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | cloud: 4 | config: 5 | uri: http://config:8888 6 | -------------------------------------------------------------------------------- /remainder-service/src/main/resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | 4 | MAINTAINER Alexsandro 5 | ENV REFRESHED_AT 2017-09-17 6 | 7 | ENV TERM xterm 8 | ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom 9 | 10 | RUN apt-get update -qq \ 11 | && apt-get install -qqy curl wget \ 12 | && apt-get clean \ 13 | \ 14 | && touch /var/log/todo.log \ 15 | && chmod 666 /var/log/todo.log 16 | 17 | ADD application/lib/springboot-webapp.jar /app.jar 18 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 19 | RUN bash -c 'chmod +x wait-for-it.sh' 20 | 21 | # install Filebeat 22 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 23 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 24 | && dpkg -i ${FILEBEAT_VERSION} \ 25 | && rm ${FILEBEAT_VERSION} 26 | 27 | # configure Filebeat 28 | ADD filebeat.yml /etc/filebeat/filebeat.yml 29 | 30 | # CA cert 31 | RUN mkdir -p /etc/pki/tls/certs 32 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 33 | 34 | # start Filebeat 35 | ADD ./start.sh /usr/local/bin/start.sh 36 | RUN chmod +x /usr/local/bin/start.sh 37 | CMD [ "/usr/local/bin/start.sh" ] -------------------------------------------------------------------------------- /remainder-service/src/main/resources/docker/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - /var/log/todo.log 21 | document_type: log4j 22 | multiline: 23 | pattern: '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}' 24 | negate: true 25 | match: after 26 | - 27 | paths: 28 | - /usr/local/tomcat/logs/*.out 29 | - /usr/local/tomcat/logs/*.log 30 | document_type: tomcat 31 | -------------------------------------------------------------------------------- /remainder-service/src/main/resources/docker/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /remainder-service/src/main/resources/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 6 | -------------------------------------------------------------------------------- /remainder-service/src/test/java/com/apssouza/configuration/RepositoryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.boot.autoconfigure.domain.EntityScan; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 7 | import org.springframework.transaction.annotation.EnableTransactionManagement; 8 | 9 | /** 10 | * 11 | * @author apssouza 12 | */ 13 | @Configuration 14 | @EnableAutoConfiguration 15 | @EnableTransactionManagement 16 | @EntityScan(basePackages = {"com.apssouza.entities"}) 17 | @EnableJpaRepositories(basePackages = {"com.apssouza.repositories"}) 18 | public class RepositoryConfiguration { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /remainder-service/src/test/java/com/apssouza/entities/TodoIT.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this license header, choose License Headers in Project Properties. 3 | * To change this template file, choose Tools | Templates 4 | * and open the template in the editor. 5 | */ 6 | package com.apssouza.entities; 7 | 8 | import com.apssouza.configuration.RepositoryConfiguration; 9 | import java.util.Iterator; 10 | import java.util.Set; 11 | import javax.validation.ConstraintViolation; 12 | import javax.validation.Validation; 13 | import javax.validation.Validator; 14 | import javax.validation.ValidatorFactory; 15 | import org.junit.Assert; 16 | import static org.junit.Assert.assertTrue; 17 | import org.junit.Test; 18 | import org.junit.runner.RunWith; 19 | import org.springframework.boot.test.context.SpringBootTest; 20 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 21 | 22 | /** 23 | * 24 | * @author apssouza 25 | */ 26 | @RunWith(SpringJUnit4ClassRunner.class) 27 | @SpringBootTest(classes = {RepositoryConfiguration.class}) 28 | public class TodoIT { 29 | 30 | 31 | @Test 32 | public void validateTodoValid() { 33 | ToDo toDo = new ToDo("apssouza22@gmail.com","caption", "description 1", 6); 34 | ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 35 | Validator validator = factory.getValidator(); 36 | Set> constraintViolations = validator.validate(toDo); 37 | assertTrue(constraintViolations.isEmpty()); 38 | } 39 | 40 | @Test 41 | public void validateTodoInValid() { 42 | ToDo toDo = new ToDo("apssouza22@gmail.com","c", "description 1", 6); 43 | ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); 44 | Validator validator = factory.getValidator(); 45 | Set> constraintViolations = validator.validate(toDo); 46 | 47 | if (!constraintViolations.isEmpty()) { 48 | Iterator itr = constraintViolations.iterator(); 49 | while (itr.hasNext()) { 50 | ConstraintViolation next = (ConstraintViolation)itr.next(); 51 | Assert.assertEquals("size must be between 2 and 256", next.getMessage()); 52 | } 53 | } 54 | } 55 | 56 | 57 | 58 | } 59 | -------------------------------------------------------------------------------- /todo-infra/README: -------------------------------------------------------------------------------- 1 | # Infra module 2 | 3 | This module contains common components across the services. Ex Kafka integration 4 | with Spring stream, events and etc 5 | -------------------------------------------------------------------------------- /todo-infra/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | todo-infra 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Module - Infra 11 | The common infrastructure across the system 12 | 13 | parent-todo-ms 14 | com.apssouza 15 | 0.0.1-SNAPSHOT 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | org.springframework.cloud 24 | spring-cloud-stream-binder-kafka 25 | 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-stream 30 | 1.2.1.RELEASE 31 | jar 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /todo-infra/src/main/java/com/apssouza/infra/AbstractDomainEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.infra; 2 | 3 | import java.time.Instant; 4 | 5 | /** 6 | * Abstract system event. The domain event across all services 7 | * 8 | * @author apssouza 9 | */ 10 | public abstract class AbstractDomainEvent implements AppEvent { 11 | 12 | protected String uuid; 13 | 14 | protected Instant when = Instant.now(); 15 | 16 | @Override 17 | public String uuid() { 18 | return uuid; 19 | } 20 | 21 | @Override 22 | public Instant when() { 23 | return when; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /todo-infra/src/main/java/com/apssouza/infra/AppEvent.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.infra; 2 | 3 | import java.time.Instant; 4 | 5 | /** 6 | * 7 | * The application event 8 | * 9 | * @author apssouza 10 | */ 11 | public interface AppEvent { 12 | 13 | String uuid(); 14 | 15 | Instant when(); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /todo-infra/src/main/java/com/apssouza/infra/EventPublisher.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.infra; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.cloud.stream.annotation.EnableBinding; 5 | import org.springframework.cloud.stream.messaging.Source; 6 | import org.springframework.context.ApplicationEventPublisher; 7 | import org.springframework.messaging.Message; 8 | import org.springframework.messaging.MessageChannel; 9 | import org.springframework.messaging.support.MessageBuilder; 10 | import org.springframework.stereotype.Component; 11 | 12 | /** 13 | * 14 | * The project event publisher handler We are using distributed event with Kafka 15 | * and local event with Spring event publisher 16 | * 17 | * @author apssouza 18 | */ 19 | @Component 20 | @EnableBinding(Source.class) 21 | public class EventPublisher { 22 | 23 | private final MessageChannel channel; 24 | 25 | private final ApplicationEventPublisher publisher; 26 | 27 | /** 28 | * 29 | * @param source 30 | * @param publisher 31 | */ 32 | @Autowired 33 | public EventPublisher(Source source, ApplicationEventPublisher publisher) { 34 | this.channel = source.output(); 35 | this.publisher = publisher; 36 | } 37 | 38 | public void publish(AppEvent event) { 39 | publisher.publishEvent(event); 40 | } 41 | 42 | public void stream(AppEvent event) { 43 | Message msg = MessageBuilder.withPayload(event) 44 | .setHeader("type", event.getClass().getSimpleName()) 45 | .build(); 46 | channel.send(msg); 47 | System.out.println("published"); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /user-service/Jenkinsfile: -------------------------------------------------------------------------------- 1 | node { 2 | stage('Fetch changes') { 3 | git 'https://github.com/apssouza22/java-microservice.git' 4 | } 5 | stage('Build image') { 6 | // Run the maven build 7 | if (isUnix()) { 8 | sh "mvn -f ./user-service/pom.xml -Pdockerimage docker:build" 9 | } else { 10 | echo "Not ready for windows" 11 | } 12 | } 13 | stage('Deploy ECS') { 14 | echo "TODO deploy on AWS" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /user-service/README: -------------------------------------------------------------------------------- 1 | # User service 2 | 3 | This service is responsible for dealing with users of our system, we use this service to login and user informations 4 | -------------------------------------------------------------------------------- /user-service/nb-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 16 | true 17 | 18 | 19 | -------------------------------------------------------------------------------- /user-service/nbactions-release-profile.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | process-classes 10 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 11 | 12 | 13 | -classpath %classpath com.apssouza.BasicApplication 14 | java 15 | 16 | 17 | 18 | debug 19 | 20 | jar 21 | 22 | 23 | process-classes 24 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 25 | 26 | 27 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -classpath %classpath com.apssouza.BasicApplication 28 | java 29 | true 30 | 31 | 32 | 33 | profile 34 | 35 | jar 36 | 37 | 38 | process-classes 39 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 40 | 41 | 42 | -classpath %classpath com.apssouza.BasicApplication 43 | java 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /user-service/nbactions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | run 5 | 6 | jar 7 | 8 | 9 | spring-boot:run 10 | 11 | 12 | -noverify -XX:TieredStopAtLevel=1 13 | com.example.BasicApplication 14 | always 15 | .nbRestartTrigger 16 | 17 | 18 | 19 | debug 20 | 21 | jar 22 | 23 | 24 | spring-boot:run 25 | 26 | 27 | -Xdebug -Xrunjdwp:transport=dt_socket,server=n,address=${jpda.address} -noverify -XX:TieredStopAtLevel=1 28 | com.example.BasicApplication 29 | always 30 | .nbRestartTrigger 31 | true 32 | 33 | 34 | 35 | profile 36 | 37 | jar 38 | 39 | 40 | process-classes 41 | org.codehaus.mojo:exec-maven-plugin:1.2.1:exec 42 | 43 | 44 | -classpath %classpath com.example.BasicApplication 45 | java 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/BasicApplication.java: -------------------------------------------------------------------------------- 1 | package com.apssouza; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class BasicApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(BasicApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/bootstrap/UserLoader.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.bootstrap; 2 | 3 | import org.apache.log4j.Logger; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.context.ApplicationListener; 6 | import org.springframework.context.event.ContextRefreshedEvent; 7 | import com.apssouza.entities.Account; 8 | import org.springframework.stereotype.Component; 9 | import com.apssouza.repositories.AccountRepository; 10 | 11 | /** 12 | * An User data loader into database 13 | * 14 | * @author apssouza 15 | */ 16 | @Component 17 | public class UserLoader implements ApplicationListener { 18 | 19 | private final AccountRepository userRepository; 20 | 21 | private final Logger log = Logger.getLogger(this.getClass().getCanonicalName()); 22 | 23 | @Autowired 24 | public UserLoader(AccountRepository todoRepository) { 25 | this.userRepository = todoRepository; 26 | } 27 | 28 | @Override 29 | public void onApplicationEvent(ContextRefreshedEvent e) { 30 | Account user1 = new Account("Alex lindo", "apssouza22@gmail.com", "1234"); 31 | Account user2 = new Account("Gaekke delicia", "gaelle@meama.com", "2222"); 32 | Account user3 = new Account("Márcia almeida", "marciapalito@hotmail.com", "2222"); 33 | 34 | userRepository.save(user1); 35 | userRepository.save(user2); 36 | userRepository.save(user3); 37 | 38 | log.info("Created the todos."); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/configuration/H2DbConfiguration.java: -------------------------------------------------------------------------------- 1 | 2 | package com.apssouza.configuration; 3 | 4 | 5 | import org.h2.server.web.WebServlet; 6 | import org.springframework.boot.web.servlet.ServletRegistrationBean; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | /** 11 | * Configuration to enable access to the h2db console 12 | * @author apssouza 13 | */ 14 | @Configuration 15 | public class H2DbConfiguration { 16 | @Bean 17 | ServletRegistrationBean h2servletRegistration(){ 18 | ServletRegistrationBean registrationBean = new ServletRegistrationBean( new WebServlet()); 19 | registrationBean.addUrlMappings("/console/*"); 20 | return registrationBean; 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/configuration/ServiceDiscoveryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.configuration; 2 | 3 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 4 | import org.springframework.context.annotation.Configuration; 5 | 6 | /** 7 | * Eureka service discovery client configuration 8 | * 9 | * @author apssouza 10 | */ 11 | @Configuration 12 | @EnableDiscoveryClient 13 | public class ServiceDiscoveryConfiguration { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/controllers/AccountController.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.controllers; 2 | 3 | import com.apssouza.entities.Account; 4 | import com.apssouza.exceptions.DataNotFoundException; 5 | import java.net.URI; 6 | import java.util.List; 7 | import java.util.Optional; 8 | import javax.validation.Valid; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.web.bind.annotation.GetMapping; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.PostMapping; 15 | import org.springframework.web.bind.annotation.PutMapping; 16 | import org.springframework.web.bind.annotation.RequestBody; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RestController; 19 | import org.springframework.web.servlet.support.ServletUriComponentsBuilder; 20 | import com.apssouza.services.AccountService; 21 | import org.springframework.web.bind.annotation.RequestParam; 22 | 23 | /** 24 | * Account's entry points 25 | * 26 | * @author apssouza 27 | */ 28 | @RequestMapping("/accounts") 29 | @RestController 30 | public class AccountController { 31 | 32 | @Autowired 33 | AccountService userService; 34 | 35 | @Autowired 36 | public AccountController( 37 | AccountService userService 38 | ) { 39 | this.userService = userService; 40 | } 41 | 42 | @GetMapping 43 | public List all() { 44 | return userService.all(); 45 | } 46 | 47 | @PostMapping 48 | public ResponseEntity save(@RequestBody @Valid Account account) { 49 | Account saved = this.userService.save(account); 50 | Long id = saved.getId(); 51 | if (id != null) { 52 | URI location = ServletUriComponentsBuilder 53 | .fromCurrentRequest().path("/{id}") 54 | .buildAndExpand(id).toUri(); 55 | return ResponseEntity.created(location).build(); 56 | } 57 | return ResponseEntity.noContent().build(); 58 | } 59 | 60 | @PutMapping("{id}") 61 | public ResponseEntity update( 62 | @PathVariable long id, 63 | @RequestBody @Valid Account user 64 | ) { 65 | return ResponseEntity.ok(userService.update(id, user)); 66 | } 67 | 68 | @GetMapping("{id}") 69 | public ResponseEntity find(@PathVariable long id) { 70 | Optional findById = userService.findById(id); 71 | return findById.map(todo -> { 72 | return ResponseEntity.ok(todo); 73 | }).orElseThrow( 74 | () -> new DataNotFoundException("user not found") 75 | ); 76 | } 77 | 78 | @GetMapping("search") 79 | public ResponseEntity find(@RequestParam("email") String email) { 80 | Optional account = userService.findByEmail(email); 81 | return account.map(a -> { 82 | return ResponseEntity.ok(a); 83 | }).orElseThrow( 84 | () -> new DataNotFoundException("user not found") 85 | ); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/entities/Account.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.entities; 2 | 3 | import javax.persistence.Column; 4 | import javax.validation.constraints.NotNull; 5 | import javax.validation.constraints.Size; 6 | import javax.persistence.Entity; 7 | import javax.persistence.GeneratedValue; 8 | import javax.persistence.Id; 9 | import javax.persistence.Version; 10 | import org.hibernate.validator.constraints.Email; 11 | 12 | /** 13 | * Account Entity 14 | * 15 | * @author apssouza 16 | */ 17 | @Entity 18 | public class Account { 19 | 20 | @Id 21 | @GeneratedValue 22 | private long id; 23 | 24 | @NotNull 25 | private String password; 26 | 27 | @NotNull 28 | @Size(min = 2, max = 256) 29 | private String name; 30 | 31 | @Email 32 | @NotNull 33 | @Column(unique = true) 34 | private String email; 35 | 36 | @Version 37 | private long version; 38 | 39 | public Account() { 40 | } 41 | 42 | public Account(String name, String email, String pass) { 43 | this.name = name; 44 | this.email = email; 45 | this.password = pass; 46 | } 47 | 48 | public long getId() { 49 | return id; 50 | } 51 | 52 | public void setId(long id) { 53 | this.id = id; 54 | } 55 | 56 | public String getName() { 57 | return name; 58 | } 59 | 60 | public void setName(String name) { 61 | this.name = name; 62 | } 63 | 64 | public String getEmail() { 65 | return email; 66 | } 67 | 68 | public void setEmail(String email) { 69 | this.email = email; 70 | } 71 | 72 | public String getPassword() { 73 | return password; 74 | } 75 | 76 | public void setAuthId(String pass) { 77 | this.password = pass; 78 | } 79 | 80 | public long getVersion() { 81 | return version; 82 | } 83 | 84 | public void setVersion(long version) { 85 | this.version = version; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/exceptions/DataNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.exceptions; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.web.bind.annotation.ResponseStatus; 5 | 6 | /** 7 | * Data not found exception. It will return the Not found HTTP status code 8 | * 9 | * @author Apssouza 10 | */ 11 | @ResponseStatus(HttpStatus.NOT_FOUND) 12 | public class DataNotFoundException extends RuntimeException { 13 | 14 | public DataNotFoundException(String msg) { 15 | super(msg); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/repositories/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.repositories; 2 | 3 | import com.apssouza.entities.Account; 4 | import java.util.Optional; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | /** 9 | * Account interface repository 10 | * 11 | * @author apssouza 12 | */ 13 | @Repository 14 | public interface AccountRepository extends JpaRepository { 15 | 16 | Optional findByEmail(String email); 17 | } 18 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/services/AccountService.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.entities.Account; 4 | import com.apssouza.exceptions.DataNotFoundException; 5 | import java.util.List; 6 | import java.util.Optional; 7 | 8 | /** 9 | * Account service interface 10 | * 11 | * @author apssouza 12 | */ 13 | public interface AccountService { 14 | 15 | Optional findById(long id); 16 | 17 | List all(); 18 | 19 | Account save(Account user); 20 | 21 | Account update(Long id, Account user) throws DataNotFoundException; 22 | 23 | Optional findByEmail(String name); 24 | 25 | void delete(Account a); 26 | } 27 | -------------------------------------------------------------------------------- /user-service/src/main/java/com/apssouza/services/AccountServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.apssouza.services; 2 | 3 | import com.apssouza.entities.Account; 4 | import com.apssouza.exceptions.DataNotFoundException; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import com.apssouza.repositories.AccountRepository; 10 | 11 | /** 12 | * @see AccountService 13 | * @author apssouza 14 | */ 15 | @Service 16 | public class AccountServiceImpl implements AccountService { 17 | 18 | @Autowired 19 | private AccountRepository accountRepository; 20 | 21 | @Override 22 | public Optional findById(long id) { 23 | return Optional.ofNullable(this.accountRepository.findOne(id)); 24 | } 25 | 26 | @Override 27 | public List all() { 28 | return this.accountRepository.findAll(); 29 | } 30 | 31 | @Override 32 | public Account save(Account user) { 33 | return this.accountRepository.save(user); 34 | } 35 | 36 | @Override 37 | public Account update(Long id, Account user) throws DataNotFoundException { 38 | return this.findById(id) 39 | .map(u -> { 40 | u.setEmail(user.getEmail()); 41 | u.setName(user.getName()); 42 | u.setAuthId(user.getPassword()); 43 | return save(u); 44 | }).orElseThrow(() -> new DataNotFoundException("User not found")); 45 | } 46 | 47 | @Override 48 | public Optional findByEmail(String email) { 49 | return accountRepository.findByEmail(email); 50 | } 51 | 52 | @Override 53 | public void delete(Account a) { 54 | accountRepository.delete(a); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /user-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name = user 2 | 3 | # Root logger option 4 | log4j.rootLogger=INFO, file, stdout 5 | 6 | # Direct log messages to a log file 7 | log4j.appender.file=org.apache.log4j.RollingFileAppender 8 | log4j.appender.file.File=/var/log/todo.log 9 | log4j.appender.file.MaxFileSize=10MB 10 | log4j.appender.file.MaxBackupIndex=10 11 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 12 | log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 13 | 14 | # Direct log messages to stdout 15 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 16 | log4j.appender.stdout.Target=System.out 17 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 18 | log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n 19 | 20 | 21 | # Hibernate logging options (INFO only shows startup messages) 22 | # Log JDBC bind parameter runtime arguments 23 | 24 | log4j.logger.org.hibernate.SQL=debug 25 | log4j.logger.org.hibernate.type=trace 26 | log4j.logger.org.hibernate.type.descriptor.sql=trace 27 | -------------------------------------------------------------------------------- /user-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | --- 2 | spring: 3 | cloud: 4 | config: 5 | uri: http://config:8888 6 | -------------------------------------------------------------------------------- /user-service/src/main/resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8 2 | 3 | 4 | MAINTAINER Alexsandro 5 | ENV REFRESHED_AT 2017-09-17 6 | 7 | ENV TERM xterm 8 | ENV JAVA_OPTS -Djava.security.egd=file:/dev/./urandom 9 | 10 | RUN apt-get update -qq \ 11 | && apt-get install -qqy curl wget \ 12 | && apt-get clean \ 13 | \ 14 | && touch /var/log/todo.log \ 15 | && chmod 666 /var/log/todo.log 16 | 17 | ADD application/lib/springboot-webapp.jar /app.jar 18 | ADD https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh wait-for-it.sh 19 | RUN bash -c 'chmod +x wait-for-it.sh' 20 | 21 | # install Filebeat 22 | ENV FILEBEAT_VERSION=filebeat_1.2.3_amd64.deb 23 | RUN curl -L -O https://download.elastic.co/beats/filebeat/${FILEBEAT_VERSION} \ 24 | && dpkg -i ${FILEBEAT_VERSION} \ 25 | && rm ${FILEBEAT_VERSION} 26 | 27 | # configure Filebeat 28 | ADD filebeat.yml /etc/filebeat/filebeat.yml 29 | 30 | # CA cert 31 | RUN mkdir -p /etc/pki/tls/certs 32 | ADD logstash-beats.crt /etc/pki/tls/certs/logstash-beats.crt 33 | 34 | # start Filebeat 35 | ADD ./start.sh /usr/local/bin/start.sh 36 | RUN chmod +x /usr/local/bin/start.sh 37 | CMD [ "/usr/local/bin/start.sh" ] -------------------------------------------------------------------------------- /user-service/src/main/resources/docker/filebeat.yml: -------------------------------------------------------------------------------- 1 | output: 2 | logstash: 3 | enabled: true 4 | hosts: 5 | - elk:5044 6 | timeout: 15 7 | tls: 8 | certificate_authorities: 9 | - /etc/pki/tls/certs/logstash-beats.crt 10 | 11 | filebeat: 12 | prospectors: 13 | - 14 | paths: 15 | - /var/log/syslog 16 | - /var/log/auth.log 17 | document_type: syslog 18 | - 19 | paths: 20 | - /var/log/todo.log 21 | document_type: log4j 22 | multiline: 23 | pattern: '^[[:digit:]]{4}-[[:digit:]]{2}-[[:digit:]]{2}' 24 | negate: true 25 | match: after 26 | - 27 | paths: 28 | - /usr/local/tomcat/logs/*.out 29 | - /usr/local/tomcat/logs/*.log 30 | document_type: tomcat 31 | -------------------------------------------------------------------------------- /user-service/src/main/resources/docker/logstash-beats.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC6zCCAdOgAwIBAgIJANPZwuf+5wTLMA0GCSqGSIb3DQEBCwUAMAwxCjAIBgNV 3 | BAMMASowHhcNMTUxMjI4MTA0NTMyWhcNMjUxMjI1MTA0NTMyWjAMMQowCAYDVQQD 4 | DAEqMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+jHFvhyYKiPXc7k 5 | 0c33f2QV+1hHNyW/uwcJbp5jG82cuQ41v70Z1+b2veBW4sUlDY3yAIEOPSUD8ASt 6 | 9m72CAo4xlwYKDvm/Sa3KJtDk0NrQiz6PPyBUFsY+Bj3xn6Nz1RW5YaP+Q1Hjnks 7 | PEyQu4vLgfTSGYBHLD4gvs8wDWY7aaKf8DfuP7Ov74Qlj2GOxnmiDEF4tirlko0r 8 | qQcvBgujCqA7rNoG+QDmkn3VrxtX8mKF72bxQ7USCyoxD4cWV2mU2HD2Maed3KHj 9 | KAvDAzSyBMjI+qi9IlPN5MR7rVqUV0VlSKXBVPct6NG7x4WRwnoKjTXnr3CRADD0 10 | 4uvbQQIDAQABo1AwTjAdBgNVHQ4EFgQUVFurgDwdcgnCYxszc0dWMWhB3DswHwYD 11 | VR0jBBgwFoAUVFurgDwdcgnCYxszc0dWMWhB3DswDAYDVR0TBAUwAwEB/zANBgkq 12 | hkiG9w0BAQsFAAOCAQEAaLSytepMb5LXzOPr9OiuZjTk21a2C84k96f4uqGqKV/s 13 | okTTKD0NdeY/IUIINMq4/ERiqn6YDgPgHIYvQheWqnJ8ir69ODcYCpsMXIPau1ow 14 | T8c108BEHqBMEjkOQ5LrEjyvLa/29qJ5JsSSiULHvS917nVgY6xhcnRZ0AhuJkiI 15 | ARKXwpO5tqJi6BtgzX/3VDSOgVZbvX1uX51Fe9gWwPDgipnYaE/t9TGzJEhKwSah 16 | kNr+7RM+Glsv9rx1KcWcx4xxY3basG3/KwvsGAFPvk5tXbZ780VuNFTTZw7q3p8O 17 | Gk1zQUBOie0naS0afype5qFMPp586SF/2xAeb68gLg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /user-service/src/main/resources/docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | curl -XPUT 'http://elk:9200/_template/filebeat?pretty' -d@/etc/filebeat/filebeat.template.json 4 | /etc/init.d/filebeat start 5 | java -Djava.security.egd=file:/dev/./urandom -jar /app.jar 6 | --------------------------------------------------------------------------------