├── .gitignore ├── LICENSE ├── README.md ├── admin ├── .gitignore ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── packtpub │ │ │ └── yummy │ │ │ └── admin │ │ │ └── AdminApplication.java │ └── resources │ │ ├── application.yaml │ │ └── bootstrap.yaml │ └── test │ └── java │ └── com │ └── packtpub │ └── yummy │ └── admin │ └── AdminApplicationTests.java ├── baselayout ├── pom.xml └── src │ └── main │ └── resources │ └── templates │ └── layout.html ├── bookmarks ├── .bowerrc ├── Dockerfile ├── SERVICE.marker ├── bower.json ├── mvnw ├── mvnw.cmd ├── pom.xml ├── seleniumdriver │ └── chromedriver └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── packtpub │ │ │ └── yummy │ │ │ ├── BookmarksApplication.java │ │ │ ├── config │ │ │ ├── AmqpConfig.java │ │ │ ├── DataInitialization.java │ │ │ ├── ErrorAdvice.java │ │ │ ├── SecurityConfig.java │ │ │ └── WebConfig.java │ │ │ ├── model │ │ │ ├── Bookmark.java │ │ │ └── BookmarkResourceAssembler.java │ │ │ ├── rest │ │ │ ├── BookmarkController.java │ │ │ ├── BookmarksController.java │ │ │ └── ServiceDocumentController.java │ │ │ ├── service │ │ │ ├── BookmarkRowMapper.java │ │ │ └── BookmarkService.java │ │ │ └── ui │ │ │ ├── BookmarkUiController.java │ │ │ └── HomeController.java │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── application.yaml │ │ ├── bootstrap.yaml │ │ ├── db │ │ └── migration │ │ │ ├── V1.1__init.sql │ │ │ ├── V1.2__add_more_fields.sql │ │ │ └── V1.3__create_user_tables.sql │ │ ├── static │ │ └── components │ │ │ ├── bookmark-form.html │ │ │ ├── bookmarks-view.html │ │ │ └── elements.html │ │ └── templates │ │ ├── bookmark │ │ └── details.html │ │ └── index.html │ └── test │ ├── java │ └── com │ │ └── packtpub │ │ └── yummy │ │ ├── MessagingTest.java │ │ ├── YummyApplicationTests.java │ │ └── rest │ │ ├── BookmarkControllerTest.java │ │ ├── BookmarksControllerTest.java │ │ └── ServiceDocumentControllerTest.java │ └── resources │ ├── application.properties │ └── bootstrap.yaml ├── configserver ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── packtpub │ │ │ └── yummy │ │ │ └── configserver │ │ │ └── ConfigServerApplication.java │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── bootstrap.yaml │ │ └── configs │ │ ├── application-dev.yaml │ │ ├── application-docker.yaml │ │ └── application.yaml │ └── test │ ├── java │ └── com │ │ └── packtpub │ │ └── yummy │ │ └── configserver │ │ └── ConfigServerApplicationTests.java │ └── resources │ └── application.properties ├── hystrixdashboard ├── .gitignore ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── packtpub │ │ │ └── yummy │ │ │ └── hystrixdashboard │ │ │ └── HystrixdashboardApplication.java │ └── resources │ │ └── application.properties │ └── test │ └── java │ └── com │ └── packtpub │ └── yummy │ └── hystrixdashboard │ └── HystrixdashboardApplicationTests.java ├── ratings ├── .bowerrc ├── .gitignore ├── Dockerfile ├── bower.json ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── packtpub │ │ │ └── yummy │ │ │ └── ratings │ │ │ ├── EventService.java │ │ │ ├── RatingController.java │ │ │ ├── RatingRepository.java │ │ │ ├── RatingResult.java │ │ │ ├── RatingVote.java │ │ │ ├── RatingsApplication.java │ │ │ └── config │ │ │ ├── AmqpConfig.java │ │ │ ├── ErrorAdvice.java │ │ │ ├── SecurityConfig.java │ │ │ └── WebConfig.java │ └── resources │ │ ├── application.yaml │ │ ├── bootstrap.yaml │ │ ├── db │ │ └── migration │ │ │ └── V1.1__initial.sql │ │ └── static │ │ └── components │ │ └── rating-ctrl.html │ └── test │ ├── java │ └── com │ │ └── packtpub │ │ └── yummy │ │ └── ratings │ │ ├── MessagingTests.java │ │ └── RatingsApplicationTests.java │ └── resources │ ├── application.properties │ └── bootstrap.yaml ├── reverseproxy ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── packtpub │ │ │ └── yummy │ │ │ └── reverseproxy │ │ │ ├── CorrelationIdZuulFilter.java │ │ │ ├── ErrorPageController.java │ │ │ ├── ReverseProxyApplication.java │ │ │ └── ZuulLoginFilter.java │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── application.yaml │ │ └── bootstrap.yaml │ └── test │ ├── java │ └── com │ │ └── packtpub │ │ └── yummy │ │ └── reverseproxy │ │ └── ReverseProxyApplicationTests.java │ └── resources │ └── bootstrap.yaml ├── serviceregistry ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── packtpub │ │ │ └── yummy │ │ │ └── serviceregistry │ │ │ └── ServiceRegistryApplication.java │ └── resources │ │ ├── META-INF │ │ └── spring.factories │ │ ├── application.yaml │ │ └── bootstrap.yaml │ └── test │ ├── java │ └── com │ │ └── packtpub │ │ └── yummy │ │ └── serviceregistry │ │ └── ServiceRegistryApplicationTests.java │ └── resources │ └── bootstrap.yaml ├── setup ├── buildAll.sh ├── dc-common.yaml ├── docker-compose.yaml ├── helper_buildIn.sh ├── kubernetes │ ├── admin-pod.yaml │ ├── bookmarks-service-pod.yaml │ ├── configserver-pod.yaml │ ├── hystrixdashboard-pod.yaml │ ├── kubernetes-dashboard.yaml │ ├── mysqlbm-pod.yaml │ ├── mysqlra-pod.yaml │ ├── mysqlus-pod.yaml │ ├── nginx-ingress.yaml │ ├── rabbitmq-pod.yaml │ ├── ratings-service-pod.yaml │ ├── redis-pod.yaml │ ├── redisCommander-pod.yaml │ ├── reverseproxy-pod.yaml │ ├── serviceregistry-pod.yaml │ ├── turbine-pod.yaml │ ├── users-service-pod.yaml │ └── zipkin-pod.yaml ├── runAll.sh ├── startInfraServices.sh ├── stopAll.sh └── stopService.sh ├── turbine ├── .gitignore ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── packtpub │ │ │ └── yummy │ │ │ └── turbine │ │ │ └── TurbineApplication.java │ └── resources │ │ ├── application.yaml │ │ └── bootstrap.yaml │ └── test │ └── java │ └── com │ └── packtpub │ └── yummy │ └── turbine │ └── TurbineApplicationTests.java └── users ├── .gitignore ├── Dockerfile ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── packtpub │ │ └── yummy │ │ └── users │ │ ├── UsersApplication.java │ │ ├── config │ │ ├── DataInitialization.java │ │ ├── SecurityConfig.java │ │ └── WebConfig.java │ │ └── service │ │ └── UserService.java └── resources │ ├── META-INF │ └── spring.factories │ ├── application.yaml │ ├── bootstrap.yaml │ ├── db │ └── migration │ │ └── V1.0__init.sql │ └── templates │ └── login.html └── test ├── java └── com │ └── packtpub │ └── yummy │ └── users │ └── UsersApplicationTests.java └── resources ├── application.properties └── bootstrap.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .mvn/ 3 | *.iml 4 | .DS_Store 5 | rabbitmq 6 | target/ 7 | !.mvn/wrapper/maven-wrapper.jar 8 | application.pid 9 | 10 | ### STS ### 11 | .apt_generated 12 | .classpath 13 | .factorypath 14 | .project 15 | .settings 16 | .springBeans 17 | 18 | ### IntelliJ IDEA ### 19 | .idea 20 | *.iws 21 | *.ipr 22 | 23 | ### NetBeans ### 24 | nbproject/private/ 25 | build/ 26 | nbbuild/ 27 | dist/ 28 | nbdist/ 29 | .nb-gradle/ 30 | 31 | bower_components -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Packt 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Microservices with Spring Cloud [Integrated Course] 5 | This is the code repository for [Microservices with Spring Cloud [Integrated Course]](https://www.packtpub.com/virtualization-and-cloud/microservices-spring-cloud-integrated-course?utm_source=github&utm_medium=repository&utm_campaign=9781788392426), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the video course from start to finish. 6 | ## About the Video Course 7 | In this course, you will learn how to split an existing application into smaller services and what you need to build, deploy, and run it. You will learn how you can use Docker to support your local development and how you can utilize it to run your application in the cloud. To work with multiple services, you will need (for example) service discovery and reverse proxies. To be able to maintain the development pace, you also need to break up your user interface, so every service can serve its own UI, and you need to learn how to communicate with these services synchronously using REST and asynchronously using events. To run your application, you need to know what is going on in your distributed application, so monitoring and tracing calls is an important topic as well, and one that you'll learn about. So overall, this course will give you valuable insights and recipes with which to create your own distributed application, for deployment to the cloud. 8 | 9 | You will also see what needs to be done to upgrade a spring boot 1.x service to spring boot 2 with the recent spring cloud release. 10 | 11 |

What You Will Learn

12 |
13 |
18 | 19 | ## Instructions and Navigation 20 | ### Assumed Knowledge 21 | To fully benefit from the coverage included in this course, you will need:
22 | 23 |  Spring Framework knowledge 24 | 25 |  Spring Boot knowledge, ideally from lesson 1-2 of this course 26 | 27 |  An understanding of basic HTML and CSS syntax 28 | 29 |  (Optional) Experience with deployment of java services 30 | 31 | ### Technical Requirements 32 | This course has the following software requirements:
33 |  IntelliJ IDEA (ideally ultimate, there is a trial version for 30 days!) 34 | 35 |  Java 8+ 36 | 37 |  Maven 3,x (also included in intelliJ) 38 | 39 | This course has been tested on the following system configuration: 40 | 41 |  OS: Windows 7, MacOS 42 | 43 |  Processor: Quad Core 3.0 Ghz 44 | 45 |  Memory: 16GB 46 | 47 |  Hard Disk Space: 500MB 48 | 49 | 50 | ## Related Products 51 | * [Spring Boot - Getting Started [Integrated Course]](https://www.packtpub.com/web-development/spring-boot-getting-started-integrated-course?utm_source=github&utm_medium=repository&utm_campaign=9781788298636) 52 | 53 | * [Advanced Spring Boot [Integrated Course]](https://www.packtpub.com/web-development/advanced-spring-boot-integrated-course?utm_source=github&utm_medium=repository&utm_campaign=9781788392297) 54 | 55 | * [Hands-on Application Development with Spring Boot 2.0 [Video]](https://www.packtpub.com/application-development/hands-application-development-spring-boot-20-video?utm_source=github&utm_medium=repository&utm_campaign=9781789137712) 56 | 57 | ### Download a free PDF 58 | 59 | If you have already purchased a print or Kindle version of this book, you can get a DRM-free PDF version at no cost.
Simply click on the link to claim your free PDF.
60 |

https://packt.link/free-ebook/9781788392426

-------------------------------------------------------------------------------- /admin/.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 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /admin/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 4 | 5 | COPY target/service.jar /usr/app/service.jar 6 | EXPOSE 8080 11111 7 | ENV ENVIRONMENT="local" 8 | # do not use ENTRYPOINT ["java", "-XX..."] it doesn't use environment variables for parameters! 9 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --spring.profiles.active=$ENVIRONMENT,docker --spring.cloud.config.uri=http://configserver:8888 -------------------------------------------------------------------------------- /admin/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /admin/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.packtpub.yummy 7 | admin 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | admin 12 | Admin project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 2.0.1 26 | Finchley.RELEASE 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-actuator 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-web 37 | 38 | 39 | de.codecentric 40 | spring-boot-admin-starter-server 41 | 42 | 43 | org.springframework.cloud 44 | spring-cloud-starter-bus-amqp 45 | 46 | 47 | org.springframework.cloud 48 | spring-cloud-starter-config 49 | 50 | 51 | org.springframework.cloud 52 | spring-cloud-starter-netflix-eureka-client 53 | 54 | 55 | 56 | org.springframework.boot 57 | spring-boot-starter-test 58 | test 59 | 60 | 61 | 62 | 63 | 64 | 65 | org.springframework.cloud 66 | spring-cloud-dependencies 67 | ${spring-cloud.version} 68 | pom 69 | import 70 | 71 | 72 | de.codecentric 73 | spring-boot-admin-dependencies 74 | ${spring-boot-admin.version} 75 | pom 76 | import 77 | 78 | 79 | 80 | 81 | 82 | service 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-maven-plugin 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /admin/src/main/java/com/packtpub/yummy/admin/AdminApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.admin; 2 | 3 | import de.codecentric.boot.admin.server.config.EnableAdminServer; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @SpringBootApplication 8 | @EnableAdminServer 9 | public class AdminApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(AdminApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /admin/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | 2 | server.port: 6060 3 | -------------------------------------------------------------------------------- /admin/src/main/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: 'admin' 3 | cloud: 4 | config: 5 | enabled: true 6 | failFast: true 7 | retry: 8 | max-attempts: 60 9 | discovery: 10 | enabled: false 11 | uri: 'http://localhost:8888' 12 | 13 | -------------------------------------------------------------------------------- /admin/src/test/java/com/packtpub/yummy/admin/AdminApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.admin; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class AdminApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /baselayout/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.packtpub.yummy 8 | baselayout 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-dependencies 16 | 2.0.3.RELEASE 17 | pom 18 | import 19 | 20 | 21 | 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-thymeleaf 26 | 27 | 28 | org.thymeleaf.extras 29 | thymeleaf-extras-springsecurity4 30 | 31 | 32 | org.thymeleaf.extras 33 | thymeleaf-extras-java8time 34 | 35 | 36 | org.webjars 37 | bootstrap 38 | 3.3.7-1 39 | 40 | 41 | org.webjars 42 | webjars-locator 43 | 0.34 44 | 45 | 46 | -------------------------------------------------------------------------------- /baselayout/src/main/resources/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | List of all bookmarks 9 | 11 | 12 | 13 | 14 |
15 |

