├── .gitignore ├── README.md ├── archimedes ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codependent │ │ │ └── storyteller │ │ │ └── ArchimedesApplication.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── codependent │ └── storyteller │ └── ArchimedesApplicationTests.java ├── config-server ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codependent │ │ │ └── storyteller │ │ │ └── ConfigServerApplication.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── codependent │ └── storyteller │ └── ConfigServerApplicationTests.java ├── diagram.png ├── hystrix-dashboard ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ ├── codependent │ │ │ └── storyteller │ │ │ │ └── HystrixDashboardApplication.java │ │ │ └── netflix │ │ │ └── turbine │ │ │ ├── discovery │ │ │ └── Instance.java │ │ │ └── monitor │ │ │ ├── cluster │ │ │ └── ClusterMonitor.java │ │ │ └── instance │ │ │ └── InstanceMonitor.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── com │ └── codependent │ └── storyteller │ └── HystrixDashboardApplicationTests.java ├── images-ms ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codependent │ │ │ └── storyteller │ │ │ ├── ImageService.java │ │ │ └── RandomImageMsApplication.java │ └── resources │ │ ├── bootstrap.yml │ │ └── images │ │ ├── minion-carl.jpg │ │ ├── minion-dave.jpg │ │ ├── minion-evil.jpg │ │ ├── minion-kevin.jpg │ │ ├── minion-phil.jpg │ │ ├── minion-stuart.jpg │ │ ├── minion-tim.jpg │ │ ├── minion-tom.jpg │ │ └── minion-wolverine.jpg │ └── test │ └── java │ └── com │ └── codependent │ └── storyteller │ └── RandomImageMsApplicationTests.java ├── stories-ms ├── .gitignore ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── codependent │ │ │ └── storyteller │ │ │ ├── HtmlGeneratorMsApplication.java │ │ │ └── StoryService.java │ └── resources │ │ └── bootstrap.yml │ └── test │ └── java │ └── com │ └── codependent │ └── storyteller │ └── HtmlGeneratorMsApplicationTests.java └── storyteller-api ├── .gitignore ├── .springBeans ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── codependent │ │ └── storyteller │ │ ├── StoryClient.java │ │ └── StoryTellerApiApplication.java └── resources │ └── bootstrap.yml └── test └── java └── com └── codependent └── storyteller └── RandomImageMsApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | /.metadata 2 | /RemoteSystemsTempFiles 3 | /Servers 4 | /archimedes/bin 5 | /archimedes/.mvn 6 | /archimedes/.bin 7 | /archimedes/.settings 8 | /archimedes/.classpath 9 | /archimedes/.project 10 | /random-image-ms/bin 11 | /random-image-ms/.mvn 12 | /random-image-ms/.bin 13 | /random-image-ms/.settings 14 | /random-image-ms/.classpath 15 | /random-image-ms/.project 16 | /random-story-ms/bin 17 | /random-story-ms/.mvn 18 | /random-story-ms/.bin 19 | /random-story-ms/.settings 20 | /random-story-ms/.classpath 21 | /random-story-ms/.project 22 | /storyteller-api/bin 23 | /storyteller-api/.mvn 24 | /storyteller-api/.bin 25 | /storyteller-api/.settings 26 | /storyteller-api/.classpath 27 | /storyteller-api/.project 28 | /config-server/bin 29 | /config-server/.mvn 30 | /config-server/.bin 31 | /config-server/.settings 32 | /config-server/.classpath 33 | /config-server/.project -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # storyteller-microservices 2 | 3 | Storyteller Microservices implemented with Spring Boot + Spring Cloud Netflix 4 | 5 | * **archimedes**: acts as Eureka Server. Endpoint: `http://localhost:8761` 6 | * **config-server**: external config server from a [Git Repo](https://github.com/codependent/storyteller-microservices-config). Endpoint: `http://localhost:8888` 7 | * **hystrix-dashboard**: aggretated metrics using Turbine. IMPORTANT: overrides some Turbine files to allow having multiple applications on the same host. [More info](https://github.com/Netflix/Turbine/pull/105). Endpoint: `http://localhost:10000` 8 | * **images-ms**: mid-tier Eureka Client that returns a random image URL. Endpoint: `http://localhost:9999/images?random=true&fields=url` 9 | * **stories-ms**: mid-tier Eureka Client that generates a random HTML story inserting a random image gotten from the previous service. Endpoint: `http://localhost:9988/stories?random=true` 10 | * **storyteller-api**: (master/high-availability branches) API Eureka Client that invokes stories-ms, using a **Feign** client, to get a random story. Endpoint: `http://localhost:9977/api/stories?random=true` 11 | * **gatekeeper**: (zuul/high-availability branches) Zuul edge service that substitutes storyteller-api as the external entry point. Endpoint: `http://localhost:9977/api/stories?random=true` 12 | 13 | This structure tries to simulate a scenario like the following: 14 | 15 | ![Microservices architecture](https://raw.githubusercontent.com/codependent/storyteller-microservices/master/diagram.png) 16 | 17 | One API service exposed to clients and two mid tier services, all of them sharing a Eureka server instance (Archimedes) and a ConfigServer that loads the properties from a Git repo. 18 | 19 | ***Branch differences*** 20 | 21 | * **master**: storyteller-api acts as a gateway for the internal microservices and uses a Feign client to invoke stories-ms. **[At the moment](https://github.com/Netflix/feign/issues/298) there is no way to specify a fallback method for Feign clients.** 22 | * **no-config-server**: same as master without using a centralized config-server. 23 | * **zuul**: uses a zuul reverse-proxy instead of storyteller-api gateway. 24 | * **high-availability**: high availability environment using two eureka registers, a zuul reverse proxy, and 2 instances of each service. 25 | * **high-availability-rxjava**: Same as above but using reactive programming. It also adds 2 **Spring Cloud Stream** microservices, a log processor and a central logger. Uses **Spring Cloud Sleuth** in all microservices for request tracing in **Zipkin**. The projects have been dockerized and can be launched using docker compose. 26 | * **high-availability-rxjava-sidecar**: Polyglot version in which Sidecar integrates a Node.js microservice. 27 | * **consul**: Consul replaces Eureka Server as microservice registry. 28 | -------------------------------------------------------------------------------- /archimedes/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.mvn 3 | /.bin 4 | /.settings 5 | .classpath 6 | .project 7 | /.springBeans 8 | -------------------------------------------------------------------------------- /archimedes/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /archimedes/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 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /archimedes/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.codependent.storyteller 7 | archimedes 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | Archimedes 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.3.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | 31 | 32 | 33 | org.springframework.cloud 34 | spring-cloud-starter-eureka-server 35 | 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-starter-parent 49 | Brixton.M3 50 | pom 51 | import 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.springframework.boot 60 | spring-boot-maven-plugin 61 | 62 | 63 | 64 | 65 | 66 | 67 | spring-snapshots 68 | Spring Snapshots 69 | https://repo.spring.io/snapshot 70 | 71 | true 72 | 73 | 74 | 75 | spring-milestones 76 | Spring Milestones 77 | https://repo.spring.io/milestone 78 | 79 | false 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /archimedes/src/main/java/com/codependent/storyteller/ArchimedesApplication.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.springframework.boot.autoconfigure.SpringBootApplication; 4 | import org.springframework.boot.builder.SpringApplicationBuilder; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @EnableEurekaServer 8 | @SpringBootApplication 9 | public class ArchimedesApplication { 10 | 11 | public static void main(String[] args) { 12 | new SpringApplicationBuilder(ArchimedesApplication.class).web(true).run(args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /archimedes/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: ${PORT:8761} 3 | 4 | eureka: 5 | instance: 6 | hostname: localhost 7 | client: 8 | registerWithEureka: false 9 | fetchRegistry: false 10 | serviceUrl: 11 | defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 12 | server: 13 | # enableSelfPreservation: false 14 | # waitTimeInMsWhenSyncEmpty: 0 15 | 16 | logging: 17 | # file: /var/memento/security.log 18 | level: 19 | org.springframework.web: 'DEBUG' -------------------------------------------------------------------------------- /archimedes/src/test/java/com/codependent/storyteller/ArchimedesApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.SpringApplicationConfiguration; 6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 | 8 | import com.codependent.storyteller.ArchimedesApplication; 9 | 10 | @RunWith(SpringJUnit4ClassRunner.class) 11 | @SpringApplicationConfiguration(classes = ArchimedesApplication.class) 12 | public class ArchimedesApplicationTests { 13 | 14 | @Test 15 | public void contextLoads() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /config-server/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | -------------------------------------------------------------------------------- /config-server/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /config-server/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 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /config-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.codependent.storyteller 7 | config-server 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | config-server 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.3.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | 31 | 32 | 33 | org.springframework.cloud 34 | spring-cloud-starter-eureka 35 | 36 | 37 | 38 | org.springframework.cloud 39 | spring-cloud-config-server 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-test 45 | test 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.cloud 53 | spring-cloud-starter-parent 54 | Brixton.M3 55 | pom 56 | import 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-maven-plugin 66 | 67 | 68 | 69 | 70 | 71 | 72 | spring-snapshots 73 | Spring Snapshots 74 | https://repo.spring.io/snapshot 75 | 76 | true 77 | 78 | 79 | 80 | spring-milestones 81 | Spring Milestones 82 | https://repo.spring.io/milestone 83 | 84 | false 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /config-server/src/main/java/com/codependent/storyteller/ConfigServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 7 | 8 | @EnableConfigServer 9 | @EnableEurekaClient 10 | @SpringBootApplication 11 | public class ConfigServerApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(ConfigServerApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /config-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8888 3 | 4 | info: 5 | description: Spring Cloud Config Server 6 | 7 | eureka: 8 | client: 9 | serviceUrl: 10 | defaultZone: http://localhost:8761/eureka/ 11 | healthcheck: 12 | enabled: true 13 | 14 | spring: 15 | application: 16 | name: configserver 17 | cloud: 18 | config: 19 | server: 20 | git: 21 | uri: https://github.com/codependent/storyteller-microservices-config 22 | # uri: file:///C:/SoftDesarrollo/6-Workspaces/sts/storyteller-microservices-config -------------------------------------------------------------------------------- /config-server/src/test/java/com/codependent/storyteller/ConfigServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.SpringApplicationConfiguration; 6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 | 8 | import com.codependent.storyteller.ConfigServerApplication; 9 | 10 | @RunWith(SpringJUnit4ClassRunner.class) 11 | @SpringApplicationConfiguration(classes = ConfigServerApplication.class) 12 | public class ConfigServerApplicationTests { 13 | 14 | @Test 15 | public void contextLoads() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/diagram.png -------------------------------------------------------------------------------- /hystrix-dashboard/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.settings/ 3 | /bin/ 4 | /.classpath 5 | /.project 6 | /.mvn/ 7 | -------------------------------------------------------------------------------- /hystrix-dashboard/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /hystrix-dashboard/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 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /hystrix-dashboard/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.codependent.storyteller 7 | hystrix-dashboard 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | hystrix-dashboard 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.3.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.cloud 29 | spring-cloud-starter-hystrix-dashboard 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-turbine 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-test 38 | test 39 | 40 | 41 | 42 | 43 | 44 | 45 | org.springframework.cloud 46 | spring-cloud-starter-parent 47 | Brixton.M3 48 | pom 49 | import 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-maven-plugin 59 | 60 | 61 | 62 | 63 | 64 | 65 | spring-snapshots 66 | Spring Snapshots 67 | https://repo.spring.io/snapshot 68 | 69 | true 70 | 71 | 72 | 73 | spring-milestones 74 | Spring Milestones 75 | https://repo.spring.io/milestone 76 | 77 | false 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /hystrix-dashboard/src/main/java/com/codependent/storyteller/HystrixDashboardApplication.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; 6 | import org.springframework.cloud.netflix.turbine.EnableTurbine; 7 | 8 | @EnableHystrixDashboard 9 | @EnableTurbine 10 | @SpringBootApplication 11 | public class HystrixDashboardApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(HystrixDashboardApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /hystrix-dashboard/src/main/java/com/netflix/turbine/discovery/Instance.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Netflix, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.netflix.turbine.discovery; 17 | 18 | import static org.junit.Assert.*; 19 | 20 | import java.util.HashMap; 21 | import java.util.Map; 22 | 23 | import org.junit.Test; 24 | 25 | import com.netflix.turbine.monitor.cluster.ObservationCriteria; 26 | 27 | /** 28 | * Class that encapsulates a host or machine that is vending data to Turbine. 29 | * 30 | *

