├── .gitignore ├── LICENSE ├── README.md ├── api-gateway ├── .classpath ├── .gitignore ├── .project ├── .settings │ ├── gradle │ │ ├── org.springsource.ide.eclipse.gradle.core.import.prefs │ │ ├── org.springsource.ide.eclipse.gradle.core.prefs │ │ └── org.springsource.ide.eclipse.gradle.refresh.prefs │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── java │ └── com │ │ └── rohitghatol │ │ └── microservice │ │ └── gateway │ │ ├── Application.java │ │ └── config │ │ └── OAuthConfiguration.java │ └── resources │ ├── application.yml │ └── bootstrap.yml ├── auth-server ├── .classpath ├── .gitignore ├── .project ├── .settings │ ├── gradle │ │ ├── org.springsource.ide.eclipse.gradle.core.import.prefs │ │ ├── org.springsource.ide.eclipse.gradle.core.prefs │ │ └── org.springsource.ide.eclipse.gradle.refresh.prefs │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── java │ └── com │ │ └── rohitghatol │ │ └── microservice │ │ └── auth │ │ ├── Application.java │ │ ├── api │ │ └── AuthUserController.java │ │ └── config │ │ ├── OAuthConfiguration.java │ │ └── ResourceServerConfiguration.java │ └── resources │ ├── application.yml │ ├── bootstrap.yml │ └── schema.sql ├── build-all-projects.sh ├── comments-webservice ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── java │ └── com │ │ └── rohitghatol │ │ └── microservices │ │ └── comments │ │ ├── Application.java │ │ ├── apis │ │ └── CommentsController.java │ │ ├── config │ │ └── CommentsConfiguration.java │ │ └── dtos │ │ └── CommentDTO.java │ └── resources │ ├── application.yml │ └── bootstrap.yml ├── config-server ├── .classpath ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── java │ └── com │ │ └── rohitghatol │ │ └── microservices │ │ └── config │ │ └── Application.java │ └── resources │ ├── application.yml │ └── bootstrap.yml ├── docker-compose.yml ├── docker-image-all-projects.sh ├── images ├── Application_Components.jpg ├── Decentralized Goverance.png ├── OAuth2 abstract protocol flow.png └── Target_Architecture.jpg ├── task-webservice ├── .classpath ├── .gitignore ├── .project ├── .settings │ ├── gradle │ │ ├── org.springsource.ide.eclipse.gradle.core.import.prefs │ │ ├── org.springsource.ide.eclipse.gradle.core.prefs │ │ └── org.springsource.ide.eclipse.gradle.refresh.prefs │ └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── java │ └── com │ │ └── rohitghatol │ │ └── microservices │ │ └── task │ │ ├── Application.java │ │ ├── apis │ │ ├── CommentsService.java │ │ └── TaskController.java │ │ ├── config │ │ ├── OAuthClientConfiguration.java │ │ └── TaskConfiguration.java │ │ ├── dtos │ │ └── TaskDTO.java │ │ └── model │ │ ├── CommentCollectionResource.java │ │ └── CommentResource.java │ └── resources │ ├── application.yml │ └── bootstrap.yml ├── understanding_notes.pages ├── user-webservice ├── .classpath ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src │ └── main │ ├── java │ └── com │ │ └── rohitghatol │ │ └── microservices │ │ └── user │ │ ├── Application.java │ │ ├── apis │ │ └── UserController.java │ │ ├── config │ │ └── UserConfiguration.java │ │ └── dto │ │ └── UserDTO.java │ └── resources │ ├── application.yml │ └── bootstrap.yml ├── web-portal ├── .classpath ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── public │ ├── css │ │ └── bootstrap.min.css │ ├── index.html │ ├── js │ │ ├── app │ │ │ ├── controller │ │ │ │ ├── homeController.js │ │ │ │ ├── navController.js │ │ │ │ ├── taskController.js │ │ │ │ └── userController.js │ │ │ ├── oauthapp.js │ │ │ └── services │ │ │ │ └── dataservice.js │ │ └── libs │ │ │ ├── angular-route.min.js │ │ │ └── angular.min.js │ └── views │ │ ├── home.html │ │ ├── task-comments.html │ │ ├── task-details.html │ │ ├── task.html │ │ └── user.html └── src │ └── main │ ├── java │ └── com │ │ └── rohitghatol │ │ └── microservices │ │ └── portal │ │ └── Application.java │ └── resources │ ├── application.yml │ └── bootstrap.yml └── webservice-registry ├── .classpath ├── .gitignore ├── .project ├── README.md ├── build.gradle ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src └── main ├── java └── com │ └── rohitghatol │ └── microservices │ └── registry │ └── Application.java └── resources ├── application.yml └── bootstrap.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | 14 | build 15 | bin 16 | .settings 17 | .gradle 18 | .DS_Store 19 | .classpath 20 | -------------------------------------------------------------------------------- /api-gateway/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | -------------------------------------------------------------------------------- /api-gateway/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | api-gateway 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /api-gateway/.settings/gradle/org.springsource.ide.eclipse.gradle.core.import.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleImportPreferences 2 | #Mon Apr 06 13:25:59 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | enableDependendencyManagement=true 10 | projects=; 11 | -------------------------------------------------------------------------------- /api-gateway/.settings/gradle/org.springsource.ide.eclipse.gradle.core.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences 2 | #Mon Apr 06 13:26:03 PDT 2015 3 | org.springsource.ide.eclipse.gradle.linkedresources= 4 | org.springsource.ide.eclipse.gradle.rootprojectloc= 5 | -------------------------------------------------------------------------------- /api-gateway/.settings/gradle/org.springsource.ide.eclipse.gradle.refresh.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.actions.GradleRefreshPreferences 2 | #Mon Apr 06 13:26:02 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | useHierarchicalNames=false 10 | -------------------------------------------------------------------------------- /api-gateway/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Tue Apr 07 15:03:53 PDT 2015 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.7 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.7 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /api-gateway/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | The api-gateway application acts the router and authentication and authorization endpoint. 4 | 5 | The Zuul api gateway solves a very common use case where a UI application wants to proxy calls to one or more back end services. This feature is useful for a user interface to proxy to the backend services it requires, avoiding the need to manage CORS and authentication concerns independently for all the backends.For example in our application `/api/user/**` endpoint is mapped to the `user-webservice`. 6 | 7 | It also knows how to invoke the authorization server in case the user is not authenticated. Once the authentication is complete, it relays the OAuth2 token to the respective services so that they can find the authenticated user and provide services. 8 | 9 | ##Pre-requisites 10 | 11 | ### Projects that need to be started before 12 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 13 | * [webserver-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 14 | 15 | ### Running the application 16 | * Build the application by running the `./gradlew clean build` gradle command at the "task-webservice" project root folder on the terminal. 17 | * If you want to run the application as jar file, then run `java -jar build/libs/sample-api-gateway-0.0.1.jar` command at the terminal. 18 | 19 | ## External Configuration 20 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. -------------------------------------------------------------------------------- /api-gateway/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | project.ext { 3 | bootVersion = '1.2.3.RELEASE' 4 | cloudVersion = '1.0.0.RELEASE' 5 | seurityVersion = '2.0.7.RELEASE' 6 | } 7 | repositories { 8 | mavenCentral() 9 | jcenter() 10 | } 11 | 12 | dependencies { 13 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" 14 | classpath 'se.transmode.gradle:gradle-docker:1.2' 15 | } 16 | } 17 | 18 | apply plugin: 'eclipse' 19 | apply plugin: 'spring-boot' 20 | apply plugin: 'java' 21 | apply plugin: 'docker' 22 | 23 | jar { 24 | baseName = 'sample-api-gateway' 25 | version = '0.0.1' 26 | } 27 | 28 | repositories { 29 | mavenCentral() 30 | jcenter() 31 | } 32 | dependencies { 33 | compile("org.springframework.boot:spring-boot-starter-web:${project.bootVersion}") 34 | compile("org.springframework.boot:spring-boot-starter-actuator:${project.bootVersion}") 35 | compile("org.springframework.boot:spring-boot-starter-data-jpa:${project.bootVersion}") 36 | compile("mysql:mysql-connector-java:5.1.30") 37 | compile("org.springframework.cloud:spring-cloud-config-client:${project.cloudVersion}") 38 | compile("org.springframework.cloud:spring-cloud-starter-eureka:${project.cloudVersion}") 39 | compile("org.springframework.cloud:spring-cloud-starter-zuul:${project.cloudVersion}") 40 | compile("org.springframework.cloud:spring-cloud-starter-security:${project.cloudVersion}") 41 | 42 | compile("org.springframework.boot:spring-boot-starter-security:${project.bootVersion}") 43 | compile("org.springframework.security.oauth:spring-security-oauth2:${project.seurityVersion}") 44 | 45 | testCompile group: 'junit', name: 'junit', version: '4.+' 46 | testCompile 'org.springframework:spring-test:4.0.6.RELEASE' 47 | } 48 | 49 | /** 50 | * These values(group & mainClassName) are required by the gradle docker plugin. 51 | * 52 | * The "group" value feeds into the docker tag and is required if you want to push the images 53 | * to docker hub. 54 | * 55 | * The "mainClassName" value tells which class has the "main" entry point for running the 56 | * Spring boot application. 57 | */ 58 | group = 'anilallewar' 59 | mainClassName = 'com.rohitghatol.microservice.gateway.Application' 60 | 61 | sourceCompatibility = 1.7 62 | targetCompatibility = 1.7 63 | 64 | distDocker { 65 | exposePort 8080 66 | setEnvironment 'JAVA_OPTS', '-Dspring.profiles.active=docker' 67 | } 68 | 69 | /** 70 | * On Mac, docker can't be connected locally since it is running in a separate VM. 71 | * 72 | * NOTE: If you have not added your TLS certs to boot2docker; you would need to change 73 | * docker to run the API on HTTP; while boot2docker 1.3 comes with TLS enabled. Hence 74 | * you need to run the following command "$(docker run sequenceiq/socat)" at the docker 75 | * prompt so that this image maps the api to HTTP port. You can check that it is working 76 | * correctly using the command "curl http://192.168.59.103:2375/_ping" 77 | * 78 | * 79 | * In order to change docker to run the remote API, we need to set the following flags: 80 | * 1. useApi true => Use the Docker Remote API instead of a locally installed docker binary. 81 | * 2. hostUrl => set the URL used to contact the Docker server. Defaults to http://localhost:2375 82 | */ 83 | docker { 84 | useApi true 85 | hostUrl 'http://192.168.59.103:2375' 86 | baseImage = 'java:7' 87 | } 88 | 89 | bootRun { 90 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4000,suspend=n','-Dspring.profiles.active=dev'] 91 | } 92 | 93 | run { 94 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4000,suspend=n','-Dspring.profiles.active=dev'] 95 | } 96 | 97 | 98 | task createWrapper(type: Wrapper) { 99 | gradleVersion = '2.0' 100 | } 101 | 102 | -------------------------------------------------------------------------------- /api-gateway/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 20:52:39 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /api-gateway/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /api-gateway/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/rohitghatol/microservice/gateway/Application.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservice.gateway; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 9 | import org.springframework.cloud.netflix.zuul.EnableZuulProxy; 10 | import org.springframework.cloud.security.oauth2.resource.EnableOAuth2Resource; 11 | import org.springframework.cloud.security.oauth2.sso.EnableOAuth2Sso; 12 | import org.springframework.context.annotation.ComponentScan; 13 | import org.springframework.context.annotation.Configuration; 14 | 15 | 16 | /** 17 | * The Main Spring Boot Application class which does the following 18 | *
    19 | *
  1. Act as a Eureka client; this behavior is provided by the 20 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 21 | * the external configuration provided by the config server.
  2. 22 | *
  3. Act as Zuul reverse proxy; this behavior is provided by the 23 | * {@link EnableZuulProxy} annotation. Annotating the application with 24 | * {@link EnableZuulProxy} forwards local calls to the appropriate service. By 25 | * convention, a service with the Eureka ID "users", will receive requests from 26 | * the proxy located at /users (with the prefix stripped).
  4. 27 | *
  5. Enable OAuth2 single sign on (SSO) using the {@link EnableOAuth2Sso} 28 | * annotation. 29 | *
      30 | *
    1. If your app has a Spring Cloud Zuul embedded reverse proxy (using 31 | * {@link EnableZuulProxy}) then you can ask it to forward OAuth2 access tokens 32 | * downstream to the services it is proxying.
    2. 33 | *
    3. If you also add the {@link EnableOAuth2Sso} annotation; then it will (in 34 | * addition to loggin the user in and grabbing a token) pass the authentication 35 | * token downstream to the /proxy/* services.
    4. 36 | *
    5. If those services are implemented with {@link EnableOAuth2Resource} then 37 | * they will get a valid token in the correct header.
    6. 38 | *
    39 | *
  6. 40 | *
  7. Note that all these annotations work in conjunction with properties 41 | * defined in the external configuration files specified by the config server. 42 | *
  8. 43 | *
44 | * 45 | * @author rohitghatol 46 | */ 47 | 48 | @Configuration 49 | @ComponentScan 50 | @EnableAutoConfiguration 51 | @EnableZuulProxy 52 | @EnableEurekaClient 53 | @EnableOAuth2Sso 54 | public class Application { 55 | 56 | /** 57 | * The main method. 58 | * 59 | * @param args 60 | * the arguments 61 | */ 62 | public static void main(String[] args) { 63 | SpringApplication.run(Application.class, args); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /api-gateway/src/main/java/com/rohitghatol/microservice/gateway/config/OAuthConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservice.gateway.config; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.servlet.Filter; 6 | import javax.servlet.FilterChain; 7 | import javax.servlet.ServletException; 8 | import javax.servlet.http.Cookie; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | import org.springframework.cloud.security.oauth2.sso.OAuth2SsoConfigurerAdapter; 13 | import org.springframework.context.annotation.Configuration; 14 | import org.springframework.http.HttpMethod; 15 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 16 | import org.springframework.security.web.csrf.CsrfFilter; 17 | import org.springframework.security.web.csrf.CsrfToken; 18 | import org.springframework.security.web.csrf.CsrfTokenRepository; 19 | import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository; 20 | import org.springframework.stereotype.Component; 21 | import org.springframework.web.filter.OncePerRequestFilter; 22 | import org.springframework.web.util.WebUtils; 23 | 24 | 25 | /** 26 | * The Class OAuthConfiguration that sets up the OAuth2 single sign on 27 | * configuration and the web security associated with it. 28 | */ 29 | @Configuration 30 | @Component 31 | public class OAuthConfiguration extends OAuth2SsoConfigurerAdapter { 32 | 33 | private static final String CSRF_COOKIE_NAME = "XSRF-TOKEN"; 34 | private static final String CSRF_ANGULAR_HEADER_NAME = "X-XSRF-TOKEN"; 35 | 36 | @Override 37 | public void match(RequestMatchers matchers) { 38 | matchers.anyRequest(); 39 | } 40 | 41 | /** 42 | * Define the security that applies to the proxy 43 | */ 44 | @Override 45 | public void configure(HttpSecurity http) throws Exception { 46 | http 47 | .authorizeRequests() 48 | //Allow access to all static resources without authentication 49 | .antMatchers("/","/**/*.html").permitAll() 50 | .anyRequest().authenticated() 51 | .antMatchers(HttpMethod.GET, "/api/user/**","/api/task/**").access("#oauth2.hasScope('read')") 52 | .antMatchers(HttpMethod.OPTIONS, "/api/user/**","/api/task/**").access("#oauth2.hasScope('read')") 53 | .antMatchers(HttpMethod.POST, "/api/user/**","/api/task/**").access("#oauth2.hasScope('write')") 54 | .antMatchers(HttpMethod.PUT, "/api/user/**","/api/task/**").access("#oauth2.hasScope('write')") 55 | .antMatchers(HttpMethod.PATCH, "/api/user/**","/api/task/**").access("#oauth2.hasScope('write')") 56 | .antMatchers(HttpMethod.DELETE, "/api/user/**","/api/task/**").access("#oauth2.hasScope('write')") 57 | .and().csrf().csrfTokenRepository(this.getCSRFTokenRepository()) 58 | .and().addFilterAfter(this.createCSRFHeaderFilter(), CsrfFilter.class); 59 | } 60 | 61 | /** 62 | * Spring security offers in-built protection for cross site request forgery 63 | * (CSRF) by needing a custom token in the header for any requests that are 64 | * NOT safe i.e. modify the resources from the server e.g. POST, PUT & PATCH 65 | * etc.
66 | *
67 | * 68 | * This protection is achieved using cookies that send a custom value (would 69 | * remain same for the session) in the first request and then the front-end 70 | * would send back the value as a custom header.
71 | *
72 | * 73 | * In this method we create a filter that is applied to the web security as 74 | * follows: 75 | *
    76 | *
  1. Spring security provides the CSRF token value as a request attribute; 77 | * so we extract it from there.
  2. 78 | *
  3. If we have the token, Angular wants the cookie name to be 79 | * "XSRF-TOKEN". So we add the cookie if it's not there and set the path for 80 | * the cookie to be "/" which is root. In more complicated cases, this might 81 | * have to be the context root of the api gateway.
  4. 82 | *
  5. We forward the request to the next filter in the chain
  6. 83 | *
84 | * 85 | * The request-to-cookie filter that we add needs to be after the 86 | * csrf() filter so that the request attribute for CsrfToken 87 | * has been already added before we start to process it. 88 | * 89 | * @return 90 | */ 91 | private Filter createCSRFHeaderFilter() { 92 | return new OncePerRequestFilter() { 93 | @Override 94 | protected void doFilterInternal(HttpServletRequest request, 95 | HttpServletResponse response, FilterChain filterChain) 96 | throws ServletException, IOException { 97 | CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class 98 | .getName()); 99 | if (csrf != null) { 100 | Cookie cookie = WebUtils.getCookie(request, CSRF_COOKIE_NAME); 101 | String token = csrf.getToken(); 102 | if (cookie == null || token != null 103 | && !token.equals(cookie.getValue())) { 104 | cookie = new Cookie(CSRF_COOKIE_NAME, token); 105 | cookie.setPath("/"); 106 | response.addCookie(cookie); 107 | } 108 | } 109 | filterChain.doFilter(request, response); 110 | } 111 | }; 112 | } 113 | 114 | /** 115 | * Angular sends the CSRF token in a custom header named "X-XSRF-TOKEN" 116 | * rather than the default "X-CSRF-TOKEN" that Spring security expects. 117 | * Hence we are now telling Spring security to expect the token in the 118 | * "X-XSRF-TOKEN" header.

119 | * 120 | * This customization is added to the csrf() filter. 121 | * 122 | * @return 123 | */ 124 | private CsrfTokenRepository getCSRFTokenRepository() { 125 | HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository(); 126 | repository.setHeaderName(CSRF_ANGULAR_HEADER_NAME); 127 | return repository; 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /api-gateway/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | org: 4 | springframework: 5 | security: DEBUG -------------------------------------------------------------------------------- /api-gateway/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: api-gateway 4 | cloud: 5 | config: 6 | uri: http://localhost:8888 7 | 8 | --- 9 | 10 | spring: 11 | profiles: docker 12 | cloud: 13 | config: 14 | uri: http://192.168.59.103:8888 -------------------------------------------------------------------------------- /auth-server/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | -------------------------------------------------------------------------------- /auth-server/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | auth-server 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /auth-server/.settings/gradle/org.springsource.ide.eclipse.gradle.core.import.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleImportPreferences 2 | #Mon Apr 06 13:25:59 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | enableDependendencyManagement=true 10 | projects=; 11 | -------------------------------------------------------------------------------- /auth-server/.settings/gradle/org.springsource.ide.eclipse.gradle.core.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences 2 | #Mon Apr 06 13:26:03 PDT 2015 3 | org.springsource.ide.eclipse.gradle.linkedresources= 4 | org.springsource.ide.eclipse.gradle.rootprojectloc= 5 | -------------------------------------------------------------------------------- /auth-server/.settings/gradle/org.springsource.ide.eclipse.gradle.refresh.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.actions.GradleRefreshPreferences 2 | #Mon Apr 06 13:26:02 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | useHierarchicalNames=false 10 | -------------------------------------------------------------------------------- /auth-server/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Tue Apr 07 12:01:04 PDT 2015 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.7 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.7 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /auth-server/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | project.ext { 3 | bootVersion = '1.2.3.RELEASE' 4 | cloudVersion = '1.0.0.RELEASE' 5 | seurityVersion = '2.0.7.RELEASE' 6 | } 7 | repositories { 8 | mavenCentral() 9 | jcenter() 10 | } 11 | 12 | dependencies { 13 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" 14 | classpath 'se.transmode.gradle:gradle-docker:1.2' 15 | } 16 | } 17 | 18 | apply plugin: 'eclipse' 19 | apply plugin: 'spring-boot' 20 | apply plugin: 'java' 21 | apply plugin: 'docker' 22 | 23 | 24 | jar { 25 | baseName = 'sample-auth-server' 26 | version = '0.0.1' 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | jcenter() 32 | } 33 | dependencies { 34 | compile("org.springframework.boot:spring-boot-starter-web:${project.bootVersion}") 35 | compile("org.springframework.boot:spring-boot-starter-actuator:${project.bootVersion}") 36 | compile("org.springframework.boot:spring-boot-starter-data-jpa:${project.bootVersion}") 37 | compile("mysql:mysql-connector-java:5.1.30") 38 | compile("org.springframework.cloud:spring-cloud-config-client:${project.cloudVersion}") 39 | compile("org.springframework.cloud:spring-cloud-starter-eureka:${project.cloudVersion}") 40 | compile("org.springframework.cloud:spring-cloud-starter-eureka:${project.cloudVersion}") 41 | 42 | compile("org.springframework.cloud:spring-cloud-starter-security:${project.cloudVersion}") 43 | compile("org.springframework.boot:spring-boot-starter-security:${project.bootVersion}") 44 | compile("org.springframework.security.oauth:spring-security-oauth2:${project.seurityVersion}") 45 | 46 | testCompile group: 'junit', name: 'junit', version: '4.+' 47 | testCompile 'org.springframework:spring-test:4.0.6.RELEASE' 48 | } 49 | 50 | group = 'anilallewar' 51 | mainClassName = 'com.rohitghatol.microservice.auth.Application' 52 | 53 | sourceCompatibility = 1.7 54 | targetCompatibility = 1.7 55 | 56 | 57 | distDocker { 58 | exposePort 8899 59 | setEnvironment 'JAVA_OPTS', '-Dspring.profiles.active=docker' 60 | } 61 | 62 | docker { 63 | useApi true 64 | hostUrl 'http://192.168.59.103:2375' 65 | baseImage = 'java:7' 66 | } 67 | 68 | bootRun { 69 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4100,suspend=n','-Dspring.profiles.active=dev'] 70 | } 71 | 72 | run { 73 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4100,suspend=n','-Dspring.profiles.active=dev'] 74 | } 75 | 76 | task createWrapper(type: Wrapper) { 77 | gradleVersion = '2.0' 78 | } 79 | 80 | -------------------------------------------------------------------------------- /auth-server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 20:53:22 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /auth-server/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /auth-server/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /auth-server/src/main/java/com/rohitghatol/microservice/auth/Application.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservice.auth; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 9 | import org.springframework.context.annotation.ComponentScan; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 12 | 13 | /** 14 | * The Main Spring Boot Application class that starts the authorization 15 | * server.
16 | *
17 | * 18 | * Note that the server is also a Eureka client so as to register with the 19 | * Eureka server and be auto-discovered by other Eureka clients. 20 | * 21 | * @author rohitghatol 22 | */ 23 | 24 | @ComponentScan 25 | @EnableAutoConfiguration 26 | @EnableEurekaClient 27 | public class Application { 28 | 29 | /** 30 | * The main method. 31 | * 32 | * @param args 33 | * the arguments 34 | */ 35 | public static void main(String[] args) { 36 | SpringApplication.run(Application.class, args); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /auth-server/src/main/java/com/rohitghatol/microservice/auth/api/AuthUserController.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservice.auth.api; 2 | 3 | import java.security.Principal; 4 | 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | /** 9 | * REST endpoint to be used by other micro-services using SSO to validate the 10 | * authentication of the logged in user. 11 | * 12 | * @author anilallewar 13 | * 14 | */ 15 | @RestController 16 | @RequestMapping("/") 17 | public class AuthUserController { 18 | 19 | /** 20 | * Return the principal identifying the logged in user 21 | * @param user 22 | * @return 23 | */ 24 | @RequestMapping("/me") 25 | public Principal getCurrentLoggedInUser(Principal user) { 26 | return user; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /auth-server/src/main/java/com/rohitghatol/microservice/auth/config/OAuthConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservice.auth.config; 2 | 3 | import javax.sql.DataSource; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.core.Ordered; 9 | import org.springframework.core.annotation.Order; 10 | import org.springframework.security.authentication.AuthenticationManager; 11 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 12 | import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter; 13 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 14 | import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; 15 | import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 16 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 17 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 18 | import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; 19 | import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices; 20 | import org.springframework.security.oauth2.provider.code.JdbcAuthorizationCodeServices; 21 | import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore; 22 | 23 | /** 24 | * The Class OAuth2Config defines the authorization server that would 25 | * authenticate the user and define the client that seeks authorization on the 26 | * resource owner's behalf. 27 | */ 28 | @Configuration 29 | @EnableAuthorizationServer 30 | public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter { 31 | 32 | @Autowired 33 | private AuthenticationManager auth; 34 | 35 | @Autowired 36 | private DataSource dataSource; 37 | 38 | private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 39 | 40 | /** 41 | * The OAuth2 tokens are defined in the datasource defined in the 42 | * auth-server.yml file stored in the Spring Cloud config 43 | * github repository. 44 | * 45 | * @return 46 | */ 47 | @Bean 48 | public JdbcTokenStore tokenStore() { 49 | return new JdbcTokenStore(dataSource); 50 | } 51 | 52 | @Bean 53 | protected AuthorizationCodeServices authorizationCodeServices() { 54 | return new JdbcAuthorizationCodeServices(dataSource); 55 | } 56 | 57 | @Override 58 | public void configure(AuthorizationServerSecurityConfigurer security) 59 | throws Exception { 60 | security.passwordEncoder(passwordEncoder); 61 | } 62 | 63 | /** 64 | * We set our authorization storage feature specifying that we would use the 65 | * JDBC store for token and authorization code storage.
66 | *
67 | * 68 | * We also attach the {@link AuthenticationManager} so that password grants 69 | * can be processed. 70 | */ 71 | @Override 72 | public void configure(AuthorizationServerEndpointsConfigurer endpoints) 73 | throws Exception { 74 | endpoints.authorizationCodeServices(authorizationCodeServices()) 75 | .authenticationManager(auth).tokenStore(tokenStore()) 76 | .approvalStoreDisabled(); 77 | } 78 | 79 | /** 80 | * Setup the client application which attempts to get access to user's 81 | * account after user permission. 82 | */ 83 | @Override 84 | public void configure(ClientDetailsServiceConfigurer clients) 85 | throws Exception { 86 | 87 | clients.jdbc(dataSource) 88 | .passwordEncoder(passwordEncoder) 89 | .withClient("client") 90 | .authorizedGrantTypes("authorization_code", "client_credentials", 91 | "refresh_token","password", "implicit") 92 | .authorities("ROLE_CLIENT") 93 | .resourceIds("apis") 94 | .scopes("read") 95 | .secret("secret") 96 | .accessTokenValiditySeconds(300); 97 | 98 | } 99 | 100 | /** 101 | * Configure the {@link AuthenticationManagerBuilder} with initial 102 | * configuration to setup users. 103 | * 104 | * @author anilallewar 105 | * 106 | */ 107 | @Configuration 108 | @Order(Ordered.LOWEST_PRECEDENCE - 20) 109 | protected static class AuthenticationManagerConfiguration extends 110 | GlobalAuthenticationConfigurerAdapter { 111 | 112 | @Autowired 113 | private DataSource dataSource; 114 | 115 | /** 116 | * Setup 2 users with different roles 117 | */ 118 | @Override 119 | public void init(AuthenticationManagerBuilder auth) throws Exception { 120 | // @formatter:off 121 | auth.jdbcAuthentication().dataSource(dataSource).withUser("dave") 122 | .password("secret").roles("USER"); 123 | auth.jdbcAuthentication().dataSource(dataSource).withUser("anil") 124 | .password("password").roles("ADMIN"); 125 | // @formatter:on 126 | } 127 | } 128 | 129 | } -------------------------------------------------------------------------------- /auth-server/src/main/java/com/rohitghatol/microservice/auth/config/ResourceServerConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservice.auth.config; 5 | 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 8 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 10 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 11 | import org.springframework.stereotype.Component; 12 | 13 | /** 14 | * Since the "me" endpoint needs to be protected to be accessed only after the 15 | * OAuth2 authentication is successful; the server also becomes a resource 16 | * server. 17 | * 18 | * @author anilallewar 19 | * 20 | */ 21 | @Configuration 22 | @EnableResourceServer 23 | public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { 24 | 25 | /** 26 | * Configure security to allow access to the /me endpoint only if the OAuth 27 | * authorization returns "read" scope.
28 | *
29 | * 30 | * If you look at 31 | * {@link OAuthConfiguration#configure(org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer)} 32 | * to check that by default the authorization server allows "read" scope 33 | * only. 34 | */ 35 | @Override 36 | public void configure(HttpSecurity http) throws Exception { 37 | // @formatter:off 38 | http 39 | .requestMatchers().antMatchers("/me") 40 | .and() 41 | .authorizeRequests() 42 | .antMatchers("/me").access("#oauth2.hasScope('read')"); 43 | // @formatter:on 44 | } 45 | 46 | /** 47 | * Id of the resource that you are letting the client have access to. 48 | * Supposing you have another api ("say api2"), then you can customize the 49 | * access within resource server to define what api is for what resource id. 50 | *
51 | *
52 | * 53 | * So suppose you have 2 APIs, then you can define 2 resource servers. 54 | *
    55 | *
  1. Client 1 has been configured for access to resourceid1, so he can 56 | * only access "api1" if the resource server configures the resourceid to 57 | * "api1".
  2. 58 | *
  3. Client 1 can't access resource server 2 since it has configured the 59 | * resource id to "api2" 60 | *
  4. 61 | *
62 | * 63 | */ 64 | @Override 65 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 66 | resources.resourceId("apis"); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /auth-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | org: 4 | springframework: 5 | security: DEBUG -------------------------------------------------------------------------------- /auth-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: auth-server 4 | cloud: 5 | config: 6 | uri: http://localhost:8888 7 | 8 | --- 9 | 10 | spring: 11 | profiles: docker 12 | cloud: 13 | config: 14 | uri: http://192.168.59.103:8888 15 | -------------------------------------------------------------------------------- /auth-server/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | 2 | DROP TABLE IF EXISTS `ClientDetails`; 3 | CREATE TABLE `ClientDetails` ( 4 | `appId` varchar(256) NOT NULL, 5 | `resourceIds` varchar(256) DEFAULT NULL, 6 | `appSecret` varchar(256) DEFAULT NULL, 7 | `scope` varchar(256) DEFAULT NULL, 8 | `grantTypes` varchar(256) DEFAULT NULL, 9 | `redirectUrl` varchar(256) DEFAULT NULL, 10 | `authorities` varchar(256) DEFAULT NULL, 11 | `access_token_validity` int(11) DEFAULT NULL, 12 | `refresh_token_validity` int(11) DEFAULT NULL, 13 | `additionalInformation` varchar(4096) DEFAULT NULL, 14 | PRIMARY KEY (`appId`) 15 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 16 | 17 | 18 | 19 | 20 | DROP TABLE IF EXISTS `authorities`; 21 | CREATE TABLE `authorities` ( 22 | `username` varchar(50) NOT NULL, 23 | `authority` varchar(50) NOT NULL, 24 | UNIQUE KEY `ix_auth_username` (`username`,`authority`) 25 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 26 | 27 | 28 | 29 | DROP TABLE IF EXISTS `oauth_access_token`; 30 | CREATE TABLE `oauth_access_token` ( 31 | `token_id` varchar(256) DEFAULT NULL, 32 | `token` blob, 33 | `authentication_id` varchar(256) DEFAULT NULL, 34 | `user_name` varchar(256) DEFAULT NULL, 35 | `client_id` varchar(256) DEFAULT NULL, 36 | `authentication` blob, 37 | `refresh_token` varchar(256) DEFAULT NULL 38 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 39 | 40 | 41 | 42 | DROP TABLE IF EXISTS `oauth_client_details`; 43 | CREATE TABLE `oauth_client_details` ( 44 | `client_id` varchar(256) NOT NULL, 45 | `resource_ids` varchar(256) DEFAULT NULL, 46 | `client_secret` varchar(256) DEFAULT NULL, 47 | `scope` varchar(256) DEFAULT NULL, 48 | `authorized_grant_types` varchar(256) DEFAULT NULL, 49 | `web_server_redirect_uri` varchar(256) DEFAULT NULL, 50 | `authorities` varchar(256) DEFAULT NULL, 51 | `access_token_validity` int(11) DEFAULT NULL, 52 | `refresh_token_validity` int(11) DEFAULT NULL, 53 | `additional_information` varchar(4096) DEFAULT NULL, 54 | `autoapprove` varchar(256) DEFAULT NULL, 55 | PRIMARY KEY (`client_id`) 56 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 57 | 58 | 59 | 60 | DROP TABLE IF EXISTS `oauth_code`; 61 | CREATE TABLE `oauth_code` ( 62 | `code` varchar(256) DEFAULT NULL, 63 | `authentication` blob 64 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 65 | 66 | 67 | DROP TABLE IF EXISTS `oauth_refresh_token`; 68 | CREATE TABLE `oauth_refresh_token` ( 69 | `token_id` varchar(256) DEFAULT NULL, 70 | `token` blob, 71 | `authentication` blob 72 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 73 | 74 | DROP TABLE IF EXISTS `users`; 75 | CREATE TABLE `users` ( 76 | `username` varchar(50) NOT NULL, 77 | `password` varchar(50) NOT NULL, 78 | `enabled` tinyint(1) NOT NULL, 79 | PRIMARY KEY (`username`) 80 | ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 81 | 82 | -------------------------------------------------------------------------------- /build-all-projects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd api-gateway; ./gradlew clean build; cd .. 4 | cd auth-server; ./gradlew clean build; cd .. 5 | cd config-server; ./gradlew clean build; cd .. 6 | cd task-webservice; ./gradlew clean build; cd .. 7 | cd user-webservice; ./gradlew clean build; cd .. 8 | cd web-portal; ./gradlew clean build; cd .. 9 | cd webservice-registry; ./gradlew clean build; cd .. 10 | cd comments-webservice; ./gradlew clean build; cd .. 11 | -------------------------------------------------------------------------------- /comments-webservice/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | .DS_Store 4 | /.gradle/ 5 | -------------------------------------------------------------------------------- /comments-webservice/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | comments-webservice 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | 20 | 1438821709492 21 | 22 | 22 23 | 24 | org.eclipse.ui.ide.multiFilter 25 | 1.0-name-matches-false-false-.DS_Store 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /comments-webservice/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **comments** related functionality and serves as one component. It defines the REST endpoints that are used to provide comment functionality. 4 | 5 | Note that this component is only used internally by the "task" microservice and is NOT actually exposed at the API gateway level. 6 | 7 | ##Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 11 | * [webserver-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 12 | 13 | ### Running the application 14 | * Build the application by running the `./gradlew clean build` gradle command at the "comments-webservice" project root folder on the terminal. 15 | * If you want to run the application as jar file, then run `java -jar build/libs/sample-comments-webservice-0.0.1.jar` command at the terminal. 16 | 17 | ## External Configuration 18 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. -------------------------------------------------------------------------------- /comments-webservice/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | project.ext { 3 | bootVersion = '1.2.3.RELEASE' 4 | cloudVersion = '1.0.0.RELEASE' 5 | seurityVersion = '2.0.7.RELEASE' 6 | } 7 | repositories { 8 | mavenCentral() 9 | jcenter() 10 | } 11 | 12 | dependencies { 13 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" 14 | classpath 'se.transmode.gradle:gradle-docker:1.2' 15 | } 16 | } 17 | 18 | apply plugin: 'eclipse' 19 | apply plugin: 'spring-boot' 20 | apply plugin: 'java' 21 | apply plugin: 'docker' 22 | 23 | 24 | jar { 25 | baseName = 'sample-comments-webservice' 26 | version = '0.0.1' 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | jcenter() 32 | } 33 | dependencies { 34 | compile("org.springframework.boot:spring-boot-starter-web:${project.bootVersion}") 35 | compile("org.springframework.boot:spring-boot-starter-actuator:${project.bootVersion}") 36 | compile("org.springframework.cloud:spring-cloud-config-client:${project.cloudVersion}") 37 | compile("org.springframework.cloud:spring-cloud-starter-eureka:${project.cloudVersion}") 38 | compile("org.springframework.cloud:spring-cloud-starter-hystrix:${project.cloudVersion}") 39 | 40 | compile("org.springframework.cloud:spring-cloud-starter-security:${project.cloudVersion}") 41 | compile("org.springframework.boot:spring-boot-starter-security:${project.bootVersion}") 42 | compile("org.springframework.security.oauth:spring-security-oauth2:${project.seurityVersion}") 43 | 44 | testCompile group: 'junit', name: 'junit', version: '4.+' 45 | testCompile 'org.springframework:spring-test:4.0.6.RELEASE' 46 | } 47 | 48 | group = 'anilallewar' 49 | mainClassName = 'com.rohitghatol.microservices.comments.Application' 50 | 51 | sourceCompatibility = 1.7 52 | targetCompatibility = 1.7 53 | 54 | distDocker { 55 | exposePort 8080 56 | setEnvironment 'JAVA_OPTS', '-Dspring.profiles.active=docker' 57 | } 58 | 59 | docker { 60 | useApi true 61 | hostUrl 'http://192.168.59.103:2375' 62 | baseImage = 'java:7' 63 | } 64 | 65 | bootRun { 66 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4400,suspend=n','-Dspring.profiles.active=dev'] 67 | } 68 | 69 | run { 70 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4400,suspend=n','-Dspring.profiles.active=dev'] 71 | } 72 | 73 | task createWrapper(type: Wrapper) { 74 | gradleVersion = '2.0' 75 | } 76 | 77 | -------------------------------------------------------------------------------- /comments-webservice/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 20:51:06 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /comments-webservice/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /comments-webservice/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /comments-webservice/src/main/java/com/rohitghatol/microservices/comments/Application.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.comments; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 9 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 10 | import org.springframework.cloud.security.oauth2.resource.EnableOAuth2Resource; 11 | import org.springframework.context.annotation.ComponentScan; 12 | 13 | /** 14 | * The boot application class that defines the spring boot application to have 15 | * the following properties
16 | *
17 | * 18 | *
    19 | *
  1. Act as a Eureka client; this behavior is provided by the 20 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 21 | * the external configuration provided by the config server.
  2. 22 | *
  3. The security is enabled to be covered by OAuth2 access token using the 23 | * {@link EnableOAuth2Resource} annotation. The URL from where the user would be 24 | * authenticated is provided by the 25 | * spring.oauth2.resource.userInfoUri property defined in the 26 | * external configuration.
  4. 27 | *
  5. {@link EnableEurekaClient} makes the app into both a Eureka "instance" (i.e. it 28 | * registers itself) and a "client" (i.e. it can query the registry to locate 29 | * other services).
  6. 30 | *
  7. Note that all these annotations work in conjunction with properties 31 | * defined in the external configuration files specified by the config server. 32 | *
  8. 33 | *
34 | * 35 | * @author rohitghatol 36 | * 37 | */ 38 | @EnableAutoConfiguration 39 | @ComponentScan 40 | @EnableEurekaClient 41 | @EnableOAuth2Resource 42 | public class Application { 43 | public static void main(String[] args) { 44 | 45 | SpringApplication.run(Application.class,args); 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /comments-webservice/src/main/java/com/rohitghatol/microservices/comments/apis/CommentsController.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservices.comments.apis; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import com.rohitghatol.microservices.comments.dtos.CommentDTO; 15 | 16 | /** 17 | * REST endpoint for the comments functionality
18 | *
19 | * 20 | * Note that this endpoint is supposed to be consumed by the Task webservice and 21 | * is not accessible to the general public; i.e. the api-gateway doesn't handle 22 | * requests for comments-webservice. 23 | * 24 | * @author anilallewar 25 | * 26 | */ 27 | @RestController 28 | @RequestMapping("/comments") 29 | public class CommentsController { 30 | 31 | private SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); 32 | 33 | private List comments = null; 34 | 35 | /** 36 | * Public constructor to initialize the comments and handle the 37 | * ParseException 38 | * 39 | * @throws ParseException 40 | */ 41 | public CommentsController() throws ParseException { 42 | this.comments = Arrays.asList(new CommentDTO("task11", "comment on task11", formatter.parse("2015-04-23")), 43 | new CommentDTO("task12", "comment on task12", formatter.parse("2015-05-12")), 44 | new CommentDTO("task11", "new comment on task11", formatter.parse("2015-04-27")), 45 | new CommentDTO("task21", "comment on task21", formatter.parse("2015-01-15")), 46 | new CommentDTO("task22", "comment on task22", formatter.parse("2015-03-05"))); 47 | } 48 | 49 | /** 50 | * Get comments for specific taskid that is passed in the path. 51 | * 52 | * @param taskId 53 | * @return 54 | */ 55 | @RequestMapping(value = "/{taskId}", method = RequestMethod.GET, headers = "Accept=application/json") 56 | public List getCommentsByTaskId(@PathVariable("taskId") String taskId) { 57 | List commentListToReturn = new ArrayList(); 58 | for (CommentDTO currentComment : comments) { 59 | if (currentComment.getTaskId().equalsIgnoreCase(taskId)) { 60 | commentListToReturn.add(currentComment); 61 | } 62 | } 63 | 64 | return commentListToReturn; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /comments-webservice/src/main/java/com/rohitghatol/microservices/comments/config/CommentsConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.comments.config; 5 | 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.http.HttpMethod; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 11 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 12 | 13 | /** 14 | * Resource server configuration defining what endpoints are protected. 15 | * 16 | * @author anilallewar 17 | * 18 | */ 19 | @Configuration 20 | @EnableResourceServer 21 | public class CommentsConfiguration extends ResourceServerConfigurerAdapter { 22 | 23 | /** 24 | * Provide security so that endpoints are only served if the request is 25 | * already authenticated. 26 | */ 27 | @Override 28 | public void configure(HttpSecurity http) throws Exception { 29 | // @formatter:off 30 | http.requestMatchers() 31 | .antMatchers("/**") 32 | .and() 33 | .authorizeRequests() 34 | .anyRequest() 35 | .authenticated() 36 | .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')") 37 | .antMatchers(HttpMethod.OPTIONS, "/**").access("#oauth2.hasScope('read')") 38 | .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") 39 | .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") 40 | .antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')") 41 | .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')"); 42 | // @formatter:on 43 | } 44 | 45 | /** 46 | * Id of the resource that you are letting the client have access to. 47 | * Supposing you have another api ("say api2"), then you can customize the 48 | * access within resource server to define what api is for what resource id. 49 | *
50 | *
51 | * 52 | * So suppose you have 2 APIs, then you can define 2 resource servers. 53 | *
    54 | *
  1. Client 1 has been configured for access to resourceid1, so he can 55 | * only access "api1" if the resource server configures the resourceid to 56 | * "api1".
  2. 57 | *
  3. Client 1 can't access resource server 2 since it has configured the 58 | * resource id to "api2" 59 | *
  4. 60 | *
61 | * 62 | */ 63 | @Override 64 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 65 | resources.resourceId("apis"); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /comments-webservice/src/main/java/com/rohitghatol/microservices/comments/dtos/CommentDTO.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.comments.dtos; 5 | 6 | import java.io.IOException; 7 | import java.util.Date; 8 | 9 | import com.fasterxml.jackson.core.JsonGenerator; 10 | import com.fasterxml.jackson.core.JsonProcessingException; 11 | import com.fasterxml.jackson.databind.JsonSerializer; 12 | import com.fasterxml.jackson.databind.SerializerProvider; 13 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 14 | 15 | /** 16 | * Represents comments on Task. 17 | * 18 | * @author anilallewar 19 | */ 20 | public class CommentDTO { 21 | 22 | /** The task id. */ 23 | private String taskId; 24 | 25 | /** The last name. */ 26 | private String comment; 27 | 28 | /** The completed. */ 29 | private Date posted; 30 | 31 | /** 32 | * Instantiates a new task dto. 33 | */ 34 | public CommentDTO() { 35 | super(); 36 | 37 | } 38 | 39 | /** 40 | * Instantiates a new task dto. 41 | * 42 | * @param taskId 43 | * the task id 44 | * @param description 45 | * the description 46 | */ 47 | public CommentDTO(String taskId, String comment, Date posted) { 48 | super(); 49 | this.taskId = taskId; 50 | this.comment = comment; 51 | this.posted = posted; 52 | } 53 | 54 | /** 55 | * @return the taskId 56 | */ 57 | public String getTaskId() { 58 | return taskId; 59 | } 60 | 61 | /** 62 | * @param taskId 63 | * the taskId to set 64 | */ 65 | public void setTaskId(String taskId) { 66 | this.taskId = taskId; 67 | } 68 | 69 | /** 70 | * @return the comment 71 | */ 72 | public String getComment() { 73 | return comment; 74 | } 75 | 76 | /** 77 | * @param comment 78 | * the comment to set 79 | */ 80 | public void setComment(String comment) { 81 | this.comment = comment; 82 | } 83 | 84 | /** 85 | * @return the posted 86 | */ 87 | @JsonSerialize(using = CustomDateToLongSerializer.class) 88 | public Date getPosted() { 89 | return posted; 90 | } 91 | 92 | /** 93 | * @param posted 94 | * the posted to set 95 | */ 96 | public void setPosted(Date posted) { 97 | this.posted = posted; 98 | } 99 | 100 | /* 101 | * (non-Javadoc) 102 | * 103 | * @see java.lang.Object#hashCode() 104 | */ 105 | @Override 106 | public int hashCode() { 107 | final int prime = 31; 108 | int result = 1; 109 | result = prime * result + ((comment == null) ? 0 : comment.hashCode()); 110 | result = prime * result + ((posted == null) ? 0 : posted.hashCode()); 111 | result = prime * result + ((taskId == null) ? 0 : taskId.hashCode()); 112 | return result; 113 | } 114 | 115 | /* 116 | * (non-Javadoc) 117 | * 118 | * @see java.lang.Object#equals(java.lang.Object) 119 | */ 120 | @Override 121 | public boolean equals(Object obj) { 122 | if (this == obj) 123 | return true; 124 | if (obj == null) 125 | return false; 126 | if (getClass() != obj.getClass()) 127 | return false; 128 | CommentDTO other = (CommentDTO) obj; 129 | if (comment == null) { 130 | if (other.comment != null) 131 | return false; 132 | } else if (!comment.equals(other.comment)) 133 | return false; 134 | if (posted == null) { 135 | if (other.posted != null) 136 | return false; 137 | } else if (!posted.equals(other.posted)) 138 | return false; 139 | if (taskId == null) { 140 | if (other.taskId != null) 141 | return false; 142 | } else if (!taskId.equals(other.taskId)) 143 | return false; 144 | return true; 145 | } 146 | 147 | /* 148 | * (non-Javadoc) 149 | * 150 | * @see java.lang.Object#toString() 151 | */ 152 | @Override 153 | public String toString() { 154 | return "CommentDTO [taskId=" + taskId + ", comment=" + comment + ", posted=" + posted + "]"; 155 | } 156 | 157 | } 158 | 159 | /** 160 | * Custom date serializer that converts the date to long before sending it out 161 | * 162 | * @author anilallewar 163 | * 164 | */ 165 | class CustomDateToLongSerializer extends JsonSerializer { 166 | 167 | @Override 168 | public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) 169 | throws IOException, JsonProcessingException { 170 | jgen.writeNumber(value.getTime()); 171 | } 172 | } -------------------------------------------------------------------------------- /comments-webservice/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/comments-webservice/src/main/resources/application.yml -------------------------------------------------------------------------------- /comments-webservice/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | 4 | # Name of the service that is using with Zuul routes to forward specific requests to this service 5 | name: comments-webservice 6 | cloud: 7 | config: 8 | 9 | # Define the URL from where this service would pick up it's external configuration. Note that it is 10 | # pointing to the config-server aplication 11 | uri: http://localhost:8888 12 | 13 | --- 14 | 15 | spring: 16 | profiles: docker 17 | cloud: 18 | config: 19 | uri: http://192.168.59.103:8888 -------------------------------------------------------------------------------- /config-server/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | -------------------------------------------------------------------------------- /config-server/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | config-server 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /config-server/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application loads and makes the **external configuration** available to rest of the applications. Note that the external configuration can be hosted either on GitHub or on local file system. 4 | 5 | The respective applications pick up the configuration based on a `.yml` file defined in the configuration by matching the service's `spring.application.name` property defined in the `bootstrap.yml` file. 6 | 7 | ##Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * This is the first application that needs to run since it pulls the configuration information(like what port to run etc) that is needed by rest of the applications to start. 11 | 12 | ### Running the application 13 | * Build the application by running the `./gradlew clean build` gradle command at the "config-server" project root folder on the terminal. 14 | * If you want to run the application as jar file, then run `java -jar build/libs/sample-config-server-0.0.1.jar` command at the terminal. 15 | -------------------------------------------------------------------------------- /config-server/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | project.ext { 3 | bootVersion = '1.2.3.RELEASE' 4 | cloudVersion = '1.0.0.RELEASE' 5 | } 6 | repositories { 7 | mavenCentral() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" 13 | classpath 'se.transmode.gradle:gradle-docker:1.2' 14 | } 15 | } 16 | 17 | apply plugin: 'eclipse' 18 | apply plugin: 'spring-boot' 19 | apply plugin: 'java' 20 | apply plugin: 'docker' 21 | 22 | 23 | jar { 24 | baseName = 'sample-config-server' 25 | version = '0.0.1' 26 | } 27 | 28 | repositories { 29 | mavenCentral() 30 | jcenter() 31 | } 32 | dependencies { 33 | compile("org.springframework.boot:spring-boot-starter-web:${project.bootVersion}") 34 | compile("org.springframework.boot:spring-boot-starter-actuator:${project.bootVersion}") 35 | compile("org.springframework.cloud:spring-cloud-config-server:1.0.0.RELEASE") 36 | 37 | testCompile group: 'junit', name: 'junit', version: '4.+' 38 | testCompile 'org.springframework:spring-test:4.0.6.RELEASE' 39 | } 40 | 41 | group = 'anilallewar' 42 | mainClassName = 'com.rohitghatol.microservices.config.Application' 43 | 44 | sourceCompatibility = 1.7 45 | targetCompatibility = 1.7 46 | 47 | 48 | distDocker { 49 | exposePort 8888 50 | setEnvironment 'JAVA_OPTS', '-Dspring.profiles.active=docker' 51 | } 52 | 53 | docker { 54 | useApi true 55 | hostUrl 'http://192.168.59.103:2375' 56 | baseImage = 'java:7' 57 | } 58 | 59 | task createWrapper(type: Wrapper) { 60 | gradleVersion = '2.0' 61 | } 62 | 63 | -------------------------------------------------------------------------------- /config-server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/config-server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /config-server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 20:50:40 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /config-server/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /config-server/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /config-server/src/main/java/com/rohitghatol/microservices/config/Application.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.config; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.config.server.EnableConfigServer; 9 | import org.springframework.context.annotation.ComponentScan; 10 | 11 | 12 | /** 13 | * The Main Spring Boot Application class.
14 | *
15 | * 16 | * The {@link EnableConfigServer} annotation defines that this application will 17 | * serve as the REST based API for providing external configuration.
18 | *
19 | * 20 | * The external repository from where the configuration will be picked up is 21 | * defined in the {@linkplain application.yml} file. 22 | * 23 | * @author rohitghatol 24 | */ 25 | @EnableAutoConfiguration 26 | @EnableConfigServer 27 | @ComponentScan 28 | public class Application { 29 | 30 | /** 31 | * The main method. 32 | * 33 | * @param args the arguments 34 | */ 35 | public static void main(String[] args) { 36 | SpringApplication.run(Application.class, args); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /config-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | server: 5 | git: 6 | uri: https://github.com/anilallewar/sample-config 7 | # While in development mode, you can configure the config server to pick up configuration files from 8 | # the file system 9 | 10 | # uri: file://Users/anilallewar/Documents/Anil Allewar/Trainings/Code Samples/Enterprise Java/Micro Services/sample-config 11 | 12 | # Defines the port where the config server is running so that rest of the services can pick up 13 | # their external configurations 14 | server: 15 | port: 8888 -------------------------------------------------------------------------------- /config-server/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: configserver -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | configserver: 2 | image: anilallewar/config-server 3 | restart: always 4 | 5 | eurekaregistry: 6 | image: anilallewar/webservice-registry 7 | restart: always 8 | ports: 9 | - "8761:8761" 10 | links: 11 | - configserver 12 | 13 | authserver: 14 | image: anilallewar/auth-server 15 | restart: always 16 | ports: 17 | - "8899:8899" 18 | links: 19 | - configserver 20 | 21 | apigateway: 22 | image: anilallewar/api-gateway 23 | restart: always 24 | links: 25 | - eurekaregistry 26 | - authserver 27 | - configserver 28 | 29 | webportal: 30 | image: anilallewar/web-portal 31 | restart: always 32 | links: 33 | - eurekaregistry 34 | - configserver 35 | 36 | userwebservice: 37 | image: anilallewar/user-webservice 38 | restart: always 39 | links: 40 | - eurekaregistry 41 | - authserver 42 | - configserver 43 | 44 | taskwebservice: 45 | image: anilallewar/task-webservice 46 | restart: always 47 | links: 48 | - eurekaregistry 49 | - authserver 50 | - configserver 51 | 52 | commentswebservice: 53 | image: anilallewar/comments-webservice 54 | restart: always 55 | links: 56 | - eurekaregistry 57 | - authserver 58 | - configserver -------------------------------------------------------------------------------- /docker-image-all-projects.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd api-gateway; ./gradlew clean build distDocker; cd .. 4 | cd auth-server; ./gradlew clean build distDocker; cd .. 5 | cd config-server; ./gradlew clean build distDocker; cd .. 6 | cd task-webservice; ./gradlew clean build distDocker; cd .. 7 | cd user-webservice; ./gradlew clean build distDocker; cd .. 8 | cd web-portal; ./gradlew clean build distDocker; cd .. 9 | cd webservice-registry; ./gradlew clean build distDocker; cd .. 10 | cd comments-webservice; ./gradlew clean build distDocker; cd .. -------------------------------------------------------------------------------- /images/Application_Components.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/images/Application_Components.jpg -------------------------------------------------------------------------------- /images/Decentralized Goverance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/images/Decentralized Goverance.png -------------------------------------------------------------------------------- /images/OAuth2 abstract protocol flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/images/OAuth2 abstract protocol flow.png -------------------------------------------------------------------------------- /images/Target_Architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/images/Target_Architecture.jpg -------------------------------------------------------------------------------- /task-webservice/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | -------------------------------------------------------------------------------- /task-webservice/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | task-webservice 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | 20 | 1438895288093 21 | 22 | 22 23 | 24 | org.eclipse.ui.ide.multiFilter 25 | 1.0-name-matches-false-false-.DS_Store 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /task-webservice/.settings/gradle/org.springsource.ide.eclipse.gradle.core.import.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleImportPreferences 2 | #Mon Apr 06 13:25:59 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | enableDependendencyManagement=true 10 | projects=; 11 | -------------------------------------------------------------------------------- /task-webservice/.settings/gradle/org.springsource.ide.eclipse.gradle.core.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences 2 | #Mon Apr 06 13:26:03 PDT 2015 3 | org.springsource.ide.eclipse.gradle.linkedresources= 4 | org.springsource.ide.eclipse.gradle.rootprojectloc= 5 | -------------------------------------------------------------------------------- /task-webservice/.settings/gradle/org.springsource.ide.eclipse.gradle.refresh.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.actions.GradleRefreshPreferences 2 | #Mon Apr 06 13:26:02 PDT 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | useHierarchicalNames=false 10 | -------------------------------------------------------------------------------- /task-webservice/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Mon Apr 06 19:41:01 PDT 2015 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.7 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.7 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /task-webservice/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **task** related functionality and serves as one component. It defines the REST endpoints that are used to provide task functionality. 4 | 5 | This micro-service also provides an example of to call another OAuth2 protected service from within this service using OAuth2 client configuration. The OAuth2 bearer token that has been passed to the task service is propogated to the "comments" service to get the comments for the given task. 6 | 7 | ##Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 11 | * [webserver-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 12 | 13 | ### Running the application 14 | * Build the application by running the `./gradlew clean build` gradle command at the "task-webservice" project root folder on the terminal. 15 | * If you want to run the application as jar file, then run `java -jar build/libs/sample-task-webservice-0.0.1.jar` command at the terminal. 16 | 17 | ## External Configuration 18 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. -------------------------------------------------------------------------------- /task-webservice/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | project.ext { 3 | bootVersion = '1.2.3.RELEASE' 4 | cloudVersion = '1.0.0.RELEASE' 5 | seurityVersion = '2.0.7.RELEASE' 6 | } 7 | repositories { 8 | mavenCentral() 9 | jcenter() 10 | } 11 | 12 | dependencies { 13 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" 14 | classpath 'se.transmode.gradle:gradle-docker:1.2' 15 | } 16 | } 17 | 18 | apply plugin: 'eclipse' 19 | apply plugin: 'spring-boot' 20 | apply plugin: 'java' 21 | apply plugin: 'docker' 22 | 23 | 24 | jar { 25 | baseName = 'sample-task-webservice' 26 | version = '0.0.1' 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | jcenter() 32 | } 33 | dependencies { 34 | compile("org.springframework.boot:spring-boot-starter-web:${project.bootVersion}") 35 | compile("org.springframework.boot:spring-boot-starter-actuator:${project.bootVersion}") 36 | compile("org.springframework.cloud:spring-cloud-config-client:${project.cloudVersion}") 37 | compile("org.springframework.cloud:spring-cloud-starter-eureka:${project.cloudVersion}") 38 | compile("org.springframework.cloud:spring-cloud-starter-hystrix:${project.cloudVersion}") 39 | 40 | compile("org.springframework.cloud:spring-cloud-starter-security:${project.cloudVersion}") 41 | compile("org.springframework.boot:spring-boot-starter-security:${project.bootVersion}") 42 | compile("org.springframework.security.oauth:spring-security-oauth2:${project.seurityVersion}") 43 | 44 | testCompile group: 'junit', name: 'junit', version: '4.+' 45 | testCompile 'org.springframework:spring-test:4.0.6.RELEASE' 46 | } 47 | 48 | group = 'anilallewar' 49 | mainClassName = 'com.rohitghatol.microservices.task.Application' 50 | 51 | sourceCompatibility = 1.7 52 | targetCompatibility = 1.7 53 | 54 | distDocker { 55 | exposePort 8080 56 | setEnvironment 'JAVA_OPTS', '-Dspring.profiles.active=docker' 57 | } 58 | 59 | docker { 60 | useApi true 61 | hostUrl 'http://192.168.59.103:2375' 62 | baseImage = 'java:7' 63 | } 64 | 65 | bootRun { 66 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4300,suspend=n','-Dspring.profiles.active=dev'] 67 | } 68 | 69 | run { 70 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4300,suspend=n','-Dspring.profiles.active=dev'] 71 | } 72 | 73 | task createWrapper(type: Wrapper) { 74 | gradleVersion = '2.0' 75 | } 76 | 77 | -------------------------------------------------------------------------------- /task-webservice/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 20:53:39 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /task-webservice/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /task-webservice/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/rohitghatol/microservices/task/Application.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.task; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 9 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 10 | import org.springframework.cloud.security.oauth2.resource.EnableOAuth2Resource; 11 | import org.springframework.context.annotation.ComponentScan; 12 | 13 | /** 14 | * The boot application class that defines the spring boot application to have 15 | * the following properties
16 | *
17 | * 18 | *
    19 | *
  1. Act as a Eureka client; this behavior is provided by the 20 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 21 | * the external configuration provided by the config server.
  2. 22 | *
  3. The security is enabled to be covered by OAuth2 access token using the 23 | * {@link EnableOAuth2Resource} annotation. The URL from where the user would be 24 | * authenticated is provided by the 25 | * spring.oauth2.resource.userInfoUri property defined in the 26 | * external configuration.
  4. 27 | *
  5. {@link EnableEurekaClient} makes the app into both a Eureka "instance" (i.e. it 28 | * registers itself) and a "client" (i.e. it can query the registry to locate 29 | * other services).
  6. 30 | *
  7. {@link EnableCircuitBreaker} allows the application to respond to 31 | + * failures on services it relies. For example consider that you have an 32 | + * "employee" service that uses the "address" service to get addresses. Now if 33 | + * the address service goes down, then we can provide a fallback method using 34 | + * the circuit breaker. Now the address would be sent back using the static 35 | + * value from the method till the "address" service comes back again.
  8. 36 | *
  9. Note that all these annotations work in conjunction with properties 37 | * defined in the external configuration files specified by the config server. 38 | *
  10. 39 | *
40 | * 41 | * @author rohitghatol 42 | * 43 | */ 44 | @EnableAutoConfiguration 45 | @ComponentScan 46 | @EnableEurekaClient 47 | @EnableOAuth2Resource 48 | @EnableCircuitBreaker 49 | public class Application { 50 | public static void main(String[] args) { 51 | 52 | SpringApplication.run(Application.class,args); 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/rohitghatol/microservices/task/apis/CommentsService.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservices.task.apis; 2 | 3 | import java.util.Calendar; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.security.oauth2.client.OAuth2RestOperations; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.stereotype.Service; 9 | 10 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 11 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; 12 | import com.rohitghatol.microservices.task.model.CommentCollectionResource; 13 | import com.rohitghatol.microservices.task.model.CommentResource; 14 | 15 | /** 16 | * The {@link HystrixCommand} works since Spring makes a proxy to intercept the 17 | * request and call the fallback method if the method errs.
18 | *
19 | * 20 | * Hence the {@link HystrixCommand} needs to be in separate {@link Component} or 21 | * {@link Service} stereotypes so that Spring can proxy them. 22 | * 23 | * @author anilallewar 24 | * 25 | */ 26 | @Service 27 | public class CommentsService { 28 | 29 | @Autowired 30 | private OAuth2RestOperations restTemplate; 31 | 32 | /** 33 | * Returns the comments for the task; note that this applies a circuit 34 | * breaker that would return the default value if the comments-webservice 35 | * was down. 36 | * 37 | * Discussion on HystrixProperty 38 | *
    39 | *
  1. execution.isolation.strategy: The value of "SEMAPHORE" enables 40 | * Hystrix to use the current thread for executing this command. Since we 41 | * need to use the parent HttpRequest to pass the OAuth2 access token, we 42 | * are constrained in using the calling thread. The number of concurrent 43 | * requests that can be made to the command is limited by the semaphore(or 44 | * counter) value; default is 10.In a normal scenario, you would use 45 | * isolation strategy of "THREAD" that executes the Hystrix command in a 46 | * separate thread pool. This is desirable because it doesn't block the 47 | * calling thread and lets us handle faulty client libraries, client 48 | * performance considerations etc.
  2. 49 | *
  3. circuitBreaker.requestVolumeThreshold:This property sets the 50 | * minimum number of requests in a rolling window that will trip the 51 | * circuit. For example, if the value is 20, then if only 19 requests are 52 | * received in the rolling window (say a window of 10 seconds) the circuit 53 | * will not trip open even if all 19 failed. We have a lower value in this 54 | * sample application so as to trip early.
  4. 55 | *
  5. circuitBreaker.sleepWindowInMilliseconds:This property sets 56 | * the amount of time, after tripping the circuit, to reject requests before 57 | * allowing attempts again to determine if the circuit should again be 58 | * closed. We again have a lower value so that Hystrix tries to pass single 59 | * request to the called service quickly.
  6. 60 | *
61 | * 62 | * @param taskId 63 | * @return 64 | */ 65 | @HystrixCommand(fallbackMethod = "getFallbackCommentsForTask", commandProperties = { 66 | @HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE"), 67 | @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), 68 | @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "1000") }) 69 | public CommentCollectionResource getCommentsForTask(String taskId) { 70 | // Get the comments for this task 71 | return restTemplate.getForObject(String.format("http://comments-webservice/comments/%s", taskId), 72 | CommentCollectionResource.class); 73 | 74 | } 75 | 76 | /** 77 | * Gets the default comments for task. Need to add the suppress warning 78 | * since the method is not directly used by the class. 79 | * 80 | * @return the default comments for task 81 | */ 82 | @SuppressWarnings("unused") 83 | private CommentCollectionResource getFallbackCommentsForTask(String taskId) { 84 | // Get the default comments 85 | CommentCollectionResource comments = new CommentCollectionResource(); 86 | comments.addComment(new CommentResource(taskId, "default comment", Calendar.getInstance().getTime())); 87 | 88 | return comments; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/rohitghatol/microservices/task/apis/TaskController.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservices.task.apis; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RequestMethod; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import com.rohitghatol.microservices.task.dtos.TaskDTO; 14 | 15 | /** 16 | * REST endpoint for the task functionality 17 | * 18 | * @author anilallewar 19 | * 20 | */ 21 | @RestController 22 | @RequestMapping("/") 23 | public class TaskController { 24 | 25 | @Autowired 26 | private CommentsService commentsService; 27 | 28 | private List tasks = Arrays.asList(new TaskDTO("task11", "description11", "1"), 29 | new TaskDTO("task12", "description12", "1"), new TaskDTO("task13", "description13", "1"), 30 | new TaskDTO("task21", "description21", "2"), new TaskDTO("task22", "description22", "2")); 31 | 32 | /** 33 | * Get all tasks 34 | * 35 | * @return 36 | */ 37 | @RequestMapping(method = RequestMethod.GET, headers = "Accept=application/json") 38 | public List getTasks() { 39 | return tasks; 40 | } 41 | 42 | /** 43 | * Get tasks for specific taskid 44 | * 45 | * @param taskId 46 | * @return 47 | */ 48 | @RequestMapping(value = "{taskId}", method = RequestMethod.GET, headers = "Accept=application/json") 49 | public TaskDTO getTaskByTaskId(@PathVariable("taskId") String taskId) { 50 | TaskDTO taskToReturn = null; 51 | for (TaskDTO currentTask : tasks) { 52 | if (currentTask.getTaskId().equalsIgnoreCase(taskId)) { 53 | taskToReturn = currentTask; 54 | break; 55 | } 56 | } 57 | 58 | if (taskToReturn != null) { 59 | taskToReturn.setComments(this.commentsService.getCommentsForTask(taskId)); 60 | } 61 | return taskToReturn; 62 | } 63 | 64 | /** 65 | * Get tasks for specific user that is passed in 66 | * 67 | * @param taskId 68 | * @return 69 | */ 70 | @RequestMapping(value = "/usertask/{userName}", method = RequestMethod.GET, headers = "Accept=application/json") 71 | public List getTasksByUserName(@PathVariable("userName") String userName) { 72 | List taskListToReturn = new ArrayList(); 73 | for (TaskDTO currentTask : tasks) { 74 | if (currentTask.getUserName().equalsIgnoreCase(userName)) { 75 | taskListToReturn.add(currentTask); 76 | } 77 | } 78 | 79 | return taskListToReturn; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/rohitghatol/microservices/task/config/OAuthClientConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservices.task.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.security.oauth2.client.OAuth2ClientContext; 7 | import org.springframework.security.oauth2.client.OAuth2RestOperations; 8 | import org.springframework.security.oauth2.client.OAuth2RestTemplate; 9 | import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails; 10 | import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; 11 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; 12 | 13 | /** 14 | * Configuration that sets up the OAuth2 client operation for making calls to 15 | * the comments-webservice. 16 | * 17 | * @author anilallewar 18 | * 19 | */ 20 | @Configuration 21 | @EnableOAuth2Client 22 | public class OAuthClientConfiguration { 23 | 24 | @Value("${spring.oauth2.client.userAuthorizationUri}") 25 | private String authorizeUrl; 26 | 27 | @Value("${spring.oauth2.client.accessTokenUri}") 28 | private String tokenUrl; 29 | 30 | @Value("${spring.oauth2.client.clientId}") 31 | private String clientId; 32 | 33 | /** 34 | * RestTempate that relays the OAuth2 token passed to the task webservice. 35 | * 36 | * @param oauth2ClientContext 37 | * @return 38 | */ 39 | @Bean 40 | public OAuth2RestOperations restTemplate(OAuth2ClientContext oauth2ClientContext) { 41 | return new OAuth2RestTemplate(resource(), oauth2ClientContext); 42 | } 43 | 44 | /** 45 | * Setup details where the OAuth2 server is. 46 | * @return 47 | */ 48 | @Bean 49 | protected OAuth2ProtectedResourceDetails resource() { 50 | AuthorizationCodeResourceDetails resource = new AuthorizationCodeResourceDetails(); 51 | resource.setAccessTokenUri(tokenUrl); 52 | resource.setUserAuthorizationUri(authorizeUrl); 53 | resource.setClientId(clientId); 54 | resource.setClientSecret("secret"); 55 | return resource; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/rohitghatol/microservices/task/config/TaskConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.task.config; 5 | 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.http.HttpMethod; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 11 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 12 | 13 | /** 14 | * Resource server configuration defining what endpoints are protected. 15 | * 16 | * @author anilallewar 17 | * 18 | */ 19 | @Configuration 20 | @EnableResourceServer 21 | public class TaskConfiguration extends ResourceServerConfigurerAdapter { 22 | 23 | /** 24 | * Provide security so that endpoints are only served if the request is 25 | * already authenticated. 26 | */ 27 | @Override 28 | public void configure(HttpSecurity http) throws Exception { 29 | // @formatter:off 30 | http.requestMatchers() 31 | .antMatchers("/**") 32 | .and() 33 | .authorizeRequests() 34 | .anyRequest() 35 | .authenticated() 36 | .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')") 37 | .antMatchers(HttpMethod.OPTIONS, "/**").access("#oauth2.hasScope('read')") 38 | .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") 39 | .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") 40 | .antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')") 41 | .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')"); 42 | // @formatter:on 43 | } 44 | 45 | /** 46 | * Id of the resource that you are letting the client have access to. 47 | * Supposing you have another api ("say api2"), then you can customize the 48 | * access within resource server to define what api is for what resource id. 49 | *
50 | *
51 | * 52 | * So suppose you have 2 APIs, then you can define 2 resource servers. 53 | *
    54 | *
  1. Client 1 has been configured for access to resourceid1, so he can 55 | * only access "api1" if the resource server configures the resourceid to 56 | * "api1".
  2. 57 | *
  3. Client 1 can't access resource server 2 since it has configured the 58 | * resource id to "api2" 59 | *
  4. 60 | *
61 | * 62 | */ 63 | @Override 64 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 65 | resources.resourceId("apis"); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/rohitghatol/microservices/task/dtos/TaskDTO.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.task.dtos; 5 | 6 | import com.rohitghatol.microservices.task.model.CommentCollectionResource; 7 | 8 | /** 9 | * Represents Todo Task. 10 | * 11 | * @author rohitghatol 12 | */ 13 | public class TaskDTO { 14 | 15 | /** The task id. */ 16 | private String taskId; 17 | 18 | /** The last name. */ 19 | private String description; 20 | 21 | /** The completed. */ 22 | private boolean completed; 23 | 24 | /** The user name with whom the task is associated. */ 25 | private String userName; 26 | 27 | /** The comments. */ 28 | private CommentCollectionResource comments; 29 | 30 | /** 31 | * Instantiates a new task dto. 32 | */ 33 | public TaskDTO() { 34 | super(); 35 | 36 | } 37 | 38 | /** 39 | * Instantiates a new task dto. 40 | * 41 | * @param taskId the task id 42 | * @param description the description 43 | */ 44 | public TaskDTO(String taskId, String description, String userName) { 45 | super(); 46 | this.taskId = taskId; 47 | this.description = description; 48 | this.completed = false; 49 | this.userName = userName; 50 | } 51 | 52 | /** 53 | * Gets the task id. 54 | * 55 | * @return the task id 56 | */ 57 | public String getTaskId() { 58 | return taskId; 59 | } 60 | 61 | /** 62 | * Sets the task id. 63 | * 64 | * @param taskId the new task id 65 | */ 66 | public void setTaskId(String taskId) { 67 | this.taskId = taskId; 68 | } 69 | 70 | /** 71 | * Gets the description. 72 | * 73 | * @return the description 74 | */ 75 | public String getDescription() { 76 | return description; 77 | } 78 | 79 | /** 80 | * Sets the description. 81 | * 82 | * @param description the new description 83 | */ 84 | public void setDescription(String description) { 85 | this.description = description; 86 | } 87 | 88 | /** 89 | * Checks if is completed. 90 | * 91 | * @return true, if is completed 92 | */ 93 | public boolean isCompleted() { 94 | return completed; 95 | } 96 | 97 | /** 98 | * Sets the completed. 99 | * 100 | * @param completed the new completed 101 | */ 102 | public void setCompleted(boolean completed) { 103 | this.completed = completed; 104 | } 105 | 106 | 107 | /** 108 | * @return the userName 109 | */ 110 | public String getUserName() { 111 | return userName; 112 | } 113 | 114 | /** 115 | * @param userName the userName to set 116 | */ 117 | public void setUserName(String userName) { 118 | this.userName = userName; 119 | } 120 | 121 | /** 122 | * @return the comments 123 | */ 124 | public CommentCollectionResource getComments() { 125 | return comments; 126 | } 127 | 128 | /** 129 | * @param comments the comments to set 130 | */ 131 | public void setComments(CommentCollectionResource comments) { 132 | this.comments = comments; 133 | } 134 | 135 | /* (non-Javadoc) 136 | * @see java.lang.Object#hashCode() 137 | */ 138 | @Override 139 | public int hashCode() { 140 | final int prime = 31; 141 | int result = 1; 142 | result = prime * result + ((comments == null) ? 0 : comments.hashCode()); 143 | result = prime * result + (completed ? 1231 : 1237); 144 | result = prime * result + ((description == null) ? 0 : description.hashCode()); 145 | result = prime * result + ((taskId == null) ? 0 : taskId.hashCode()); 146 | result = prime * result + ((userName == null) ? 0 : userName.hashCode()); 147 | return result; 148 | } 149 | 150 | /* (non-Javadoc) 151 | * @see java.lang.Object#equals(java.lang.Object) 152 | */ 153 | @Override 154 | public boolean equals(Object obj) { 155 | if (this == obj) 156 | return true; 157 | if (obj == null) 158 | return false; 159 | if (getClass() != obj.getClass()) 160 | return false; 161 | TaskDTO other = (TaskDTO) obj; 162 | if (comments == null) { 163 | if (other.comments != null) 164 | return false; 165 | } else if (!comments.equals(other.comments)) 166 | return false; 167 | if (completed != other.completed) 168 | return false; 169 | if (description == null) { 170 | if (other.description != null) 171 | return false; 172 | } else if (!description.equals(other.description)) 173 | return false; 174 | if (taskId == null) { 175 | if (other.taskId != null) 176 | return false; 177 | } else if (!taskId.equals(other.taskId)) 178 | return false; 179 | if (userName == null) { 180 | if (other.userName != null) 181 | return false; 182 | } else if (!userName.equals(other.userName)) 183 | return false; 184 | return true; 185 | } 186 | 187 | /* (non-Javadoc) 188 | * @see java.lang.Object#toString() 189 | */ 190 | @Override 191 | public String toString() { 192 | return "TaskDTO [taskId=" + taskId + ", description=" + description + ", completed=" + completed + ", userName=" 193 | + userName + ", comments=" + comments + "]"; 194 | } 195 | 196 | } 197 | -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/rohitghatol/microservices/task/model/CommentCollectionResource.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.task.model; 5 | 6 | import java.io.IOException; 7 | import java.util.ArrayList; 8 | import java.util.Date; 9 | import java.util.List; 10 | 11 | import com.fasterxml.jackson.core.JsonParser; 12 | import com.fasterxml.jackson.core.JsonProcessingException; 13 | import com.fasterxml.jackson.databind.DeserializationContext; 14 | import com.fasterxml.jackson.databind.JsonDeserializer; 15 | import com.fasterxml.jackson.databind.JsonNode; 16 | import com.fasterxml.jackson.databind.annotation.JsonDeserialize; 17 | 18 | /** 19 | * @author anilallewar 20 | * 21 | */ 22 | @JsonDeserialize(using = CommentsCollectionDeserializer.class) 23 | public class CommentCollectionResource { 24 | private List taskComments; 25 | 26 | /** 27 | * Adds the comment. 28 | * 29 | * @param comment 30 | * the comment 31 | */ 32 | public void addComment(CommentResource comment) { 33 | if (this.taskComments == null) { 34 | this.taskComments = new ArrayList<>(); 35 | } 36 | this.taskComments.add(comment); 37 | } 38 | 39 | /** 40 | * @return the taskComments 41 | */ 42 | public List getTaskComments() { 43 | return taskComments; 44 | } 45 | 46 | /** 47 | * @param taskComments 48 | * the taskComments to set 49 | */ 50 | public void setTaskComments(List taskComments) { 51 | this.taskComments = taskComments; 52 | } 53 | 54 | /* 55 | * (non-Javadoc) 56 | * 57 | * @see java.lang.Object#hashCode() 58 | */ 59 | @Override 60 | public int hashCode() { 61 | final int prime = 31; 62 | int result = 1; 63 | result = prime * result + ((taskComments == null) ? 0 : taskComments.hashCode()); 64 | return result; 65 | } 66 | 67 | /* 68 | * (non-Javadoc) 69 | * 70 | * @see java.lang.Object#equals(java.lang.Object) 71 | */ 72 | @Override 73 | public boolean equals(Object obj) { 74 | if (this == obj) 75 | return true; 76 | if (obj == null) 77 | return false; 78 | if (getClass() != obj.getClass()) 79 | return false; 80 | CommentCollectionResource other = (CommentCollectionResource) obj; 81 | if (taskComments == null) { 82 | if (other.taskComments != null) 83 | return false; 84 | } else if (!taskComments.equals(other.taskComments)) 85 | return false; 86 | return true; 87 | } 88 | 89 | /* 90 | * (non-Javadoc) 91 | * 92 | * @see java.lang.Object#toString() 93 | */ 94 | @Override 95 | public String toString() { 96 | return "CommentCollectionResource [taskComments=" + taskComments + "]"; 97 | } 98 | } 99 | 100 | /** 101 | * Inner class to perform the de-serialization of the comments array 102 | * 103 | * @author anilallewar 104 | * 105 | */ 106 | class CommentsCollectionDeserializer extends JsonDeserializer { 107 | @Override 108 | public CommentCollectionResource deserialize(JsonParser jp, DeserializationContext ctxt) 109 | throws IOException, JsonProcessingException { 110 | CommentCollectionResource commentArrayResource = new CommentCollectionResource(); 111 | CommentResource commentResource = null; 112 | 113 | JsonNode jsonNode = jp.readValueAsTree(); 114 | 115 | for (JsonNode childNode : jsonNode) { 116 | if (childNode.has(CommentResource.JP_TASKID)) { 117 | commentResource = new CommentResource(); 118 | commentResource.setTaskId(childNode.get(CommentResource.JP_TASKID).asText()); 119 | commentResource.setComment(childNode.get(CommentResource.JP_COMMENT).asText()); 120 | commentResource.setPosted(new Date(childNode.get(CommentResource.JP_POSTED).asLong())); 121 | 122 | commentArrayResource.addComment(commentResource); 123 | } 124 | } 125 | return commentArrayResource; 126 | 127 | } 128 | } -------------------------------------------------------------------------------- /task-webservice/src/main/java/com/rohitghatol/microservices/task/model/CommentResource.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservices.task.model; 2 | 3 | import java.io.IOException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Date; 6 | 7 | import com.fasterxml.jackson.annotation.JsonProperty; 8 | import com.fasterxml.jackson.core.JsonGenerator; 9 | import com.fasterxml.jackson.core.JsonProcessingException; 10 | import com.fasterxml.jackson.databind.JsonSerializer; 11 | import com.fasterxml.jackson.databind.SerializerProvider; 12 | import com.fasterxml.jackson.databind.annotation.JsonSerialize; 13 | 14 | /** 15 | * Represents comments on Task. 16 | * 17 | * @author anilallewar 18 | */ 19 | public class CommentResource { 20 | 21 | public static final String JP_TASKID = "taskId"; 22 | public static final String JP_COMMENT = "comment"; 23 | public static final String JP_POSTED = "posted"; 24 | 25 | /** The task id. */ 26 | private String taskId; 27 | 28 | /** The last name. */ 29 | private String comment; 30 | 31 | /** The completed. */ 32 | private Date posted; 33 | 34 | /** 35 | * Instantiates a new comment resource 36 | */ 37 | public CommentResource() { 38 | super(); 39 | 40 | } 41 | 42 | /** 43 | * Instantiates a new comment resource 44 | * 45 | * @param taskId 46 | * @param comment 47 | * @param posted 48 | */ 49 | public CommentResource(String taskId, String comment, Date posted) { 50 | super(); 51 | this.taskId = taskId; 52 | this.comment = comment; 53 | this.posted = posted; 54 | } 55 | 56 | /** 57 | * @return the taskId 58 | */ 59 | @JsonProperty(JP_TASKID) 60 | public String getTaskId() { 61 | return taskId; 62 | } 63 | 64 | /** 65 | * @param taskId 66 | * the taskId to set 67 | */ 68 | public void setTaskId(String taskId) { 69 | this.taskId = taskId; 70 | } 71 | 72 | /** 73 | * @return the comment 74 | */ 75 | @JsonProperty(JP_COMMENT) 76 | public String getComment() { 77 | return comment; 78 | } 79 | 80 | /** 81 | * @param comment 82 | * the comment to set 83 | */ 84 | public void setComment(String comment) { 85 | this.comment = comment; 86 | } 87 | 88 | /** 89 | * @return the posted 90 | */ 91 | @JsonProperty(JP_POSTED) 92 | @JsonSerialize(using = CustomDateToStringSerializer.class) 93 | public Date getPosted() { 94 | return posted; 95 | } 96 | 97 | /** 98 | * @param posted 99 | * the posted to set 100 | */ 101 | public void setPosted(Date posted) { 102 | this.posted = posted; 103 | } 104 | 105 | /* 106 | * (non-Javadoc) 107 | * 108 | * @see java.lang.Object#hashCode() 109 | */ 110 | @Override 111 | public int hashCode() { 112 | final int prime = 31; 113 | int result = 1; 114 | result = prime * result + ((comment == null) ? 0 : comment.hashCode()); 115 | result = prime * result + ((posted == null) ? 0 : posted.hashCode()); 116 | result = prime * result + ((taskId == null) ? 0 : taskId.hashCode()); 117 | return result; 118 | } 119 | 120 | /* 121 | * (non-Javadoc) 122 | * 123 | * @see java.lang.Object#equals(java.lang.Object) 124 | */ 125 | @Override 126 | public boolean equals(Object obj) { 127 | if (this == obj) 128 | return true; 129 | if (obj == null) 130 | return false; 131 | if (getClass() != obj.getClass()) 132 | return false; 133 | CommentResource other = (CommentResource) obj; 134 | if (comment == null) { 135 | if (other.comment != null) 136 | return false; 137 | } else if (!comment.equals(other.comment)) 138 | return false; 139 | if (posted == null) { 140 | if (other.posted != null) 141 | return false; 142 | } else if (!posted.equals(other.posted)) 143 | return false; 144 | if (taskId == null) { 145 | if (other.taskId != null) 146 | return false; 147 | } else if (!taskId.equals(other.taskId)) 148 | return false; 149 | return true; 150 | } 151 | 152 | /* 153 | * (non-Javadoc) 154 | * 155 | * @see java.lang.Object#toString() 156 | */ 157 | @Override 158 | public String toString() { 159 | return "CommentResource [taskId=" + taskId + ", comment=" + comment + ", posted=" + posted + "]"; 160 | } 161 | 162 | } 163 | 164 | /** 165 | * Custom date serializer that converts the date to String before sending it out 166 | * 167 | * @author anilallewar 168 | * 169 | */ 170 | class CustomDateToStringSerializer extends JsonSerializer { 171 | 172 | private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); 173 | 174 | @Override 175 | public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider) 176 | throws IOException, JsonProcessingException { 177 | String dateString = dateFormat.format(value); 178 | jgen.writeString(dateString); 179 | } 180 | } -------------------------------------------------------------------------------- /task-webservice/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/task-webservice/src/main/resources/application.yml -------------------------------------------------------------------------------- /task-webservice/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | 4 | # Name of the service that is using with Zuul routes to forward specific requests to this service 5 | name: task-webservice 6 | cloud: 7 | config: 8 | 9 | # Define the URL from where this service would pick up it's external configuration. Note that it is 10 | # pointing to the config-server aplication 11 | uri: http://localhost:8888 12 | 13 | --- 14 | 15 | spring: 16 | profiles: docker 17 | cloud: 18 | config: 19 | uri: http://192.168.59.103:8888 -------------------------------------------------------------------------------- /understanding_notes.pages: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/understanding_notes.pages -------------------------------------------------------------------------------- /user-webservice/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | -------------------------------------------------------------------------------- /user-webservice/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | user-webservice 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /user-webservice/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **user** related functionality and serves as one component. It defines the REST endpoints that are used to provide user functionality. 4 | 5 | ##Pre-requisites 6 | 7 | ### Projects that need to be started before 8 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 9 | * [webservice-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 10 | 11 | ### Running the application 12 | * Build the application by running the `./gradlew clean build` gradle command at the "user-webservice" project root folder on the terminal. 13 | * If you want to run the application as jar file, then run `java -jar build/libs/sample-user-webservice-0.0.1.jar` command at the terminal. 14 | 15 | ## External Configuration 16 | The project derives it's external configuration from the [config server](/../../blob/master/config-server/README.md) service. Note that we have defined the `spring.cloud.config.uri` in the `bootstrap.yml` file and that tells the application where to pick up the external confiurations. In our case, the URL points to the running [config server](/../../blob/master/config-server/README.md) server. You also need to have the `spring-cloud-config-client` dependency in the classpath so that the application can comsume the config server. 17 | 18 | A Spring Cloud application operates by creating a "bootstrap" context, which is a parent context for the main application. This bootstrap context loads properties from external sources (the config-server) and decrypts the properties if required. 19 | 20 | The bootstrap context for external configuration is located by convention at `bootstrap.yml` whereas the internal configuration is located by convention at `application.yml`. Note that you can also have `.properties` file instead of `.yml` files. -------------------------------------------------------------------------------- /user-webservice/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | project.ext { 3 | bootVersion = '1.2.3.RELEASE' 4 | cloudVersion = '1.0.0.RELEASE' 5 | seurityVersion = '2.0.7.RELEASE' 6 | } 7 | repositories { 8 | mavenCentral() 9 | jcenter() 10 | } 11 | 12 | dependencies { 13 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" 14 | classpath 'se.transmode.gradle:gradle-docker:1.2' 15 | } 16 | } 17 | 18 | apply plugin: 'eclipse' 19 | apply plugin: 'spring-boot' 20 | apply plugin: 'java' 21 | apply plugin: 'docker' 22 | 23 | jar { 24 | baseName = 'sample-user-webservice' 25 | version = '0.0.1' 26 | } 27 | 28 | repositories { 29 | mavenCentral() 30 | jcenter() 31 | } 32 | dependencies { 33 | compile("org.springframework.boot:spring-boot-starter-web:${project.bootVersion}") 34 | compile("org.springframework.boot:spring-boot-starter-actuator:${project.bootVersion}") 35 | compile("org.springframework.cloud:spring-cloud-config-client:${project.cloudVersion}") 36 | compile("org.springframework.cloud:spring-cloud-starter-eureka:${project.cloudVersion}") 37 | 38 | compile("org.springframework.cloud:spring-cloud-starter-security:${project.cloudVersion}") 39 | compile("org.springframework.boot:spring-boot-starter-security:${project.bootVersion}") 40 | compile("org.springframework.security.oauth:spring-security-oauth2:${project.seurityVersion}") 41 | 42 | testCompile group: 'junit', name: 'junit', version: '4.+' 43 | testCompile 'org.springframework:spring-test:4.0.6.RELEASE' 44 | } 45 | 46 | group = 'anilallewar' 47 | mainClassName = 'com.rohitghatol.microservices.user.Application' 48 | 49 | sourceCompatibility = 1.7 50 | targetCompatibility = 1.7 51 | 52 | distDocker { 53 | exposePort 8080 54 | setEnvironment 'JAVA_OPTS', '-Dspring.profiles.active=docker' 55 | } 56 | 57 | docker { 58 | useApi true 59 | hostUrl 'http://192.168.59.103:2375' 60 | baseImage = 'java:7' 61 | } 62 | 63 | bootRun { 64 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4200,suspend=n','-Dspring.profiles.active=dev'] 65 | } 66 | 67 | run { 68 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4200,suspend=n','-Dspring.profiles.active=dev'] 69 | } 70 | 71 | task createWrapper(type: Wrapper) { 72 | gradleVersion = '2.0' 73 | } 74 | 75 | -------------------------------------------------------------------------------- /user-webservice/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/user-webservice/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /user-webservice/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 20:52:58 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /user-webservice/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /user-webservice/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/rohitghatol/microservices/user/Application.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.user; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 9 | import org.springframework.cloud.security.oauth2.resource.EnableOAuth2Resource; 10 | import org.springframework.context.annotation.ComponentScan; 11 | 12 | /** 13 | * The boot application class that defines the spring boot application to have 14 | * the following properties
15 | *
16 | * 17 | *
    18 | *
  1. Act as a Eureka client; this behavior is provided by the 19 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 20 | * the external configuration provided by the config server.
  2. 21 | *
  3. The security is enabled to be covered by OAuth2 access token using the 22 | * {@link EnableOAuth2Resource} annotation. The URL from where the user would be 23 | * authenticated is provided by the 24 | * spring.oauth2.resource.userInfoUri property defined in the 25 | * external configuration.
  4. 26 | *
  5. @EnableEurekaClient makes the app into both a Eureka "instance" (i.e. it 27 | * registers itself) and a "client" (i.e. it can query the registry to locate 28 | * other services).
  6. 29 | *
  7. Note that all these annotations work in conjunction with properties 30 | * defined in the external configuration files specified by the config server. 31 | *
  8. 32 | *
33 | * 34 | * @author rohitghatol 35 | * 36 | */ 37 | @EnableAutoConfiguration 38 | @ComponentScan 39 | @EnableEurekaClient 40 | @EnableOAuth2Resource 41 | public class Application { 42 | public static void main(String[] args) { 43 | 44 | SpringApplication.run(Application.class,args); 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/rohitghatol/microservices/user/apis/UserController.java: -------------------------------------------------------------------------------- 1 | package com.rohitghatol.microservices.user.apis; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestMethod; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import com.rohitghatol.microservices.user.dto.UserDTO; 13 | 14 | /** 15 | * REST endpoint for the user functionality 16 | * 17 | * @author anilallewar 18 | * 19 | */ 20 | @RestController 21 | @RequestMapping("/") 22 | public class UserController { 23 | 24 | @Value("${mail.domain}") 25 | private String mailDomain; 26 | 27 | private List users = Arrays.asList(new UserDTO("Anil", "Allewar", "1", "anil.allewar@" + mailDomain), 28 | new UserDTO("Rohit", "Ghatol", "2", "rohit.ghatol@" + mailDomain), 29 | new UserDTO("John", "Snow", "3", "john.snow@" + mailDomain)); 30 | 31 | /** 32 | * Return all users 33 | * 34 | * @return 35 | */ 36 | @RequestMapping(method = RequestMethod.GET, headers = "Accept=application/json") 37 | public List getUsers() { 38 | return users; 39 | } 40 | 41 | /** 42 | * Return user associated with specific user name 43 | * 44 | * @param userName 45 | * @return 46 | */ 47 | @RequestMapping(value = "{userName}", method = RequestMethod.GET, headers = "Accept=application/json") 48 | public UserDTO getUserByUserName(@PathVariable("userName") String userName) { 49 | UserDTO userDtoToReturn = null; 50 | for (UserDTO currentUser : users) { 51 | if (currentUser.getUserName().equalsIgnoreCase(userName)) { 52 | userDtoToReturn = currentUser; 53 | break; 54 | } 55 | } 56 | 57 | return userDtoToReturn; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/rohitghatol/microservices/user/config/UserConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.user.config; 5 | 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.http.HttpMethod; 8 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 9 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; 10 | import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; 11 | import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; 12 | 13 | /** 14 | * Resource server configuration defining what endpoints are protected. 15 | * 16 | * @author anilallewar 17 | * 18 | */ 19 | @Configuration 20 | @EnableResourceServer 21 | public class UserConfiguration extends ResourceServerConfigurerAdapter { 22 | 23 | /** 24 | * Provide security so that endpoints are only served if the request is 25 | * already authenticated. 26 | */ 27 | @Override 28 | public void configure(HttpSecurity http) throws Exception { 29 | // @formatter:off 30 | http.requestMatchers() 31 | .antMatchers("/**") 32 | .and() 33 | .authorizeRequests() 34 | .anyRequest() 35 | .authenticated() 36 | .antMatchers(HttpMethod.GET, "/**").access("#oauth2.hasScope('read')") 37 | .antMatchers(HttpMethod.OPTIONS, "/**").access("#oauth2.hasScope('read')") 38 | .antMatchers(HttpMethod.POST, "/**").access("#oauth2.hasScope('write')") 39 | .antMatchers(HttpMethod.PUT, "/**").access("#oauth2.hasScope('write')") 40 | .antMatchers(HttpMethod.PATCH, "/**").access("#oauth2.hasScope('write')") 41 | .antMatchers(HttpMethod.DELETE, "/**").access("#oauth2.hasScope('write')"); 42 | // @formatter:on 43 | } 44 | 45 | /** 46 | * Id of the resource that you are letting the client have access to. 47 | * Supposing you have another api ("say api2"), then you can customize the 48 | * access within resource server to define what api is for what resource id. 49 | *
50 | *
51 | * 52 | * So suppose you have 2 APIs, then you can define 2 resource servers. 53 | *
    54 | *
  1. Client 1 has been configured for access to resourceid1, so he can 55 | * only access "api1" if the resource server configures the resourceid to 56 | * "api1".
  2. 57 | *
  3. Client 1 can't access resource server 2 since it has configured the 58 | * resource id to "api2" 59 | *
  4. 60 | *
61 | * 62 | */ 63 | @Override 64 | public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 65 | resources.resourceId("apis"); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /user-webservice/src/main/java/com/rohitghatol/microservices/user/dto/UserDTO.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.user.dto; 5 | 6 | 7 | /** 8 | * Represents User identified by username 9 | * 10 | * @author rohitghatol 11 | */ 12 | public class UserDTO { 13 | 14 | /** The first name. */ 15 | private String firstName; 16 | 17 | /** The last name. */ 18 | private String lastName; 19 | 20 | /** The user name. */ 21 | private String userName; 22 | 23 | /** The email address. */ 24 | private String emailAddress; 25 | 26 | /** 27 | * Instantiates a new user dto. 28 | */ 29 | public UserDTO() { 30 | super(); 31 | // TODO Auto-generated constructor stub 32 | } 33 | 34 | /** 35 | * Instantiates a new user dto. 36 | * 37 | * @param firstName the first name 38 | * @param lastName the last name 39 | * @param userName the user name 40 | * @param emailAddress the email address 41 | */ 42 | public UserDTO(String firstName, String lastName, String userName, 43 | String emailAddress) { 44 | super(); 45 | this.firstName = firstName; 46 | this.lastName = lastName; 47 | this.userName = userName; 48 | this.emailAddress = emailAddress; 49 | } 50 | 51 | /** 52 | * Gets the first name. 53 | * 54 | * @return the first name 55 | */ 56 | public String getFirstName() { 57 | return firstName; 58 | } 59 | 60 | /** 61 | * Sets the first name. 62 | * 63 | * @param firstName the new first name 64 | */ 65 | public void setFirstName(String firstName) { 66 | this.firstName = firstName; 67 | } 68 | 69 | /** 70 | * Gets the last name. 71 | * 72 | * @return the last name 73 | */ 74 | public String getLastName() { 75 | return lastName; 76 | } 77 | 78 | /** 79 | * Sets the last name. 80 | * 81 | * @param lastName the new last name 82 | */ 83 | public void setLastName(String lastName) { 84 | this.lastName = lastName; 85 | } 86 | 87 | /** 88 | * Gets the user name. 89 | * 90 | * @return the user name 91 | */ 92 | public String getUserName() { 93 | return userName; 94 | } 95 | 96 | /** 97 | * Sets the user name. 98 | * 99 | * @param userName the new user name 100 | */ 101 | public void setUserName(String userName) { 102 | this.userName = userName; 103 | } 104 | 105 | /** 106 | * Gets the email address. 107 | * 108 | * @return the email address 109 | */ 110 | public String getEmailAddress() { 111 | return emailAddress; 112 | } 113 | 114 | /** 115 | * Sets the email address. 116 | * 117 | * @param emailAddress the new email address 118 | */ 119 | public void setEmailAddress(String emailAddress) { 120 | this.emailAddress = emailAddress; 121 | } 122 | 123 | /* (non-Javadoc) 124 | * @see java.lang.Object#hashCode() 125 | */ 126 | @Override 127 | public int hashCode() { 128 | final int prime = 31; 129 | int result = 1; 130 | result = prime * result 131 | + ((emailAddress == null) ? 0 : emailAddress.hashCode()); 132 | result = prime * result 133 | + ((firstName == null) ? 0 : firstName.hashCode()); 134 | result = prime * result 135 | + ((lastName == null) ? 0 : lastName.hashCode()); 136 | result = prime * result 137 | + ((userName == null) ? 0 : userName.hashCode()); 138 | return result; 139 | } 140 | 141 | /* (non-Javadoc) 142 | * @see java.lang.Object#equals(java.lang.Object) 143 | */ 144 | @Override 145 | public boolean equals(Object obj) { 146 | if (this == obj) 147 | return true; 148 | if (obj == null) 149 | return false; 150 | if (getClass() != obj.getClass()) 151 | return false; 152 | UserDTO other = (UserDTO) obj; 153 | if (emailAddress == null) { 154 | if (other.emailAddress != null) 155 | return false; 156 | } else if (!emailAddress.equals(other.emailAddress)) 157 | return false; 158 | if (firstName == null) { 159 | if (other.firstName != null) 160 | return false; 161 | } else if (!firstName.equals(other.firstName)) 162 | return false; 163 | if (lastName == null) { 164 | if (other.lastName != null) 165 | return false; 166 | } else if (!lastName.equals(other.lastName)) 167 | return false; 168 | if (userName == null) { 169 | if (other.userName != null) 170 | return false; 171 | } else if (!userName.equals(other.userName)) 172 | return false; 173 | return true; 174 | } 175 | 176 | /* (non-Javadoc) 177 | * @see java.lang.Object#toString() 178 | */ 179 | @Override 180 | public String toString() { 181 | return "UserDTO [firstName=" + firstName + ", lastName=" + lastName 182 | + ", userName=" + userName + ", emailAddress=" + emailAddress 183 | + "]"; 184 | } 185 | 186 | 187 | } 188 | -------------------------------------------------------------------------------- /user-webservice/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | org: 4 | springframework: 5 | security: DEBUG -------------------------------------------------------------------------------- /user-webservice/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | 4 | # Name of the service that is using with Zuul routes to forward specific requests to this service 5 | name: user-webservice 6 | cloud: 7 | config: 8 | 9 | # Define the URL from where this service would pick up it's external configuration. Note that it is 10 | # pointing to the config-server aplication 11 | uri: http://localhost:8888 12 | 13 | --- 14 | 15 | spring: 16 | profiles: docker 17 | cloud: 18 | config: 19 | uri: http://192.168.59.103:8888 -------------------------------------------------------------------------------- /web-portal/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /web-portal/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | -------------------------------------------------------------------------------- /web-portal/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | web-portal 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.springsource.ide.eclipse.gradle.core.nature 16 | org.eclipse.jdt.core.javanature 17 | 18 | 19 | -------------------------------------------------------------------------------- /web-portal/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This is a Single Page Application(SPA) that has the user facing UI beinng used in the application. It uses the following technologies 4 | * Angular - (base, routes) 5 | * Bootstrap for CSS and layout 6 | * Gradle for build - we could have used grunt/gulp instead 7 | 8 | It is perfectly acceptable to have the SPA not start using the Spring boot application. You would only need to change the Zuul route to forward the request to the actual SPA hosted URL. 9 | 10 | ##Pre-requisites 11 | 12 | ### Projects that need to be started before 13 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 14 | * [webserver-registry](/../../blob/master/webservice-registry/README.md) - For starting the Eureka server since the authorization server also is a micro-service that needs to be registered with Eureka server. 15 | 16 | ### Running the application 17 | * Build the application by running the `./gradlew clean build` gradle command at the "web-portal" project root folder on the terminal. 18 | * If you want to run the application as jar file, then run `java -jar build/libs/sample-web-portal-0.0.1.jar` command at the terminal. 19 | 20 | ## External Configuration 21 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. 22 | -------------------------------------------------------------------------------- /web-portal/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | project.ext { 3 | bootVersion = '1.2.3.RELEASE' 4 | cloudVersion = '1.0.0.RELEASE' 5 | } 6 | repositories { 7 | mavenCentral() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" 13 | classpath 'se.transmode.gradle:gradle-docker:1.2' 14 | } 15 | } 16 | 17 | apply plugin: 'eclipse' 18 | apply plugin: 'spring-boot' 19 | apply plugin: 'java' 20 | apply plugin: 'docker' 21 | 22 | mainClassName = 'com.rohitghatol.microservices.portal.Application' 23 | 24 | jar { 25 | baseName = 'sample-web-portal' 26 | version = '0.0.1' 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | jcenter() 32 | } 33 | dependencies { 34 | compile("org.springframework.boot:spring-boot-starter-web:${project.bootVersion}") 35 | compile("org.springframework.boot:spring-boot-starter-actuator:${project.bootVersion}") 36 | compile("org.springframework.cloud:spring-cloud-config-client:${project.cloudVersion}") 37 | compile("org.springframework.cloud:spring-cloud-starter-eureka:${project.cloudVersion}") 38 | 39 | testCompile group: 'junit', name: 'junit', version: '4.+' 40 | testCompile 'org.springframework:spring-test:4.0.6.RELEASE' 41 | } 42 | 43 | group = 'anilallewar' 44 | mainClassName = 'com.rohitghatol.microservices.portal.Application' 45 | 46 | sourceCompatibility = 1.7 47 | targetCompatibility = 1.7 48 | 49 | bootRun { 50 | jvmArgs = ['-Xdebug', '-Xrunjdwp:server=y,transport=dt_socket,address=4010,suspend=n','-Dspring.profiles.active=dev'] 51 | } 52 | 53 | distDocker { 54 | exposePort 8080 55 | setEnvironment 'JAVA_OPTS', '-Dspring.profiles.active=docker' 56 | } 57 | 58 | docker { 59 | useApi true 60 | hostUrl 'http://192.168.59.103:2375' 61 | baseImage = 'java:7' 62 | } 63 | 64 | task createWrapper(type: Wrapper) { 65 | gradleVersion = '2.0' 66 | } 67 | 68 | -------------------------------------------------------------------------------- /web-portal/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 20:54:04 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /web-portal/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /web-portal/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /web-portal/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | OAuth Demo with bootstrap 6 | 7 | 17 | 18 | 19 | 20 | 66 | 67 |
68 |
69 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /web-portal/public/js/app/controller/homeController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('oauthApp') 4 | .controller('homeCtrl', function () {}); 5 | -------------------------------------------------------------------------------- /web-portal/public/js/app/controller/navController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('oauthApp') 4 | .controller('navigationCtrl', ['$rootScope', '$scope', '$http', '$location', 'dataService', function ($rootScope, $scope, $http, $location, dataService) { 5 | 6 | var assignAuthenticationStatus = function (data) { 7 | if (data.name) { 8 | $rootScope.userAuthenticated = true; 9 | $rootScope.loggedInUserName = data.name; 10 | } else { 11 | $rootScope.userAuthenticated = false; 12 | } 13 | }; 14 | 15 | var handleError = function (error) { 16 | console.log(error); 17 | $rootScope.userAuthenticated = false; 18 | }; 19 | 20 | dataService.getLoggedInUser().then(assignAuthenticationStatus, handleError); 21 | 22 | $scope.logout = function () { 23 | $http.post('logout', {}).success(function () { 24 | $rootScope.userAuthenticated = false; 25 | $location.path("/"); 26 | }).error(function (data) { 27 | $rootScope.userAuthenticated = false; 28 | }); 29 | } 30 | }]); 31 | -------------------------------------------------------------------------------- /web-portal/public/js/app/controller/taskController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name oauthApp.controller:UserCtrl 6 | * @description 7 | * # PreviewPlaceHolderCtrl 8 | * Controller of the alertApp 9 | */ 10 | angular.module('oauthApp') 11 | .controller('taskCtrl', function ($scope, $location, $http, dataService) { 12 | 13 | // Assigns data from the task service into "token" 14 | // variables in controller scope. 15 | var assignAllTaskDataToScope = function (data) { 16 | $scope.taskDataArray = data; 17 | }; 18 | 19 | var logError = function (error) { 20 | console.log(error); 21 | }; 22 | 23 | // Assign data for a single user 24 | var assignTaskDataToScope = function (data) { 25 | $scope.taskData = data; 26 | }; 27 | 28 | var assignUserTaskDataToScope = function (data) { 29 | $scope.taskDataForUser = data; 30 | }; 31 | 32 | // Method exposed to get specific task data 33 | this.getTaskDataByTaskId = function (taskId) { 34 | dataService.getTaskDataByTaskId(taskId) 35 | .then(assignTaskDataToScope, logError); 36 | }; 37 | 38 | // Method exposed to get specific task data 39 | this.getTaskDataByUserName = function (userName) { 40 | dataService.getTaskDataByUserName(userName) 41 | .then(assignUserTaskDataToScope, logError); 42 | }; 43 | 44 | //When the script loads, get all the user's data 45 | dataService.getAllTaskData() 46 | .then(assignAllTaskDataToScope, logError); 47 | }); 48 | -------------------------------------------------------------------------------- /web-portal/public/js/app/controller/userController.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc function 5 | * @name oauthApp.controller:UserCtrl 6 | * @description 7 | * # PreviewPlaceHolderCtrl 8 | * Controller of the alertApp 9 | */ 10 | angular.module('oauthApp') 11 | .controller('userCtrl', function ($scope, $location, $http, dataService) { 12 | 13 | // Assigns data from the user service into "token" 14 | // variables in controller scope. 15 | var assignAllUserDataToScope = function (data) { 16 | $scope.userDataArray = data; 17 | }; 18 | 19 | var logError = function (error) { 20 | console.log(error); 21 | }; 22 | 23 | // Assign data for a single user 24 | var assignUserDataToScope = function (data) { 25 | $scope.userData = data; 26 | }; 27 | 28 | // Method exposed to get specific user data 29 | this.getUserDataByUserName = function (userName) { 30 | dataService.getUserDataByUserName(userName) 31 | .then(assignUserDataToScope, logError); 32 | }; 33 | 34 | //When the script loads, get all the user's data 35 | dataService.getAllUserData() 36 | .then(assignAllUserDataToScope, logError); 37 | }); -------------------------------------------------------------------------------- /web-portal/public/js/app/oauthapp.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('oauthApp', ['ngRoute']) 4 | .config(function ($routeProvider, $httpProvider) { 5 | $routeProvider.when('/', { 6 | templateUrl: 'views/home.html', 7 | controller: 'homeCtrl' 8 | }).when('/user', { 9 | templateUrl: 'views/user.html', 10 | controller: 'userCtrl', 11 | controllerAs: 'userController' 12 | }).when('/task', { 13 | templateUrl: 'views/task.html', 14 | controller: 'taskCtrl', 15 | controllerAs: 'taskController' 16 | }).otherwise('/'); 17 | 18 | //Custom header is needed starting angular 1.3; else Spring security might pop authentication dialog 19 | // by sending the WWW-Authenticate header field in the 401 Unauhorized HTTP response 20 | $httpProvider.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest'; 21 | }) 22 | .directive("taskComments", function () { 23 | return { 24 | restrict: 'E', 25 | scope: { 26 | taskComments: '=comments' 27 | }, 28 | templateUrl: "views/task-comments.html" 29 | }; 30 | }) 31 | .directive("taskDetails", function () { 32 | return { 33 | restrict: 'E', 34 | templateUrl: "views/task-details.html" 35 | }; 36 | }); 37 | -------------------------------------------------------------------------------- /web-portal/public/js/app/services/dataservice.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * @ngdoc service 5 | * @name alertApp.dataService 6 | * @description 7 | * # dataService 8 | * Factory in the alertApp. 9 | */ 10 | angular.module('oauthApp') 11 | .factory('dataService', function ($http, $q) { 12 | // We always use this angular service within the preview context 13 | var userApi = '/api/user'; 14 | 15 | var taskApi = '/api/task'; 16 | 17 | var loggedInUserApi = '/api/loggedinuser/me'; 18 | 19 | // This method makes the REST call and the response is parsed by 20 | // Angular.js by default to convert to JSON. If the response is 21 | // successfully parsed then the JSON is available as an 'object' 22 | var makeRestCall = function (url) { 23 | return $http.get(url) 24 | .then(function (response) { 25 | 26 | if (typeof response.data === 'object') { 27 | return response.data; 28 | } else { 29 | // invalid response 30 | return $q.reject(response.data); 31 | } 32 | 33 | }, function (response) { 34 | // something went wrong 35 | return $q.reject(response.data); 36 | }); 37 | }; 38 | 39 | return { 40 | getAllUserData: function () { 41 | // Make call to the api to get all users 42 | return makeRestCall(userApi); 43 | }, 44 | 45 | getAllTaskData: function () { 46 | // Make call to the api to get all tasks 47 | return makeRestCall(taskApi); 48 | }, 49 | 50 | getUserDataByUserName: function (userName) { 51 | // Make call to the api to get user details by user name 52 | return makeRestCall(userApi + '/' + userName); 53 | }, 54 | 55 | getTaskDataByTaskId: function (taskId) { 56 | // Make call to theapi to get task details by task id 57 | return makeRestCall(taskApi + '/' + taskId); 58 | }, 59 | 60 | getTaskDataByUserName: function (userName) { 61 | return makeRestCall(taskApi + '/' + 'usertask' + '/' + userName); 62 | }, 63 | 64 | getLoggedInUser: function () { 65 | // Make call to get the current logged in user 66 | return makeRestCall(loggedInUserApi); 67 | } 68 | }; 69 | }); -------------------------------------------------------------------------------- /web-portal/public/js/libs/angular-route.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | AngularJS v1.2.16 3 | (c) 2010-2014 Google, Inc. http://angularjs.org 4 | License: MIT 5 | */ 6 | (function(n,e,A){'use strict';function x(s,g,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);h&&(h.$destroy(),h=null);l&&(k.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){k.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});h=d.scope=b;h.$emit("$viewContentLoaded");h.$eval(u)}else y()} 7 | var h,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){}, 8 | {prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},k=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;k.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b= 9 | "/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,h){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart", 10 | d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=h.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl= 11 | b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(k,function(f,k){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var h=1,p=g.length;h 2 |

Hi {{loggedInUserName}}

3 |
4 | Click on the login link to authenticate 5 |
6 | 7 | -------------------------------------------------------------------------------- /web-portal/public/views/task-comments.html: -------------------------------------------------------------------------------- 1 |
2 |

Task Comments

3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
IDCommentDate
{{comment.taskId}}{{comment.comment}}{{comment.posted}}
15 |
16 | -------------------------------------------------------------------------------- /web-portal/public/views/task-details.html: -------------------------------------------------------------------------------- 1 |

Task Details

2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
IDDescriptionCompletedUser Name
{{taskData.taskId}}{{taskData.description}}{{taskData.completed}}{{taskData.userName}}
17 | -------------------------------------------------------------------------------- /web-portal/public/views/task.html: -------------------------------------------------------------------------------- 1 |
2 |

Task Summary

3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
IDDescriptionCompleted
{{task.taskId}}{{task.description}}{{task.completed}}
17 |
18 | 19 |
20 | 21 | 22 | 23 | 24 |
25 | 26 |
27 | -------------------------------------------------------------------------------- /web-portal/public/views/user.html: -------------------------------------------------------------------------------- 1 |
2 |

User Summary

3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 |
IDFirst NameLast Name
{{user.userName}}{{user.firstName}}{{user.lastName}}
18 |
19 | 20 |
21 |

User Details

22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
IDFirst NameLastNameEmail
{{userData.userName}}{{userData.firstName}}{{userData.lastName}}{{userData.emailAddress}}
37 |
38 | 39 |
-------------------------------------------------------------------------------- /web-portal/src/main/java/com/rohitghatol/microservices/portal/Application.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.portal; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 9 | import org.springframework.context.annotation.ComponentScan; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * The boot application class that defines the spring boot application to have 14 | * the following properties
15 | *
16 | * 17 | *
    18 | *
  1. Act as a Eureka client; this behavior is provided by the 19 | * {@link EnableEurekaClient} annotation. The Eureka server URL is provided by 20 | * the external configuration provided by the config server.
  2. 21 | *
  3. No security is defined for this application since it's the client facing 22 | * UI application.
  4. 23 | *
  5. All the UI artifacts are stored under the "public" folder at 24 | * the root.
  6. 25 | *
26 | * 27 | * @author rohitghatol 28 | * 29 | */ 30 | @EnableAutoConfiguration 31 | @ComponentScan 32 | @Configuration 33 | @EnableEurekaClient 34 | public class Application { 35 | public static void main(String[] args) { 36 | 37 | SpringApplication.run(Application.class,args); 38 | 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /web-portal/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/web-portal/src/main/resources/application.yml -------------------------------------------------------------------------------- /web-portal/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: web-portal 4 | cloud: 5 | config: 6 | uri: http://localhost:8888 7 | 8 | --- 9 | 10 | spring: 11 | profiles: docker 12 | cloud: 13 | config: 14 | uri: http://192.168.59.103:8888 -------------------------------------------------------------------------------- /webservice-registry/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | /.gradle/ 4 | -------------------------------------------------------------------------------- /webservice-registry/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | webservice-registry 4 | 5 | 6 | 7 | org.springsource.ide.eclipse.gradle.core.nature 8 | org.eclipse.jdt.core.javanature 9 | 10 | 11 | 12 | org.eclipse.jdt.core.javabuilder 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /webservice-registry/README.md: -------------------------------------------------------------------------------- 1 | #Overview 2 | 3 | This application provides the **Eureka Server** that provides service discivery and enables all Eureka clients to discover each other. 4 | 5 | When a client registers with Eureka, it provides meta-data about itself such as host and port, health indicator URL, home page etc. Eureka receives heartbeat messages from each instance belonging to a service. If the heartbeat fails over a configurable timetable, the instance is normally removed from the registry. 6 | 7 | ##Pre-requisites 8 | 9 | ### Projects that need to be started before 10 | * [config server](/../../blob/master/config-server/README.md) - For pulling the configuration information 11 | 12 | ### Running the application 13 | * Build the application by running the `./gradlew clean build` gradle command at the "webservice-registry" project root folder on the terminal. 14 | * If you want to run the application as jar file, then run `java -jar build/libs/sample-webservice-registry-0.0.1.jar` command at the terminal. 15 | 16 | ## External Configuration 17 | Please refer to [user webservice](/../../blob/master/user-webservice/README.md) for details on how the external configuration works. Note that there is separate configuration file for each Spring application; the application should refer to it's own .yml file for configuration. -------------------------------------------------------------------------------- /webservice-registry/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | project.ext { 3 | bootVersion = '1.2.3.RELEASE' 4 | cloudVersion = '1.0.0.RELEASE' 5 | } 6 | repositories { 7 | mavenCentral() 8 | jcenter() 9 | } 10 | 11 | dependencies { 12 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" 13 | classpath 'se.transmode.gradle:gradle-docker:1.2' 14 | classpath "io.spring.gradle:dependency-management-plugin:1.0.2.RELEASE" 15 | } 16 | } 17 | 18 | apply plugin: 'eclipse' 19 | apply plugin: 'spring-boot' 20 | apply plugin: 'java' 21 | apply plugin: 'docker' 22 | 23 | apply plugin: "io.spring.dependency-management" 24 | 25 | dependencyManagement { 26 | imports { 27 | mavenBom 'org.springframework.cloud:spring-cloud-starter-parent:1.0.0.RELEASE' 28 | } 29 | } 30 | 31 | springBoot { 32 | requiresUnpack = ['com.netflix.eureka:eureka-core','com.netflix.eureka:eureka-client'] 33 | } 34 | 35 | jar { 36 | baseName = 'sample-webservice-registry' 37 | version = '0.0.1' 38 | } 39 | 40 | repositories { 41 | mavenCentral() 42 | jcenter() 43 | } 44 | dependencies { 45 | compile("org.springframework.boot:spring-boot-starter-web:${project.bootVersion}") 46 | compile("org.springframework.boot:spring-boot-starter-actuator:${project.bootVersion}") 47 | compile("org.springframework.cloud:spring-cloud-config-client:${project.cloudVersion}") 48 | compile("org.springframework.cloud:spring-cloud-starter-eureka-server:${project.cloudVersion}") 49 | 50 | testCompile group: 'junit', name: 'junit', version: '4.+' 51 | testCompile 'org.springframework:spring-test:4.0.6.RELEASE' 52 | } 53 | 54 | group = 'anilallewar' 55 | mainClassName = 'com.rohitghatol.microservices.registry.Application' 56 | 57 | sourceCompatibility = 1.7 58 | targetCompatibility = 1.7 59 | 60 | distDocker { 61 | exposePort 8761 62 | setEnvironment 'JAVA_OPTS', '-Dspring.profiles.active=docker' 63 | } 64 | 65 | docker { 66 | useApi true 67 | hostUrl 'http://192.168.59.103:2375' 68 | baseImage = 'java:7' 69 | } 70 | 71 | task createWrapper(type: Wrapper) { 72 | gradleVersion = '2.0' 73 | } 74 | -------------------------------------------------------------------------------- /webservice-registry/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Apr 26 20:52:02 IST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-bin.zip 7 | -------------------------------------------------------------------------------- /webservice-registry/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /webservice-registry/src/main/java/com/rohitghatol/microservices/registry/Application.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.rohitghatol.microservices.registry; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 8 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 9 | import org.springframework.context.annotation.ComponentScan; 10 | import org.springframework.context.annotation.Configuration; 11 | 12 | /** 13 | * The Main Spring Boot Application class that starts the Eureka discovery 14 | * server since the application is annotated with {@link EnableEurekaServer}. 15 | *
16 | *
17 | * 18 | * Note that all these annotations work in conjunction with properties defined 19 | * in the external configuration files specified by the config server. 20 | * 21 | * @author rohitghatol 22 | */ 23 | 24 | @EnableEurekaServer 25 | @Configuration 26 | @ComponentScan 27 | @EnableAutoConfiguration 28 | public class Application { 29 | 30 | /** 31 | * The main method. 32 | * 33 | * @param args the arguments 34 | */ 35 | public static void main(String[] args) { 36 | SpringApplication.run(Application.class, args); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /webservice-registry/src/main/resources/application.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitghatol/spring-boot-microservices/a3c9df9350a07578df281949e6018d01ac37238e/webservice-registry/src/main/resources/application.yml -------------------------------------------------------------------------------- /webservice-registry/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: webservice-registry 4 | cloud: 5 | config: 6 | uri: http://localhost:8888 7 | 8 | --- 9 | 10 | spring: 11 | profiles: docker 12 | cloud: 13 | config: 14 | uri: http://192.168.59.103:8888 15 | --------------------------------------------------------------------------------