List of all bookmarks

16 |
17 |
18 | 19 | Login 20 | 21 |
22 |
23 | Hello Username 24 |
25 | 26 |
27 |
28 |
29 |
30 | 31 | 38 | 39 | -------------------------------------------------------------------------------- /bookmarks/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "src/main/resources/static/components/bower_components" 3 | } -------------------------------------------------------------------------------- /bookmarks/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 4 | 5 | COPY target/service.jar /usr/app/service.jar 6 | EXPOSE 8080 11111 7 | ENV ENVIRONMENT="local" 8 | ENV DB_NAME="db" 9 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --spring.profiles.active=$ENVIRONMENT,docker --db.name=$DB_NAME --spring.cloud.config.uri=http://configserver:8888 -------------------------------------------------------------------------------- /bookmarks/SERVICE.marker: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Microservices-with-Spring-Cloud/948b1efd780fd1c20bca134f98395882df976c5c/bookmarks/SERVICE.marker -------------------------------------------------------------------------------- /bookmarks/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bookmarks", 3 | "dependencies": { 4 | "polymer": "Polymer/polymer#^2.0.0", 5 | "bower": "*", 6 | "iron-ajax": "PolymerElements/iron-ajax#^2.1.3", 7 | "install": "^1.0.4", 8 | "paper-input": "polymerelements/paper-input#^2.2.3", 9 | "paper-button": "polymerelements/paper-button#^2.1.1", 10 | "paper-dialog": "polymerelements/paper-dialog#^2.1.1", 11 | "iron-star-rating": "chadweimer/iron-star-rating#^2.0.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /bookmarks/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /bookmarks/seleniumdriver/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Microservices-with-Spring-Cloud/948b1efd780fd1c20bca134f98395882df976c5c/bookmarks/seleniumdriver/chromedriver -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/BookmarksApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 7 | import org.springframework.context.ConfigurableApplicationContext; 8 | import org.springframework.retry.annotation.EnableRetry; 9 | import org.springframework.web.context.support.StandardServletEnvironment; 10 | 11 | import java.util.Arrays; 12 | 13 | @SpringBootApplication 14 | @EnableCircuitBreaker 15 | @EnableRetry 16 | @Slf4j 17 | public class BookmarksApplication { 18 | 19 | public static void main(String[] args) { 20 | SpringApplication app = new SpringApplication(BookmarksApplication.class); 21 | if (noActiveProfiles(args)) { 22 | app.setAdditionalProfiles("dev", System.getProperty("user.name")); 23 | } 24 | ConfigurableApplicationContext context = app.run(args); 25 | 26 | log.info(""); 27 | log.info("#######################"); 28 | log.info("##### Initialized! ####"); 29 | log.info("#######################"); 30 | log.info(" go to: http://localhost:8080"); 31 | } 32 | 33 | private static boolean noActiveProfiles(String[] args) { 34 | return new StandardServletEnvironment().getActiveProfiles().length == 0 35 | && Arrays.stream(args) 36 | .noneMatch(param -> param.startsWith("--spring.profiles.active")); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/config/AmqpConfig.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.config; 2 | 3 | import org.springframework.cloud.stream.annotation.EnableBinding; 4 | import org.springframework.cloud.stream.annotation.Output; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.messaging.MessageChannel; 7 | 8 | @Configuration 9 | @EnableBinding(AmqpConfig.EventSource.class) 10 | public class AmqpConfig { 11 | public interface EventSource { 12 | String BOOKMARK_DELETIONS = "bookmarkDeletions"; 13 | 14 | @Output(BOOKMARK_DELETIONS) 15 | MessageChannel bookmarkDeletions(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/config/DataInitialization.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.config; 2 | 3 | import com.packtpub.yummy.model.Bookmark; 4 | import com.packtpub.yummy.service.BookmarkService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.context.event.ApplicationReadyEvent; 7 | import org.springframework.context.ApplicationListener; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public class DataInitialization implements ApplicationListener { 12 | 13 | @Autowired 14 | BookmarkService bookmarkService; 15 | 16 | @Override 17 | public void onApplicationEvent(ApplicationReadyEvent event) { 18 | if (!bookmarkService.findAll().iterator().hasNext()) { 19 | bookmarkService.addBookmark(new Bookmark("Packt publishing", "http://packtpub.com")); 20 | bookmarkService.addBookmark(new Bookmark("orchit GmbH", "http://orchit.de")); 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/config/ErrorAdvice.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.config; 2 | 3 | import lombok.Getter; 4 | import lombok.ToString; 5 | import org.springframework.dao.IncorrectResultSizeDataAccessException; 6 | import org.springframework.dao.OptimisticLockingFailureException; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.validation.FieldError; 9 | import org.springframework.validation.ObjectError; 10 | import org.springframework.web.bind.MethodArgumentNotValidException; 11 | import org.springframework.web.bind.annotation.ControllerAdvice; 12 | import org.springframework.web.bind.annotation.ExceptionHandler; 13 | import org.springframework.web.bind.annotation.ResponseBody; 14 | import org.springframework.web.bind.annotation.ResponseStatus; 15 | 16 | import java.util.List; 17 | import java.util.stream.Collectors; 18 | 19 | @ControllerAdvice 20 | public class ErrorAdvice { 21 | 22 | @ExceptionHandler(IncorrectResultSizeDataAccessException.class) 23 | @ResponseStatus(HttpStatus.NOT_FOUND) 24 | public @ResponseBody 25 | String elementNotFound(IncorrectResultSizeDataAccessException e) { 26 | return "Could not find element! " + e.getMessage(); 27 | } 28 | 29 | @ExceptionHandler(OptimisticLockingFailureException.class) 30 | @ResponseStatus(HttpStatus.CONFLICT) 31 | public @ResponseBody 32 | String elementNotFound(OptimisticLockingFailureException e) { 33 | return "Conflict! " + e.getMessage(); 34 | } 35 | 36 | @ExceptionHandler(MethodArgumentNotValidException.class) 37 | @ResponseStatus(HttpStatus.BAD_REQUEST) 38 | public @ResponseBody 39 | List badRequest(MethodArgumentNotValidException e) { 40 | return e.getBindingResult().getAllErrors().stream() 41 | .map(err -> new ErrorMessage(err)) 42 | .collect(Collectors.toList()); 43 | 44 | } 45 | 46 | @Getter @ToString 47 | public static class ErrorMessage { 48 | String message, code, field, objectName; 49 | 50 | public ErrorMessage(ObjectError objectError) { 51 | message = objectError.getDefaultMessage(); 52 | code = objectError.getCode(); 53 | objectName = objectError.getObjectName(); 54 | if (objectError instanceof FieldError) { 55 | field = ((FieldError) objectError).getField(); 56 | } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.config; 2 | 3 | import lombok.AllArgsConstructor; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 8 | 9 | @Configuration 10 | @AllArgsConstructor 11 | @EnableGlobalMethodSecurity(prePostEnabled = true) 12 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 13 | 14 | @Override 15 | protected void configure(HttpSecurity http) throws Exception { 16 | http 17 | .authorizeRequests() 18 | .antMatchers("/", "/actuator/**").permitAll() 19 | .anyRequest().authenticated() 20 | .and().httpBasic() 21 | .and().csrf().disable(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.config; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.http.converter.HttpMessageConverter; 8 | import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; 9 | import org.springframework.web.client.RestTemplate; 10 | import org.springframework.web.servlet.LocaleResolver; 11 | import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; 12 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 13 | import org.springframework.web.servlet.i18n.SessionLocaleResolver; 14 | 15 | import java.util.List; 16 | import java.util.Locale; 17 | 18 | @Configuration 19 | public class WebConfig implements WebMvcConfigurer { 20 | 21 | @Override 22 | public void extendMessageConverters(List> converters) { 23 | converters.removeIf(c -> c instanceof Jaxb2RootElementHttpMessageConverter); 24 | } 25 | 26 | @Override 27 | public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { 28 | configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8); 29 | } 30 | 31 | @Bean 32 | public LocaleResolver localeResolver() { 33 | SessionLocaleResolver slr = new SessionLocaleResolver(); 34 | slr.setDefaultLocale(Locale.GERMANY); 35 | return slr; 36 | } 37 | 38 | @Bean 39 | @LoadBalanced 40 | public RestTemplate restTemplate() { 41 | return new RestTemplate(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/model/Bookmark.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.model; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonProperty; 5 | import lombok.Data; 6 | import org.hibernate.validator.constraints.Length; 7 | import org.hibernate.validator.constraints.URL; 8 | 9 | import javax.validation.constraints.NotEmpty; 10 | import javax.validation.constraints.NotNull; 11 | import java.time.LocalDateTime; 12 | import java.util.UUID; 13 | 14 | @Data 15 | public class Bookmark { 16 | @Length(max=255) 17 | @NotEmpty @NotNull 18 | private String description; 19 | private LocalDateTime createdOn; 20 | private LocalDateTime updatedOn; 21 | @Length(max=255) 22 | @NotEmpty @NotNull 23 | @URL 24 | private String url; 25 | private UUID uuid; 26 | private int version; 27 | 28 | @SuppressWarnings("unused") 29 | public Bookmark() { 30 | 31 | } 32 | 33 | public Bookmark(String description, String url) { 34 | this.url = url; 35 | uuid = null; 36 | this.description = description; 37 | } 38 | 39 | @JsonCreator 40 | public Bookmark(@JsonProperty("uuid") UUID uuid, 41 | @JsonProperty("description") String description, 42 | @JsonProperty("url") String url, 43 | @JsonProperty("version") int version, 44 | @JsonProperty("createdOn") LocalDateTime createdOn, 45 | @JsonProperty("updatedOn") LocalDateTime updatedOn) { 46 | this.description = description; 47 | this.createdOn = createdOn; 48 | this.updatedOn = updatedOn; 49 | this.url = url; 50 | this.uuid = uuid; 51 | this.version = version; 52 | } 53 | public Bookmark withUuid(UUID uuid) { 54 | return new Bookmark(uuid, description, url, version, createdOn, updatedOn); 55 | } 56 | 57 | public Bookmark withUrl(String newUrl) { 58 | return new Bookmark(uuid, description, newUrl, version, createdOn, updatedOn); 59 | } 60 | } -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/model/BookmarkResourceAssembler.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.model; 2 | 3 | import com.packtpub.yummy.rest.BookmarkController; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.hateoas.Resource; 6 | import org.springframework.hateoas.ResourceAssembler; 7 | import org.springframework.stereotype.Component; 8 | 9 | import javax.servlet.http.HttpServletRequest; 10 | import java.util.List; 11 | import java.util.stream.Collectors; 12 | import java.util.stream.StreamSupport; 13 | 14 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 15 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 16 | 17 | @Component 18 | public class BookmarkResourceAssembler implements ResourceAssembler> { 19 | 20 | @Autowired 21 | HttpServletRequest request; 22 | 23 | @Override 24 | public Resource toResource(Bookmark entity) { 25 | Resource resource = new Resource<>(entity, 26 | linkTo(methodOn(BookmarkController.class).getBookmark(entity.getUuid())).withSelfRel()); 27 | if(request.isUserInRole("ADMIN")){ 28 | resource.add( 29 | linkTo(methodOn(BookmarkController.class).getBookmark(entity.getUuid())).withRel("update"), 30 | linkTo(methodOn(BookmarkController.class).getBookmark(entity.getUuid())).withRel("delete") 31 | ); 32 | } 33 | return resource; 34 | } 35 | 36 | public List> toResourceList(Iterable list){ 37 | return StreamSupport.stream(list.spliterator(),false) 38 | .map(this::toResource) 39 | .collect(Collectors.toList()); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/rest/BookmarkController.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.rest; 2 | 3 | import com.packtpub.yummy.model.BookmarkResourceAssembler; 4 | import com.packtpub.yummy.model.Bookmark; 5 | import com.packtpub.yummy.service.BookmarkService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.hateoas.Resource; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.http.MediaType; 10 | import org.springframework.http.ResponseEntity; 11 | import org.springframework.security.access.prepost.PreAuthorize; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import javax.validation.Valid; 15 | import java.util.NoSuchElementException; 16 | import java.util.UUID; 17 | 18 | @RestController 19 | @PreAuthorize("hasRole('USER')") 20 | @RequestMapping(value = "bookmark", produces = {"application/hal+json;charset=UTF-8", MediaType.APPLICATION_JSON_UTF8_VALUE}) 21 | public class BookmarkController { 22 | @Autowired 23 | BookmarkResourceAssembler assembler; 24 | @Autowired 25 | BookmarkService bookmarkService; 26 | 27 | @GetMapping("template") 28 | public Resource getBookmarkTemplate() { 29 | return assembler.toResource(new Bookmark("describe me","http://fix.me")); 30 | } 31 | 32 | @GetMapping("{id}") 33 | public Resource getBookmark(@PathVariable UUID id) { 34 | return assembler.toResource(bookmarkService.find(id)); 35 | } 36 | 37 | @PutMapping("{id}") 38 | @PreAuthorize("hasRole('ADMIN')") 39 | public Resource updateBookmark(@PathVariable UUID id, @RequestBody @Valid Bookmark bookmark) { 40 | return assembler.toResource(bookmarkService.update(bookmark.withUuid(id))); 41 | } 42 | 43 | @DeleteMapping("{id}") 44 | @PreAuthorize("hasRole('ADMIN')") 45 | public ResponseEntity deleteBookmark(@PathVariable UUID id) { 46 | try { 47 | bookmarkService.delete(id); 48 | return ResponseEntity.status(HttpStatus.OK).build(); 49 | } catch (NoSuchElementException e) { 50 | return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build(); 51 | } 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/rest/BookmarksController.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.rest; 2 | 3 | import com.packtpub.yummy.model.Bookmark; 4 | import com.packtpub.yummy.model.BookmarkResourceAssembler; 5 | import com.packtpub.yummy.service.BookmarkService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.hateoas.Resource; 8 | import org.springframework.hateoas.Resources; 9 | import org.springframework.hateoas.mvc.BasicLinkBuilder; 10 | import org.springframework.http.MediaType; 11 | import org.springframework.http.ResponseEntity; 12 | import org.springframework.security.access.prepost.PreAuthorize; 13 | import org.springframework.web.bind.annotation.*; 14 | 15 | import javax.servlet.http.HttpServletRequest; 16 | import javax.validation.Valid; 17 | import java.util.UUID; 18 | 19 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 20 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 21 | 22 | @RestController 23 | @RequestMapping(value = "bookmarks", produces = {"application/hal+json;charset=UTF-8", MediaType.APPLICATION_JSON_UTF8_VALUE}) 24 | @PreAuthorize("hasRole('USER')") 25 | public class BookmarksController { 26 | @Autowired 27 | BookmarkResourceAssembler resourceAssembler; 28 | @Autowired 29 | BookmarkService bookmarkService; 30 | 31 | @PostMapping 32 | @PreAuthorize("hasRole('ADMIN')") 33 | public ResponseEntity addBookmark(@RequestBody @Valid Bookmark bookmark){ 34 | UUID uuid = bookmarkService.addBookmark(bookmark); 35 | return ResponseEntity.created( 36 | BasicLinkBuilder.linkToCurrentMapping() 37 | .slash("bookmark") 38 | .slash(uuid) 39 | .toUri()) 40 | .build(); 41 | } 42 | 43 | @GetMapping 44 | public Resources> findAllBookmarks(HttpServletRequest request){ 45 | Resources> bookmarks = new Resources<>( 46 | resourceAssembler.toResourceList(bookmarkService.findAll()), 47 | BasicLinkBuilder.linkToCurrentMapping() 48 | .slash("bookmarks").withSelfRel() 49 | ); 50 | if(request.isUserInRole("ADMIN")){ 51 | bookmarks.add( 52 | linkTo(methodOn(BookmarksController.class).addBookmark(null)).withRel("add"), 53 | linkTo(methodOn(BookmarkController.class).getBookmarkTemplate()).withRel("template") 54 | ); 55 | } 56 | return bookmarks; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/rest/ServiceDocumentController.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.rest; 2 | 3 | import org.springframework.hateoas.Resource; 4 | import org.springframework.hateoas.mvc.BasicLinkBuilder; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.net.URISyntaxException; 10 | 11 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; 12 | import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; 13 | 14 | @RestController 15 | @RequestMapping(produces = "application/hal+json;charset=UTF-8") 16 | public class ServiceDocumentController { 17 | @GetMapping("/") 18 | public Resource getServiceDocument() throws URISyntaxException { 19 | return new Resource<>("Yummy is the best service", 20 | BasicLinkBuilder.linkToCurrentMapping().withSelfRel(), 21 | linkTo(methodOn(BookmarksController.class).addBookmark(null)).withRel("bookmarks") 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/service/BookmarkRowMapper.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.service; 2 | 3 | import com.packtpub.yummy.model.Bookmark; 4 | import org.springframework.jdbc.core.RowMapper; 5 | 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.util.UUID; 9 | 10 | class BookmarkRowMapper implements RowMapper { 11 | @Override 12 | public Bookmark mapRow(ResultSet rs, int rowNum) throws SQLException { 13 | return new Bookmark( 14 | UUID.fromString(rs.getString("uuid")), 15 | rs.getString("description"), 16 | rs.getString("url"), 17 | rs.getInt("version"), 18 | rs.getTimestamp("createdon").toLocalDateTime(), 19 | rs.getTimestamp("updatedon").toLocalDateTime() 20 | ); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/service/BookmarkService.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.service; 2 | 3 | import com.packtpub.yummy.config.AmqpConfig; 4 | import com.packtpub.yummy.model.Bookmark; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Data; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.cloud.context.config.annotation.RefreshScope; 9 | import org.springframework.dao.DataAccessException; 10 | import org.springframework.dao.OptimisticLockingFailureException; 11 | import org.springframework.http.HttpStatus; 12 | import org.springframework.jdbc.core.JdbcTemplate; 13 | import org.springframework.messaging.support.MessageBuilder; 14 | import org.springframework.stereotype.Service; 15 | import org.springframework.transaction.annotation.Transactional; 16 | import org.springframework.web.bind.annotation.ResponseStatus; 17 | 18 | import java.util.UUID; 19 | 20 | @Service 21 | @Transactional 22 | @RefreshScope 23 | public class BookmarkService { 24 | 25 | @Autowired 26 | AmqpConfig.EventSource source; 27 | 28 | @Autowired 29 | JdbcTemplate jdbcTemplate; 30 | 31 | public UUID addBookmark(Bookmark bookmark) { 32 | UUID uuid = UUID.randomUUID(); 33 | jdbcTemplate.update("INSERT INTO bookmark (url, uuid, version, description)" + 34 | " VALUES (?,?,1,?)", bookmark.getUrl(), uuid.toString(), bookmark.getDescription()); 35 | System.out.println("http://localhost:8080/bookmark/" + uuid); 36 | return uuid; 37 | } 38 | 39 | public Bookmark find(UUID id) { 40 | return jdbcTemplate.queryForObject("SELECT * FROM bookmark WHERE uuid=?", 41 | new BookmarkRowMapper(), id.toString()); 42 | 43 | } 44 | 45 | public Iterable findAll() { 46 | return jdbcTemplate.query("SELECT * FROM bookmark", 47 | new BookmarkRowMapper()); 48 | } 49 | 50 | public Bookmark update(Bookmark bookmark) { 51 | find(bookmark.getUuid()); 52 | int update = jdbcTemplate.update( 53 | "UPDATE bookmark SET url=?, description=?, " + 54 | " updatedon=current_timestamp(), version=version+1 " + 55 | " WHERE uuid=? AND version =?", 56 | bookmark.getUrl(), bookmark.getDescription(), bookmark.getUuid().toString(), bookmark.getVersion() 57 | ); 58 | if (update != 1) throw new OptimisticLockingFailureException("Stale update detected for " + bookmark.getUuid()); 59 | return find(bookmark.getUuid()); 60 | } 61 | 62 | public void delete(UUID id) { 63 | if (jdbcTemplate.update("DELETE FROM bookmark WHERE uuid=?", id.toString()) != 1) 64 | throw new NotModifiedDataAccessException("Bookmark already gone"); 65 | source.bookmarkDeletions().send(MessageBuilder 66 | .withPayload( 67 | new DeletionEvent("bookmark", id.toString())) 68 | .build()); 69 | } 70 | 71 | @ResponseStatus(HttpStatus.NOT_MODIFIED) 72 | public static class NotModifiedDataAccessException extends DataAccessException { 73 | 74 | public NotModifiedDataAccessException(String msg) { 75 | super(msg); 76 | } 77 | } 78 | 79 | @Data 80 | @AllArgsConstructor 81 | public static class DeletionEvent { 82 | String type; 83 | String entityId; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/ui/BookmarkUiController.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ui; 2 | 3 | import com.packtpub.yummy.model.Bookmark; 4 | import com.packtpub.yummy.service.BookmarkService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.dao.IncorrectResultSizeDataAccessException; 7 | import org.springframework.security.access.prepost.PreAuthorize; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.ui.Model; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.ModelAttribute; 12 | import org.springframework.web.bind.annotation.PathVariable; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | 15 | import java.util.Optional; 16 | import java.util.UUID; 17 | 18 | @Controller 19 | @PreAuthorize("hasRole('USER')") 20 | @RequestMapping("/bookmark/") 21 | public class BookmarkUiController { 22 | @Autowired 23 | BookmarkService bookmarkService; 24 | 25 | @ModelAttribute 26 | public Bookmark bookmark(@PathVariable Optional id){ 27 | return id 28 | .map(uuid -> bookmarkService.find(uuid)) 29 | .orElseThrow(()-> new IncorrectResultSizeDataAccessException(1)); 30 | } 31 | 32 | @GetMapping("{id}") 33 | public String details(@PathVariable UUID id, Model model) { 34 | return "bookmark/details"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bookmarks/src/main/java/com/packtpub/yummy/ui/HomeController.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ui; 2 | 3 | import org.springframework.security.access.prepost.PreAuthorize; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | 8 | @Controller 9 | @RequestMapping("/") 10 | public class HomeController { 11 | 12 | @GetMapping 13 | @PreAuthorize("isAuthenticated()") 14 | public String displayHome() { 15 | return "index"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /bookmarks/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.context.ApplicationListener=\ 2 | org.springframework.boot.context.ApplicationPidFileWriter -------------------------------------------------------------------------------- /bookmarks/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: "jdbc:mysql://localhost:3306/packtdb" 4 | username: "packt" 5 | password: "superSecret" 6 | 7 | -------------------------------------------------------------------------------- /bookmarks/src/main/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: 'bookmarks' 3 | cloud: 4 | config: 5 | failFast: true 6 | retry: 7 | max-attempts: 60 8 | discovery: 9 | enabled: false 10 | uri: 'http://localhost:8888' 11 | -------------------------------------------------------------------------------- /bookmarks/src/main/resources/db/migration/V1.1__init.sql: -------------------------------------------------------------------------------- 1 | create table bookmark( 2 | uuid CHAR(36) not null, 3 | url VARCHAR(255), 4 | version int not null default 1, 5 | PRIMARY KEY (uuid) 6 | ) -------------------------------------------------------------------------------- /bookmarks/src/main/resources/db/migration/V1.2__add_more_fields.sql: -------------------------------------------------------------------------------- 1 | 2 | ALTER TABLE bookmark ADD description VARCHAR(255) NULL; 3 | ALTER TABLE bookmark ADD createdon TIMESTAMP DEFAULT current_timestamp() NULL; 4 | ALTER TABLE bookmark ADD updatedon TIMESTAMP DEFAULT current_timestamp() NULL; -------------------------------------------------------------------------------- /bookmarks/src/main/resources/db/migration/V1.3__create_user_tables.sql: -------------------------------------------------------------------------------- 1 | 2 | 3 | CREATE TABLE users ( 4 | username VARCHAR(255) NOT NULL, 5 | password VARCHAR(255) NOT NULL, 6 | enabled TINYINT NOT NULL DEFAULT 1, 7 | PRIMARY KEY (username) 8 | ); 9 | 10 | CREATE TABLE user_roles ( 11 | user_role_id INT(11) NOT NULL AUTO_INCREMENT, 12 | username VARCHAR(255) NOT NULL, 13 | role VARCHAR(255) NOT NULL, 14 | PRIMARY KEY (user_role_id), 15 | CONSTRAINT uni_username_role UNIQUE (role, username), 16 | CONSTRAINT fk_username FOREIGN KEY (username) REFERENCES users (username) 17 | ON DELETE CASCADE ON UPDATE CASCADE 18 | ); 19 | -------------------------------------------------------------------------------- /bookmarks/src/main/resources/static/components/bookmark-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 36 | 80 | -------------------------------------------------------------------------------- /bookmarks/src/main/resources/static/components/bookmarks-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 53 | 99 | -------------------------------------------------------------------------------- /bookmarks/src/main/resources/static/components/elements.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bookmarks/src/main/resources/templates/bookmark/details.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | Bookmark details view 9 | 10 | 11 | 12 |