Turbine uses the notion of cluster to group Instances together for agggregation. 31 | * 32 | *

Turbine also treats the host status as a first class citizen where the status conveys whether the 33 | * host is ready to serve data etc. 34 | *

38 | *

Once Turbine disconnects, all the relevant data from that host is purged from it's aggregated state. 39 | * 40 | *

You can also use the attrs to add in free form details about an Instance. 41 | * e.g ec2-availability-zone, build revision etc. 42 | *

Then you can also write your own {@link ObservationCriteria} implementation to decide how to filter out 43 | * relevant hosts to aggregate data from. 44 | * 45 | */ 46 | public class Instance implements Comparable { 47 | 48 | private final String hostname; 49 | private final String cluster; 50 | private final boolean isUp; 51 | private final Map attributes; 52 | 53 | /** 54 | * @param host 55 | * @param clusterName 56 | * @param status 57 | */ 58 | public Instance(String host, String clusterName, boolean status) { 59 | hostname = host; 60 | cluster = clusterName; 61 | isUp = status; 62 | attributes = new HashMap(); 63 | } 64 | 65 | @Override 66 | public boolean equals(Object obj) { 67 | if (this == obj) return true; 68 | if (obj == null) return false; 69 | if (getClass() != obj.getClass()) return false; 70 | 71 | Instance other = (Instance) obj; 72 | 73 | boolean equals = true; 74 | equals &= (this.hostname != null) ? (this.hostname.equals(other.hostname)) : (other.hostname == null); 75 | equals &= (this.cluster != null) ? (this.cluster.equals(other.cluster)) : (other.cluster == null); 76 | equals &= (this.isUp == other.isUp); 77 | if(attributes != null && attributes.get("port") != null){ 78 | String port = attributes.get("port"); 79 | if(other.getAttributes() != null && other.getAttributes().get("port") != null){ 80 | equals &= (port == other.getAttributes().get("port")); 81 | } 82 | } 83 | 84 | return equals; 85 | } 86 | 87 | @Override 88 | public int hashCode() { 89 | final int prime = 31; 90 | int result = 1; 91 | result = prime * result + ((hostname == null) ? 0 : hostname.hashCode()); 92 | result = prime * result + ((cluster == null) ? 0 : cluster.hashCode()); 93 | result = prime * result + (isUp ? 1 : 0); 94 | if(attributes != null && attributes.get("port") != null){ 95 | result = prime * result + (attributes.get("port").hashCode()); 96 | } 97 | return result; 98 | } 99 | 100 | @Override 101 | public String toString() { 102 | return "StatsInstance [hostname=" + hostname + ", cluster: " + cluster + ", isUp: " + isUp + ", attrs=" + attributes.toString() + "]"; 103 | } 104 | 105 | /** 106 | * @return String 107 | */ 108 | public String getHostname() { 109 | return hostname; 110 | } 111 | 112 | /** 113 | * @return String 114 | */ 115 | public String getCluster() { 116 | return cluster; 117 | } 118 | 119 | /** 120 | * @return true/false 121 | */ 122 | public boolean isUp() { 123 | return isUp; 124 | } 125 | 126 | /** 127 | * @return Map 128 | */ 129 | public Map getAttributes() { 130 | return attributes; 131 | } 132 | 133 | @Override 134 | public int compareTo(Instance other) { 135 | return this.getHostname().compareTo(other.getHostname()); 136 | } 137 | 138 | public static class UnitTest { 139 | 140 | @Test 141 | public void testHostEquals() throws Exception { 142 | 143 | Instance host1 = new Instance("h1", "c1", true); 144 | Instance host2 = new Instance("h1", "c2", false); 145 | Instance host3 = new Instance("h2", "c1", true); 146 | 147 | assertFalse(host1.equals(host2)); 148 | assertFalse(host1.equals(host3)); 149 | assertFalse(host2.equals(host3)); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /hystrix-dashboard/src/main/java/com/netflix/turbine/monitor/cluster/ClusterMonitor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Netflix, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.netflix.turbine.monitor.cluster; 17 | 18 | import static org.mockito.Matchers.any; 19 | import static org.mockito.Mockito.mock; 20 | import static org.mockito.Mockito.verify; 21 | import static org.mockito.Mockito.when; 22 | 23 | import java.lang.management.ManagementFactory; 24 | import java.util.Collection; 25 | import java.util.Collections; 26 | import java.util.concurrent.atomic.AtomicInteger; 27 | 28 | import javax.management.MBeanServer; 29 | import javax.management.ObjectName; 30 | 31 | import org.junit.Test; 32 | import org.junit.runner.RunWith; 33 | import org.mockito.Mock; 34 | import org.mockito.runners.MockitoJUnitRunner; 35 | import org.slf4j.Logger; 36 | import org.slf4j.LoggerFactory; 37 | 38 | import com.netflix.servo.annotations.DataSourceType; 39 | import com.netflix.servo.annotations.Monitor; 40 | import com.netflix.turbine.data.AggDataFromCluster; 41 | import com.netflix.turbine.data.DataFromSingleInstance; 42 | import com.netflix.turbine.data.TurbineData; 43 | import com.netflix.turbine.data.meta.MetaInfoUpdator; 44 | import com.netflix.turbine.data.meta.MetaInformation; 45 | import com.netflix.turbine.discovery.Instance; 46 | import com.netflix.turbine.discovery.InstanceObservable; 47 | import com.netflix.turbine.discovery.InstanceObservable.InstanceObserver; 48 | import com.netflix.turbine.handler.TurbineDataDispatcher; 49 | import com.netflix.turbine.handler.TurbineDataHandler; 50 | import com.netflix.turbine.monitor.MonitorConsole; 51 | import com.netflix.turbine.monitor.TurbineDataMonitor; 52 | import com.netflix.turbine.monitor.instance.InstanceMonitor; 53 | import com.netflix.turbine.monitor.instance.InstanceUrlClosure; 54 | 55 | /** 56 | * A class that represents a {@link TurbineDataMonitor} for a cluster of {@link Instance}s. 57 | *

The ClusterMonitor exhibits functionality that can be used for any extending class to manage it's respective {@link InstanceMonitor}s 58 | * as {@link Instance}s go up and down in a dynamic environment and ensure that they receive data from the most up to date set of hosts. 59 | * 60 | *

This includes 61 | *

67 | * 68 | * @param 69 | */ 70 | public abstract class ClusterMonitor extends TurbineDataMonitor { 71 | 72 | private static final Logger logger = LoggerFactory.getLogger(ClusterMonitor.class); 73 | 74 | protected final String name; 75 | 76 | // stuff needed for cluster monitor management 77 | protected final TurbineDataDispatcher clusterDispatcher; 78 | protected final MonitorConsole clusterConsole; 79 | 80 | // stuff needed for host monitor management 81 | protected final TurbineDataDispatcher hostDispatcher; 82 | protected final MonitorConsole hostConsole; 83 | 84 | protected volatile boolean stopped = false; 85 | 86 | protected final Instance statsInstance; 87 | protected final InstanceObservable instanceObservable; 88 | protected final InstanceUrlClosure urlClosure; 89 | protected final InstanceObserver monitorManager; 90 | 91 | private final AtomicInteger hostCount = new AtomicInteger(0); 92 | 93 | /** 94 | * @param name 95 | * @param clusterDispatcher : the dispatcher to dispatch cluster events to - e.g aggregated events 96 | * @param clusterConsole : the console to register itself with, so that it can be discoverd by other listeners to cluster data 97 | * @param hostDispatcher : the dispatcher to receive host events from 98 | * @param hostConsole : the host console to maintain host connections in. 99 | * @param urlClosure : the config dictating how to connect to a host. 100 | */ 101 | public ClusterMonitor(String name, 102 | TurbineDataDispatcher clusterDispatcher, MonitorConsole clusterConsole, 103 | TurbineDataDispatcher hostDispatcher, MonitorConsole hostConsole, 104 | InstanceUrlClosure urlClosure) { 105 | this(name, 106 | clusterDispatcher, clusterConsole, 107 | hostDispatcher, hostConsole, 108 | urlClosure, 109 | InstanceObservable.getInstance()); 110 | } 111 | 112 | protected ClusterMonitor(String name, 113 | TurbineDataDispatcher cDispatcher, MonitorConsole cConsole, 114 | TurbineDataDispatcher hDispatcher, MonitorConsole hConsole, 115 | InstanceUrlClosure urlClosure, 116 | InstanceObservable instanceObservable) { 117 | this.name = name; 118 | this.clusterDispatcher = cDispatcher; 119 | this.clusterConsole = cConsole; 120 | 121 | this.hostDispatcher = hDispatcher; 122 | this.hostConsole = hConsole; 123 | 124 | this.urlClosure = urlClosure; 125 | this.instanceObservable = instanceObservable; 126 | 127 | this.monitorManager = new ClusterMonitorInstanceManager(); 128 | 129 | this.statsInstance = new Instance(name, "clustetAgg", true); 130 | } 131 | 132 | @Override 133 | public String getName() { 134 | return name; 135 | } 136 | 137 | @Override 138 | public Instance getStatsInstance() { 139 | return statsInstance; 140 | } 141 | 142 | /** 143 | * Start the monitor and register with the InstanceObservable to get updates on host status 144 | * @throws Exception 145 | */ 146 | @Override 147 | public void startMonitor() throws Exception { 148 | // start up the monitor workers from here and register the event handlers 149 | logger.info("Starting up the cluster monitor for " + name); 150 | instanceObservable.register(monitorManager); 151 | 152 | MetaInformation metaInfo = getMetaInformation(); 153 | if (metaInfo != null) { 154 | MetaInfoUpdator.addMetaInfo(metaInfo); 155 | } 156 | } 157 | 158 | /** 159 | * Stop the monitor, shut down resources that were created and notify listeners downstream about the event. 160 | */ 161 | @Override 162 | public void stopMonitor() { 163 | logger.info("Stopping cluster monitor for " + name); 164 | stopped = true; 165 | // remove my event handler from all host monitors 166 | instanceObservable.deregister(monitorManager); 167 | // notify people below me that this monitor is shutting down 168 | clusterDispatcher.handleHostLost(getStatsInstance()); 169 | // remove the handler from the host level dispatcher 170 | hostDispatcher.deregisterEventHandler(getEventHandler()); 171 | // remove this monitor from the StatsEventConsole 172 | clusterConsole.removeMonitor(getName()); 173 | 174 | clusterDispatcher.stopDispatcher(); 175 | 176 | MetaInformation metaInfo = getMetaInformation(); 177 | if (metaInfo != null) { 178 | MetaInfoUpdator.removeMetaInfo(metaInfo); 179 | } 180 | 181 | try { 182 | MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 183 | mbs.unregisterMBean(new ObjectName("ClusterMonitorMBean:name=ClusterMonitorStats_" + name)); 184 | } catch (Exception e) { 185 | } 186 | } 187 | 188 | /** 189 | * @return {@link MonitorConsole}<{@link DataFromSingleInstance}> 190 | */ 191 | public MonitorConsole getInstanceMonitors() { 192 | return hostConsole; 193 | } 194 | 195 | @Monitor(name="hostCount", type=DataSourceType.GAUGE) 196 | public int getHostCount() { 197 | return hostCount.get(); 198 | } 199 | 200 | public boolean isRunning() { 201 | return this.clusterDispatcher.running(); 202 | } 203 | 204 | /** 205 | * @return {@link TurbineDataDispatcher} 206 | */ 207 | @Override 208 | public TurbineDataDispatcher getDispatcher() { 209 | return clusterDispatcher; 210 | } 211 | 212 | /** 213 | * To be implemented by extending cluster monitors such as the aggregator. 214 | * 215 | * @return {@link TurbineDataHandler}<{@link DataFromSingleInstance}> 216 | */ 217 | public abstract TurbineDataHandler getEventHandler(); 218 | 219 | /** 220 | * @return {@link ObservationCriteria} 221 | */ 222 | public abstract ObservationCriteria getObservationCriteria(); 223 | 224 | /** 225 | * Helper method that registers a listener to this cluster monitor. 226 | * @param eventHandler 227 | */ 228 | public void registerListenertoClusterMonitor(TurbineDataHandler eventHandler) { 229 | 230 | TurbineDataHandler oldHandler = getDispatcher().findHandlerForHost(getStatsInstance(), eventHandler.getName()); 231 | if (oldHandler == null) { 232 | logger.info("Registering event handler for cluster monitor: " + eventHandler.getName()); 233 | getDispatcher().registerEventHandler(getStatsInstance(), eventHandler); 234 | logger.info("All event handlers for cluster monitor: " +getDispatcher().getAllHandlerNames().toString()); 235 | } else { 236 | logger.info("Handler: " + oldHandler.getName() + " already registered to host: " + getStatsInstance()); 237 | } 238 | } 239 | 240 | /** 241 | * Track meta info for this cluster. This feature is optional. Do not override if you don't want meta info 242 | * from your cluster monitor. 243 | * One can set the config property 'turbine.MetaInfoUpdator.enabled' to value 'false' to turn off the updator as well. 244 | * 245 | * @return 246 | */ 247 | protected MetaInformation getMetaInformation() { 248 | return null; 249 | } 250 | 251 | /** 252 | * Helper class that responds to hostup and hostdown events and thus can start / stop InstanceMonitors 253 | * 254 | */ 255 | public class ClusterMonitorInstanceManager implements InstanceObserver { 256 | 257 | @Override 258 | public String getName() { 259 | return name; 260 | } 261 | 262 | public void hostUp(Instance host) { 263 | 264 | if (!(getObservationCriteria().observeHost(host))) { 265 | return; 266 | } 267 | 268 | TurbineDataMonitor monitor = getMonitor(host); 269 | try { 270 | if(hostDispatcher.findHandlerForHost(host, getEventHandler().getName()) == null) { 271 | // this handler is not already present for this host, then add it 272 | hostDispatcher.registerEventHandler(host, getEventHandler()); 273 | } 274 | monitor.startMonitor(); 275 | } catch(Throwable t) { 276 | logger.info("Failed to start monitor: " + monitor.getName() + ", ex message: ", t); 277 | monitor.stopMonitor(); 278 | logger.info("Removing monitor from stats event console"); 279 | TurbineDataMonitor oldMonitor = hostConsole.removeMonitor(monitor.getName()); 280 | if (oldMonitor != null) { 281 | hostCount.decrementAndGet(); 282 | } 283 | } 284 | } 285 | 286 | public void hostDown(Instance host) { 287 | TurbineDataMonitor hostMonitor = hostConsole.findMonitor(host.getHostname()); 288 | if(hostMonitor != null) { 289 | hostCount.decrementAndGet(); 290 | hostMonitor.stopMonitor(); 291 | logger.info("Removing monitor from stats event console"); 292 | hostConsole.removeMonitor(hostMonitor.getName()); 293 | } 294 | } 295 | 296 | private TurbineDataMonitor getMonitor(Instance host) { 297 | String hostName = host.getHostname(); 298 | if(host.getAttributes() != null && host.getAttributes().get("port") != null){ 299 | hostName += ":" + host.getAttributes().get("port"); 300 | } 301 | TurbineDataMonitor monitor = hostConsole.findMonitor(hostName); 302 | if (monitor == null) { 303 | monitor = new InstanceMonitor(host, urlClosure, hostDispatcher, hostConsole); 304 | hostCount.incrementAndGet(); 305 | return hostConsole.findOrRegisterMonitor(monitor); 306 | } else { 307 | return monitor; 308 | } 309 | } 310 | 311 | @Override 312 | public void hostsUp(Collection hosts) { 313 | for (Instance host: hosts) { 314 | try { 315 | hostUp(host); 316 | } catch(Throwable t) { 317 | logger.error("Could not start monitor on hostUp: " + host.toString(), t); 318 | } 319 | } 320 | } 321 | 322 | @Override 323 | public void hostsDown(Collection hosts) { 324 | for (Instance host: hosts) { 325 | try { 326 | hostDown(host); 327 | } catch(Throwable t) { 328 | logger.error("Could not stop monitor on hostDown: " + host.toString(), t); 329 | } 330 | } 331 | } 332 | } 333 | 334 | 335 | @RunWith(MockitoJUnitRunner.class) 336 | public static class UnitTest { 337 | 338 | // the cluster related stuff 339 | @Mock private TurbineDataDispatcher cDispatcher; 340 | @Mock private MonitorConsole cConsole; 341 | 342 | // the host monitor related stuff 343 | @Mock private TurbineDataDispatcher hDispatcher; 344 | @Mock private MonitorConsole hConsole; 345 | 346 | @Mock private InstanceObservable iObservable; 347 | protected InstanceUrlClosure testUrlClosure = new InstanceUrlClosure() { 348 | @Override 349 | public String getUrlPath(Instance host) { 350 | return ""; 351 | } 352 | }; 353 | 354 | @Mock private TurbineDataHandler handler; 355 | @Mock private ObservationCriteria mCriteria; 356 | 357 | @Test 358 | public void testCleanStartupAndShutdown() throws Exception { 359 | 360 | TestClusterMonitor monitor = new TestClusterMonitor(); 361 | 362 | monitor.startMonitor(); 363 | 364 | verify(iObservable).register(monitor.monitorManager); 365 | 366 | monitor.stopMonitor(); 367 | 368 | verify(iObservable).deregister(monitor.monitorManager); 369 | verify(cDispatcher).handleHostLost(monitor.statsInstance); 370 | verify(cDispatcher).stopDispatcher(); 371 | verify(hDispatcher).deregisterEventHandler(handler); 372 | verify(cConsole).removeMonitor(monitor.getName()); 373 | } 374 | 375 | @Test 376 | public void testHostUp() throws Exception { 377 | 378 | InstanceMonitor hostMon = mock(InstanceMonitor.class); 379 | when(hConsole.findMonitor(any(String.class))).thenReturn(hostMon); 380 | 381 | when(mCriteria.observeHost(any(Instance.class))).thenReturn(true); 382 | 383 | TestClusterMonitor monitor = new TestClusterMonitor(); 384 | 385 | Instance host1 = new Instance("testHost1", "testCluster", true); 386 | 387 | monitor.monitorManager.hostsUp(Collections.singletonList(host1)); 388 | 389 | verify(hConsole).findMonitor(host1.getHostname()); 390 | verify(hostMon).startMonitor(); 391 | verify(hDispatcher).registerEventHandler(host1, handler); 392 | } 393 | 394 | @Test 395 | public void testHostDown() throws Exception { 396 | 397 | Instance host1 = new Instance("testHost1", "testCluster", false); 398 | 399 | InstanceMonitor hostMon = mock(InstanceMonitor.class); 400 | when(hConsole.findMonitor(any(String.class))).thenReturn(hostMon); 401 | when(hostMon.getName()).thenReturn(host1.getHostname()); 402 | 403 | TestClusterMonitor monitor = new TestClusterMonitor(); 404 | 405 | 406 | monitor.monitorManager.hostsDown(Collections.singletonList(host1)); 407 | 408 | verify(hConsole).findMonitor(host1.getHostname()); 409 | verify(hostMon).stopMonitor(); 410 | verify(hConsole).removeMonitor("testHost1"); 411 | } 412 | 413 | private class TestClusterMonitor extends ClusterMonitor { 414 | 415 | public TestClusterMonitor() { 416 | super("testMonitor", cDispatcher, cConsole, hDispatcher, hConsole, testUrlClosure, iObservable); 417 | } 418 | 419 | @Override 420 | public TurbineDataHandler getEventHandler() { 421 | return handler; 422 | } 423 | 424 | @Override 425 | public ObservationCriteria getObservationCriteria() { 426 | return mCriteria; 427 | } 428 | } 429 | } 430 | } -------------------------------------------------------------------------------- /hystrix-dashboard/src/main/java/com/netflix/turbine/monitor/instance/InstanceMonitor.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2012 Netflix, Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.netflix.turbine.monitor.instance; 17 | 18 | import static org.junit.Assert.assertFalse; 19 | import static org.junit.Assert.assertNotNull; 20 | import static org.junit.Assert.assertNull; 21 | import static org.junit.Assert.assertTrue; 22 | import static org.mockito.Matchers.any; 23 | import static org.mockito.Mockito.atLeastOnce; 24 | import static org.mockito.Mockito.mock; 25 | import static org.mockito.Mockito.never; 26 | import static org.mockito.Mockito.times; 27 | import static org.mockito.Mockito.verify; 28 | import static org.mockito.Mockito.when; 29 | 30 | import java.io.BufferedReader; 31 | import java.io.File; 32 | import java.io.FileInputStream; 33 | import java.io.IOException; 34 | import java.io.InputStream; 35 | import java.io.InputStreamReader; 36 | import java.net.NoRouteToHostException; 37 | import java.net.UnknownHostException; 38 | import java.util.ArrayList; 39 | import java.util.Collection; 40 | import java.util.HashMap; 41 | import java.util.Iterator; 42 | import java.util.List; 43 | import java.util.Map; 44 | import java.util.Timer; 45 | import java.util.TimerTask; 46 | import java.util.concurrent.Callable; 47 | import java.util.concurrent.ExecutorService; 48 | import java.util.concurrent.Executors; 49 | import java.util.concurrent.Future; 50 | import java.util.concurrent.ThreadFactory; 51 | import java.util.concurrent.TimeUnit; 52 | import java.util.concurrent.atomic.AtomicInteger; 53 | import java.util.concurrent.atomic.AtomicLong; 54 | import java.util.concurrent.atomic.AtomicReference; 55 | 56 | import org.apache.commons.io.IOUtils; 57 | import org.apache.http.HttpEntity; 58 | import org.apache.http.HttpResponse; 59 | import org.apache.http.StatusLine; 60 | import org.apache.http.client.HttpClient; 61 | import org.apache.http.client.methods.HttpGet; 62 | import org.apache.http.client.methods.HttpUriRequest; 63 | import org.apache.http.conn.ClientConnectionManager; 64 | import org.apache.http.entity.InputStreamEntity; 65 | import org.apache.http.impl.client.DefaultHttpClient; 66 | import org.apache.http.params.HttpConnectionParams; 67 | import org.apache.http.params.HttpParams; 68 | import org.codehaus.jackson.JsonParseException; 69 | import org.codehaus.jackson.map.JsonMappingException; 70 | import org.codehaus.jackson.map.ObjectMapper; 71 | import org.codehaus.jackson.map.ObjectReader; 72 | import org.junit.Before; 73 | import org.junit.Test; 74 | import org.slf4j.Logger; 75 | import org.slf4j.LoggerFactory; 76 | 77 | import com.netflix.config.ConfigurationManager; 78 | import com.netflix.config.DynamicBooleanProperty; 79 | import com.netflix.config.DynamicIntProperty; 80 | import com.netflix.config.DynamicPropertyFactory; 81 | import com.netflix.turbine.data.DataFromSingleInstance; 82 | import com.netflix.turbine.discovery.Instance; 83 | import com.netflix.turbine.handler.PerformanceCriteria; 84 | import com.netflix.turbine.handler.TurbineDataDispatcher; 85 | import com.netflix.turbine.handler.TurbineDataHandler; 86 | import com.netflix.turbine.monitor.MonitorConsole; 87 | import com.netflix.turbine.monitor.TurbineDataMonitor; 88 | 89 | /** 90 | * Class that represents a single connection to an {@link Instance}. 91 | *

The InstanceMonitor connects to the host as prescribed by the {@link InstanceUrlClosure} and then streams data down. 92 | * It assumes that the data format is json. 93 | *

The monitor looks for 1st class attributes name and type and the rest of the attributes are parsed into one of 2 attribute maps 94 | * i.e either numericAttributes or stringAttributes. 95 | * 96 | *

The monitor also keeps retrying the host connection unless told to do otherwise. It gives up reconnecting when it finds a bad status code 97 | * such as a 404 not found or {@link UnknownHostException}. 98 | *

However the monitor continues to retry the connection even when it receives an {@link IOException} in order to be resilient against network flakiness. 99 | * 100 | *

Each InstanceMonitor has access to the {@link TurbineDataDispatcher} to dispatch data to. This helps it be decoupled from the {@link TurbineDataHandler} underneath. 101 | * If the dispatcher tells the monitor that there is no one listening then the monitor shuts itself down for efficiency. 102 | */ 103 | public class InstanceMonitor extends TurbineDataMonitor { 104 | 105 | private static final Logger logger = LoggerFactory.getLogger(InstanceMonitor.class); 106 | 107 | private static final ThreadFactory InstanceMonitorThreadFactory = new ThreadFactory() { 108 | private static final String ThreadName = "InstanceMonitor"; 109 | 110 | private final ThreadFactory defaultFactory = Executors.defaultThreadFactory(); 111 | 112 | public Thread newThread(Runnable r) { 113 | Thread thread = defaultFactory.newThread(r); 114 | thread.setDaemon(true); 115 | thread.setName(ThreadName); 116 | return thread; 117 | } 118 | }; 119 | 120 | public static final ExecutorService ThreadPool = Executors.newCachedThreadPool(InstanceMonitorThreadFactory); 121 | 122 | // whether we should employ our "skip line" logic to avoid latency buildups 123 | private static DynamicBooleanProperty skipLineLogic = DynamicPropertyFactory.getInstance().getBooleanProperty("turbine.InstanceMonitor.eventStream.skipLineLogic.enabled", true); 124 | // how latent responses need to be before we trigger the skip logic 125 | private static DynamicIntProperty latencyThreshold = DynamicPropertyFactory.getInstance().getIntProperty("turbine.InstanceMonitor.eventStream.skipLineLogic.latencyThreshold", 2500); 126 | // how long we should wait before processing lines again after a 'latencyThreshold' is met 127 | private static DynamicIntProperty skipLogicDelay = DynamicPropertyFactory.getInstance().getIntProperty("turbine.InstanceMonitor.eventStream.skipLineLogic.delay", 500); 128 | private static DynamicIntProperty hostRetryMillis = DynamicPropertyFactory.getInstance().getIntProperty("turbine.InstanceMonitor.hostRertyMillis", 1000); 129 | 130 | // Tracking state for InstanceMonitor 131 | private enum State { 132 | NotStarted, Running, StopRequested, CleanedUp; 133 | } 134 | 135 | private final AtomicReference monitorState = new AtomicReference(State.NotStarted); 136 | 137 | // the StatsInstance host to connect to 138 | private final Instance host; 139 | private final TurbineDataDispatcher dispatcher; 140 | private final MonitorConsole monitorConsole; 141 | 142 | private BufferedReader reader ; 143 | 144 | private final GatewayHttpClient gatewayHttpClient; 145 | 146 | private final String url; 147 | 148 | // some constants 149 | private static final String NAME_KEY = "name"; 150 | private static final String TYPE_KEY = "type"; 151 | private static final String CURRENT_TIME = "currentTime"; 152 | 153 | private static final String DATA_PREFIX = "data"; 154 | private static final String OPEN_BRACE = "{"; 155 | private static final String REPORTING_HOSTS = "reportingHosts"; 156 | 157 | private final ObjectReader objectReader; 158 | private volatile Future taskFuture; 159 | private final AtomicLong lastEventUpdateTime = new AtomicLong(-1L); 160 | 161 | // useful for debugging purposes, remove later 162 | private final DynamicBooleanProperty LogEnabled; 163 | 164 | /** 165 | * @param host - the host to monitor 166 | * @param urlClosure - config on how to connect to host 167 | * @param dispatcher - the dispatcher to send data to 168 | * @param monitorConsole - the console to manage itself in on startup and shutdown 169 | */ 170 | public InstanceMonitor(Instance host, 171 | InstanceUrlClosure urlClosure, 172 | TurbineDataDispatcher dispatcher, 173 | MonitorConsole monitorConsole) { 174 | this(host, new ProdGatewayHttpClient(), urlClosure, dispatcher, monitorConsole); 175 | } 176 | 177 | private InstanceMonitor(Instance host, 178 | GatewayHttpClient httpClient, 179 | InstanceUrlClosure urlClosure, 180 | TurbineDataDispatcher dispatcher, 181 | MonitorConsole monitorConsole) { 182 | this.host = host; 183 | this.gatewayHttpClient = httpClient; 184 | this.dispatcher = dispatcher; 185 | this.monitorConsole = monitorConsole; 186 | this.url = urlClosure.getUrlPath(host); 187 | logger.info("Url for host: " + url + " " + host.getCluster()); 188 | 189 | ObjectMapper objectMapper = new ObjectMapper(); 190 | objectReader = objectMapper.reader(Map.class); 191 | 192 | LogEnabled = DynamicPropertyFactory.getInstance().getBooleanProperty("InstanceMonitor.LogEnabled." + host.getHostname(), false); 193 | } 194 | 195 | /** 196 | * The name of the InstanceMonitor. 197 | * @return String 198 | */ 199 | @Override 200 | public String getName() { 201 | String hostName = host.getHostname(); 202 | if(this.host.getAttributes() != null && this.host.getAttributes().get("port") != null){ 203 | hostName += ":" + this.host.getAttributes().get("port"); 204 | } 205 | return hostName; 206 | } 207 | 208 | /** 209 | * @return {@link Instance} 210 | */ 211 | @Override 212 | public Instance getStatsInstance() { 213 | return host; 214 | } 215 | 216 | /** 217 | * @return {@link TurbineDataDispatcher}<{@link DataFromSingleInstance}> 218 | */ 219 | @Override 220 | public TurbineDataDispatcher getDispatcher() { 221 | return dispatcher; 222 | } 223 | 224 | /** 225 | * Start monitoring 226 | */ 227 | @Override 228 | public void startMonitor() throws Exception { 229 | // This is the only state that we allow startMonitor to proceed in 230 | if (monitorState.get() != State.NotStarted) { 231 | return; 232 | } 233 | 234 | taskFuture = ThreadPool.submit(new Callable() { 235 | 236 | @Override 237 | public Void call() throws Exception { 238 | 239 | try { 240 | init(); 241 | monitorState.set(State.Running); 242 | while(monitorState.get() == State.Running) { 243 | doWork(); 244 | } 245 | } catch(Throwable t) { 246 | logger.warn("Stopping InstanceMonitor for: " + getStatsInstance().getHostname() + " " + getStatsInstance().getCluster(), t); 247 | } finally { 248 | if (monitorState.get() == State.Running) { 249 | monitorState.set(State.StopRequested); 250 | } 251 | cleanup(); 252 | monitorState.set(State.CleanedUp); 253 | } 254 | return null; 255 | } 256 | }); 257 | } 258 | 259 | /** 260 | * Request monitor to stop 261 | */ 262 | public void stopMonitor() { 263 | monitorState.set(State.StopRequested); 264 | logger.info("Host monitor stop requested: " + getName()); 265 | 266 | if (taskFuture != null) { 267 | logger.info("Cancelling InstanceMonitor task future"); 268 | taskFuture.cancel(true); 269 | } 270 | } 271 | 272 | @Override 273 | public long getLastEventUpdateTime() { 274 | return lastEventUpdateTime.get(); 275 | } 276 | 277 | /** 278 | * Private helper which does all the work 279 | * @throws Exception 280 | */ 281 | private void doWork() throws Exception { 282 | 283 | DataFromSingleInstance instanceData = null; 284 | 285 | instanceData = getNextStatsData(); 286 | if(instanceData == null) { 287 | return; 288 | } else { 289 | lastEventUpdateTime.set(System.currentTimeMillis()); 290 | } 291 | 292 | List list = new ArrayList(); 293 | list.add(instanceData); 294 | 295 | /* send to all handlers */ 296 | boolean continueRunning = dispatcher.pushData(getStatsInstance(), list); 297 | if(!continueRunning) { 298 | logger.info("No more listeners to the host monitor, stopping monitor for: " + host.getHostname() + " " + host.getCluster()); 299 | monitorState.set(State.StopRequested); 300 | return; 301 | } 302 | } 303 | 304 | /** 305 | * Init resources required 306 | * @throws Exception 307 | */ 308 | private void init() throws Exception { 309 | 310 | HttpGet httpget = new HttpGet(url); 311 | 312 | HttpResponse response = gatewayHttpClient.getHttpClient().execute(httpget); 313 | 314 | HttpEntity entity = response.getEntity(); 315 | InputStream is = entity.getContent(); 316 | reader = new BufferedReader(new InputStreamReader(is)); 317 | 318 | int statusCode = response.getStatusLine().getStatusCode(); 319 | if (statusCode != 200) { 320 | // this is unexpected. We probably have the wrong endpoint. Print the response out for debugging and give up here. 321 | List responseMessage = IOUtils.readLines(reader); 322 | logger.error("Could not initiate connection to host, giving up: " + responseMessage); 323 | throw new MisconfiguredHostException(responseMessage.toString()); 324 | } 325 | } 326 | 327 | /** 328 | * Cleanup resources created 329 | * @throws Exception 330 | */ 331 | private void cleanup() throws Exception { 332 | if (monitorState.get() == State.CleanedUp) { 333 | // this has already been done. Return 334 | return; 335 | } 336 | logger.info("Single Server event publisher releasing http client connection for: " + host.getHostname() + " " + host.getCluster()); 337 | gatewayHttpClient.releaseConnections(); 338 | 339 | // let the dispatcher know that this monitor is shutting down 340 | dispatcher.handleHostLost(getStatsInstance()); 341 | 342 | // tell the stats console that this monitor is going away. 343 | logger.info("Removing monitor from StatsEventConsole: " + host.getHostname() + " " + host.getCluster()); 344 | monitorConsole.removeMonitor(getName()); 345 | 346 | monitorState.set(State.CleanedUp); 347 | } 348 | 349 | /** 350 | * Create {@link DataFromSingleInstance} from every line coming over the network connection 351 | * @return {@link DataFromSingleInstance} 352 | * @throws Exception 353 | */ 354 | private DataFromSingleInstance getNextStatsData() throws Exception { 355 | 356 | long skipProcessingUntil = 0; 357 | 358 | try { 359 | String line = null; 360 | while ((line = reader.readLine()) != null) { 361 | 362 | if(Thread.currentThread().isInterrupted()) { 363 | logger.info("Current thread is interrupted, returning."); 364 | monitorState.set(State.StopRequested); 365 | return null; 366 | } 367 | 368 | long currentTime = System.currentTimeMillis(); 369 | 370 | if (skipLineLogic.get()) { 371 | if (currentTime < skipProcessingUntil) { 372 | // continue ... skip processing and just keep reading from the stream 373 | if (logger.isDebugEnabled()) { 374 | logger.debug("Skipping event to catch up to end of feed and reduce latency"); 375 | } 376 | continue; 377 | } 378 | } 379 | 380 | line = line.trim(); 381 | if (line.length() == 0 || (!line.startsWith(DATA_PREFIX))) { 382 | // empty line or invalid so skip processing to next line 383 | continue; 384 | } 385 | 386 | // we expect JSON on data lines 387 | int pos = line.indexOf(OPEN_BRACE); 388 | if (pos < 0) { 389 | continue; 390 | } 391 | String jsonString = line.substring(pos); 392 | 393 | try { 394 | Map json = objectReader.readValue(jsonString); 395 | 396 | String type = (String) json.remove(TYPE_KEY); 397 | String name = (String) json.remove(NAME_KEY); 398 | 399 | if (type == null || name == null) { 400 | if (logger.isDebugEnabled()) { 401 | logger.debug("Type and/or name missing, skipping line: " + line); 402 | } 403 | return null; 404 | } 405 | 406 | long timeOfEvent = -1; 407 | long latency = -1; 408 | if (skipLineLogic.get()) { 409 | // we have the actual time the event data was created so use that to track latency 410 | if (json.containsKey(CURRENT_TIME)) { 411 | timeOfEvent = (Long) json.get(CURRENT_TIME); 412 | } 413 | 414 | if (timeOfEvent <= 0) { 415 | // default to using now as the time ... it won't track actual latency, but will track from this point on 416 | timeOfEvent = System.currentTimeMillis(); 417 | json.put(CURRENT_TIME, timeOfEvent); 418 | } 419 | 420 | latency = currentTime - timeOfEvent; 421 | if (timeOfEvent > 0) { 422 | if (logger.isDebugEnabled()) { 423 | logger.debug("----> Pushed to cluster. Latency of event: " + latency + " + timeOfEvent: " + timeOfEvent + " [" + name + "]"); 424 | } 425 | } 426 | } 427 | 428 | if (skipLineLogic.get() && timeOfEvent > 0 && latency > latencyThreshold.get()) { 429 | // tell the loop to ignore all events for the next X milliseconds so it can just read data from the stream and catch up 430 | if (logger.isDebugEnabled()) { 431 | logger.info("Telling stream reader to wait for 1 second before processing anymore so it can catch up." + latency); 432 | } 433 | skipProcessingUntil = System.currentTimeMillis() + skipLogicDelay.get(); 434 | // we also skip pushing this data since it's latent and we would rather quickly catch up and send current data than sending this latent data 435 | 436 | markEventDiscarded(); 437 | continue; 438 | } 439 | 440 | HashMap nAttrs = new HashMap(); 441 | HashMap sAttrs = new HashMap(); 442 | HashMap> mapAttrs = new HashMap>(); 443 | 444 | @SuppressWarnings("unchecked") 445 | // the JSONObject doesn't use generics so I'm ignoring the warning 446 | Iterator keys = json.keySet().iterator(); 447 | while (keys.hasNext()) { 448 | String key = keys.next(); 449 | Object value = json.get(key); 450 | 451 | if (value instanceof Integer) { 452 | long longValue = ((Integer) value).longValue(); 453 | nAttrs.put(key, longValue); 454 | } else if (value instanceof Long) { 455 | long longValue = (Long) value; 456 | nAttrs.put(key, longValue); 457 | } else if (value instanceof Map) { 458 | Map mapValue = (Map) value; 459 | mapAttrs.put(key, mapValue); 460 | } else { 461 | sAttrs.put(key, String.valueOf(value)); 462 | } 463 | } 464 | 465 | 466 | if (!nAttrs.containsKey(REPORTING_HOSTS)) { 467 | nAttrs.put(REPORTING_HOSTS, 1L); 468 | } 469 | 470 | return new DataFromSingleInstance(this, type, name, host, nAttrs, sAttrs, mapAttrs, timeOfEvent); 471 | 472 | } catch (JsonParseException e) { 473 | if (logger.isDebugEnabled() || LogEnabled.get()) { 474 | logger.info("Got JSON Ex for host: " + this.getName() + ", ex:" + e.getMessage() + " " + line, e); 475 | } 476 | 477 | return null; 478 | } catch (JsonMappingException e) { 479 | if (logger.isDebugEnabled() || LogEnabled.get()) { 480 | logger.info("Got JSON Ex for host: " + this.getName() + ", ex:" + e.getMessage() + " " + line, e); 481 | } 482 | 483 | return null; 484 | } 485 | } 486 | 487 | } catch (IOException ioe) { 488 | logger.info("Got ioe for host: " + this.getName()); 489 | retryHostConnection(); 490 | return null; 491 | } 492 | // if we reach here, then we have no more data from this connection. 493 | String message = String.format("no more data from connection to %s", this.host.getHostname()); 494 | logger.info(message); 495 | retryHostConnection(); 496 | return null; 497 | } 498 | 499 | /** 500 | * Helper to retry the host connection on network hiccups. 501 | * @throws Exception 502 | */ 503 | private void retryHostConnection() throws Exception { 504 | 505 | boolean succeeded = false; 506 | 507 | while(!succeeded && (monitorState.get() == State.Running)) { 508 | // first clean up connection resources 509 | this.gatewayHttpClient.releaseConnections(); 510 | try { 511 | logger.info("Re-initing host connection: " + host.getHostname() + " " + host.getCluster()); 512 | this.init(); 513 | succeeded = true; 514 | } catch (NoRouteToHostException e) { 515 | logger.warn("Found no route to host connection: " + host.getHostname() + " " + host.getCluster() + " will not retry", e); 516 | monitorState.set(State.StopRequested); 517 | } catch (MisconfiguredHostException e) { 518 | logger.warn("Found MisconfiguredHostException host connection: " + host.getHostname() + " " + host.getCluster() + " will not retry", e); 519 | monitorState.set(State.StopRequested); 520 | } catch (Exception e) { 521 | logger.warn("Could not init host connection: " + host.getHostname() + " " + host.getCluster() + " will continue to retry", e); 522 | } finally { 523 | try { 524 | Thread.sleep(hostRetryMillis.get()); 525 | } catch (InterruptedException ie) { 526 | logger.warn("Instance Monitor got interrupted"); 527 | monitorState.set(State.StopRequested); 528 | } 529 | } 530 | } 531 | if (monitorState.get() != State.Running) { 532 | throw new Exception("Giving up on retry connection"); 533 | } 534 | } 535 | 536 | /** 537 | * @return true/false 538 | */ 539 | public boolean monitorRunning() { 540 | return monitorState.get() == State.Running; 541 | } 542 | 543 | /** 544 | * @return true/false 545 | */ 546 | public boolean hasStopped() { 547 | return monitorState.get() == State.CleanedUp; 548 | } 549 | 550 | /** 551 | * Helper interface for unit testing 552 | */ 553 | private interface GatewayHttpClient { 554 | HttpClient getHttpClient(); 555 | void releaseConnections(); 556 | } 557 | 558 | public static void stop() { 559 | ThreadPool.shutdown(); 560 | } 561 | 562 | private static class ProdGatewayHttpClient implements GatewayHttpClient { 563 | HttpClient httpClient; 564 | 565 | @Override 566 | public HttpClient getHttpClient() { 567 | httpClient = new DefaultHttpClient(); 568 | HttpParams httpParams = httpClient.getParams(); 569 | HttpConnectionParams.setConnectionTimeout(httpParams, 10000); 570 | HttpConnectionParams.setSoTimeout(httpParams, 10000); // we expect a 'ping' at least every 3 seconds even if no data is coming so 4 seconds means something is wrong 571 | return httpClient; 572 | } 573 | 574 | @Override 575 | public void releaseConnections() { 576 | try { 577 | if (httpClient != null && httpClient.getConnectionManager() != null) { 578 | // When HttpClient instance is no longer needed, shut down the connection manager to ensure immediate deallocation of all system resources 579 | httpClient.getConnectionManager().shutdown(); 580 | httpClient = null; 581 | } 582 | } catch (Exception e) { 583 | logger.error("We failed closing connection to the HTTP server", e); 584 | } 585 | } 586 | } 587 | 588 | 589 | private class MisconfiguredHostException extends Exception { 590 | 591 | private static final long serialVersionUID = 1L; 592 | 593 | public MisconfiguredHostException(String arg0) { 594 | super(arg0); 595 | } 596 | } 597 | 598 | public static class UnitTest { 599 | 600 | // all the stuff I could possibly need for unit testing various scenarios. 601 | Instance instance = new Instance("testInstance", "testCluster", true); 602 | HttpClient mockClient; 603 | ClientConnectionManager mockConnManager; 604 | GatewayHttpClient gatewayClient; 605 | 606 | InstanceMonitor monitor; 607 | TurbineDataDispatcher dispatcher; 608 | 609 | PerformanceCriteria perfCriteria = new PerformanceCriteria() { 610 | @Override 611 | public boolean isCritical() { 612 | return false; 613 | } 614 | @Override 615 | public int getMaxQueueSize() { 616 | return 1; 617 | } 618 | @Override 619 | public int numThreads() { 620 | return 0; 621 | } 622 | }; 623 | 624 | TurbineDataHandler eventHandler; 625 | 626 | File file; 627 | 628 | @Before 629 | public void before() { 630 | file = new File("main/testfiles/StatsSingleServerMonitorUnitTest.txt"); 631 | 632 | if (!file.exists()) { 633 | file = new File("testfiles/StatsSingleServerMonitorUnitTest.txt"); 634 | } 635 | } 636 | 637 | @SuppressWarnings("unchecked") 638 | private void doTheMockMagic(InputStream dataStream) throws Exception { 639 | 640 | // property override that states that it is ok to receive really old data (we need to do this since we are re-driving old static data through this test) 641 | ConfigurationManager.getConfigInstance().setProperty("turbine.InstanceMonitor.eventStream.skipLineLogic.enabled", false); 642 | 643 | StatusLine sLine = mock(StatusLine.class); 644 | when(sLine.getStatusCode()).thenReturn(200); 645 | 646 | HttpResponse mockResponse = mock(HttpResponse.class); 647 | when(mockResponse.getEntity()).thenReturn(new InputStreamEntity(dataStream, -1)); 648 | when(mockResponse.getStatusLine()).thenReturn(sLine); 649 | 650 | mockConnManager = mock(ClientConnectionManager.class); 651 | mockClient = mock(HttpClient.class); 652 | 653 | when(mockClient.execute(any(HttpUriRequest.class))).thenReturn(mockResponse); 654 | when(mockClient.getConnectionManager()).thenReturn(mockConnManager); 655 | 656 | gatewayClient = new GatewayHttpClient() { 657 | @Override 658 | public HttpClient getHttpClient() { 659 | return mockClient; 660 | } 661 | @Override 662 | public void releaseConnections() { 663 | mockConnManager.shutdown(); 664 | } 665 | }; 666 | 667 | InstanceUrlClosure urlClosure = mock(InstanceUrlClosure.class); 668 | when(urlClosure.getUrlPath(instance)).thenReturn("http://foo.com/"); 669 | 670 | dispatcher = new TurbineDataDispatcher("TEST"); 671 | monitor = new InstanceMonitor(instance, gatewayClient, urlClosure, dispatcher, new MonitorConsole()); 672 | 673 | eventHandler = mock(TurbineDataHandler.class); 674 | when(eventHandler.getName()).thenReturn("handler"); 675 | when(eventHandler.getCriteria()).thenReturn(perfCriteria); 676 | 677 | 678 | monitor.getDispatcher().registerEventHandler(instance, eventHandler); 679 | 680 | return; 681 | } 682 | 683 | @Test 684 | public void testProcessFiniteStream() throws Exception { 685 | 686 | doTheMockMagic(new FileInputStream(file)); 687 | 688 | monitor.startMonitor(); 689 | 690 | Thread.sleep(1000); 691 | 692 | verify(mockConnManager, times(1)).shutdown(); 693 | verify(eventHandler, never()).handleHostLost(instance); 694 | 695 | monitor.stopMonitor(); 696 | 697 | Thread.sleep(500); 698 | 699 | verify(eventHandler, times(1)).handleHostLost(instance); 700 | assertNull(monitor.getDispatcher().findHandlerForHost(instance, "handler")); 701 | 702 | dispatcher.stopDispatcher(); 703 | } 704 | 705 | class InfiniteInputStream extends InputStream { 706 | 707 | InputStream in = null; 708 | @Override 709 | public int read() throws IOException { 710 | if(in == null) { 711 | in = new FileInputStream(file); 712 | } 713 | int read = in.read(); 714 | if(read != -1) { 715 | return read; 716 | } 717 | in.close(); 718 | in = new FileInputStream(file); 719 | return in.read(); 720 | } 721 | } 722 | 723 | 724 | @Test(timeout=2000) 725 | public void testProcessInfiniteStream() throws Exception { 726 | 727 | doTheMockMagic(new InfiniteInputStream()); 728 | 729 | monitor.startMonitor(); 730 | Thread.sleep(1000); 731 | 732 | assertTrue(monitor.monitorRunning()); 733 | 734 | monitor.stopMonitor(); 735 | 736 | while(!monitor.hasStopped()) { 737 | Thread.sleep(50); 738 | } 739 | 740 | verify(mockConnManager, times(1)).shutdown(); 741 | verify(eventHandler, times(1)).handleHostLost(instance); 742 | assertNull(monitor.getDispatcher().findHandlerForHost(instance, "handler")); 743 | 744 | dispatcher.stopDispatcher(); 745 | } 746 | 747 | @Test 748 | public void testInfiniteRetryOnIOException() throws Exception { 749 | 750 | TimeBombInputStream timeBombStream = new TimeBombInputStream(); 751 | 752 | doTheMockMagic(timeBombStream); 753 | 754 | monitor.startMonitor(); 755 | Thread.sleep(100); 756 | assertTrue(monitor.monitorRunning()); 757 | 758 | Thread.sleep(3000); 759 | 760 | assertTrue(monitor.monitorRunning()); 761 | assertTrue(timeBombStream.count.get() >= 1); 762 | 763 | verify(mockConnManager, atLeastOnce()).shutdown(); 764 | verify(eventHandler, never()).handleHostLost(instance); 765 | 766 | monitor.stopMonitor(); 767 | assertFalse(monitor.monitorRunning()); 768 | 769 | Thread.sleep(2000); 770 | 771 | verify(mockConnManager, atLeastOnce()).shutdown(); 772 | verify(eventHandler, times(1)).handleHostLost(instance); 773 | assertNull(monitor.getDispatcher().findHandlerForHost(instance, "handler")); 774 | 775 | assertTrue(monitor.hasStopped()); 776 | 777 | dispatcher.stopDispatcher(); 778 | } 779 | 780 | @Test(timeout=2000) 781 | public void testStartMonitorAndNoEventHandlers() throws Exception { 782 | 783 | doTheMockMagic(new InfiniteInputStream()); 784 | 785 | monitor.getDispatcher().deregisterEventHandler("handler"); 786 | monitor.startMonitor(); 787 | Thread.sleep(200); 788 | 789 | while(monitor.monitorRunning()) { 790 | Thread.sleep(50); 791 | } 792 | 793 | verify(mockConnManager, atLeastOnce()).shutdown(); 794 | 795 | assertNull(monitor.getDispatcher().findHandlerForHost(instance, "handler")); 796 | 797 | dispatcher.stopDispatcher(); 798 | } 799 | 800 | private static PerformanceCriteria testCriteria = new PerformanceCriteria() { 801 | @Override 802 | public boolean isCritical() { 803 | return false; 804 | } 805 | @Override 806 | public int getMaxQueueSize() { 807 | return 10000; 808 | } 809 | @Override 810 | public int numThreads() { 811 | return 10; 812 | } 813 | }; 814 | 815 | private class StatsCounter implements TurbineDataHandler { 816 | 817 | private AtomicInteger count = new AtomicInteger(0); 818 | private boolean handleHostLostCalled = false; 819 | 820 | String nameS; 821 | StatsCounter(String name) { 822 | this.nameS = name; 823 | } 824 | @Override 825 | public String getName() { 826 | return nameS; 827 | } 828 | 829 | @Override 830 | public void handleData(Collection stats) { 831 | count.addAndGet(stats.size()); 832 | } 833 | 834 | @Override 835 | public void handleHostLost(Instance host) { 836 | handleHostLostCalled = true; 837 | } 838 | 839 | int getCount() { 840 | return count.get(); 841 | } 842 | @Override 843 | public PerformanceCriteria getCriteria() { 844 | return testCriteria; 845 | } 846 | } 847 | 848 | private class TimeBombInputStream extends InfiniteInputStream { 849 | 850 | private volatile boolean blowUp = false; 851 | private final AtomicInteger count = new AtomicInteger(0); 852 | 853 | private TimeBombInputStream() { 854 | TimerTask task = new TimerTask() { 855 | @Override 856 | public void run() { 857 | blowUp = true; 858 | } 859 | }; 860 | Timer timer = new Timer(); 861 | timer.schedule(task, 500); 862 | } 863 | 864 | @Override 865 | public int read() throws IOException { 866 | if(blowUp) { 867 | count.incrementAndGet(); 868 | throw new IOException("Kaboom"); 869 | } 870 | return super.read(); 871 | } 872 | } 873 | 874 | @Test 875 | public void testStopMonitorOnNoRouteToHostException() throws Exception { 876 | 877 | TimeBombInputStream timeBombStream = new TimeBombInputStream(); 878 | 879 | // property override that states that it is ok to receive really old data (we need to do this since we are re-driving old static data through this test) 880 | ConfigurationManager.getConfigInstance().setProperty("turbine.InstanceMonitor.eventStream.skipLineLogic.enabled", false); 881 | 882 | StatusLine sLine = mock(StatusLine.class); 883 | when(sLine.getStatusCode()).thenReturn(200); 884 | 885 | final HttpResponse mockResponse = mock(HttpResponse.class); 886 | when(mockResponse.getEntity()).thenReturn(new InputStreamEntity(timeBombStream, -1)); 887 | when(mockResponse.getStatusLine()).thenReturn(sLine); 888 | 889 | mockConnManager = mock(ClientConnectionManager.class); 890 | mockClient = mock(HttpClient.class); 891 | 892 | when(mockClient.execute(any(HttpUriRequest.class))).thenReturn(mockResponse).thenThrow(new NoRouteToHostException()); 893 | 894 | when(mockClient.getConnectionManager()).thenReturn(mockConnManager); 895 | 896 | gatewayClient = new GatewayHttpClient() { 897 | @Override 898 | public HttpClient getHttpClient() { 899 | return mockClient; 900 | } 901 | @Override 902 | public void releaseConnections() { 903 | mockConnManager.shutdown(); 904 | } 905 | }; 906 | 907 | InstanceUrlClosure urlClosure = mock(InstanceUrlClosure.class); 908 | when(urlClosure.getUrlPath(instance)).thenReturn("http://foo.com/"); 909 | 910 | dispatcher = new TurbineDataDispatcher("TEST"); 911 | monitor = new InstanceMonitor(instance, gatewayClient, urlClosure, dispatcher, new MonitorConsole()); 912 | 913 | eventHandler = mock(TurbineDataHandler.class); 914 | when(eventHandler.getName()).thenReturn("handler"); 915 | when(eventHandler.getCriteria()).thenReturn(perfCriteria); 916 | 917 | 918 | monitor.getDispatcher().registerEventHandler(instance, eventHandler); 919 | 920 | monitor.startMonitor(); 921 | Thread.sleep(2000); 922 | assertFalse(monitor.monitorRunning()); 923 | 924 | verify(mockConnManager, times(2)).shutdown(); 925 | verify(eventHandler, times(1)).handleHostLost(instance); 926 | 927 | assertNull(monitor.getDispatcher().findHandlerForHost(instance, "handler")); 928 | assertTrue(monitor.hasStopped()); 929 | 930 | dispatcher.stopDispatcher(); 931 | } 932 | 933 | 934 | @Test 935 | public void testStartMonitorsAndTransientEventHandlers() throws Exception { 936 | 937 | doTheMockMagic( new InfiniteInputStream()); 938 | 939 | monitor.getDispatcher().deregisterEventHandler("handler"); 940 | 941 | StatsCounter c1 = new StatsCounter("c1"); 942 | monitor.getDispatcher().registerEventHandler(instance, c1); 943 | 944 | monitor.startMonitor(); 945 | 946 | Thread.sleep(500); 947 | 948 | StatsCounter c2 = new StatsCounter("c2"); 949 | monitor.getDispatcher().registerEventHandler(instance, c2); 950 | 951 | Thread.sleep(500); 952 | 953 | assertNotNull(monitor.getDispatcher().findHandlerForHost(instance, "c1")); 954 | assertNotNull(monitor.getDispatcher().findHandlerForHost(instance, "c2")); 955 | assertFalse(c1.handleHostLostCalled); 956 | assertFalse(c2.handleHostLostCalled); 957 | 958 | monitor.getDispatcher().deregisterEventHandler("c2"); 959 | 960 | Thread.sleep(500); 961 | 962 | monitor.getDispatcher().deregisterEventHandler("c1"); 963 | 964 | while(monitor.monitorRunning()) { 965 | Thread.sleep(50); 966 | } 967 | 968 | assertNull(monitor.getDispatcher().findHandlerForHost(instance, "handler")); 969 | assertNull(monitor.getDispatcher().findHandlerForHost(instance, "c1")); 970 | assertNull(monitor.getDispatcher().findHandlerForHost(instance, "c2")); 971 | 972 | assertTrue(c1.getCount() > 0); 973 | assertTrue(c2.getCount() > 0); 974 | assertTrue(c1.getCount() > c2.getCount()); 975 | assertTrue(c1.handleHostLostCalled); 976 | assertTrue(c2.handleHostLostCalled); 977 | 978 | dispatcher.stopDispatcher(); 979 | } 980 | } 981 | } 982 | -------------------------------------------------------------------------------- /hystrix-dashboard/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: hystrix-dashboard 4 | 5 | server: 6 | port: 10000 7 | 8 | turbine: 9 | appConfig: stories-microservice,storyteller-api 10 | instanceUrlSuffix: /hystrix.stream 11 | clusterNameExpression: new String("default") -------------------------------------------------------------------------------- /hystrix-dashboard/src/test/java/com/codependent/storyteller/HystrixDashboardApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.SpringApplicationConfiguration; 6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 | 8 | @RunWith(SpringJUnit4ClassRunner.class) 9 | @SpringApplicationConfiguration(classes = HystrixDashboardApplication.class) 10 | public class HystrixDashboardApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /images-ms/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.mvn 3 | /.bin 4 | /.settings 5 | .classpath 6 | .project 7 | /.springBeans 8 | -------------------------------------------------------------------------------- /images-ms/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /images-ms/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 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /images-ms/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.codependent.storyteller 7 | images-ms 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | RandomImageMs 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.3.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-config 34 | 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-starter-eureka 39 | 40 | 41 | 42 | org.springframework.boot 43 | spring-boot-starter-aop 44 | 45 | 46 | org.springframework.retry 47 | spring-retry 48 | 49 | 50 | 51 | commons-io 52 | commons-io 53 | 2.4 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter-test 59 | test 60 | 61 | 62 | 63 | 64 | 65 | 66 | org.springframework.cloud 67 | spring-cloud-starter-parent 68 | Brixton.M3 69 | pom 70 | import 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.springframework.boot 79 | spring-boot-maven-plugin 80 | 81 | 82 | 83 | 84 | 85 | 86 | spring-snapshots 87 | Spring Snapshots 88 | https://repo.spring.io/snapshot 89 | 90 | true 91 | 92 | 93 | 94 | spring-milestones 95 | Spring Milestones 96 | https://repo.spring.io/milestone 97 | 98 | false 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /images-ms/src/main/java/com/codependent/storyteller/ImageService.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.springframework.stereotype.Service; 4 | 5 | @Service 6 | public class ImageService { 7 | 8 | public static String[] images = { 9 | "minion-carl.jpg", 10 | "minion-dave.jpg", 11 | "minion-evil.jpg", 12 | "minion-kevin.jpg", 13 | "minion-phil.jpg", 14 | "minion-stuart.jpg", 15 | "minion-tim.jpg", 16 | "minion-tom.jpg", 17 | "minion-wolverine.jpg" 18 | }; 19 | 20 | public String getRandomImage(){ 21 | long random = Math.round(Math.random()*(images.length-1)); 22 | return images[(int)random]; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /images-ms/src/main/java/com/codependent/storyteller/RandomImageMsApplication.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.InputStream; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import javax.servlet.ServletOutputStream; 10 | import javax.servlet.http.HttpServletRequest; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | import org.apache.commons.io.IOUtils; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.beans.factory.annotation.Value; 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | import org.springframework.boot.builder.SpringApplicationBuilder; 20 | import org.springframework.cloud.context.config.annotation.RefreshScope; 21 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 22 | import org.springframework.web.bind.annotation.PathVariable; 23 | import org.springframework.web.bind.annotation.RequestMapping; 24 | import org.springframework.web.bind.annotation.RestController; 25 | 26 | @RestController 27 | @EnableEurekaClient 28 | @RefreshScope 29 | @SpringBootApplication 30 | public class RandomImageMsApplication { 31 | 32 | private Logger logger = LoggerFactory.getLogger(getClass()); 33 | 34 | @Value("${images-ms-message}") 35 | private String message; 36 | 37 | @Autowired 38 | private ImageService imageService; 39 | 40 | @RequestMapping(value="/images", params={"random=true", "fields=url"}) 41 | public Map getRandomImageUrl(HttpServletRequest request) { 42 | logger.info("[{}] getRandomImageUrl()", message); 43 | String scheme = request.getScheme(); 44 | String server = request.getServerName(); 45 | int port = request.getServerPort(); 46 | Map image = new HashMap(); 47 | image.put("imageUrl", scheme+"://"+server+":"+port+"/images/"+imageService.getRandomImage()); 48 | return image; 49 | } 50 | 51 | @RequestMapping("/images/{image:.+}") 52 | public void getRandomImage(@PathVariable String image, HttpServletResponse response) throws Exception { 53 | InputStream is = new FileInputStream(new File(getClass().getResource("/images/"+image).toURI())); 54 | ServletOutputStream os = response.getOutputStream(); 55 | IOUtils.copy(is, os); 56 | response.setContentType("image/jpg"); 57 | } 58 | 59 | public static void main(String[] args) { 60 | new SpringApplicationBuilder(RandomImageMsApplication.class).web(true).run(args); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /images-ms/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: images-microservice 4 | cloud: 5 | config: 6 | discovery: 7 | enabled: true 8 | failFast: true 9 | retry: 10 | maxAttempts: 100 11 | initialInterval: 2000 12 | maxInterval: 3000 13 | multiplier: 1.5 14 | 15 | server: 16 | port: 9999 17 | 18 | eureka: 19 | client: 20 | serviceUrl: 21 | defaultZone: http://localhost:8761/eureka/ 22 | healthcheck: 23 | enabled: true 24 | 25 | logging: 26 | # file: /var/memento/security.log 27 | level: 28 | org.springframework.web: 'DEBUG' -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-carl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-carl.jpg -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-dave.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-dave.jpg -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-evil.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-evil.jpg -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-kevin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-kevin.jpg -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-phil.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-phil.jpg -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-stuart.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-stuart.jpg -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-tim.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-tim.jpg -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-tom.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-tom.jpg -------------------------------------------------------------------------------- /images-ms/src/main/resources/images/minion-wolverine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codependent/storyteller-microservices/f15919fb7b3df3fff44980863702709b79ad612d/images-ms/src/main/resources/images/minion-wolverine.jpg -------------------------------------------------------------------------------- /images-ms/src/test/java/com/codependent/storyteller/RandomImageMsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.SpringApplicationConfiguration; 6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 | 8 | import com.codependent.storyteller.RandomImageMsApplication; 9 | 10 | @RunWith(SpringJUnit4ClassRunner.class) 11 | @SpringApplicationConfiguration(classes = RandomImageMsApplication.class) 12 | public class RandomImageMsApplicationTests { 13 | 14 | @Test 15 | public void contextLoads() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /stories-ms/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.mvn 3 | /.bin 4 | /.settings 5 | .classpath 6 | .project -------------------------------------------------------------------------------- /stories-ms/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /stories-ms/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 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /stories-ms/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.codependent.storyteller 7 | stories-ms 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | stories-ms 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.3.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-hystrix 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-config 38 | 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-starter-eureka 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter-aop 48 | 49 | 50 | org.springframework.retry 51 | spring-retry 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-test 57 | test 58 | 59 | 60 | 61 | 62 | 63 | 64 | org.springframework.cloud 65 | spring-cloud-starter-parent 66 | Brixton.M3 67 | pom 68 | import 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-maven-plugin 78 | 79 | 80 | 81 | 82 | 83 | 84 | spring-snapshots 85 | Spring Snapshots 86 | https://repo.spring.io/snapshot 87 | 88 | true 89 | 90 | 91 | 92 | spring-milestones 93 | Spring Milestones 94 | https://repo.spring.io/milestone 95 | 96 | false 97 | 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /stories-ms/src/main/java/com/codependent/storyteller/HtmlGeneratorMsApplication.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import java.net.URISyntaxException; 4 | import java.util.Map; 5 | 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.SpringApplication; 13 | import org.springframework.boot.autoconfigure.SpringBootApplication; 14 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 15 | import org.springframework.cloud.context.config.annotation.RefreshScope; 16 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RestController; 19 | import org.springframework.web.client.RestClientException; 20 | 21 | @RestController 22 | @EnableEurekaClient 23 | @EnableCircuitBreaker 24 | @RefreshScope 25 | @SpringBootApplication 26 | public class HtmlGeneratorMsApplication { 27 | 28 | private Logger logger = LoggerFactory.getLogger(getClass()); 29 | 30 | @Value("${stories-ms-message}") 31 | private String message; 32 | 33 | @Autowired 34 | private StoryService storyService; 35 | 36 | @RequestMapping(value="/stories", params="random=true") 37 | public String generateHtml(HttpServletResponse response) throws RestClientException, URISyntaxException{ 38 | logger.info("[{}] generateHtml()", message); 39 | Map randomImage = storyService.getRandomImage(); 40 | 41 | String html = ""+storyService.getRandomStory()+""; 42 | html = String.format(html, randomImage.get("imageUrl")); 43 | response.setContentType("text/html"); 44 | return html; 45 | } 46 | 47 | public static void main(String[] args) { 48 | SpringApplication.run(HtmlGeneratorMsApplication.class, args); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /stories-ms/src/main/java/com/codependent/storyteller/StoryService.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.core.ParameterizedTypeReference; 10 | import org.springframework.http.HttpMethod; 11 | import org.springframework.stereotype.Service; 12 | import org.springframework.web.client.RestTemplate; 13 | 14 | import com.netflix.appinfo.InstanceInfo; 15 | import com.netflix.discovery.EurekaClient; 16 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 17 | 18 | @Service 19 | public class StoryService { 20 | 21 | private static String[] stories = { 22 | "

Once upon a time there lived

", 23 | "

In an Italian habour, at the foot of the mountain, lives our friend

", 24 | "

A long time ago in a galaxy far, far away...

", 25 | }; 26 | 27 | private Logger logger = LoggerFactory.getLogger(getClass()); 28 | 29 | @Autowired 30 | private EurekaClient discoveryClient; 31 | 32 | private RestTemplate restTemplate = new RestTemplate(); 33 | 34 | @HystrixCommand(fallbackMethod="imageServiceNotAvailable") 35 | public Map getRandomImage(){ 36 | InstanceInfo ii = discoveryClient.getNextServerFromEureka("IMAGES-MICROSERVICE", false); 37 | String homePageUrl = ii.getHomePageUrl(); 38 | Map imageInfo = restTemplate.exchange(homePageUrl+"/images?random=true&fields=url", HttpMethod.GET, null, new ParameterizedTypeReference>() {}, new Object[]{}).getBody(); 39 | return imageInfo; 40 | } 41 | 42 | public String getRandomStory(){ 43 | long random = Math.round(Math.random()*(stories.length-1)); 44 | return stories[(int)random]; 45 | } 46 | 47 | protected Map imageServiceNotAvailable(){ 48 | logger.warn("imageServiceNotAvailable()"); 49 | Map i = new HashMap(); 50 | i.put("imageUrl", "https://camo.githubusercontent.com/e871b5d002a9699e7a2d9fa0178af5c72f0743e0/68747470733a2f2f6e6574666c69782e6769746875622e636f6d2f487973747269782f696d616765732f687973747269782d6c6f676f2d7461676c696e652d3835302e706e67"); 51 | return i; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /stories-ms/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: stories-microservice 4 | cloud: 5 | config: 6 | discovery: 7 | enabled: true 8 | failFast: true 9 | retry: 10 | maxAttempts: 100 11 | initialInterval: 2000 12 | maxInterval: 3000 13 | multiplier: 1.5 14 | 15 | server: 16 | port: 9988 17 | 18 | eureka: 19 | client: 20 | serviceUrl: 21 | defaultZone: http://localhost:8761/eureka/ 22 | healthcheck: 23 | enabled: true 24 | 25 | logging: 26 | # file: /var/memento/security.log 27 | level: 28 | org.springframework.web: 'DEBUG' -------------------------------------------------------------------------------- /stories-ms/src/test/java/com/codependent/storyteller/HtmlGeneratorMsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.SpringApplicationConfiguration; 6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 | 8 | import com.codependent.storyteller.HtmlGeneratorMsApplication; 9 | 10 | @RunWith(SpringJUnit4ClassRunner.class) 11 | @SpringApplicationConfiguration(classes = HtmlGeneratorMsApplication.class) 12 | public class HtmlGeneratorMsApplicationTests { 13 | 14 | @Test 15 | public void contextLoads() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /storyteller-api/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.mvn 3 | /.bin 4 | /.settings 5 | .classpath 6 | .project -------------------------------------------------------------------------------- /storyteller-api/.springBeans: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /storyteller-api/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # 58 | # Look for the Apple JDKs first to preserve the existing behaviour, and then look 59 | # for the new JDKs provided by Oracle. 60 | # 61 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then 62 | # 63 | # Apple JDKs 64 | # 65 | export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home 66 | fi 67 | 68 | if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then 69 | # 70 | # Apple JDKs 71 | # 72 | export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 73 | fi 74 | 75 | if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then 76 | # 77 | # Oracle JDKs 78 | # 79 | export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home 80 | fi 81 | 82 | if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then 83 | # 84 | # Apple JDKs 85 | # 86 | export JAVA_HOME=`/usr/libexec/java_home` 87 | fi 88 | ;; 89 | esac 90 | 91 | if [ -z "$JAVA_HOME" ] ; then 92 | if [ -r /etc/gentoo-release ] ; then 93 | JAVA_HOME=`java-config --jre-home` 94 | fi 95 | fi 96 | 97 | if [ -z "$M2_HOME" ] ; then 98 | ## resolve links - $0 may be a link to maven's home 99 | PRG="$0" 100 | 101 | # need this for relative symlinks 102 | while [ -h "$PRG" ] ; do 103 | ls=`ls -ld "$PRG"` 104 | link=`expr "$ls" : '.*-> \(.*\)$'` 105 | if expr "$link" : '/.*' > /dev/null; then 106 | PRG="$link" 107 | else 108 | PRG="`dirname "$PRG"`/$link" 109 | fi 110 | done 111 | 112 | saveddir=`pwd` 113 | 114 | M2_HOME=`dirname "$PRG"`/.. 115 | 116 | # make it fully qualified 117 | M2_HOME=`cd "$M2_HOME" && pwd` 118 | 119 | cd "$saveddir" 120 | # echo Using m2 at $M2_HOME 121 | fi 122 | 123 | # For Cygwin, ensure paths are in UNIX format before anything is touched 124 | if $cygwin ; then 125 | [ -n "$M2_HOME" ] && 126 | M2_HOME=`cygpath --unix "$M2_HOME"` 127 | [ -n "$JAVA_HOME" ] && 128 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 129 | [ -n "$CLASSPATH" ] && 130 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 131 | fi 132 | 133 | # For Migwn, ensure paths are in UNIX format before anything is touched 134 | if $mingw ; then 135 | [ -n "$M2_HOME" ] && 136 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 137 | [ -n "$JAVA_HOME" ] && 138 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 139 | # TODO classpath? 140 | fi 141 | 142 | if [ -z "$JAVA_HOME" ]; then 143 | javaExecutable="`which javac`" 144 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 145 | # readlink(1) is not available as standard on Solaris 10. 146 | readLink=`which readlink` 147 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 148 | if $darwin ; then 149 | javaHome="`dirname \"$javaExecutable\"`" 150 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 151 | else 152 | javaExecutable="`readlink -f \"$javaExecutable\"`" 153 | fi 154 | javaHome="`dirname \"$javaExecutable\"`" 155 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 156 | JAVA_HOME="$javaHome" 157 | export JAVA_HOME 158 | fi 159 | fi 160 | fi 161 | 162 | if [ -z "$JAVACMD" ] ; then 163 | if [ -n "$JAVA_HOME" ] ; then 164 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 165 | # IBM's JDK on AIX uses strange locations for the executables 166 | JAVACMD="$JAVA_HOME/jre/sh/java" 167 | else 168 | JAVACMD="$JAVA_HOME/bin/java" 169 | fi 170 | else 171 | JAVACMD="`which java`" 172 | fi 173 | fi 174 | 175 | if [ ! -x "$JAVACMD" ] ; then 176 | echo "Error: JAVA_HOME is not defined correctly." >&2 177 | echo " We cannot execute $JAVACMD" >&2 178 | exit 1 179 | fi 180 | 181 | if [ -z "$JAVA_HOME" ] ; then 182 | echo "Warning: JAVA_HOME environment variable is not set." 183 | fi 184 | 185 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 186 | 187 | # For Cygwin, switch paths to Windows format before running java 188 | if $cygwin; then 189 | [ -n "$M2_HOME" ] && 190 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 191 | [ -n "$JAVA_HOME" ] && 192 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 193 | [ -n "$CLASSPATH" ] && 194 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 195 | fi 196 | 197 | # traverses directory structure from process work directory to filesystem root 198 | # first directory with .mvn subdirectory is considered project base directory 199 | find_maven_basedir() { 200 | local basedir=$(pwd) 201 | local wdir=$(pwd) 202 | while [ "$wdir" != '/' ] ; do 203 | if [ -d "$wdir"/.mvn ] ; then 204 | basedir=$wdir 205 | break 206 | fi 207 | wdir=$(cd "$wdir/.."; pwd) 208 | done 209 | echo "${basedir}" 210 | } 211 | 212 | # concatenates all lines of a file 213 | concat_lines() { 214 | if [ -f "$1" ]; then 215 | echo "$(tr -s '\n' ' ' < "$1")" 216 | fi 217 | } 218 | 219 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} 220 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 221 | 222 | # Provide a "standardized" way to retrieve the CLI args that will 223 | # work with both Windows and non-Windows executions. 224 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 225 | export MAVEN_CMD_LINE_ARGS 226 | 227 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 228 | 229 | exec "$JAVACMD" \ 230 | $MAVEN_OPTS \ 231 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 232 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 233 | ${WRAPPER_LAUNCHER} "$@" 234 | -------------------------------------------------------------------------------- /storyteller-api/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 | set MAVEN_CMD_LINE_ARGS=%* 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | 121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" 122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 123 | 124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% 125 | if ERRORLEVEL 1 goto error 126 | goto end 127 | 128 | :error 129 | set ERROR_CODE=1 130 | 131 | :end 132 | @endlocal & set ERROR_CODE=%ERROR_CODE% 133 | 134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 138 | :skipRcPost 139 | 140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 142 | 143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 144 | 145 | exit /B %ERROR_CODE% -------------------------------------------------------------------------------- /storyteller-api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.codependent.storyteller 7 | story-teller-api 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | StoryTellerAPI 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.3.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-config 34 | 35 | 36 | org.springframework.cloud 37 | spring-cloud-starter-eureka 38 | 39 | 40 | 41 | org.springframework.cloud 42 | spring-cloud-starter-hystrix 43 | 44 | 45 | 46 | org.springframework.cloud 47 | spring-cloud-starter-feign 48 | 49 | 50 | 51 | org.springframework.boot 52 | spring-boot-starter-aop 53 | 54 | 55 | org.springframework.retry 56 | spring-retry 57 | 58 | 59 | 60 | commons-io 61 | commons-io 62 | 2.4 63 | 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-test 68 | test 69 | 70 | 71 | 72 | 73 | 74 | 75 | org.springframework.cloud 76 | spring-cloud-starter-parent 77 | Brixton.M3 78 | pom 79 | import 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | org.springframework.boot 88 | spring-boot-maven-plugin 89 | 90 | 91 | 92 | 93 | 94 | 95 | spring-snapshots 96 | Spring Snapshots 97 | https://repo.spring.io/snapshot 98 | 99 | true 100 | 101 | 102 | 103 | spring-milestones 104 | Spring Milestones 105 | https://repo.spring.io/milestone 106 | 107 | false 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /storyteller-api/src/main/java/com/codependent/storyteller/StoryClient.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.springframework.cloud.netflix.feign.FeignClient; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | import org.springframework.web.bind.annotation.RequestMethod; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | 8 | @FeignClient("stories-microservice") 9 | public interface StoryClient { 10 | 11 | @RequestMapping(method = RequestMethod.GET, value = "/stories", params="random") 12 | String getStory(@RequestParam("random") boolean random); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /storyteller-api/src/main/java/com/codependent/storyteller/StoryTellerApiApplication.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import javax.servlet.http.HttpServletResponse; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.boot.autoconfigure.SpringBootApplication; 10 | import org.springframework.boot.builder.SpringApplicationBuilder; 11 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 12 | import org.springframework.cloud.context.config.annotation.RefreshScope; 13 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 14 | import org.springframework.cloud.netflix.feign.EnableFeignClients; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | @RestController 19 | @RequestMapping("/api") 20 | @EnableEurekaClient 21 | @EnableFeignClients 22 | @EnableCircuitBreaker 23 | @RefreshScope 24 | @SpringBootApplication 25 | public class StoryTellerApiApplication { 26 | 27 | private Logger logger = LoggerFactory.getLogger(getClass()); 28 | 29 | @Value("${storyteller-api-message}") 30 | private String message; 31 | 32 | @Autowired 33 | private StoryClient sgc; 34 | 35 | @RequestMapping(value="/stories", params="random=true") 36 | public String getRandomStory(HttpServletResponse response) { 37 | logger.info("[{}] getRandomStory()", message); 38 | String randomStory = sgc.getStory(true); 39 | response.setContentType("text/html"); 40 | return randomStory; 41 | } 42 | 43 | public static void main(String[] args) { 44 | new SpringApplicationBuilder(StoryTellerApiApplication.class).web(true).run(args); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /storyteller-api/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: storyteller-api 4 | cloud: 5 | config: 6 | discovery: 7 | enabled: true 8 | failFast: true 9 | retry: 10 | maxAttempts: 100 11 | initialInterval: 2000 12 | maxInterval: 3000 13 | multiplier: 1.5 14 | 15 | server: 16 | port: 9977 17 | 18 | eureka: 19 | client: 20 | serviceUrl: 21 | defaultZone: http://localhost:8761/eureka/ 22 | healthcheck: 23 | enabled: true 24 | # registerWithEureka: false 25 | 26 | hystrix: 27 | command: 28 | getStory: 29 | execution: 30 | isolation: 31 | thread: 32 | timeoutInMilliseconds: 2000 33 | 34 | logging: 35 | # file: /var/memento/security.log 36 | level: 37 | org.springframework.web: 'DEBUG' -------------------------------------------------------------------------------- /storyteller-api/src/test/java/com/codependent/storyteller/RandomImageMsApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.codependent.storyteller; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.SpringApplicationConfiguration; 6 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 7 | 8 | import com.codependent.storyteller.StoryTellerApiApplication; 9 | 10 | @RunWith(SpringJUnit4ClassRunner.class) 11 | @SpringApplicationConfiguration(classes = StoryTellerApiApplication.class) 12 | public class RandomImageMsApplicationTests { 13 | 14 | @Test 15 | public void contextLoads() { 16 | } 17 | 18 | } 19 | --------------------------------------------------------------------------------