Bookmark Details

13 |
14 | Hello Username 15 |
16 |
17 | 18 | 19 | 20 |
21 | Link 22 |
23 |
24 | Created on: now 25 |
26 |
27 | Last update on: now 28 |
29 |
30 | Back to the List 31 | 32 | Edit 34 |
36 | 37 |
38 |
39 |
40 |
41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /bookmarks/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | List of all bookmarks 10 | 11 | 12 | 16 | 17 | 18 | 19 |
20 |

List of all bookmarks

21 |
22 | Hello Username 23 |
24 |
25 | 26 |
27 |
28 | 29 | 30 | 31 |
32 | 33 | 34 |
35 | 36 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /bookmarks/src/test/java/com/packtpub/yummy/MessagingTest.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.packtpub.yummy.config.AmqpConfig; 6 | import com.packtpub.yummy.service.BookmarkService; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.boot.test.mock.mockito.MockBean; 12 | import org.springframework.cloud.stream.test.binder.MessageCollector; 13 | import org.springframework.jdbc.core.JdbcTemplate; 14 | import org.springframework.messaging.Message; 15 | import org.springframework.test.context.junit4.SpringRunner; 16 | 17 | import java.util.UUID; 18 | 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | import static org.mockito.ArgumentMatchers.anyString; 21 | import static org.mockito.ArgumentMatchers.eq; 22 | import static org.mockito.Mockito.when; 23 | 24 | @RunWith(SpringRunner.class) 25 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 26 | public class MessagingTest { 27 | @Autowired 28 | BookmarkService service; 29 | @MockBean 30 | JdbcTemplate jdbcTemplate; 31 | @Autowired 32 | AmqpConfig.EventSource source; 33 | @Autowired 34 | ObjectMapper mapper; 35 | @Autowired 36 | MessageCollector collector; 37 | 38 | @Test 39 | public void messageIsSent() throws JsonProcessingException { 40 | UUID id = UUID.randomUUID(); 41 | when(jdbcTemplate.update(anyString(), eq(id.toString()))).thenReturn(1); 42 | 43 | service.delete(id); 44 | 45 | Message received = 46 | (Message) collector.forChannel(source.bookmarkDeletions()).poll(); 47 | assertThat(received.getPayload()).isEqualTo( 48 | mapper.writer().writeValueAsString( 49 | new BookmarkService.DeletionEvent("bookmark", id.toString()) 50 | ) 51 | ); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /bookmarks/src/test/java/com/packtpub/yummy/YummyApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class YummyApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /bookmarks/src/test/java/com/packtpub/yummy/rest/BookmarksControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.rest; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.packtpub.yummy.model.Bookmark; 6 | import com.packtpub.yummy.service.BookmarkService; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.mockito.Mockito; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.beans.factory.annotation.Qualifier; 13 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 14 | import org.springframework.boot.test.context.SpringBootTest; 15 | import org.springframework.boot.test.mock.mockito.MockBean; 16 | import org.springframework.hateoas.Resources; 17 | import org.springframework.http.MediaType; 18 | import org.springframework.security.test.context.support.WithMockUser; 19 | import org.springframework.test.context.junit4.SpringRunner; 20 | import org.springframework.test.web.servlet.MockMvc; 21 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 22 | 23 | import java.util.Arrays; 24 | 25 | import static org.hamcrest.CoreMatchers.is; 26 | import static org.hamcrest.MatcherAssert.assertThat; 27 | import static org.hamcrest.Matchers.greaterThanOrEqualTo; 28 | import static org.junit.Assert.assertTrue; 29 | import static org.mockito.Mockito.never; 30 | import static org.mockito.Mockito.when; 31 | import static org.mockito.internal.verification.VerificationModeFactory.atLeastOnce; 32 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; 33 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; 34 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 35 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; 36 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 37 | 38 | @RunWith(SpringRunner.class) 39 | @SpringBootTest 40 | @AutoConfigureMockMvc 41 | @WithMockUser(username = "admin", roles = {"ADMIN", "USER"}) 42 | public class BookmarksControllerTest { 43 | @Autowired 44 | MockMvc mvc; 45 | @MockBean 46 | BookmarkService bookmarkService; 47 | @Autowired 48 | @Qualifier("_halObjectMapper") 49 | ObjectMapper mapper; 50 | 51 | @Before 52 | public void setup() { 53 | Mockito.reset(bookmarkService); 54 | } 55 | 56 | @Test 57 | public void addABookmark() throws Exception { 58 | Bookmark value = new Bookmark("Packt publishing", "http://packtpub.com"); 59 | addBookmark(value); 60 | Mockito.verify(bookmarkService, atLeastOnce()).addBookmark(Mockito.any(Bookmark.class)); 61 | } 62 | 63 | @Test 64 | public void addABookmarkFailsBecauseDescriptionIsNull() throws Exception { 65 | Bookmark value = new Bookmark(null, "http://packtpub.com"); 66 | mvc.perform( 67 | post("/bookmarks") 68 | .contentType(MediaType.APPLICATION_JSON_UTF8) 69 | .content(mapper.writeValueAsString(value)) 70 | .with(csrf()) 71 | ).andDo(print()) 72 | .andExpect(status().isBadRequest()) 73 | .andExpect(jsonPath("$[0].field").value("description")); 74 | Mockito.verify(bookmarkService, never()).addBookmark(Mockito.any(Bookmark.class)); 75 | } 76 | 77 | @Test 78 | public void addABookmarkFailsBecauseUrlIsNull() throws Exception { 79 | Bookmark value = new Bookmark("testtest", "broken://url.com"); 80 | mvc.perform( 81 | post("/bookmarks") 82 | .contentType(MediaType.APPLICATION_JSON_UTF8) 83 | .content(mapper.writeValueAsString(value)) 84 | .with(csrf()) 85 | ).andDo(print()) 86 | .andExpect(status().isBadRequest()) 87 | .andExpect(jsonPath("$[0].field").value("url")); 88 | Mockito.verify(bookmarkService, never()).addBookmark(Mockito.any(Bookmark.class)); 89 | } 90 | 91 | @Test 92 | public void getAllBookmarks() throws Exception { 93 | 94 | when(bookmarkService.findAll()).thenReturn(Arrays.asList( 95 | new Bookmark("Packt publishing", "http://packtpub.com"), 96 | new Bookmark("orchit GmbH homepage", "http://orchit.de"))); 97 | String result = mvc.perform( 98 | MockMvcRequestBuilders.get("/bookmarks") 99 | .accept("application/hal+json;charset=UTF-8", "application/json;charset=UTF-8") 100 | ).andDo(print()) 101 | .andReturn().getResponse().getContentAsString(); 102 | Resources output = mapper.readValue(result, new TypeReference>() { 103 | }); 104 | 105 | assertThat(output.getContent().size(), is(greaterThanOrEqualTo(2))); 106 | assertTrue(output.getContent().stream() 107 | .anyMatch(bookmark -> 108 | bookmark.getUrl().equals("http://orchit.de"))); 109 | assertTrue(output.getContent().stream() 110 | .anyMatch(bookmark -> 111 | bookmark.getUrl().equals("http://packtpub.com"))); 112 | } 113 | 114 | private void addBookmark(Bookmark value) throws Exception { 115 | mvc.perform( 116 | post("/bookmarks") 117 | .contentType(MediaType.APPLICATION_JSON_UTF8) 118 | .content(mapper.writeValueAsString(value)) 119 | .with(csrf()) 120 | ).andExpect(status().isCreated()); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /bookmarks/src/test/java/com/packtpub/yummy/rest/ServiceDocumentControllerTest.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.rest; 2 | 3 | import com.fasterxml.jackson.core.type.TypeReference; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import org.hamcrest.Matchers; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.beans.factory.annotation.Qualifier; 10 | import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.hateoas.Resource; 13 | import org.springframework.security.test.context.support.WithMockUser; 14 | import org.springframework.test.context.junit4.SpringRunner; 15 | import org.springframework.test.web.servlet.MockMvc; 16 | import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; 17 | 18 | import java.util.List; 19 | import java.util.stream.Collectors; 20 | 21 | import static junit.framework.TestCase.assertEquals; 22 | import static org.hamcrest.MatcherAssert.assertThat; 23 | import static org.junit.Assert.assertTrue; 24 | import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 25 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; 26 | 27 | @RunWith(SpringRunner.class) 28 | @SpringBootTest 29 | @AutoConfigureMockMvc 30 | @WithMockUser(username = "user", roles = "USER") 31 | public class ServiceDocumentControllerTest { 32 | @Autowired 33 | MockMvc mvc; 34 | @Autowired @Qualifier("_halObjectMapper") 35 | ObjectMapper mapper; 36 | 37 | @Test 38 | public void getServiceDocument() throws Exception { 39 | String result = mvc.perform( 40 | MockMvcRequestBuilders.get("/") 41 | .accept("application/hal+json;charset=UTF-8") 42 | ).andDo(print()) 43 | .andExpect(content() 44 | .contentTypeCompatibleWith("application/hal+json;charset=UTF-8")) 45 | .andReturn().getResponse().getContentAsString(); 46 | 47 | Resource value = mapper.readValue(result, new TypeReference>() { 48 | }); 49 | 50 | List linkRels = value.getLinks().stream().map(link -> link.getRel()).collect(Collectors.toList()); 51 | assertThat(linkRels, Matchers.hasItem("self")); 52 | assertEquals(value.getLink("self"), value.getId()); 53 | 54 | assertTrue(value.hasLink("bookmarks")); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /bookmarks/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=org.h2.Driver 2 | spring.datasource.url=jdbc:h2:mem:db;DB_CLOSE_DELAY=-1 3 | spring.datasource.username=sa 4 | spring.datasource.password=sa 5 | #Disable discovery 6 | eureka.client.enabled=false 7 | spring.jpa.show-sql=true 8 | spring.profiles.active=test 9 | spring.data.redis.repositories.enabled=false 10 | spring.session.store-type=none 11 | 12 | -------------------------------------------------------------------------------- /bookmarks/src/test/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /configserver/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 4 | 5 | COPY target/service.jar /usr/app/service.jar 6 | EXPOSE 8888 11111 7 | 8 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --spring.rabbitmq.host=rabbitmq -------------------------------------------------------------------------------- /configserver/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /configserver/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.packtpub.yummy 7 | configserver 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | ConfigServer 12 | Serving your configs 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Finchley.RELEASE 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-properties-migrator 32 | runtime 33 | 34 | 35 | org.springframework.cloud 36 | spring-cloud-config-server 37 | 38 | 39 | org.springframework.cloud 40 | spring-cloud-starter-bus-amqp 41 | 42 | 43 | 44 | org.springframework.boot 45 | spring-boot-starter-test 46 | test 47 | 48 | 49 | 50 | 51 | 52 | 53 | org.springframework.cloud 54 | spring-cloud-dependencies 55 | ${spring-cloud.version} 56 | pom 57 | import 58 | 59 | 60 | 61 | 62 | 63 | service 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-maven-plugin 68 | 69 | true 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | spring-milestones 78 | Spring milestones 79 | https://repo.spring.io/libs-milestones 80 | 81 | false 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /configserver/src/main/java/com/packtpub/yummy/configserver/ConfigServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.configserver; 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 @EnableConfigServer 8 | public class ConfigServerApplication { 9 | 10 | public static void main(String[] args) { 11 | SpringApplication.run(ConfigServerApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /configserver/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.context.ApplicationListener=\ 2 | org.springframework.boot.context.ApplicationPidFileWriter -------------------------------------------------------------------------------- /configserver/src/main/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: configserver 4 | profiles: 5 | active: native 6 | cloud: 7 | config: 8 | server: 9 | native: 10 | search-locations: classpath:/configs 11 | rabbitmq: 12 | username: 'packt' 13 | password: 'publishing' 14 | 15 | server.port: 8888 16 | 17 | management: 18 | server: 19 | port: 11111 20 | 21 | 22 | -------------------------------------------------------------------------------- /configserver/src/main/resources/configs/application-dev.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #logging.level: 4 | # org.springframework.web: DEBUG 5 | # com.packtpub: DEBUG 6 | 7 | eureka: 8 | instance: 9 | instance-id: '${spring.application.name}:${random.value}' 10 | -------------------------------------------------------------------------------- /configserver/src/main/resources/configs/application-docker.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: "jdbc:mysql://${db.name:db}:3306/packtdb" 4 | redis: 5 | host: "redis" 6 | rabbitmq: 7 | host: "rabbitmq" 8 | eureka: 9 | client: 10 | service-url: 11 | defaultZone: 'http://serviceregistry:8761/eureka/' 12 | management: 13 | server: 14 | port: 11111 15 | server: 16 | port: 8080 -------------------------------------------------------------------------------- /configserver/src/main/resources/configs/application.yaml: -------------------------------------------------------------------------------- 1 | 2 | management: 3 | endpoints: 4 | web: 5 | exposure: 6 | include: "*" 7 | eureka: 8 | instance: 9 | preferIpAddress: true 10 | client: 11 | service-url: 12 | defaultZone: 'http://localhost:8761/eureka/' 13 | spring: 14 | jackson: 15 | serialization: 16 | indent-output: true 17 | redis: 18 | host: localhost 19 | port: 6379 20 | session: 21 | store-type: redis 22 | rabbitmq: 23 | username: 'packt' 24 | password: 'publishing' 25 | sleuth.sampler.probability: 0.9 26 | cloud: 27 | config: 28 | #otherwise the clients would lead to a lot of logging and load on the configserver 29 | server.health.enabled: false 30 | #otherwise we can't override the port via command line args 31 | overrideSystemProperties: false 32 | 33 | 34 | server: 35 | use-forward-headers: true 36 | -------------------------------------------------------------------------------- /configserver/src/test/java/com/packtpub/yummy/configserver/ConfigServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.configserver; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ConfigServerApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /configserver/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | management.server.port=0 -------------------------------------------------------------------------------- /hystrixdashboard/.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 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /hystrixdashboard/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 4 | 5 | COPY target/service.jar /usr/app/service.jar 6 | EXPOSE 8080 11111 7 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --server.port=8080 --management.server.port=11111 -------------------------------------------------------------------------------- /hystrixdashboard/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /hystrixdashboard/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.packtpub.yummy 7 | hystrixdashboard 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | hystrixdashboard 12 | A dashing board 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Finchley.RELEASE 26 | 27 | 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-netflix-hystrix-dashboard 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-actuator 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-test 40 | test 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.cloud 48 | spring-cloud-dependencies 49 | ${spring-cloud.version} 50 | pom 51 | import 52 | 53 | 54 | 55 | 56 | 57 | service 58 | 59 | 60 | org.springframework.boot 61 | spring-boot-maven-plugin 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /hystrixdashboard/src/main/java/com/packtpub/yummy/hystrixdashboard/HystrixdashboardApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.hystrixdashboard; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; 6 | 7 | @SpringBootApplication 8 | @EnableHystrixDashboard 9 | public class HystrixdashboardApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(HystrixdashboardApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /hystrixdashboard/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=9998 -------------------------------------------------------------------------------- /hystrixdashboard/src/test/java/com/packtpub/yummy/hystrixdashboard/HystrixdashboardApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.hystrixdashboard; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class HystrixdashboardApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ratings/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "src/main/resources/static/components/bower_components" 3 | } -------------------------------------------------------------------------------- /ratings/.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 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /ratings/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 4 | 5 | COPY target/service.jar /usr/app/service.jar 6 | EXPOSE 8080 11111 7 | ENV DB_NAME="db" 8 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --spring.profiles.active=$ENVIRONMENT,docker --db.name=$DB_NAME --spring.cloud.config.uri=http://configserver:8888 -------------------------------------------------------------------------------- /ratings/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ratings", 3 | "dependencies": { 4 | "polymer": "Polymer/polymer#^2.0.0", 5 | "bower": "*", 6 | "iron-ajax": "PolymerElements/iron-ajax#^2.1.3", 7 | "install": "^1.0.4", 8 | "iron-star-rating": "chadweimer/iron-star-rating#^2.0.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ratings/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/EventService.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings; 2 | 3 | import com.packtpub.yummy.ratings.config.AmqpConfig; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.springframework.cloud.stream.annotation.StreamListener; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | @AllArgsConstructor 13 | @Slf4j 14 | public class EventService { 15 | private RatingRepository ratingRepository; 16 | 17 | @StreamListener(AmqpConfig.MessageSink.BOOKMARK_DELETIONS) 18 | public void processDelete(BookmarkDeleteEvent event) { 19 | log.info("Received Delete event for {}", event); 20 | ratingRepository.remove(event.getType(), event.getEntityId()); 21 | } 22 | 23 | @Data 24 | @AllArgsConstructor 25 | @NoArgsConstructor 26 | public static class BookmarkDeleteEvent { 27 | String type, entityId; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/RatingController.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.web.bind.annotation.*; 6 | 7 | import javax.validation.Valid; 8 | 9 | @RestController 10 | @RequestMapping("/votes/{type}/{entityId}") 11 | @AllArgsConstructor 12 | @Slf4j 13 | public class RatingController { 14 | private RatingRepository ratingRepository; 15 | 16 | @PostMapping 17 | public void addRating(@RequestBody @Valid RatingVote ratingVote, 18 | @PathVariable String type, 19 | @PathVariable String entityId) { 20 | log.info("Got rating {} for {} with entity {}", ratingVote, type, entityId); 21 | ratingRepository.persist(type, entityId, ratingVote.getRating()); 22 | } 23 | 24 | @DeleteMapping 25 | public void deleteRating(@PathVariable String type, 26 | @PathVariable String entityId) { 27 | log.info("Remove rating for {} with entity {}", type, entityId); 28 | ratingRepository.remove(type, entityId); 29 | } 30 | 31 | @GetMapping 32 | public RatingResult getRating(@PathVariable String type, 33 | @PathVariable String entityId) { 34 | return ratingRepository.calculateRating(type, entityId); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/RatingRepository.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings; 2 | 3 | import lombok.AllArgsConstructor; 4 | import org.springframework.dao.EmptyResultDataAccessException; 5 | import org.springframework.jdbc.core.BeanPropertyRowMapper; 6 | import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; 7 | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 8 | import org.springframework.stereotype.Repository; 9 | 10 | import java.math.BigDecimal; 11 | 12 | @Repository 13 | @AllArgsConstructor 14 | public class RatingRepository { 15 | private NamedParameterJdbcTemplate jdbcTemplate; 16 | 17 | 18 | public void persist(String type, String entityId, BigDecimal rating) { 19 | jdbcTemplate.update(" insert into ratings (type, entity_id, rating)" + 20 | " values (:type, :entity_id, :rating)", 21 | new MapSqlParameterSource() 22 | .addValue("type", type) 23 | .addValue("entity_id", entityId) 24 | .addValue("rating", rating)); 25 | } 26 | 27 | public RatingResult calculateRating(String type, String entityId) { 28 | try { 29 | return jdbcTemplate.queryForObject("select type, entity_id as entityId," + 30 | " avg(rating) as rating, count(*) as ratingCount" + 31 | " from ratings" + 32 | " where type=:type and entity_id=:entity_id" + 33 | " group by type, entity_id", 34 | new MapSqlParameterSource() 35 | .addValue("type", type) 36 | .addValue("entity_id", entityId), 37 | new BeanPropertyRowMapper<>(RatingResult.class)); 38 | } catch (EmptyResultDataAccessException ex) { 39 | return new RatingResult(type, entityId, BigDecimal.ZERO, 0); 40 | } 41 | } 42 | 43 | public void remove(String type, String entityId) { 44 | jdbcTemplate.update("delete from ratings" + 45 | " where type=:type and entity_id=:entity_id", 46 | new MapSqlParameterSource() 47 | .addValue("type", type) 48 | .addValue("entity_id", entityId)); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/RatingResult.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.math.BigDecimal; 8 | 9 | @Data 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class RatingResult { 13 | private String type, entityId; 14 | private BigDecimal rating; 15 | private int ratingCount; 16 | } 17 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/RatingVote.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings; 2 | 3 | import lombok.Data; 4 | 5 | import javax.validation.constraints.DecimalMax; 6 | import javax.validation.constraints.DecimalMin; 7 | import java.math.BigDecimal; 8 | 9 | @Data 10 | public class RatingVote { 11 | @DecimalMin("0.5") @DecimalMax("5") 12 | BigDecimal rating; 13 | } 14 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/RatingsApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class RatingsApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(RatingsApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/config/AmqpConfig.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings.config; 2 | 3 | import org.springframework.cloud.stream.annotation.EnableBinding; 4 | import org.springframework.cloud.stream.annotation.Input; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.messaging.SubscribableChannel; 7 | 8 | @Configuration 9 | @EnableBinding(AmqpConfig.MessageSink.class) 10 | public class AmqpConfig { 11 | public interface MessageSink { 12 | String BOOKMARK_DELETIONS = "bookmarkDeletions"; 13 | 14 | @Input 15 | SubscribableChannel bookmarkDeletions(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/config/ErrorAdvice.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings.config; 2 | 3 | import lombok.Getter; 4 | import lombok.ToString; 5 | import org.springframework.dao.IncorrectResultSizeDataAccessException; 6 | import org.springframework.dao.OptimisticLockingFailureException; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.validation.FieldError; 9 | import org.springframework.validation.ObjectError; 10 | import org.springframework.web.bind.MethodArgumentNotValidException; 11 | import org.springframework.web.bind.annotation.ControllerAdvice; 12 | import org.springframework.web.bind.annotation.ExceptionHandler; 13 | import org.springframework.web.bind.annotation.ResponseBody; 14 | import org.springframework.web.bind.annotation.ResponseStatus; 15 | 16 | import java.util.List; 17 | import java.util.stream.Collectors; 18 | 19 | @ControllerAdvice 20 | public class ErrorAdvice { 21 | 22 | @ExceptionHandler(IncorrectResultSizeDataAccessException.class) 23 | @ResponseStatus(HttpStatus.NOT_FOUND) 24 | public @ResponseBody 25 | String elementNotFound(IncorrectResultSizeDataAccessException e) { 26 | return "Could not find element! " + e.getMessage(); 27 | } 28 | 29 | @ExceptionHandler(OptimisticLockingFailureException.class) 30 | @ResponseStatus(HttpStatus.CONFLICT) 31 | public @ResponseBody 32 | String elementNotFound(OptimisticLockingFailureException e) { 33 | return "Conflict! " + e.getMessage(); 34 | } 35 | 36 | @ExceptionHandler(MethodArgumentNotValidException.class) 37 | @ResponseStatus(HttpStatus.BAD_REQUEST) 38 | public @ResponseBody 39 | List badRequest(MethodArgumentNotValidException e) { 40 | return e.getBindingResult().getAllErrors().stream() 41 | .map(err -> new ErrorMessage(err)) 42 | .collect(Collectors.toList()); 43 | 44 | } 45 | 46 | @Getter 47 | @ToString 48 | public static class ErrorMessage { 49 | String message, code, field, objectName; 50 | 51 | public ErrorMessage(ObjectError objectError) { 52 | message = objectError.getDefaultMessage(); 53 | code = objectError.getCode(); 54 | objectName = objectError.getObjectName(); 55 | if (objectError instanceof FieldError) { 56 | field = ((FieldError) objectError).getField(); 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings.config; 2 | 3 | import lombok.AllArgsConstructor; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 8 | 9 | @Configuration 10 | @AllArgsConstructor 11 | @EnableGlobalMethodSecurity(prePostEnabled = true) 12 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 13 | 14 | @Override 15 | protected void configure(HttpSecurity http) throws Exception { 16 | http 17 | .authorizeRequests() 18 | .antMatchers("/actuator/**").permitAll() 19 | .anyRequest().authenticated() 20 | .and().csrf().disable(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ratings/src/main/java/com/packtpub/yummy/ratings/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.http.MediaType; 5 | import org.springframework.http.converter.HttpMessageConverter; 6 | import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; 7 | import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; 8 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 9 | 10 | import java.util.List; 11 | 12 | @Configuration 13 | public class WebConfig implements WebMvcConfigurer { 14 | 15 | @Override 16 | public void extendMessageConverters(List> converters) { 17 | converters.removeIf(c -> c instanceof Jaxb2RootElementHttpMessageConverter); 18 | } 19 | 20 | @Override 21 | public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { 22 | configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /ratings/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: "jdbc:mysql://localhost:3308/packtdb" 4 | username: "packt" 5 | password: "superSecret" 6 | cloud: 7 | stream: 8 | bindings: 9 | bookmarkDeletions: 10 | group: ratings 11 | server.port: 9095 12 | -------------------------------------------------------------------------------- /ratings/src/main/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: 'ratings' 3 | cloud: 4 | config: 5 | failFast: true 6 | retry: 7 | max-attempts: 60 8 | discovery: 9 | enabled: false 10 | uri: 'http://localhost:8888' 11 | 12 | -------------------------------------------------------------------------------- /ratings/src/main/resources/db/migration/V1.1__initial.sql: -------------------------------------------------------------------------------- 1 | create table ratings ( 2 | type varchar(255) not null, 3 | entity_id varchar(255) not null, 4 | rating double not null, 5 | created_on timestamp default now() not null 6 | ); 7 | create index ratings_idx 8 | on ratings (type, entity_id); -------------------------------------------------------------------------------- /ratings/src/main/resources/static/components/rating-ctrl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 14 | 54 | -------------------------------------------------------------------------------- /ratings/src/test/java/com/packtpub/yummy/ratings/MessagingTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import com.packtpub.yummy.ratings.config.AmqpConfig; 6 | import org.junit.Test; 7 | import org.junit.runner.RunWith; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | import org.springframework.boot.test.mock.mockito.MockBean; 11 | import org.springframework.messaging.support.MessageBuilder; 12 | import org.springframework.test.context.junit4.SpringRunner; 13 | 14 | import static org.mockito.Mockito.verify; 15 | 16 | @RunWith(SpringRunner.class) 17 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 18 | public class MessagingTests { 19 | @MockBean 20 | RatingRepository ratingRepository; 21 | @Autowired 22 | AmqpConfig.MessageSink sink; 23 | @Autowired 24 | ObjectMapper mapper; 25 | 26 | @Test 27 | public void messageIsProcessed() throws JsonProcessingException { 28 | String payload = mapper.writer().writeValueAsString( 29 | new EventService.BookmarkDeleteEvent("1", "2") 30 | ); 31 | 32 | sink.bookmarkDeletions().send(MessageBuilder.withPayload(payload).build()); 33 | 34 | verify(ratingRepository).remove("1", "2"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /ratings/src/test/java/com/packtpub/yummy/ratings/RatingsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.ratings; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class RatingsApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /ratings/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.profiles.active=test 2 | spring.data.redis.repositories.enabled=false 3 | spring.session.store-type=none 4 | 5 | -------------------------------------------------------------------------------- /ratings/src/test/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /reverseproxy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 4 | 5 | COPY target/service.jar /usr/app/service.jar 6 | EXPOSE 8080 11111 7 | ENV ENVIRONMENT="local" 8 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --spring.profiles.active=$ENVIRONMENT,docker --spring.cloud.config.uri=http://configserver:8888 -------------------------------------------------------------------------------- /reverseproxy/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /reverseproxy/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.packtpub.yummy 7 | reverseproxy 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | ReverseProxy 12 | Reversing your proxy 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Finchley.RELEASE 26 | 27 | 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-netflix-zuul 32 | 33 | 34 | org.projectlombok 35 | lombok 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-starter-netflix-eureka-client 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-config-client 44 | 45 | 46 | org.springframework.cloud 47 | spring-cloud-starter-bus-amqp 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-netflix-hystrix-stream 52 | 53 | 54 | org.springframework.cloud 55 | spring-cloud-starter-zipkin 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-test 61 | test 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.cloud 69 | spring-cloud-dependencies 70 | ${spring-cloud.version} 71 | pom 72 | import 73 | 74 | 75 | 76 | 77 | 78 | service 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-maven-plugin 83 | 84 | true 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | spring-milestones 93 | Spring milestones 94 | https://repo.spring.io/libs-milestones 95 | 96 | false 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /reverseproxy/src/main/java/com/packtpub/yummy/reverseproxy/CorrelationIdZuulFilter.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.reverseproxy; 2 | 3 | import com.netflix.zuul.ZuulFilter; 4 | import com.netflix.zuul.context.RequestContext; 5 | import com.netflix.zuul.exception.ZuulException; 6 | import org.slf4j.MDC; 7 | import org.springframework.stereotype.Component; 8 | 9 | import java.util.UUID; 10 | 11 | import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE; 12 | import static org.springframework.integration.IntegrationMessageHeaderAccessor.CORRELATION_ID; 13 | 14 | @Component 15 | public class CorrelationIdZuulFilter extends ZuulFilter { 16 | @Override 17 | public String filterType() { 18 | return PRE_TYPE; 19 | } 20 | 21 | @Override 22 | public int filterOrder() { 23 | return 0; 24 | } 25 | 26 | @Override 27 | public boolean shouldFilter() { 28 | return true; 29 | } 30 | 31 | @Override 32 | public Object run() throws ZuulException { 33 | String id = UUID.randomUUID().toString(); 34 | RequestContext.getCurrentContext().addZuulRequestHeader(CORRELATION_ID, id); 35 | MDC.put(CORRELATION_ID, id); 36 | return null; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /reverseproxy/src/main/java/com/packtpub/yummy/reverseproxy/ErrorPageController.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.reverseproxy; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.boot.autoconfigure.web.servlet.error.AbstractErrorController; 6 | import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver; 7 | import org.springframework.boot.web.servlet.error.ErrorAttributes; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | 11 | import javax.servlet.http.HttpServletRequest; 12 | import javax.servlet.http.HttpServletResponse; 13 | import java.io.IOException; 14 | import java.util.List; 15 | import java.util.Map; 16 | 17 | @Controller 18 | @RequestMapping 19 | public class ErrorPageController extends AbstractErrorController { 20 | private static final Logger LOG = LoggerFactory.getLogger("error"); 21 | private static final String PATH = "/error"; 22 | 23 | public ErrorPageController(ErrorAttributes errorAttributes, List errorViewResolvers) { 24 | super(errorAttributes, errorViewResolvers); 25 | } 26 | 27 | @RequestMapping(value = PATH) 28 | public void error(HttpServletRequest request, HttpServletResponse response) throws IOException { 29 | Map errorAttributes = this.getErrorAttributes(request, false); 30 | LOG.info("ERROR-PAGE:{}, IP:{}:{}, MESSAGE: {}, QUERY:{}", response.getStatus(), request.getRemoteAddr(), request.getRemotePort(), errorAttributes.get("message"), request.getAttribute("javax.servlet.error.request_uri")); 31 | response.sendError(501, String.valueOf(errorAttributes.get("message"))); 32 | } 33 | 34 | @Override 35 | public String getErrorPath() { 36 | return PATH; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /reverseproxy/src/main/java/com/packtpub/yummy/reverseproxy/ReverseProxyApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.reverseproxy; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 6 | 7 | @SpringBootApplication 8 | @EnableZuulProxy 9 | public class ReverseProxyApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(ReverseProxyApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /reverseproxy/src/main/java/com/packtpub/yummy/reverseproxy/ZuulLoginFilter.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.reverseproxy; 2 | 3 | import com.netflix.zuul.ZuulFilter; 4 | import com.netflix.zuul.context.RequestContext; 5 | import com.netflix.zuul.exception.ZuulException; 6 | import org.springframework.stereotype.Component; 7 | 8 | import java.io.IOException; 9 | 10 | import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE; 11 | 12 | @Component 13 | public class ZuulLoginFilter extends ZuulFilter { 14 | @Override 15 | public String filterType() { 16 | return POST_TYPE; 17 | } 18 | 19 | @Override 20 | public int filterOrder() { 21 | return 0; 22 | } 23 | 24 | @Override 25 | public boolean shouldFilter() { 26 | int statusCode = RequestContext.getCurrentContext().getResponseStatusCode(); 27 | return statusCode == 401 || statusCode == 403; 28 | } 29 | @Override 30 | public Object run() throws ZuulException { 31 | try { 32 | RequestContext.getCurrentContext() 33 | .getResponse() 34 | .sendRedirect("/user/login"); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | return null; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /reverseproxy/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.context.ApplicationListener=\ 2 | org.springframework.boot.context.ApplicationPidFileWriter -------------------------------------------------------------------------------- /reverseproxy/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | zuul: 2 | ignored-services: '*' 3 | routes: 4 | bookmarks: '/**' 5 | users: '/user/**' 6 | ratings: '/ratings/**' 7 | sensitive-headers: 8 | add-host-header: true 9 | 10 | -------------------------------------------------------------------------------- /reverseproxy/src/main/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: 'reverseproxy' 3 | cloud: 4 | config: 5 | failFast: true 6 | retry: 7 | max-attempts: 60 8 | discovery: 9 | enabled: false 10 | uri: 'http://localhost:8888' 11 | 12 | -------------------------------------------------------------------------------- /reverseproxy/src/test/java/com/packtpub/yummy/reverseproxy/ReverseProxyApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.reverseproxy; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ReverseProxyApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /reverseproxy/src/test/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /serviceregistry/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 4 | 5 | COPY target/service.jar /usr/app/service.jar 6 | EXPOSE 8761 11111 7 | ENV ENVIRONMENT="local" 8 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --server.port=8761 --management.server.port=11111 --spring.profiles.active=$ENVIRONMENT,docker --spring.cloud.config.uri=http://configserver:8888 -------------------------------------------------------------------------------- /serviceregistry/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /serviceregistry/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.packtpub.yummy 7 | serviceregistry 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | ServiceRegistry 12 | Registering your services 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Finchley.RELEASE 26 | 27 | 28 | 29 | 30 | org.springframework.cloud 31 | spring-cloud-starter-netflix-eureka-server 32 | 33 | 34 | org.springframework.cloud 35 | spring-cloud-starter-bus-amqp 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-config-client 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-actuator 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-test 48 | test 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.springframework.cloud 56 | spring-cloud-dependencies 57 | ${spring-cloud.version} 58 | pom 59 | import 60 | 61 | 62 | 63 | 64 | 65 | service 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | true 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | spring-milestones 80 | Spring milestones 81 | https://repo.spring.io/libs-milestones 82 | 83 | false 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /serviceregistry/src/main/java/com/packtpub/yummy/serviceregistry/ServiceRegistryApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.serviceregistry; 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 @EnableEurekaServer 8 | public class ServiceRegistryApplication { 9 | 10 | public static void main(String[] args) { 11 | SpringApplication.run(ServiceRegistryApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /serviceregistry/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.context.ApplicationListener=\ 2 | org.springframework.boot.context.ApplicationPidFileWriter -------------------------------------------------------------------------------- /serviceregistry/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | 2 | 3 | server.port: 8761 4 | 5 | eureka: 6 | client: 7 | register-with-eureka: false 8 | fetch-registry: false 9 | server: 10 | wait-time-in-ms-when-sync-empty: 0 11 | enable-self-preservation: false -------------------------------------------------------------------------------- /serviceregistry/src/main/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: 'serviceregistry' 3 | cloud: 4 | config: 5 | failFast: true 6 | retry: 7 | max-attempts: 60 8 | discovery: 9 | enabled: false 10 | uri: 'http://localhost:8888' 11 | 12 | -------------------------------------------------------------------------------- /serviceregistry/src/test/java/com/packtpub/yummy/serviceregistry/ServiceRegistryApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.serviceregistry; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ServiceRegistryApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /serviceregistry/src/test/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /setup/buildAll.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | unamestr=`uname` 4 | 5 | ## 6 | ## This script builds all maven projects located in .. 7 | ## 8 | 9 | if [[ "$unamestr" == 'Linux' ]]; then 10 | BASEDIR=`dirname $0` 11 | elif [[ "$unamestr" == 'Darwin' ]]; then 12 | BASEDIR=`dirname $(greadlink -f $0)` 13 | fi 14 | cd $BASEDIR 15 | 16 | echo Searching for pom files in `$BASEDIR/..` 17 | find .. -name pom.xml -exec ./helper_buildIn.sh {} $BASEDIR/builderrors.log \; 18 | 19 | echo "Done compiling!" -------------------------------------------------------------------------------- /setup/dc-common.yaml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | common_java: 5 | restart: on-failure 6 | volumes: 7 | - "/dev/urandom:/dev/random" 8 | mem_limit: 367001600 9 | -------------------------------------------------------------------------------- /setup/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | 3 | services: 4 | rabbitmq: 5 | image: "rabbitmq:3.7-management" 6 | restart: on-failure 7 | ports: 8 | - "5672:5672" 9 | - "15672:15672" 10 | environment: 11 | RABBITMQ_DEFAULT_USER: "packt" 12 | RABBITMQ_DEFAULT_PASS: "publishing" 13 | volumes: 14 | - ./rabbitmq:/var/lib/rabbitmq 15 | 16 | zipkin: 17 | image: openzipkin/zipkin 18 | ports: 19 | - "9410:9410" 20 | - "9411:9411" 21 | depends_on: 22 | - rabbitmq 23 | environment: 24 | RABBIT_URI: "amqp://packt:publishing@rabbitmq:5672" 25 | extends: 26 | file: ./dc-common.yaml 27 | service: common_java 28 | 29 | redis: 30 | image: "redis:alpine" 31 | restart: on-failure 32 | ports: 33 | - "6379:6379" 34 | 35 | redisCommander: 36 | image: tenstartups/redis-commander 37 | command: --redis-host redis 38 | restart: on-failure 39 | depends_on: 40 | - redis 41 | ports: 42 | - "8081:8081" 43 | 44 | mysqlbm: 45 | image: mysql:8.0 46 | restart: on-failure 47 | security_opt: 48 | - seccomp=unconfined 49 | ports: 50 | - "3306:3306" 51 | environment: 52 | MYSQL_DATABASE: "packtdb" 53 | MYSQL_USER: "packt" 54 | MYSQL_PASSWORD: "superSecret" 55 | MYSQL_ROOT_HOST: "%" 56 | MYSQL_ROOT_PASSWORD: "superDuperSecret" 57 | 58 | mysqlus: 59 | image: mysql:8.0 60 | restart: on-failure 61 | security_opt: 62 | - seccomp=unconfined 63 | ports: 64 | - "3307:3306" 65 | environment: 66 | MYSQL_DATABASE: "packtdb" 67 | MYSQL_USER: "packt" 68 | MYSQL_PASSWORD: "superSecret" 69 | MYSQL_ROOT_HOST: "%" 70 | MYSQL_ROOT_PASSWORD: "superDuperSecret" 71 | 72 | mysqlra: 73 | image: mysql:8.0 74 | restart: on-failure 75 | security_opt: 76 | - seccomp=unconfined 77 | ports: 78 | - "3308:3306" 79 | environment: 80 | MYSQL_DATABASE: "packtdb" 81 | MYSQL_USER: "packt" 82 | MYSQL_PASSWORD: "superSecret" 83 | MYSQL_ROOT_HOST: "%" 84 | MYSQL_ROOT_PASSWORD: "superDuperSecret" 85 | 86 | ### services 87 | admin: 88 | build: ../admin 89 | image: localhost:5000/admin 90 | ports: 91 | - "6060:8080" 92 | depends_on: 93 | - configserver 94 | - rabbitmq 95 | extends: 96 | file: ./dc-common.yaml 97 | service: common_java 98 | 99 | bookmarks_service: 100 | build: ../bookmarks 101 | image: localhost:5000/bookmarks 102 | depends_on: 103 | - configserver 104 | - mysqlbm 105 | - redis 106 | - serviceregistry 107 | - rabbitmq 108 | links: 109 | - "mysqlbm:db" 110 | extends: 111 | file: ./dc-common.yaml 112 | service: common_java 113 | 114 | configserver: 115 | build: ../configserver 116 | image: localhost:5000/configserver 117 | extends: 118 | file: ./dc-common.yaml 119 | service: common_java 120 | 121 | hystrixdashboard: 122 | build: ../hystrixdashboard 123 | image: localhost:5000/hystrixdashboard 124 | ports: 125 | - "9998:8080" 126 | depends_on: 127 | - configserver 128 | - rabbitmq 129 | - turbine 130 | extends: 131 | file: ./dc-common.yaml 132 | service: common_java 133 | 134 | ratings_service: 135 | build: ../ratings 136 | image: localhost:5000/ratings 137 | depends_on: 138 | - configserver 139 | - mysqlra 140 | - redis 141 | - rabbitmq 142 | links: 143 | - "mysqlra:db" 144 | extends: 145 | file: ./dc-common.yaml 146 | service: common_java 147 | 148 | reverseproxy: 149 | build: ../reverseproxy 150 | image: localhost:5000/reverseproxy 151 | ports: 152 | - "8080:8080" 153 | depends_on: 154 | - configserver 155 | - rabbitmq 156 | - redis 157 | extends: 158 | file: ./dc-common.yaml 159 | service: common_java 160 | 161 | serviceregistry: 162 | build: ../serviceregistry 163 | image: localhost:5000/serviceregistry 164 | restart: on-failure 165 | ports: 166 | - "8761:8761" 167 | depends_on: 168 | - configserver 169 | - rabbitmq 170 | extends: 171 | file: ./dc-common.yaml 172 | service: common_java 173 | 174 | turbine: 175 | build: ../turbine 176 | image: localhost:5000/turbine 177 | depends_on: 178 | - configserver 179 | - rabbitmq 180 | - serviceregistry 181 | extends: 182 | file: ./dc-common.yaml 183 | service: common_java 184 | 185 | users_service: 186 | build: ../users 187 | image: localhost:5000/users 188 | depends_on: 189 | - configserver 190 | - mysqlus 191 | - redis 192 | - rabbitmq 193 | - serviceregistry 194 | links: 195 | - "mysqlus:db" 196 | extends: 197 | file: ./dc-common.yaml 198 | service: common_java 199 | -------------------------------------------------------------------------------- /setup/helper_buildIn.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ## 4 | ## internal helper script to build the maven stuff 5 | ## 6 | 7 | DIR=`dirname $1` 8 | BUILD_ERROR_LOG=${2=builderrors.log} 9 | 10 | cd $DIR 11 | 12 | mvn clean install -DskipTests -DskipITs 13 | 14 | EXIT=$? 15 | if [ $EXIT -eq 0 ] 16 | then 17 | echo "Success!" 18 | else 19 | echo "Logging error for $DIR" >&2 20 | #logging errors is necessary because this is called in a find -exec which doesn't stop on errors 21 | #and your shell history is most likely not big enough, so you can see where to look for errors 22 | echo "`date +%H:%M:%S` : Error while building $DIR" >> $BUILD_ERROR_LOG 23 | fi 24 | exit $EXIT 25 | -------------------------------------------------------------------------------- /setup/kubernetes/admin-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: admin 6 | name: admin 7 | spec: 8 | containers: 9 | - image: localhost:5000/admin 10 | name: admin 11 | imagePullPolicy: Always 12 | env: 13 | - name: ENVIRONMENT 14 | value: 'kubernetes' 15 | ports: 16 | - containerPort: 8080 17 | - containerPort: 11111 18 | resources: 19 | limits: 20 | memory: 450Mi 21 | restartPolicy: OnFailure 22 | --- 23 | kind: Service 24 | apiVersion: v1 25 | metadata: 26 | name: admin-service 27 | spec: 28 | selector: 29 | app: admin 30 | ports: 31 | - protocol: TCP 32 | port: 8080 33 | name: api 34 | - protocol: TCP 35 | port: 11111 36 | name: actuator 37 | -------------------------------------------------------------------------------- /setup/kubernetes/bookmarks-service-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: bookmarks 6 | name: bookmarks 7 | spec: 8 | containers: 9 | - image: localhost:5000/bookmarks 10 | name: bookmarks 11 | imagePullPolicy: Always 12 | env: 13 | - name: ENVIRONMENT 14 | value: 'kubernetes' 15 | - name: DB_NAME 16 | value: 'mysqlbm' 17 | ports: 18 | - containerPort: 8080 19 | - containerPort: 11111 20 | resources: 21 | limits: 22 | memory: 550Mi 23 | restartPolicy: OnFailure 24 | --- 25 | kind: Service 26 | apiVersion: v1 27 | metadata: 28 | name: bookmarks-service 29 | spec: 30 | selector: 31 | app: bookmarks 32 | ports: 33 | - protocol: TCP 34 | port: 8080 35 | name: api 36 | - protocol: TCP 37 | port: 11111 38 | name: actuator 39 | -------------------------------------------------------------------------------- /setup/kubernetes/configserver-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: configserver 6 | name: configserver 7 | spec: 8 | containers: 9 | - image: localhost:5000/configserver 10 | name: configserver 11 | ports: 12 | - containerPort: 8888 13 | - containerPort: 11111 14 | imagePullPolicy: Always 15 | resources: 16 | limits: 17 | memory: 350Mi 18 | restartPolicy: OnFailure 19 | --- 20 | kind: Service 21 | apiVersion: v1 22 | metadata: 23 | name: configserver 24 | spec: 25 | selector: 26 | app: configserver 27 | ports: 28 | - protocol: TCP 29 | port: 8888 30 | name: api 31 | - protocol: TCP 32 | port: 11111 33 | name: actuator -------------------------------------------------------------------------------- /setup/kubernetes/hystrixdashboard-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: hystrixdashboard 6 | name: hystrixdashboard 7 | spec: 8 | containers: 9 | - image: localhost:5000/hystrixdashboard 10 | name: hystrixdashboard 11 | imagePullPolicy: Always 12 | env: 13 | - name: ENVIRONMENT 14 | value: 'kubernetes' 15 | ports: 16 | - containerPort: 8080 17 | - containerPort: 11111 18 | resources: 19 | limits: 20 | memory: 400Mi 21 | restartPolicy: OnFailure 22 | --- 23 | kind: Service 24 | apiVersion: v1 25 | metadata: 26 | name: hystrixdashboard-service 27 | spec: 28 | selector: 29 | app: hystrixdashboard 30 | ports: 31 | - protocol: TCP 32 | port: 8080 33 | name: api 34 | - protocol: TCP 35 | port: 11111 36 | name: actuator 37 | -------------------------------------------------------------------------------- /setup/kubernetes/kubernetes-dashboard.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | labels: 5 | k8s-app: kubernetes-dashboard 6 | name: kubernetes-dashboard-nodeport 7 | namespace: kube-system 8 | spec: 9 | selector: 10 | k8s-app: kubernetes-dashboard 11 | ports: 12 | - protocol: TCP 13 | port: 8443 14 | targetPort: 8443 15 | nodePort: 31234 16 | sessionAffinity: None 17 | type: NodePort 18 | 19 | -------------------------------------------------------------------------------- /setup/kubernetes/mysqlbm-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: mysqlbm 6 | name: mysqlbm 7 | spec: 8 | containers: 9 | - image: mysql:8.0 10 | name: mysqlbm 11 | env: 12 | - name: MYSQL_DATABASE 13 | value: packtdb 14 | - name: MYSQL_PASSWORD 15 | value: superSecret 16 | - name: MYSQL_ROOT_HOST 17 | value: '%' 18 | - name: MYSQL_ROOT_PASSWORD 19 | value: superDuperSecret 20 | - name: MYSQL_USER 21 | value: packt 22 | imagePullPolicy: Always 23 | ports: 24 | - containerPort: 3306 25 | resources: {} 26 | restartPolicy: OnFailure 27 | 28 | --- 29 | kind: Service 30 | apiVersion: v1 31 | metadata: 32 | name: mysqlbm 33 | spec: 34 | selector: 35 | app: mysqlbm 36 | ports: 37 | - protocol: TCP 38 | port: 3306 39 | name: api -------------------------------------------------------------------------------- /setup/kubernetes/mysqlra-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: mysqlra 7 | name: mysqlra 8 | spec: 9 | containers: 10 | - image: mysql:8.0 11 | name: mysqlra 12 | env: 13 | - name: MYSQL_DATABASE 14 | value: packtdb 15 | - name: MYSQL_PASSWORD 16 | value: superSecret 17 | - name: MYSQL_ROOT_HOST 18 | value: '%' 19 | - name: MYSQL_ROOT_PASSWORD 20 | value: superDuperSecret 21 | - name: MYSQL_USER 22 | value: packt 23 | imagePullPolicy: Always 24 | ports: 25 | - containerPort: 3306 26 | resources: {} 27 | restartPolicy: OnFailure 28 | status: {} 29 | --- 30 | kind: Service 31 | apiVersion: v1 32 | metadata: 33 | name: mysqlra 34 | spec: 35 | selector: 36 | app: mysqlra 37 | ports: 38 | - protocol: TCP 39 | port: 3306 40 | name: api -------------------------------------------------------------------------------- /setup/kubernetes/mysqlus-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: mysqlus 6 | name: mysqlus 7 | spec: 8 | containers: 9 | - image: mysql:8.0 10 | name: mysqlus 11 | env: 12 | - name: MYSQL_DATABASE 13 | value: packtdb 14 | - name: MYSQL_PASSWORD 15 | value: superSecret 16 | - name: MYSQL_ROOT_HOST 17 | value: '%' 18 | - name: MYSQL_ROOT_PASSWORD 19 | value: superDuperSecret 20 | - name: MYSQL_USER 21 | value: packt 22 | imagePullPolicy: Always 23 | ports: 24 | - containerPort: 3306 25 | resources: {} 26 | restartPolicy: OnFailure 27 | --- 28 | kind: Service 29 | apiVersion: v1 30 | metadata: 31 | name: mysqlus 32 | spec: 33 | selector: 34 | app: mysqlus 35 | ports: 36 | - protocol: TCP 37 | port: 3306 38 | name: api -------------------------------------------------------------------------------- /setup/kubernetes/nginx-ingress.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: default-http-backend 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: default-http-backend 10 | template: 11 | metadata: 12 | labels: 13 | app: default-http-backend 14 | spec: 15 | terminationGracePeriodSeconds: 60 16 | containers: 17 | - name: default-http-backend 18 | # Any image is permissable as long as: 19 | # 1. It serves a 404 page at / 20 | # 2. It serves 200 on a /healthz endpoint 21 | image: k8s.gcr.io/defaultbackend:1.0 22 | livenessProbe: 23 | httpGet: 24 | path: /healthz 25 | port: 8080 26 | scheme: HTTP 27 | initialDelaySeconds: 30 28 | timeoutSeconds: 5 29 | ports: 30 | - containerPort: 8080 31 | resources: 32 | limits: 33 | cpu: 10m 34 | memory: 20Mi 35 | requests: 36 | cpu: 10m 37 | memory: 20Mi 38 | --- 39 | kind: Service 40 | apiVersion: v1 41 | metadata: 42 | name: default-http-backend 43 | spec: 44 | selector: 45 | app: default-http-backend 46 | ports: 47 | - protocol: TCP 48 | port: 80 49 | targetPort: 8080 50 | type: NodePort 51 | --- 52 | apiVersion: apps/v1 53 | kind: Deployment 54 | metadata: 55 | name: nginx-ingress-controller 56 | spec: 57 | replicas: 1 58 | selector: 59 | matchLabels: 60 | k8s-app: nginx-ingress-lb 61 | revisionHistoryLimit: 3 62 | template: 63 | metadata: 64 | labels: 65 | k8s-app: nginx-ingress-lb 66 | spec: 67 | containers: 68 | - args: 69 | - /nginx-ingress-controller 70 | - "--default-backend-service=$(POD_NAMESPACE)/default-http-backend" 71 | env: 72 | - name: POD_NAME 73 | valueFrom: 74 | fieldRef: 75 | fieldPath: metadata.name 76 | - name: POD_NAMESPACE 77 | valueFrom: 78 | fieldRef: 79 | fieldPath: metadata.namespace 80 | image: "quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.17.1" 81 | imagePullPolicy: Always 82 | livenessProbe: 83 | httpGet: 84 | path: /healthz 85 | port: 10254 86 | scheme: HTTP 87 | initialDelaySeconds: 10 88 | timeoutSeconds: 5 89 | name: nginx-ingress-controller 90 | ports: 91 | - containerPort: 80 92 | name: http 93 | protocol: TCP 94 | terminationGracePeriodSeconds: 60 95 | --- 96 | apiVersion: v1 97 | kind: Service 98 | metadata: 99 | name: nginx-ingress 100 | spec: 101 | type: LoadBalancer 102 | ports: 103 | - name: http 104 | port: 80 105 | targetPort: http 106 | selector: 107 | k8s-app: nginx-ingress-lb 108 | 109 | --- 110 | apiVersion: extensions/v1beta1 111 | kind: Ingress 112 | metadata: 113 | name: yummy-ingress 114 | annotations: 115 | kubernetes.io/ingress.class: "nginx" 116 | spec: 117 | rules: 118 | - host: localhost 119 | http: 120 | paths: 121 | - path: / 122 | backend: 123 | serviceName: reverseproxy-service 124 | servicePort: 8080 125 | - path: /zipkin 126 | backend: 127 | serviceName: zipkin-service 128 | servicePort: 9411 129 | -------------------------------------------------------------------------------- /setup/kubernetes/rabbitmq-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: rabbitmq 6 | name: rabbitmq 7 | spec: 8 | containers: 9 | - env: 10 | - name: RABBITMQ_DEFAULT_PASS 11 | value: publishing 12 | - name: RABBITMQ_DEFAULT_USER 13 | value: packt 14 | image: rabbitmq:3.7-management 15 | name: rabbitmq 16 | imagePullPolicy: Always 17 | ports: 18 | - containerPort: 5672 19 | - containerPort: 15672 20 | volumeMounts: 21 | - mountPath: /var/lib/rabbitmq 22 | name: rabbitmq-claim0 23 | restartPolicy: OnFailure 24 | volumes: 25 | - name: rabbitmq-claim0 26 | persistentVolumeClaim: 27 | claimName: rabbitmq-claim0 28 | --- 29 | kind: Service 30 | apiVersion: v1 31 | metadata: 32 | name: rabbitmq 33 | spec: 34 | selector: 35 | app: rabbitmq 36 | ports: 37 | - protocol: TCP 38 | port: 5672 39 | name: api 40 | - protocol: TCP 41 | port: 15672 42 | name: ui 43 | 44 | --- 45 | apiVersion: v1 46 | kind: PersistentVolumeClaim 47 | metadata: 48 | labels: 49 | app: rabbitmq-claim0 50 | name: rabbitmq-claim0 51 | spec: 52 | accessModes: 53 | - ReadWriteOnce 54 | resources: 55 | requests: 56 | storage: 100Mi 57 | -------------------------------------------------------------------------------- /setup/kubernetes/ratings-service-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: ratings 6 | name: ratings 7 | spec: 8 | containers: 9 | - image: localhost:5000/ratings 10 | name: users 11 | imagePullPolicy: Always 12 | env: 13 | - name: ENVIRONMENT 14 | value: 'kubernetes' 15 | - name: DB_NAME 16 | value: 'mysqlra' 17 | ports: 18 | - containerPort: 8080 19 | - containerPort: 11111 20 | resources: 21 | limits: 22 | memory: 550Mi 23 | restartPolicy: OnFailure 24 | --- 25 | kind: Service 26 | apiVersion: v1 27 | metadata: 28 | name: ratings-service 29 | spec: 30 | selector: 31 | app: ratings 32 | ports: 33 | - protocol: TCP 34 | port: 8080 35 | name: api 36 | - protocol: TCP 37 | port: 11111 38 | name: actuator 39 | -------------------------------------------------------------------------------- /setup/kubernetes/redis-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: redis 7 | name: redis 8 | spec: 9 | containers: 10 | - image: redis:alpine 11 | name: redis 12 | imagePullPolicy: Always 13 | ports: 14 | - containerPort: 6379 15 | resources: {} 16 | restartPolicy: OnFailure 17 | status: {} 18 | --- 19 | kind: Service 20 | apiVersion: v1 21 | metadata: 22 | name: redis 23 | spec: 24 | selector: 25 | app: redis 26 | ports: 27 | - protocol: TCP 28 | port: 6379 29 | name: api -------------------------------------------------------------------------------- /setup/kubernetes/redisCommander-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | creationTimestamp: null 5 | labels: 6 | app: rediscommander 7 | name: rediscommander 8 | spec: 9 | containers: 10 | - args: 11 | - --redis-host 12 | - redis 13 | image: tenstartups/redis-commander 14 | name: rediscommander 15 | imagePullPolicy: Always 16 | ports: 17 | - containerPort: 8081 18 | resources: {} 19 | restartPolicy: OnFailure 20 | status: {} 21 | -------------------------------------------------------------------------------- /setup/kubernetes/reverseproxy-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: reverseproxy 6 | name: reverseproxy 7 | spec: 8 | containers: 9 | - image: localhost:5000/reverseproxy 10 | name: users 11 | imagePullPolicy: Always 12 | env: 13 | - name: ENVIRONMENT 14 | value: 'kubernetes' 15 | ports: 16 | - containerPort: 8080 17 | - containerPort: 11111 18 | resources: 19 | limits: 20 | memory: 450Mi 21 | restartPolicy: OnFailure 22 | --- 23 | kind: Service 24 | apiVersion: v1 25 | metadata: 26 | name: reverseproxy-service 27 | spec: 28 | selector: 29 | app: reverseproxy 30 | ports: 31 | - protocol: TCP 32 | port: 8080 33 | name: api 34 | - protocol: TCP 35 | port: 11111 36 | name: actuator 37 | -------------------------------------------------------------------------------- /setup/kubernetes/serviceregistry-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: serviceregistry 6 | name: serviceregistry 7 | spec: 8 | containers: 9 | - image: localhost:5000/serviceregistry 10 | name: serviceregistry 11 | imagePullPolicy: Always 12 | ports: 13 | - containerPort: 8761 14 | - containerPort: 11111 15 | resources: 16 | limits: 17 | memory: 450Mi 18 | restartPolicy: OnFailure 19 | --- 20 | kind: Service 21 | apiVersion: v1 22 | metadata: 23 | name: serviceregistry 24 | spec: 25 | selector: 26 | app: serviceregistry 27 | ports: 28 | - protocol: TCP 29 | port: 8761 30 | name: api 31 | - protocol: TCP 32 | port: 11111 33 | name: actuator 34 | -------------------------------------------------------------------------------- /setup/kubernetes/turbine-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: turbine 6 | name: turbine 7 | spec: 8 | containers: 9 | - image: localhost:5000/turbine 10 | name: turbine 11 | imagePullPolicy: Always 12 | ports: 13 | - containerPort: 8080 14 | - containerPort: 11111 15 | resources: 16 | limits: 17 | memory: 450Mi 18 | restartPolicy: OnFailure 19 | --- 20 | kind: Service 21 | apiVersion: v1 22 | metadata: 23 | name: turbine 24 | spec: 25 | selector: 26 | app: turbine 27 | ports: 28 | - protocol: TCP 29 | port: 8080 30 | name: api 31 | - protocol: TCP 32 | port: 11111 33 | name: actuator 34 | -------------------------------------------------------------------------------- /setup/kubernetes/users-service-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: users 6 | name: users 7 | spec: 8 | containers: 9 | - image: localhost:5000/users 10 | name: users 11 | imagePullPolicy: Always 12 | env: 13 | - name: ENVIRONMENT 14 | value: 'kubernetes' 15 | - name: DB_NAME 16 | value: 'mysqlus' 17 | ports: 18 | - containerPort: 8080 19 | - containerPort: 11111 20 | resources: 21 | limits: 22 | memory: 550Mi 23 | restartPolicy: OnFailure 24 | --- 25 | kind: Service 26 | apiVersion: v1 27 | metadata: 28 | name: users-service 29 | spec: 30 | selector: 31 | app: users 32 | ports: 33 | - protocol: TCP 34 | port: 8080 35 | name: api 36 | - protocol: TCP 37 | port: 11111 38 | name: actuator 39 | -------------------------------------------------------------------------------- /setup/kubernetes/zipkin-pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | labels: 5 | app: zipkin 6 | name: zipkin 7 | spec: 8 | containers: 9 | - env: 10 | - name: RABBIT_URI 11 | value: amqp://packt:publishing@rabbitmq:5672 12 | image: openzipkin/zipkin 13 | name: zipkin 14 | imagePullPolicy: Always 15 | ports: 16 | - containerPort: 9410 17 | - containerPort: 9411 18 | restartPolicy: OnFailure 19 | --- 20 | kind: Service 21 | apiVersion: v1 22 | metadata: 23 | name: zipkin-service 24 | spec: 25 | selector: 26 | app: zipkin 27 | ports: 28 | - protocol: TCP 29 | port: 9410 30 | name: api 31 | - protocol: TCP 32 | port: 9411 33 | name: ui 34 | -------------------------------------------------------------------------------- /setup/runAll.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | unamestr=`uname` 4 | 5 | if [[ "$unamestr" == 'Linux' ]]; then 6 | BASEDIR=`dirname $0` 7 | elif [[ "$unamestr" == 'Darwin' ]]; then 8 | BASEDIR=`dirname $(greadlink -f $0)` 9 | fi 10 | cd $BASEDIR 11 | 12 | docker-compose up -d 13 | 14 | DIRS=(configserver serviceregistry reverseproxy bookmarks users) 15 | for i in "${DIRS[@]}" 16 | do 17 | echo "" 18 | echo "############################" 19 | echo "Make sure $i is stopped" 20 | ./stopService.sh $i 21 | echo "Start: $i" 22 | cd ../$i 23 | mvn clean install -DskipTests -DskipITs 24 | cd target 25 | echo "Starting $i" 26 | ./*.jar start 2>run.log >run.log & 27 | #give the service a little bit of time 28 | sleep 5 29 | echo "Done starting $i" 30 | cd $BASEDIR 31 | done 32 | -------------------------------------------------------------------------------- /setup/startInfraServices.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | unamestr=`uname` 4 | 5 | if [[ "$unamestr" == 'Linux' ]]; then 6 | BASEDIR=`dirname $0` 7 | elif [[ "$unamestr" == 'Darwin' ]]; then 8 | BASEDIR=`dirname $(greadlink -f $0)` 9 | fi 10 | cd $BASEDIR 11 | 12 | docker-compose up -d --build rabbitmq zipkin redis redisCommander mysqlbm mysqlra mysqlus 13 | 14 | -------------------------------------------------------------------------------- /setup/stopAll.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | unamestr=`uname` 4 | 5 | if [[ "$unamestr" == 'Linux' ]]; then 6 | BASEDIR=`dirname $0` 7 | elif [[ "$unamestr" == 'Darwin' ]]; then 8 | BASEDIR=`dirname $(greadlink -f $0)` 9 | fi 10 | cd $BASEDIR 11 | 12 | docker-compose down 13 | 14 | DIRS=(configserver serviceregistry reverseproxy bookmarks users) 15 | for i in "${DIRS[@]}" 16 | do 17 | ./stopService.sh $i 18 | done 19 | -------------------------------------------------------------------------------- /setup/stopService.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | unamestr=`uname` 4 | 5 | if [[ "$unamestr" == 'Linux' ]]; then 6 | BASEDIR=`dirname $0` 7 | elif [[ "$unamestr" == 'Darwin' ]]; then 8 | BASEDIR=`dirname $(greadlink -f $0)` 9 | fi 10 | cd $BASEDIR 11 | 12 | echo "Stopping: $1" 13 | cd ../$1/target 14 | if [ -f "application.pid" ]; then 15 | echo "Found pid file for $1" 16 | pkill -F application.pid 17 | sleep 1 18 | if [ -f "application.pid" ]; then 19 | if pgrep -F "application.pid" > /dev/null 20 | then 21 | echo "Still running -- forcing kill" 22 | pkill -9 -F application.pid 23 | else 24 | echo "Removing pid file" 25 | rm application.pid 26 | fi 27 | fi 28 | else 29 | echo "Not running" 30 | fi 31 | -------------------------------------------------------------------------------- /turbine/.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 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /turbine/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | 4 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 5 | 6 | COPY target/service.jar /usr/app/service.jar 7 | EXPOSE 8080 11111 8 | ENV ENVIRONMENT="local" 9 | 10 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --spring.profiles.active=$ENVIRONMENT,docker --spring.cloud.config.uri=http://configserver:8888 -------------------------------------------------------------------------------- /turbine/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /turbine/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.packtpub.yummy 7 | turbine 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | turbine 12 | Blowing your events away 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | Finchley.RELEASE 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-amqp 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-actuator 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-bus 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-starter-config 44 | 45 | 46 | org.springframework.cloud 47 | spring-cloud-starter-netflix-eureka-client 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-starter-netflix-turbine-stream 52 | 53 | 54 | org.springframework.cloud 55 | spring-cloud-stream-binder-rabbit 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-starter-test 61 | test 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.cloud 69 | spring-cloud-dependencies 70 | ${spring-cloud.version} 71 | pom 72 | import 73 | 74 | 75 | 76 | 77 | 78 | service 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-maven-plugin 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /turbine/src/main/java/com/packtpub/yummy/turbine/TurbineApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.turbine; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.turbine.stream.EnableTurbineStream; 6 | 7 | @SpringBootApplication 8 | @EnableTurbineStream 9 | public class TurbineApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(TurbineApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /turbine/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | 2 | server.port: 9999 3 | management: 4 | server: 5 | port: 11112 -------------------------------------------------------------------------------- /turbine/src/main/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: 'turbine' 3 | cloud: 4 | config: 5 | failFast: true 6 | retry: 7 | max-attempts: 60 8 | discovery: 9 | enabled: false 10 | uri: 'http://localhost:8888' 11 | 12 | -------------------------------------------------------------------------------- /turbine/src/test/java/com/packtpub/yummy/turbine/TurbineApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.turbine; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class TurbineApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /users/.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 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /users/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jre-alpine3.8 2 | RUN apk --update add curl 3 | HEALTHCHECK CMD curl -v --fail http://localhost:11111/actuator/info || exit 1 4 | 5 | COPY target/service.jar /usr/app/service.jar 6 | EXPOSE 8080 11111 7 | ENV ENVIRONMENT="local" 8 | ENV DB_NAME="db" 9 | ENTRYPOINT java -Djava.net.preferIPv4Stack=true -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -jar /usr/app/service.jar --spring.profiles.active=$ENVIRONMENT,docker --db.name=$DB_NAME --spring.cloud.config.uri=http://configserver:8888 -------------------------------------------------------------------------------- /users/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /users/src/main/java/com/packtpub/yummy/users/UsersApplication.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.users; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UsersApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UsersApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /users/src/main/java/com/packtpub/yummy/users/config/DataInitialization.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.users.config; 2 | 3 | import com.packtpub.yummy.users.service.UserService; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.context.event.ApplicationReadyEvent; 8 | import org.springframework.context.ApplicationListener; 9 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 10 | import org.springframework.security.core.userdetails.User; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.util.Arrays; 14 | 15 | @Component 16 | public class DataInitialization implements ApplicationListener { 17 | private static final Logger LOG = LoggerFactory.getLogger(DataInitialization.class); 18 | @Autowired 19 | UserService userService; 20 | @Override 21 | public void onApplicationEvent(ApplicationReadyEvent event) { 22 | if (!userService.hasUser("admin")) { 23 | userService.addUser(new User("admin", "password", 24 | Arrays.asList( 25 | new SimpleGrantedAuthority("ROLE_ADMIN"), 26 | new SimpleGrantedAuthority("ROLE_USER") 27 | ))); 28 | } 29 | if (!userService.hasUser("user")) { 30 | userService.addUser(new User("user", "password", 31 | Arrays.asList( 32 | new SimpleGrantedAuthority("ROLE_USER") 33 | ))); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /users/src/main/java/com/packtpub/yummy/users/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.users.config; 2 | 3 | import lombok.AllArgsConstructor; 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.method.configuration.EnableGlobalMethodSecurity; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 11 | import org.springframework.security.crypto.factory.PasswordEncoderFactories; 12 | import org.springframework.security.crypto.password.PasswordEncoder; 13 | import org.springframework.web.util.DefaultUriBuilderFactory; 14 | 15 | import javax.sql.DataSource; 16 | 17 | @Configuration 18 | @AllArgsConstructor 19 | @EnableGlobalMethodSecurity(prePostEnabled = true) 20 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 21 | private final DataSource dataSource; 22 | private final DefaultUriBuilderFactory defaultUriBuilderFactory 23 | = new DefaultUriBuilderFactory(); 24 | @Bean 25 | public PasswordEncoder passwordEncoder() { 26 | return PasswordEncoderFactories.createDelegatingPasswordEncoder(); 27 | } 28 | 29 | @Override 30 | protected void configure(HttpSecurity http) throws Exception { 31 | http 32 | .authorizeRequests() 33 | .antMatchers("/webjars/**", "/actuator/**").permitAll() 34 | .anyRequest().authenticated() 35 | .and() 36 | .formLogin().loginPage("/login").permitAll() 37 | .successHandler((request, response, authentication) -> 38 | response.sendRedirect( 39 | defaultUriBuilderFactory.builder() 40 | .replacePath("/").build().toString() 41 | ) 42 | ) 43 | .and() 44 | .logout().permitAll(); 45 | } 46 | 47 | @Autowired 48 | public void configureGlobal(AuthenticationManagerBuilder builder) throws Exception { 49 | builder.jdbcAuthentication() 50 | .dataSource(dataSource) 51 | .passwordEncoder(passwordEncoder()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /users/src/main/java/com/packtpub/yummy/users/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.users.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.core.Ordered; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.http.converter.HttpMessageConverter; 8 | import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; 9 | import org.springframework.web.servlet.LocaleResolver; 10 | import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer; 11 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 12 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 13 | import org.springframework.web.servlet.i18n.SessionLocaleResolver; 14 | 15 | import java.util.List; 16 | import java.util.Locale; 17 | 18 | @Configuration 19 | public class WebConfig implements WebMvcConfigurer { 20 | 21 | 22 | @Override 23 | public void addViewControllers(ViewControllerRegistry registry) { 24 | registry.addViewController("/login").setViewName("login"); 25 | registry.setOrder(Ordered.HIGHEST_PRECEDENCE); 26 | } 27 | 28 | @Override 29 | public void extendMessageConverters(List> converters) { 30 | converters.removeIf(c -> c instanceof Jaxb2RootElementHttpMessageConverter); 31 | } 32 | 33 | @Override 34 | public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { 35 | configurer.defaultContentType(MediaType.APPLICATION_JSON_UTF8); 36 | } 37 | 38 | @Bean 39 | public LocaleResolver localeResolver(){ 40 | SessionLocaleResolver slr = new SessionLocaleResolver(); 41 | slr.setDefaultLocale(Locale.GERMANY); 42 | return slr; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /users/src/main/java/com/packtpub/yummy/users/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.users.service; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; 5 | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 6 | import org.springframework.jdbc.core.namedparam.SqlParameterSource; 7 | import org.springframework.security.core.userdetails.UserDetails; 8 | import org.springframework.security.crypto.password.PasswordEncoder; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | public class UserService { 13 | @Autowired 14 | PasswordEncoder passwordEncoder; 15 | @Autowired 16 | NamedParameterJdbcTemplate jdbcTemplate; 17 | 18 | public void addUser(UserDetails userDetails) { 19 | jdbcTemplate.update("INSERT INTO users(username, password,enabled)" + 20 | " VALUES (lower(:username),:password,1)", 21 | new MapSqlParameterSource("username", userDetails.getUsername()) 22 | .addValue("password", passwordEncoder.encode(userDetails.getPassword()))); 23 | jdbcTemplate.batchUpdate("INSERT INTO authorities(username, authority) " + 24 | "VALUES (lower(:username), :role)", 25 | (SqlParameterSource[]) userDetails.getAuthorities().stream() 26 | .map(a -> new MapSqlParameterSource("username", userDetails.getUsername()) 27 | .addValue("role", a.getAuthority())) 28 | .toArray(size -> new SqlParameterSource[size])); 29 | } 30 | 31 | public boolean hasUser(String username){ 32 | return !jdbcTemplate.query("select 1 from users where username=lower(:username)", 33 | new MapSqlParameterSource("username",username) 34 | ,(rs, rowNum) -> rs.getInt(1) 35 | ).isEmpty(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /users/src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.context.ApplicationListener=\ 2 | org.springframework.boot.context.ApplicationPidFileWriter -------------------------------------------------------------------------------- /users/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: "jdbc:mysql://localhost:3307/packtdb" 4 | username: "packt" 5 | password: "superSecret" 6 | 7 | server.port: 9070 8 | -------------------------------------------------------------------------------- /users/src/main/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | application.name: 'users' 3 | cloud: 4 | config: 5 | failFast: true 6 | retry: 7 | max-attempts: 60 8 | discovery: 9 | enabled: false 10 | uri: 'http://localhost:8888' 11 | 12 | -------------------------------------------------------------------------------- /users/src/main/resources/db/migration/V1.0__init.sql: -------------------------------------------------------------------------------- 1 | create table users ( 2 | username varchar(50) not null primary key, 3 | password varchar(500) not null, 4 | enabled boolean not null 5 | ); 6 | create table authorities ( 7 | username varchar(50) not null, 8 | authority varchar(50) not null, 9 | constraint fk_authorities_users 10 | foreign key (username) references users (username) 11 | ); 12 | create unique index ix_auth_username 13 | on authorities (username, authority); -------------------------------------------------------------------------------- /users/src/main/resources/templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Our Login Page 7 | 8 | 9 | 10 |
11 |

Login with Username and Password please

12 |
13 | 14 |
16 |
17 |
18 | Invalid username and password. 19 |
20 |
21 |
22 |
23 | You have been logged out. 24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 39 | 40 |
User:
Password:
37 | 38 |
41 |
42 | 46 | 47 | -------------------------------------------------------------------------------- /users/src/test/java/com/packtpub/yummy/users/UsersApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.yummy.users; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class UsersApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /users/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | 2 | spring.data.redis.repositories.enabled=false 3 | spring.session.store-type=none 4 | 5 | -------------------------------------------------------------------------------- /users/src/test/resources/bootstrap.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | --------------------------------------------------------------------------------