├── scripts ├── .gitignore ├── microServices.list ├── PCFServices.list ├── setVars.sh ├── deleteListedApps.sh ├── deleteListedServices.sh ├── 2_build.sh ├── doItAll.sh ├── commons.sh ├── 3_deploy.sh └── 4_addTrustCerts.sh ├── cf-SpringBootTrader-config ├── web-service-cloud.yml ├── quotes-service-cloud.yml ├── user-service-local.yml ├── web-service-local.yml ├── accounts-service-local.yml ├── gateway-service-local.yml ├── portfolio-service-local.yml ├── quotes-service-local.yml ├── zipkin-service.yml ├── analytics-service.yml ├── user-service-cloud.yml ├── portfolio-service-cloud.yml ├── accounts-service-cloud.yml ├── user-service.yml ├── accounts-service.yml ├── portfolio-service.yml ├── application-cloud.yml ├── application-debug.yml ├── web-service.yml ├── application-local.yml ├── application.yml ├── gateway-service.yml └── quotes-service.yml ├── gateway-service ├── settings.gradle ├── src │ ├── main │ │ ├── resources │ │ │ └── bootstrap.yml │ │ └── java │ │ │ └── io │ │ │ └── pivotal │ │ │ └── gateway │ │ │ ├── GatewayApplication.java │ │ │ └── config │ │ │ └── SecurityConfig.java │ └── test │ │ ├── resources │ │ ├── bootstrap.yml │ │ └── application.yml │ │ └── java │ │ └── io │ │ └── pivotal │ │ └── gateway │ │ └── GatewayApplicationTests.java ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .gitignore ├── manifest.yml └── build.gradle ├── configServer ├── .gitignore ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ ├── java │ │ └── io │ │ │ └── pivotal │ │ │ └── config │ │ │ └── ConfigServer.java │ │ └── resources │ │ └── application.yml └── build.gradle ├── analytics-scdf-sink └── src │ ├── main │ ├── resources │ │ └── META-INF │ │ │ ├── spring.provides │ │ │ └── spring-configuration-metadata-whitelist.properties │ └── java │ │ └── io │ │ └── pivotal │ │ └── analytics │ │ ├── Application.java │ │ ├── repository │ │ └── TradeRepository.java │ │ └── configuration │ │ ├── EsSinkProperties.java │ │ ├── SinkConfiguration.java │ │ └── EsConfig.java │ └── test │ ├── resources │ └── application-test.properties │ └── java │ └── io │ └── pivotal │ └── analytics │ └── TradeServiceTest.java ├── discoveryServer ├── .gitignore ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── manifest-registry.yml ├── src │ └── main │ │ ├── java │ │ └── io │ │ │ └── pivotal │ │ │ └── registry │ │ │ └── RegistryApplication.java │ │ └── resources │ │ └── application.yml ├── manifest-registry2.yml └── build.gradle ├── turbineServer ├── .gitignore ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── .springBeans ├── src │ └── main │ │ ├── resources │ │ └── application.yml │ │ └── java │ │ └── io │ │ └── pivotal │ │ └── turbine │ │ └── turbineServer.java └── build.gradle ├── quotes-service ├── src │ ├── main │ │ ├── resources │ │ │ └── bootstrap.yml │ │ └── java │ │ │ └── io │ │ │ └── pivotal │ │ │ └── quotes │ │ │ ├── domain │ │ │ ├── IexBatchQuote.java │ │ │ ├── QuoteMapper.java │ │ │ ├── IexQuote.java │ │ │ └── CompanyInfo.java │ │ │ ├── exception │ │ │ └── SymbolNotFoundException.java │ │ │ ├── QuotesApplication.java │ │ │ └── config │ │ │ └── SecurityConfig.java │ └── test │ │ ├── resources │ │ ├── bootstrap.yml │ │ └── application.yml │ │ └── java │ │ └── io │ │ └── pivotal │ │ └── quotes │ │ └── QuotesApplicationTest.java ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── README.md ├── manifest.yml └── build.gradle ├── user-service ├── src │ ├── main │ │ ├── resources │ │ │ └── bootstrap.yml │ │ └── java │ │ │ └── io │ │ │ └── pivotal │ │ │ └── user │ │ │ ├── repository │ │ │ └── UserRepository.java │ │ │ ├── config │ │ │ ├── BeanConfiguration.java │ │ │ └── SecurityConfig.java │ │ │ ├── UserApplication.java │ │ │ ├── exception │ │ │ ├── AuthenticationException.java │ │ │ └── NoRecordsFoundException.java │ │ │ └── domain │ │ │ └── AuthenticationRequest.java │ └── test │ │ ├── resources │ │ ├── bootstrap.yml │ │ └── application.yml │ │ └── java │ │ └── io │ │ └── pivotal │ │ └── user │ │ └── AccountsApplicationTest.java ├── README.md ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── manifest.yml └── build.gradle ├── web-ui ├── README.md ├── src │ ├── test │ │ ├── resources │ │ │ ├── bootstrap.yml │ │ │ └── application.yml │ │ └── java │ │ │ └── io │ │ │ └── pivotal │ │ │ └── web │ │ │ ├── WebApplicationTests.java │ │ │ └── service │ │ │ └── MarketServiceTest.java │ └── main │ │ ├── resources │ │ ├── static │ │ │ ├── images │ │ │ │ ├── logo.png │ │ │ │ ├── bg-small.gif │ │ │ │ ├── border-bg.jpg │ │ │ │ ├── icon-arrow.png │ │ │ │ ├── icon-custom.png │ │ │ │ ├── bg-container.gif │ │ │ │ ├── button-transactions.png │ │ │ │ ├── glyphicons-halflings-white.png │ │ │ │ └── pivotal-square-logo.svg │ │ │ ├── fonts │ │ │ │ ├── colabreg-webfont.eot │ │ │ │ ├── colabreg-webfont.ttf │ │ │ │ ├── colabreg-webfont.woff │ │ │ │ ├── colabthi-webfont.eot │ │ │ │ ├── colabthi-webfont.ttf │ │ │ │ ├── colabthi-webfont.woff │ │ │ │ ├── colaborate-bold-webfont.eot │ │ │ │ ├── colaborate-bold-webfont.ttf │ │ │ │ ├── colaborate-bold-webfont.woff │ │ │ │ ├── colaborate-light-webfont.eot │ │ │ │ ├── colaborate-light-webfont.ttf │ │ │ │ ├── colaborate-light-webfont.woff │ │ │ │ ├── colaborate-medium-webfont.eot │ │ │ │ ├── colaborate-medium-webfont.ttf │ │ │ │ └── colaborate-medium-webfont.woff │ │ │ └── css │ │ │ │ └── style.css │ │ ├── bootstrap.yml │ │ └── templates │ │ │ ├── error.html │ │ │ ├── fragments │ │ │ ├── quote_attribution_fragment.html │ │ │ ├── header_fragment.html │ │ │ ├── user_fragment.html │ │ │ └── analytics_fragment.html │ │ │ ├── registration.html │ │ │ ├── openaccount.html │ │ │ ├── analytics.html │ │ │ ├── trade.html │ │ │ ├── accounts.html │ │ │ ├── portfolio.html │ │ │ └── index.html │ │ └── java │ │ └── io │ │ └── pivotal │ │ └── web │ │ ├── domain │ │ ├── OrderType.java │ │ ├── Search.java │ │ ├── AuthenticationRequest.java │ │ └── CompanyInfo.java │ │ ├── exception │ │ └── OrderNotSavedException.java │ │ ├── config │ │ ├── BeanConfiguration.java │ │ ├── MvcConfig.java │ │ └── WebSecurityConfig.java │ │ ├── WebApplication.java │ │ ├── security │ │ ├── LogoutSuccessHandler.java │ │ └── CustomAuthenticationProvider.java │ │ └── service │ │ ├── AnalyticsService.java │ │ └── UserService.java ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── manifest.yml └── build.gradle ├── docs ├── springtrader.png ├── springtrader2.png ├── base-architecture-diagram.png ├── pivotal-bank-analytics-architecture-diagram.png ├── lab_full_integration_test.md ├── lab_rest_tests.md ├── lab_manual_test.md ├── lab_zipkin.md ├── lab_configserver.md ├── lab_registryserver.md ├── lab_local.md ├── lab_scale.md ├── lab_spring_cloud_gateway.md ├── lab_c2c_networking.md └── lab_bluegreen.md ├── accounts-service ├── src │ ├── test │ │ ├── resources │ │ │ ├── bootstrap.yml │ │ │ └── application.yml │ │ └── java │ │ │ └── io │ │ │ └── pivotal │ │ │ └── accounts │ │ │ └── AccountsApplicationTest.java │ └── main │ │ ├── java │ │ └── io │ │ │ └── pivotal │ │ │ └── accounts │ │ │ ├── domain │ │ │ ├── TransactionType.java │ │ │ ├── AccountType.java │ │ │ └── AccountTypeConverter.java │ │ │ ├── repository │ │ │ └── AccountRepository.java │ │ │ ├── config │ │ │ ├── BeanConfiguration.java │ │ │ └── SecurityConfig.java │ │ │ ├── AccountsApplication.java │ │ │ └── exception │ │ │ ├── AuthenticationException.java │ │ │ └── NoRecordsFoundException.java │ │ └── resources │ │ └── bootstrap.yml ├── README.md ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── manifest.yml └── build.gradle ├── analytics-service ├── src │ ├── test │ │ ├── resources │ │ │ ├── bootstrap.yml │ │ │ └── application.yml │ │ └── java │ │ │ └── io │ │ │ └── pivotal │ │ │ └── analytics │ │ │ ├── AnalyticsApplicationTest.java │ │ │ └── AnalyticsServiceTest.java │ └── main │ │ ├── resources │ │ └── bootstrap.yml │ │ └── java │ │ └── io │ │ └── pivotal │ │ └── analytics │ │ ├── config │ │ ├── BeanConfiguration.java │ │ ├── SecurityConfig.java │ │ └── EsConfig.java │ │ ├── repository │ │ └── TradeRepository.java │ │ ├── AnalyticsApplication.java │ │ ├── service │ │ └── AnalyticsService.java │ │ └── controller │ │ └── AnalyticsController.java ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── Readme.md ├── manifest.yml └── build.gradle ├── portfolio-service ├── src │ ├── test │ │ ├── resources │ │ │ ├── bootstrap.yml │ │ │ └── application.yml │ │ └── java │ │ │ └── io │ │ │ └── pivotal │ │ │ └── portfolio │ │ │ ├── PortfolioApplicationTest.java │ │ │ └── service │ │ │ └── QuoteRemoteCallServiceTest.java │ └── main │ │ ├── java │ │ └── io │ │ │ └── pivotal │ │ │ └── portfolio │ │ │ ├── domain │ │ │ ├── TransactionType.java │ │ │ └── OrderType.java │ │ │ ├── repository │ │ │ └── OrderRepository.java │ │ │ ├── config │ │ │ ├── BeanConfiguration.java │ │ │ └── SecurityConfig.java │ │ │ ├── PortfolioApplication.java │ │ │ └── service │ │ │ └── PortfolioRepositoryService.java │ │ └── resources │ │ └── bootstrap.yml ├── README.md ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── manifest.yml └── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── zipkin-server ├── src │ ├── main │ │ ├── resources │ │ │ ├── zipkin-server.yml │ │ │ └── banner.txt │ │ └── java │ │ │ ├── zipkin │ │ │ └── server │ │ │ │ ├── SecurityConfig.java │ │ │ │ ├── ZipkinServer.java │ │ │ │ └── EnableZipkinServer.java │ │ │ └── zipkin2 │ │ │ └── server │ │ │ └── internal │ │ │ ├── package-info.java │ │ │ ├── InternalZipkinConfiguration.java │ │ │ ├── EnableZipkinServer.java │ │ │ ├── RegisterZipkinHealthIndicators.java │ │ │ └── ZipkinHealthIndicator.java │ ├── it │ │ ├── minimal-dependencies │ │ │ └── README.md │ │ ├── execjar │ │ │ ├── README.md │ │ │ └── src │ │ │ │ └── test │ │ │ │ └── java │ │ │ │ └── zipkin │ │ │ │ └── execjar │ │ │ │ ├── DoesntCrashWhenKafkaBrokerIsDownTest.java │ │ │ │ ├── DoesntCrashWhenCassandraIsDownTest.java │ │ │ │ └── StrictTraceIdFalseTest.java │ │ └── settings.xml │ └── test │ │ └── java │ │ ├── zipkin │ │ └── server │ │ │ └── ITEnableZipkinServer.java │ │ └── zipkin2 │ │ └── server │ │ └── internal │ │ └── ITZipkinServerQueryDisabled.java └── manifest.yml ├── e2e-tests ├── .mvn │ └── wrapper │ │ └── maven-wrapper.properties ├── src │ └── test │ │ ├── resouces │ │ ├── order.json │ │ ├── account.json │ │ └── user.json │ │ └── java │ │ └── e2e │ │ └── E2EBase.java ├── README.md ├── .gitignore └── pom.xml ├── .gitignore └── elastic-search ├── vsphere-volume-sc-fast.yaml ├── .gitignore ├── es-svc.yaml └── readme.md /scripts/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.iml 3 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/web-service-cloud.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/quotes-service-cloud.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gateway-service/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'gateway-service' 2 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/user-service-local.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8084 3 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/web-service-local.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8080 3 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/accounts-service-local.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8082 3 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/gateway-service-local.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8085 3 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/portfolio-service-local.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8081 3 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/quotes-service-local.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8083 3 | 4 | -------------------------------------------------------------------------------- /configServer/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | .classpath 4 | .project 5 | .settings/ 6 | -------------------------------------------------------------------------------- /analytics-scdf-sink/src/main/resources/META-INF/spring.provides: -------------------------------------------------------------------------------- 1 | provides: analytics-scdf-sink -------------------------------------------------------------------------------- /discoveryServer/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | .classpath 4 | .project 5 | .settings/ 6 | -------------------------------------------------------------------------------- /turbineServer/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /bin/ 3 | .classpath 4 | .project 5 | .settings/ 6 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/zipkin-service.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: zipkin-service 4 | -------------------------------------------------------------------------------- /quotes-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: quotes-service 4 | -------------------------------------------------------------------------------- /user-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: user-service 4 | -------------------------------------------------------------------------------- /web-ui/README.md: -------------------------------------------------------------------------------- 1 | # web-ui 2 | This service is a spring boot application providing the web interface. 3 | -------------------------------------------------------------------------------- /web-ui/src/test/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/analytics-service.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: analytics-service 4 | -------------------------------------------------------------------------------- /docs/springtrader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/docs/springtrader.png -------------------------------------------------------------------------------- /docs/springtrader2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/docs/springtrader2.png -------------------------------------------------------------------------------- /gateway-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: gateway-service 4 | -------------------------------------------------------------------------------- /quotes-service/src/test/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /user-service/src/test/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /accounts-service/src/test/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /analytics-service/src/test/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /gateway-service/src/test/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /portfolio-service/src/test/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | config: 4 | enabled: false 5 | -------------------------------------------------------------------------------- /scripts/microServices.list: -------------------------------------------------------------------------------- 1 | quotes-service 2 | accounts-service 3 | portfolio-service 4 | web-ui 5 | user-service 6 | -------------------------------------------------------------------------------- /user-service/README.md: -------------------------------------------------------------------------------- 1 | # user-service 2 | This service is a spring boot application responsible for managing portfolios 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /portfolio-service/README.md: -------------------------------------------------------------------------------- 1 | # portfolio-service 2 | This service is a spring boot application responsible for managing portfolios 3 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/user-service-cloud.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jpa: 3 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect -------------------------------------------------------------------------------- /docs/base-architecture-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/docs/base-architecture-diagram.png -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/portfolio-service-cloud.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jpa: 3 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect -------------------------------------------------------------------------------- /accounts-service/README.md: -------------------------------------------------------------------------------- 1 | # accounts-service 2 | This service is a spring boot application responsible for creating and managing bank accounts. 3 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/accounts-service-cloud.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | jpa: 3 | database-platform: org.hibernate.dialect.MySQL5InnoDBDialect 4 | -------------------------------------------------------------------------------- /web-ui/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /zipkin-server/src/main/resources/zipkin-server.yml: -------------------------------------------------------------------------------- 1 | spring.profiles.include: shared 2 | spring: 3 | application: 4 | name: zipkin-server 5 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/user-service.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: user-service 4 | jpa: 5 | hibernate: 6 | ddl-auto: update -------------------------------------------------------------------------------- /configServer/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/configServer/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /e2e-tests/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.2/apache-maven-3.5.2-bin.zip -------------------------------------------------------------------------------- /quotes-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/quotes-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /turbineServer/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/turbineServer/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /user-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/user-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/images/logo.png -------------------------------------------------------------------------------- /accounts-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/accounts-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/accounts-service.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: accounts-service 4 | jpa: 5 | hibernate: 6 | ddl-auto: update -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/portfolio-service.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: portfolio-service 4 | jpa: 5 | hibernate: 6 | ddl-auto: update -------------------------------------------------------------------------------- /discoveryServer/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/discoveryServer/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gateway-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/gateway-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /quotes-service/README.md: -------------------------------------------------------------------------------- 1 | # quotes-service 2 | This service is a spring boot application responsible for providing up to date company and ticker/quote information. 3 | -------------------------------------------------------------------------------- /analytics-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/analytics-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /docs/pivotal-bank-analytics-architecture-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/docs/pivotal-bank-analytics-architecture-diagram.png -------------------------------------------------------------------------------- /portfolio-service/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/portfolio-service/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/bg-small.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/images/bg-small.gif -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/border-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/images/border-bg.jpg -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/icon-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/images/icon-arrow.png -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/icon-custom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/images/icon-custom.png -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/domain/TransactionType.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.accounts.domain; 2 | 3 | public enum TransactionType { 4 | DEBIT,CREDIT 5 | } 6 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/bg-container.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/images/bg-container.gif -------------------------------------------------------------------------------- /portfolio-service/src/main/java/io/pivotal/portfolio/domain/TransactionType.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio.domain; 2 | 3 | public enum TransactionType { 4 | DEBIT,CREDIT 5 | } 6 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colabreg-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colabreg-webfont.eot -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colabreg-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colabreg-webfont.ttf -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colabreg-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colabreg-webfont.woff -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colabthi-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colabthi-webfont.eot -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colabthi-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colabthi-webfont.ttf -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colabthi-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colabthi-webfont.woff -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/application-cloud.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | zipkin: 3 | baseUrl: https://zipkin-server/ 4 | sender: 5 | type: web 6 | pivotal: 7 | downstream-protocol: https -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/button-transactions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/images/button-transactions.png -------------------------------------------------------------------------------- /zipkin-server/src/it/minimal-dependencies/README.md: -------------------------------------------------------------------------------- 1 | # minimum-dependencies 2 | This tests that an in-memory server can start and operate without optional dependencies such as jdbc or brave. 3 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-bold-webfont.eot -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-bold-webfont.ttf -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-bold-webfont.woff -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-light-webfont.eot -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-light-webfont.ttf -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-light-webfont.woff -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-medium-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-medium-webfont.eot -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-medium-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-medium-webfont.ttf -------------------------------------------------------------------------------- /analytics-scdf-sink/src/test/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | # Provide properties for a running elasticsearch cluster 2 | es-sink.host=${ES_SINK_HOST:10.195.38.146} 3 | es-sink.port=${ES_SING_PORT:9300} -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/fonts/colaborate-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/fonts/colaborate-medium-webfont.woff -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/haew0nsh1n/pivotal-bank-demo-kr/HEAD/web-ui/src/main/resources/static/images/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /web-ui/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: web-service 4 | info: 5 | build: 6 | group: ${group} 7 | name: ${name} 8 | description: ${description} 9 | version: ${version} -------------------------------------------------------------------------------- /accounts-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: accounts-service 4 | info: 5 | build: 6 | group: ${group} 7 | name: ${name} 8 | description: ${description} 9 | version: ${version} -------------------------------------------------------------------------------- /zipkin-server/src/it/execjar/README.md: -------------------------------------------------------------------------------- 1 | # execjar 2 | This includes tests that use the exec jar produced by the zipkin-server build. 3 | 4 | It intentionally doesn't depend on any zipkin pom, to ensure the only 5 | thing in the classpath is the exec jar. 6 | -------------------------------------------------------------------------------- /accounts-service/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | sleuth: 3 | stream: 4 | enabled: false 5 | cloud: 6 | discovery: 7 | enabled: false 8 | service-registry: 9 | auto-registration: 10 | enabled: false -------------------------------------------------------------------------------- /analytics-scdf-sink/src/main/resources/META-INF/spring-configuration-metadata-whitelist.properties: -------------------------------------------------------------------------------- 1 | configuration-properties.classes=io.pivotal.analytics.configuration.EsSinkProperties 2 | configuration-properties.names=es-sink.cluster-name,es-sink.host,es-sink-port -------------------------------------------------------------------------------- /analytics-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | # profiles.active: local 3 | application: 4 | name: analytics-service 5 | info: 6 | build: 7 | group: ${group} 8 | name: ${name} 9 | description: ${description} 10 | version: ${version} -------------------------------------------------------------------------------- /e2e-tests/src/test/resouces/order.json: -------------------------------------------------------------------------------- 1 | { 2 | "userId": "davpin", 3 | "accountId": 500, 4 | "symbol": "EMC", 5 | "orderFee": 1, 6 | "completionDate": 1329759342904, 7 | "orderType": "BUY", 8 | "price": 10, 9 | "quantity": 1000, 10 | "currency": "USD" 11 | } -------------------------------------------------------------------------------- /portfolio-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | # profiles.active: local 3 | application: 4 | name: portfolio-service 5 | info: 6 | build: 7 | group: ${group} 8 | name: ${name} 9 | description: ${description} 10 | version: ${version} -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/domain/AccountType.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.accounts.domain; 2 | /** 3 | * Enumeration of types of accounts 4 | * 5 | * @author David Ferreira Pinto 6 | * 7 | */ 8 | public enum AccountType { 9 | CURRENT, SAVINGS 10 | } 11 | -------------------------------------------------------------------------------- /scripts/PCFServices.list: -------------------------------------------------------------------------------- 1 | ######## Need to confirm service name and plan based upon your cloud foundry instances 2 | p-service-registry trial discovery-service 3 | p-config-server trial config-server 4 | p-circuit-breaker-dashboard trial circuit-breaker-dashboard 5 | cleardb spark traderdb 6 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/domain/OrderType.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.domain; 2 | 3 | /** 4 | * The type of the order. It can be a BUY order or a SELL order. 5 | * 6 | * @author David Ferreira Pinto 7 | * 8 | */ 9 | public enum OrderType { 10 | BUY,SELL 11 | } 12 | -------------------------------------------------------------------------------- /web-ui/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Mar 18 09:36:18 GMT 2016 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-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /configServer/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Sep 30 10:13:14 BST 2015 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-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /turbineServer/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Sep 30 09:48:20 BST 2015 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-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /user-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jul 24 16:45:23 EDT 2018 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-4.6-all.zip 7 | -------------------------------------------------------------------------------- /accounts-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Mar 18 09:23:18 GMT 2016 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-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /analytics-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Mar 18 09:31:34 GMT 2016 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-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /discoveryServer/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Sep 30 10:25:22 BST 2015 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-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /e2e-tests/README.md: -------------------------------------------------------------------------------- 1 | # End to End Test for Pivotal Bank 2 | 3 | To execute test 4 | 5 | ``` 6 | APPLICATION_URL= mvn verify 7 | ``` 8 | 9 | The default value of APPLICATION_URL is the url of the pivotal bank api gateway 10 | (e.g. https://gateway-boring-jackal.cfapps.haas-141.pez.pivotal.io). -------------------------------------------------------------------------------- /e2e-tests/src/test/resouces/account.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": 500, 3 | "userid": "johndoe", 4 | "name": "SOME_NAME", 5 | "type": "SAVINGS", 6 | "creationdate": 1329759342904, 7 | "openbalance": 55.02, 8 | "balance": 40.1099999999999994315658113919198513031005859375, 9 | "currency": "GBP" 10 | } -------------------------------------------------------------------------------- /gateway-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Jul 31 10:25:53 EDT 2018 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-4.8.1-all.zip 7 | -------------------------------------------------------------------------------- /portfolio-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Mar 18 09:31:34 GMT 2016 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-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /quotes-service/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue Mar 15 16:53:18 GMT 2016 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-4.6-bin.zip 7 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/domain/Search.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.domain; 2 | 3 | public class Search { 4 | 5 | private String name; 6 | 7 | public String getName() { 8 | return name; 9 | } 10 | 11 | public void setName(String name) { 12 | this.name = name; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /analytics-service/Readme.md: -------------------------------------------------------------------------------- 1 | # Run Locally 2 | ELASTICSEARCH_CLUSTERNAME=elasticsearch ELASTICSEARCH_HOST=10.193.152.238 ELASTICSEARCH_PORT=32231 java -jar 3 | 4 | # Create CF User Provided Service 5 | 6 | cf create-user-provided-service es -p '{"cluster-name":"elasticsearch","host":"10.193.152.236","port":"30141"}' -------------------------------------------------------------------------------- /portfolio-service/src/main/java/io/pivotal/portfolio/domain/OrderType.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio.domain; 2 | 3 | /** 4 | * The type of the order. It can be a BUY order or a SELL order. 5 | * 6 | * @author David Ferreira Pinto 7 | * 8 | */ 9 | public enum OrderType { 10 | BUY,SELL 11 | } 12 | -------------------------------------------------------------------------------- /user-service/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | hystrix: 2 | metrics: 3 | enabled: false 4 | spring: 5 | sleuth: 6 | stream: 7 | enabled: false 8 | cloud: 9 | discovery: 10 | enabled: false 11 | service-registry: 12 | auto-registration: 13 | enabled: false 14 | -------------------------------------------------------------------------------- /gateway-service/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | hystrix: 2 | metrics: 3 | enabled: false 4 | spring: 5 | sleuth: 6 | stream: 7 | enabled: false 8 | cloud: 9 | discovery: 10 | enabled: false 11 | service-registry: 12 | auto-registration: 13 | enabled: false 14 | -------------------------------------------------------------------------------- /scripts/setVars.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # set some variables 4 | 5 | BASE_DIR=$(dirname "$(pwd)") 6 | # This shouldn't need changing, it is the URL used for Config Server 7 | GITHUB_URI=https://github.com/hshin-pivotal/pivotal-bank-demo-kr.git 8 | GITHUB_SEARCHPATHS=cf-SpringBootTrader-config 9 | GITHUB_BRANCH=master 10 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/application-debug.yml: -------------------------------------------------------------------------------- 1 | logging: 2 | level: 3 | zipkin: DEBUG 4 | io: 5 | pivotal: DEBUG 6 | com: 7 | netflix: DEBUG 8 | org: 9 | springframework: 10 | web: DEBUG 11 | cloud: 12 | sleuth: 13 | log: WARN 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | .idea 4 | *.iml 5 | 6 | out 7 | .DS_Store 8 | 9 | target/ 10 | 11 | # Ignore Gradle GUI config 12 | gradle-app.setting 13 | 14 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 15 | !gradle-wrapper.jar 16 | 17 | # Cache of project 18 | .gradletasknamecache 19 | 20 | *.log 21 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/web-service.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: web-service 4 | eureka: 5 | client: 6 | registerWithEureka: true 7 | registryFetchIntervalSeconds: 10 8 | pivotal: 9 | summary: 10 | quotes: 3 11 | symbols: 12 | it: ORCL,IBM,INTC,AMD,HPQ,CSCO,AAPL 13 | fs: JPM,C,MS,BAC,GS,WFC,BK 14 | -------------------------------------------------------------------------------- /elastic-search/vsphere-volume-sc-fast.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: fast 5 | annotations: 6 | storageclass.beta.kubernetes.io/is-default-class: "true" 7 | provisioner: kubernetes.io/vsphere-volume 8 | #parameters: 9 | # datastore: VSANDatastore 10 | # diskformat: thin 11 | # fstype: ext3 12 | -------------------------------------------------------------------------------- /docs/lab_full_integration_test.md: -------------------------------------------------------------------------------- 1 | # The following is a full integration 2 | 3 | >Make sure you check the marketplace and update /scripts/PCFServices.list accordingly 4 | 5 | 1. Clear out all apps and services in your space 6 | 2. Run /scripts/doItAll.sh 7 | 3. Run through [manual user acceptance test](lab_manual_test.md) 8 | 4. Execute the [Zipkin Lab](lab_zipkin.md) 9 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Mar 22 23:19:20 EDT 2018 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-4.6-all.zip 7 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6-all.zip 8 | -------------------------------------------------------------------------------- /quotes-service/src/main/java/io/pivotal/quotes/domain/IexBatchQuote.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.quotes.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | 5 | import java.util.HashMap; 6 | 7 | @JsonIgnoreProperties(ignoreUnknown = true) 8 | public class IexBatchQuote extends HashMap> { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /e2e-tests/src/test/resouces/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": null, 3 | "address": "", 4 | "passwd": "password", 5 | "userid": "johndoe2", 6 | "email": "anon@springsource.com", 7 | "creditcard": "", 8 | "fullname": "John Doe", 9 | "authtoken": null, 10 | "creationdate": "2018-07-28T01:31:32.123", 11 | "logoutcount": null, 12 | "lastlogin": null, 13 | "logincount": null 14 | } -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/exception/OrderNotSavedException.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.exception; 2 | 3 | public class OrderNotSavedException extends RuntimeException { 4 | /** 5 | * 6 | */ 7 | private static final long serialVersionUID = 6269912483691692397L; 8 | 9 | public OrderNotSavedException(String message) { 10 | super(message); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /gateway-service/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | /build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 12 | .sts4-cache 13 | 14 | ### IntelliJ IDEA ### 15 | .idea 16 | *.iws 17 | *.iml 18 | *.ipr 19 | /out/ 20 | 21 | ### NetBeans ### 22 | /nbproject/private/ 23 | /nbbuild/ 24 | /dist/ 25 | /nbdist/ 26 | /.nb-gradle/ -------------------------------------------------------------------------------- /quotes-service/src/main/java/io/pivotal/quotes/exception/SymbolNotFoundException.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.quotes.exception; 2 | 3 | /** 4 | * Exception representing that a quote symbol cannot be found. 5 | * @author David Ferreira Pinto 6 | * 7 | */ 8 | public class SymbolNotFoundException extends Exception { 9 | 10 | public SymbolNotFoundException(String message ) { 11 | super(message); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /analytics-scdf-sink/src/main/java/io/pivotal/analytics/Application.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class Application { 8 | public static void main(String[] args) { 9 | SpringApplication.run(Application.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /scripts/deleteListedApps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | source ./commons.sh 4 | 5 | delete() 6 | { 7 | cf delete -f -r $1 8 | } 9 | 10 | summaryOfApps 11 | 12 | file="./microServices.list" 13 | while IFS= read -r app 14 | do 15 | if [ ! "${app:0:1}" == "#" ] 16 | then 17 | app=`echo $app | cut -d "-" -f1` 18 | delete $app -f -r& 19 | fi 20 | done < "$file" 21 | 22 | wait 23 | 24 | summaryOfApps 25 | exit 0 26 | -------------------------------------------------------------------------------- /portfolio-service/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | pivotal: 2 | quotesService: 3 | name: quotes-service 4 | accountsService: 5 | name: accounts-service 6 | hystrix: 7 | metrics: 8 | enabled: false 9 | spring: 10 | sleuth: 11 | stream: 12 | enabled: false 13 | cloud: 14 | discovery: 15 | enabled: false 16 | service-registry: 17 | auto-registration: 18 | enabled: false -------------------------------------------------------------------------------- /user-service/src/main/java/io/pivotal/user/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.user.repository; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | import io.pivotal.user.domain.User; 6 | 7 | public interface UserRepository extends CrudRepository { 8 | public User findByUseridAndPasswd(String userId, String passwd); 9 | public User findByUserid(String userId); 10 | public User findByAuthtoken(String authtoken); 11 | } 12 | -------------------------------------------------------------------------------- /gateway-service/src/test/java/io/pivotal/gateway/GatewayApplicationTests.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.gateway; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class GatewayApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /e2e-tests/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | .DS_Store 3 | target/ 4 | 5 | #InteliiJ 6 | .idea/ 7 | *.iml 8 | 9 | # Compiled class file 10 | *.class 11 | 12 | # Log file 13 | *.log 14 | 15 | # BlueJ files 16 | *.ctxt 17 | 18 | # Mobile Tools for Java (J2ME) 19 | .mtj.tmp/ 20 | 21 | # Package Files # 22 | *.jar 23 | *.war 24 | *.ear 25 | *.zip 26 | *.tar.gz 27 | *.rar 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* 31 | -------------------------------------------------------------------------------- /elastic-search/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | .DS_Store 3 | target/ 4 | 5 | #InteliiJ 6 | .idea/ 7 | *.iml 8 | 9 | # Compiled class file 10 | *.class 11 | 12 | # Log file 13 | *.log 14 | 15 | # BlueJ files 16 | *.ctxt 17 | 18 | # Mobile Tools for Java (J2ME) 19 | .mtj.tmp/ 20 | 21 | # Package Files # 22 | *.jar 23 | *.war 24 | *.ear 25 | *.zip 26 | *.tar.gz 27 | *.rar 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* -------------------------------------------------------------------------------- /portfolio-service/src/main/java/io/pivotal/portfolio/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio.repository; 2 | 3 | 4 | import java.util.List; 5 | 6 | import io.pivotal.portfolio.domain.Order; 7 | 8 | import org.springframework.data.repository.CrudRepository; 9 | /** 10 | * 11 | * @author David Ferreira Pinto 12 | * 13 | */ 14 | public interface OrderRepository extends CrudRepository { 15 | 16 | List findByUserId(String userId); 17 | } 18 | -------------------------------------------------------------------------------- /configServer/src/main/java/io/pivotal/config/ConfigServer.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.config; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | 8 | @SpringBootApplication 9 | @EnableConfigServer 10 | public class ConfigServer { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(ConfigServer.class, args); 14 | } 15 | } -------------------------------------------------------------------------------- /analytics-service/src/test/java/io/pivotal/analytics/AnalyticsApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics; 2 | 3 | 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringRunner; 8 | 9 | @RunWith(SpringRunner.class) 10 | @SpringBootTest(classes = AnalyticsApplication.class) 11 | public class AnalyticsApplicationTest { 12 | 13 | @Test 14 | public void contextLoads() { 15 | } 16 | } -------------------------------------------------------------------------------- /discoveryServer/manifest-registry.yml: -------------------------------------------------------------------------------- 1 | --- 2 | env: 3 | SPRING_PROFILES_DEFAULT: cloud 4 | JAVA_OPTS: -Djava.security.egd=file:///dev/urandom 5 | #comment out for single standalone node or modify to point to Eureka peer 6 | EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://eureka-server2.emea.fe.gopivotal.com/eureka/ 7 | applications: 8 | - name: eureka-server1 9 | path: build/libs/registry-0.0.1.jar 10 | timeout: 180 11 | instances: 1 12 | memory: 512M 13 | hosts: 14 | - eureka-server1 15 | - eureka 16 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error page 5 | 6 |
7 | 8 | 9 |

404

10 |

Error java.lang.NullPointerException

11 | Back to Home Page 12 | 13 | -------------------------------------------------------------------------------- /discoveryServer/src/main/java/io/pivotal/registry/RegistryApplication.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.registry; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class RegistryApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(RegistryApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /discoveryServer/manifest-registry2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | timeout: 180 3 | instances: 1 4 | memory: 512M 5 | env: 6 | SPRING_PROFILES_DEFAULT: cloud 7 | JAVA_OPTS: -Djava.security.egd=file:///dev/urandom 8 | # Comment the line before for standalone eureka server or modify to point to Eureka peer. 9 | EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://eureka-server1.emea.fe.gopivotal.com/eureka/ 10 | applications: 11 | - name: eureka-server2 12 | path: build/libs/registry-0.0.1.jar 13 | hosts: 14 | - eureka-server2 15 | - eureka 16 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/application-local.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | instance: 3 | nonSecurePort: ${server.port} 4 | logging: 5 | level: 6 | io: 7 | pivotal: DEBUG 8 | com: 9 | netflix: INFO 10 | org: 11 | springframework: 12 | web: INFO 13 | cloud: WARN 14 | spring: 15 | zipkin: 16 | baseUrl: http://localhost:9411/ 17 | sender: 18 | type: web 19 | # disable the hystrix streaming on rabbit locally 20 | hystrix: 21 | stream: 22 | queue: 23 | enabled: false 24 | -------------------------------------------------------------------------------- /scripts/deleteListedServices.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | source ./commons.sh 3 | 4 | IFS=' ' 5 | 6 | delete() 7 | { 8 | cf delete-service -f $1 9 | } 10 | 11 | file="./PCFServices.list" 12 | while read service plan si 13 | do 14 | if [ ! "${service:0:1}" == "#" ] 15 | then 16 | delete $si & 17 | fi 18 | done < "$file" 19 | wait 20 | 21 | # Wait until services are ready 22 | while cf services | grep 'delete in progress' 23 | do 24 | sleep 20 25 | echo "Waiting for services to delete..." 26 | done 27 | 28 | summaryOfServices 29 | exit 0 30 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/config/BeanConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.config; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | @Configuration 9 | public class BeanConfiguration { 10 | @LoadBalanced 11 | @Bean 12 | public RestTemplate loadBalanced() { 13 | return new RestTemplate(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /turbineServer/.springBeans: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 5 | 6 | 7 | 8 | 9 | 10 | java:io.pivotal.turbine.turbineServer 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.accounts.repository; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.data.repository.CrudRepository; 6 | 7 | import io.pivotal.accounts.domain.Account; 8 | import io.pivotal.accounts.domain.AccountType; 9 | 10 | public interface AccountRepository extends CrudRepository { 11 | public List findByUserid(String userId); 12 | public List findByUseridAndType(String userId, AccountType type); 13 | } 14 | -------------------------------------------------------------------------------- /user-service/src/main/java/io/pivotal/user/config/BeanConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.user.config; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | @Configuration 9 | public class BeanConfiguration { 10 | @LoadBalanced 11 | @Bean 12 | public RestTemplate loadBalanced() { 13 | return new RestTemplate(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /gateway-service/src/main/java/io/pivotal/gateway/GatewayApplication.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.gateway; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.gateway.route.RouteLocator; 6 | import org.springframework.context.annotation.Bean; 7 | 8 | @SpringBootApplication 9 | public class GatewayApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(GatewayApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/config/BeanConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.accounts.config; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | @Configuration 9 | public class BeanConfiguration { 10 | @LoadBalanced 11 | @Bean 12 | public RestTemplate loadBalanced() { 13 | return new RestTemplate(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /analytics-service/src/main/java/io/pivotal/analytics/config/BeanConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.config; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | @Configuration 9 | public class BeanConfiguration { 10 | @LoadBalanced 11 | @Bean 12 | public RestTemplate loadBalanced() { 13 | return new RestTemplate(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /analytics-service/src/main/java/io/pivotal/analytics/repository/TradeRepository.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.repository; 2 | 3 | import io.pivotal.analytics.entity.Trade; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; 7 | 8 | public interface TradeRepository extends ElasticsearchRepository { 9 | 10 | Page findBySymbolOrderByCompletiondateDesc(String symbol, Pageable pageable); 11 | 12 | } -------------------------------------------------------------------------------- /portfolio-service/src/main/java/io/pivotal/portfolio/config/BeanConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio.config; 2 | 3 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | import org.springframework.web.client.RestTemplate; 7 | 8 | @Configuration 9 | public class BeanConfiguration { 10 | @LoadBalanced 11 | @Bean 12 | public RestTemplate loadBalanced() { 13 | return new RestTemplate(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /turbineServer/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | info: 2 | component: Turbine Server 3 | spring: 4 | application: 5 | name: turbineserver 6 | profiles.active: local 7 | turbine: 8 | clusterNameExpression: new String("default") 9 | appConfig: quotes-service,accounts-service,portfolio-service,web-service 10 | --- 11 | spring: 12 | profiles: local 13 | server: 14 | port: 8079 15 | eureka: 16 | client: 17 | serviceUrl: 18 | defaultZone: http://127.0.0.1:8761/eureka/ 19 | instance: 20 | nonSecurePort: ${server.port} 21 | 22 | -------------------------------------------------------------------------------- /zipkin-server/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: zipkin 4 | timeout: 180 5 | instances: 1 6 | memory: 1G 7 | path: target/zipkin.jar 8 | random-route: true 9 | services: [ discovery-service ] 10 | # When deployed to environments with self-signed certs, you have to reference your api here. See 11 | # http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html 12 | # Running /scripts/doItAll.sh or 4_addTrustCerts.sh will take care of this 13 | # env: 14 | # TRUST_CERTS: api.your-system-domain.com 15 | -------------------------------------------------------------------------------- /portfolio-service/src/test/java/io/pivotal/portfolio/PortfolioApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio; 2 | 3 | 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringRunner; 8 | 9 | @RunWith(SpringRunner.class) 10 | @SpringBootTest(classes = PortfolioApplication.class) 11 | public class PortfolioApplicationTest { 12 | /** 13 | * test loading of spring context. 14 | */ 15 | @Test 16 | public void contextLoads() { 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /web-ui/src/test/java/io/pivotal/web/WebApplicationTests.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | import org.springframework.test.context.web.WebAppConfiguration; 8 | 9 | @RunWith(SpringRunner.class) 10 | @SpringBootTest(classes = WebApplication.class) 11 | @WebAppConfiguration 12 | public class WebApplicationTests { 13 | 14 | @Test 15 | public void contextLoads() { 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /analytics-scdf-sink/src/main/java/io/pivotal/analytics/repository/TradeRepository.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.repository; 2 | 3 | import io.pivotal.analytics.entity.Trade; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; 7 | 8 | import java.util.List; 9 | 10 | public interface TradeRepository extends ElasticsearchRepository { 11 | 12 | Page findBySymbol(String symbol, Pageable pageable); 13 | 14 | } -------------------------------------------------------------------------------- /web-ui/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | pivotal: 2 | accountsService: 3 | name: account-service 4 | portfolioService: 5 | name: portfolio-service 6 | quotesService: 7 | name: quote-service 8 | userService: 9 | name: user-service 10 | analyticsService: 11 | name: analytics-service 12 | hystrix: 13 | metrics: 14 | enabled: false 15 | spring: 16 | sleuth: 17 | stream: 18 | enabled: false 19 | cloud: 20 | discovery: 21 | enabled: false 22 | service-registry: 23 | auto-registration: 24 | enabled: false 25 | 26 | -------------------------------------------------------------------------------- /web-ui/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: web 4 | path: build/libs/web.jar 5 | services: [ discovery-service, circuit-breaker-dashboard, config-server ] 6 | timeout: 180 7 | instances: 1 8 | memory: 1G 9 | random-route: true 10 | # When deployed to environments with self-signed certs, you have to reference your api here. See 11 | # http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html 12 | # Running /scripts/doItAll.sh or 4_addTrustCerts.sh will take care of this 13 | # env: 14 | # TRUST_CERTS: api.your-system-domain.com 15 | -------------------------------------------------------------------------------- /quotes-service/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: quotes 4 | path: build/libs/quotes.jar 5 | services: [ discovery-service, circuit-breaker-dashboard, config-server ] 6 | timeout: 180 7 | instances: 1 8 | memory: 1G 9 | random-route: true 10 | # When deployed to environments with self-signed certs, you have to reference your api here. See 11 | # http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html 12 | # Running /scripts/doItAll.sh or 4_addTrustCerts.sh will take care of this 13 | # env: 14 | # TRUST_CERTS: api.your-system-domain.com 15 | 16 | -------------------------------------------------------------------------------- /user-service/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: user 4 | path: build/libs/user.jar 5 | services: [ traderdb, discovery-service, circuit-breaker-dashboard, config-server ] 6 | timeout: 180 7 | instances: 1 8 | memory: 1G 9 | random-route: true 10 | # When deployed to environments with self-signed certs, you have to reference your api here. See 11 | # http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html 12 | # Running /scripts/doItAll.sh or 4_addTrustCerts.sh will take care of this 13 | # env: 14 | # TRUST_CERTS: api.your-system-domain.com 15 | -------------------------------------------------------------------------------- /analytics-service/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: analytics 4 | path: build/libs/analytics.jar 5 | services: [ discovery-service, circuit-breaker-dashboard, config-server, es ] 6 | timeout: 180 7 | instances: 1 8 | memory: 1G 9 | random-route: true 10 | # When deployed to environments with self-signed certs, you have to reference your api here. See 11 | # http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html 12 | # Running /scripts/doItAll.sh or 4_addTrustCerts.sh will take care of this 13 | # env: 14 | # TRUST_CERTS: api.your-system-domain.com 15 | -------------------------------------------------------------------------------- /gateway-service/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: gateway 4 | path: build/libs/gateway.jar 5 | services: [ discovery-service, circuit-breaker-dashboard, config-server ] 6 | timeout: 180 7 | instances: 1 8 | memory: 1G 9 | random-route: true 10 | # When deployed to environments with self-signed certs, you have to reference your api here. See 11 | # http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html 12 | # Running /scripts/doItAll.sh or 4_addTrustCerts.sh will take care of this 13 | # env: 14 | # TRUST_CERTS: api.your-system-domain.com 15 | 16 | -------------------------------------------------------------------------------- /turbineServer/src/main/java/io/pivotal/turbine/turbineServer.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.turbine; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; 6 | import org.springframework.cloud.netflix.turbine.EnableTurbine; 7 | 8 | 9 | @SpringBootApplication 10 | @EnableTurbine 11 | @EnableHystrixDashboard 12 | public class turbineServer { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(turbineServer.class, args); 16 | } 17 | } -------------------------------------------------------------------------------- /accounts-service/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: accounts 4 | path: build/libs/accounts.jar 5 | services: [ traderdb, discovery-service, circuit-breaker-dashboard, config-server ] 6 | timeout: 180 7 | instances: 1 8 | memory: 1G 9 | random-route: true 10 | # When deployed to environments with self-signed certs, you have to reference your api here. See 11 | # http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html 12 | # Running /scripts/doItAll.sh or 4_addTrustCerts.sh will take care of this 13 | # env: 14 | # TRUST_CERTS: api.your-system-domain.com 15 | -------------------------------------------------------------------------------- /portfolio-service/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | applications: 3 | - name: portfolio 4 | path: build/libs/portfolio.jar 5 | services: [ traderdb, discovery-service, circuit-breaker-dashboard, config-server ] 6 | timeout: 180 7 | instances: 1 8 | memory: 1G 9 | random-route: true 10 | # When deployed to environments with self-signed certs, you have to reference your api here. See 11 | # http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html 12 | # Running /scripts/doItAll.sh or 4_addTrustCerts.sh will take care of this 13 | # env: 14 | # TRUST_CERTS: api.your-system-domain.com 15 | -------------------------------------------------------------------------------- /user-service/src/main/java/io/pivotal/user/UserApplication.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.user; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | 8 | @SpringBootApplication 9 | @EnableDiscoveryClient 10 | @EnableCircuitBreaker 11 | public class UserApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(UserApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /zipkin-server/src/main/java/zipkin/server/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package zipkin.server; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 | 7 | @Configuration 8 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 9 | 10 | @Override 11 | protected void configure(HttpSecurity http) throws Exception { 12 | http.csrf().disable().authorizeRequests().anyRequest().permitAll(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /analytics-service/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | pivotal: 2 | quotesService: 3 | name: quotes-service 4 | accountsService: 5 | name: accounts-service 6 | vcap: 7 | services: 8 | es: 9 | credentials: 10 | cluster-name: elasticsearch 11 | host: 10.193.138.120 # replace this with valid host 12 | port: 30432 # replace this with valid port 13 | hystrix: 14 | metrics: 15 | enabled: false 16 | spring: 17 | sleuth: 18 | stream: 19 | enabled: false 20 | cloud: 21 | discovery: 22 | enabled: false 23 | service-registry: 24 | auto-registration: 25 | enabled: false -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/fragments/quote_attribution_fragment.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 |
6 |

7 | Data provided for free by IEX. View 8 | IEX's Terms of Use. 9 | All price quotes leverage 10 | IEX's Real-Time Price 11 |

12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /quotes-service/src/main/java/io/pivotal/quotes/QuotesApplication.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.quotes; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | 8 | @SpringBootApplication 9 | @EnableDiscoveryClient 10 | @EnableCircuitBreaker 11 | public class QuotesApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(QuotesApplication.class, args); 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /user-service/src/main/java/io/pivotal/user/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.user.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 | 7 | @Configuration 8 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 9 | 10 | @Override 11 | protected void configure(HttpSecurity http) throws Exception { 12 | http.csrf().disable().authorizeRequests().anyRequest().permitAll(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/AccountsApplication.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.accounts; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | 8 | @SpringBootApplication 9 | @EnableDiscoveryClient 10 | @EnableCircuitBreaker 11 | public class AccountsApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(AccountsApplication.class, args); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /quotes-service/src/main/java/io/pivotal/quotes/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.quotes.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 | 7 | @Configuration 8 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 9 | 10 | @Override 11 | protected void configure(HttpSecurity http) throws Exception { 12 | http.csrf().disable().authorizeRequests().anyRequest().permitAll(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.accounts.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 | 7 | @Configuration 8 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 9 | 10 | @Override 11 | protected void configure(HttpSecurity http) throws Exception { 12 | http.csrf().disable().authorizeRequests().anyRequest().permitAll(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /analytics-service/src/main/java/io/pivotal/analytics/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 | 7 | @Configuration 8 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 9 | 10 | @Override 11 | protected void configure(HttpSecurity http) throws Exception { 12 | http.csrf().disable().authorizeRequests().anyRequest().permitAll(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /portfolio-service/src/main/java/io/pivotal/portfolio/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 5 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 6 | 7 | @Configuration 8 | public class SecurityConfig extends WebSecurityConfigurerAdapter { 9 | 10 | @Override 11 | protected void configure(HttpSecurity http) throws Exception { 12 | http.csrf().disable().authorizeRequests().anyRequest().permitAll(); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /scripts/2_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script: 4 | # 1) Reads microservices.list 5 | # 2) Performs a gradle build on each line in the file 6 | 7 | source ./commons.sh 8 | 9 | build() 10 | { 11 | echo_msg "Building $1" 12 | cd $BASE_DIR/$1 13 | #./gradlew build ; sleep 4 14 | ./gradlew build -x test ; sleep 4 15 | } 16 | 17 | main() 18 | { 19 | file="microServices.list" 20 | while IFS= read -r app 21 | do 22 | if [ ! "${app:0:1}" == "#" ] 23 | then 24 | build $app & 25 | #sleep 4 26 | fi 27 | done < "$file" 28 | wait 29 | } 30 | 31 | main 32 | 33 | printf "\nExecuted $SCRIPTNAME in $SECONDS seconds.\n" 34 | exit 0 35 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/application.yml: -------------------------------------------------------------------------------- 1 | pivotal: 2 | quotesService: 3 | name: quotes-service 4 | userService: 5 | name: user-service 6 | accountsService: 7 | name: accounts-service 8 | portfolioService: 9 | name: portfolio-service 10 | analyticsService: 11 | name: analytics-service 12 | logging: 13 | level: 14 | io: 15 | pivotal: DEBUG 16 | com: 17 | netflix: FATAL 18 | org: 19 | springframework: 20 | web: WARN 21 | cloud: WARN 22 | spring: 23 | sleuth: 24 | sampler: 25 | probability: 1.0 26 | management: 27 | endpoints: 28 | web: 29 | exposure: 30 | include: "*" 31 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/registration.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Spring Trader - Registration 7 |
8 | 9 | 10 |
11 | 12 |
13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /user-service/src/test/java/io/pivotal/user/AccountsApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.user; 2 | 3 | import io.pivotal.user.UserApplication; 4 | 5 | import org.junit.Test; 6 | import org.junit.runner.RunWith; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | 10 | /** 11 | * Tests for the Accounts Application. 12 | * @author David Ferreira Pinto 13 | * 14 | */ 15 | @RunWith(SpringRunner.class) 16 | @SpringBootTest(classes = UserApplication.class) 17 | public class AccountsApplicationTest { 18 | /** 19 | * test loading of spring context. 20 | */ 21 | @Test 22 | public void contextLoads() { 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /scripts/doItAll.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | abort() 3 | { 4 | if [ "$?" = "0" ] 5 | then 6 | return 7 | else 8 | echo >&2 ' 9 | *************** 10 | *** ABORTED *** 11 | *************** 12 | ' 13 | echo "An error occurred on line $1. Exiting..." >&2 14 | exit 1 15 | fi 16 | } 17 | 18 | trap 'abort $LINENO' 0 19 | SECONDS=0 20 | SCRIPTNAME=`basename "$0"` 21 | 22 | ./deleteListedApps.sh & 23 | wait 24 | ./deleteListedServices.sh & 25 | wait 26 | sh ./1_createServices.sh 27 | sh ./2_build.sh 28 | sh ./3_deploy.sh 29 | if [ "$0" = "add-certs" ]; then 30 | sh ./4_addTrustCerts.sh 31 | fi 32 | 33 | echo "Executed $SCRIPTNAME in $SECONDS seconds." 34 | exit 0 35 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/WebApplication.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | import org.springframework.scheduling.annotation.EnableScheduling; 8 | 9 | @SpringBootApplication 10 | @EnableDiscoveryClient 11 | @EnableCircuitBreaker 12 | @EnableScheduling 13 | public class WebApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(WebApplication.class, args); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /docs/lab_rest_tests.md: -------------------------------------------------------------------------------- 1 | # Following can be used to test the services 2 | 3 | ## Quote 4 | ``` 5 | http /v1/quotes?q=PVTL 6 | http /v1/company/pivotal 7 | ``` 8 | 9 | ## Portfolio 10 | ``` 11 | http /porfolio/ 12 | ``` 13 | 14 | ## Accounts 15 | ``` 16 | http /accounts/ 17 | ``` 18 | 19 | ## Users 20 | ``` 21 | curl -X POST /users \ 22 | -H 'Cache-Control: no-cache' \ 23 | -H 'Content-Type: application/json' \ 24 | -d '{"id":null,"address":"","passwd":"password","userid":"johndoe2","email":"anon@springsource.com","creditcard":"","fullname":"John Doe","authtoken":null,"creationdate":"2018-07-28T01:31:32.123","logoutcount":null,"lastlogin":null,"logincount":null}' 25 | ``` 26 | -------------------------------------------------------------------------------- /quotes-service/src/test/java/io/pivotal/quotes/QuotesApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.quotes; 2 | 3 | 4 | import org.junit.Test; 5 | import org.junit.runner.RunWith; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | 10 | /** 11 | * Tests for the Quotes Application. 12 | * @author David Ferreira Pinto 13 | * 14 | */ 15 | @RunWith(SpringRunner.class) 16 | @SpringBootTest(classes = QuotesApplication.class) 17 | public class QuotesApplicationTest { 18 | 19 | /** 20 | * test loading of spring context. 21 | */ 22 | @Test 23 | public void contextLoads() { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /accounts-service/src/test/java/io/pivotal/accounts/AccountsApplicationTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.accounts; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | import org.springframework.test.context.web.WebAppConfiguration; 8 | 9 | /** 10 | * Tests for the Accounts Application. 11 | * @author David Ferreira Pinto 12 | * 13 | */ 14 | @RunWith(SpringRunner.class) 15 | @SpringBootTest(classes = AccountsApplication.class) 16 | @WebAppConfiguration 17 | public class AccountsApplicationTest { 18 | /** 19 | * test loading of spring context. 20 | */ 21 | @Test 22 | public void contextLoads() { 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/images/pivotal-square-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /gateway-service/src/main/java/io/pivotal/gateway/config/SecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.gateway.config; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.security.config.web.server.ServerHttpSecurity; 6 | import org.springframework.security.web.server.SecurityWebFilterChain; 7 | 8 | @Configuration 9 | public class SecurityConfig { 10 | @Bean 11 | SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) throws Exception { 12 | return http 13 | .csrf().disable() 14 | .authorizeExchange() 15 | .anyExchange().permitAll() 16 | .and() 17 | .build(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /configServer/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | info: 2 | component: Config Server 3 | spring: 4 | application: 5 | name: configserver 6 | profiles: 7 | active: native 8 | jmx: 9 | default_domain: cloud.config.server 10 | cloud: 11 | config: 12 | server: 13 | native: 14 | searchLocations: file:${user.dir}/../cf-SpringBootTrader-config 15 | # If you want to point to the main git, 16 | # then comment out spring.profiles.active and spring.cloud.config.server.native 17 | # and uncomment spring.cloud.config.server.git 18 | # git: 19 | # uri: https://github.com/Pivotal-Field-Engineering/pivotal-bank-demo.git 20 | # searchPaths: cf-SpringBootTrader-config 21 | management: 22 | context_path: /admin 23 | server: 24 | port: 8888 25 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/fragments/header_fragment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /scripts/commons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # set some variables 6 | . ./setVars.sh 7 | 8 | abort() 9 | { 10 | if [ "$?" = "0" ] 11 | then 12 | return 13 | else 14 | echo >&2 ' 15 | *************** 16 | *** ABORTED *** 17 | *************** 18 | ' 19 | echo "An error occurred on line $1. Exiting..." >&2 20 | exit 1 21 | fi 22 | } 23 | 24 | summaryOfServices() 25 | { 26 | echo_msg "Current Services in CF_SPACE" 27 | cf services | tail -n +4 28 | } 29 | 30 | summaryOfApps() 31 | { 32 | echo_msg "Current Apps in CF_SPACE" 33 | cf apps | tail -n +4 34 | } 35 | 36 | echo_msg() 37 | { 38 | echo "" 39 | echo "************** ${1} **************" 40 | } 41 | 42 | trap 'abort $LINENO' 0 43 | SECONDS=0 44 | SCRIPTNAME=`basename "$0"` 45 | -------------------------------------------------------------------------------- /scripts/3_deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script: 4 | # 1) Reads microServices.list 5 | # 2) Pushes each microservices to PCF 6 | # 7 | 8 | source ./commons.sh 9 | 10 | deploy() 11 | { 12 | echo_msg "Deploying $1" 13 | cd $BASE_DIR/$1 14 | cf push -f manifest.yml --random-route 15 | if [ $? -eq 0 ] 16 | then 17 | echo "Successfully deployed $1" 18 | else 19 | echo "Could not deploy $1" >&2 20 | exit 1 21 | fi 22 | } 23 | 24 | main() 25 | { 26 | file="microServices.list" 27 | while IFS= read -r app 28 | do 29 | if [ ! "${app:0:1}" == "#" ] 30 | then 31 | deploy $app & 32 | sleep 8 33 | fi 34 | done < "$file" 35 | wait 36 | 37 | summaryOfApps 38 | summaryOfServices 39 | } 40 | 41 | main 42 | 43 | printf "\nExecuted $SCRIPTNAME in $SECONDS seconds.\n" 44 | exit 0 45 | -------------------------------------------------------------------------------- /analytics-service/src/main/java/io/pivotal/analytics/AnalyticsApplication.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | /** 8 | * SpringBoot application for the portfolio microservice. 9 | * 10 | * Responsible for managing the portfolio as well as providing the API. 11 | * 12 | * @author David Ferreira Pinto 13 | * 14 | */ 15 | @SpringBootApplication 16 | @EnableDiscoveryClient 17 | @EnableCircuitBreaker 18 | public class AnalyticsApplication { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(AnalyticsApplication.class, args); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /portfolio-service/src/main/java/io/pivotal/portfolio/PortfolioApplication.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | /** 8 | * SpringBoot application for the portfolio microservice. 9 | * 10 | * Responsible for managing the portfolio as well as providing the API. 11 | * 12 | * @author David Ferreira Pinto 13 | * 14 | */ 15 | @SpringBootApplication 16 | @EnableDiscoveryClient 17 | @EnableCircuitBreaker 18 | public class PortfolioApplication { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(PortfolioApplication.class, args); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/openaccount.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Spring Trader - Open Account 7 |
8 | 9 | 10 | 12 |
13 |
14 |
15 |
16 |
17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/config/MvcConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.config; 2 | 3 | import org.springframework.context.annotation.Configuration; 4 | import org.springframework.context.annotation.Import; 5 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; 6 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 7 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 8 | 9 | @Configuration 10 | public class MvcConfig extends WebMvcConfigurerAdapter { 11 | @Override 12 | public void addResourceHandlers(ResourceHandlerRegistry registry) { 13 | if (!registry.hasMappingForPattern("/webjars/**")) { 14 | registry.addResourceHandler("/webjars/**").addResourceLocations( 15 | "classpath:/META-INF/resources/webjars/"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /web-ui/src/test/java/io/pivotal/web/service/MarketServiceTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.service; 2 | 3 | 4 | import org.junit.Before; 5 | import org.mockito.InjectMocks; 6 | import org.mockito.Mock; 7 | import org.mockito.MockitoAnnotations; 8 | import org.springframework.test.web.servlet.MockMvc; 9 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 10 | import org.springframework.web.client.RestTemplate; 11 | 12 | /** 13 | * Tests the QuoteService. 14 | * @author David Ferreira Pinto 15 | * 16 | */ 17 | public class MarketServiceTest { 18 | MockMvc mockMvc; 19 | 20 | @InjectMocks 21 | QuotesService service; 22 | 23 | @Mock 24 | RestTemplate restTemplate; 25 | 26 | @Before 27 | public void setup() { 28 | MockitoAnnotations.initMocks(this); 29 | 30 | this.mockMvc = MockMvcBuilders.standaloneSetup(service).build(); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /docs/lab_manual_test.md: -------------------------------------------------------------------------------- 1 | # Manual Test of Pivotal Bank 2 | The following script is a manual user acceptance test of Pivotal Bank. 3 | 4 | 1. Access Pivotal Bank web application root url, Login page loads 5 | 2. Register a new user, returned back to Login page 6 | 3. Submit login form with registered users credentials, Account Home page loads 7 | 4. Choose Create Account button, Create Account page loads 8 | 5. Submit Create Account form, Open Account page loads, showing the account 9 | 6. Click the Trade link at the top, Trade page loads 10 | 7. Enter stock ticker symbol and click the Get Quote button, quote appears in table 11 | 8. Enter number of shares and click the Buy button, Order page appers with Order Successful message 12 | 9. Click Accounts link at top, Accounts page appears 13 | 10. Click Portfolio lik at top, Portfolio page appears 14 | 11. Click Home link at top, Home page appears -------------------------------------------------------------------------------- /zipkin-server/src/main/java/zipkin2/server/internal/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | /** 15 | * Classes in this package are considered internal details to Zipkin's server and are unsupported 16 | * unless integrated with our server build. 17 | */ 18 | package zipkin2.server.internal; 19 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/analytics.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Spring Trader 7 |
8 | 9 | 10 |
11 | 12 |
13 |
14 |
15 |
16 |
17 | 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /scripts/4_addTrustCerts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This script 3 | # 1) Reads microservices.list 4 | # 2) Adds the TRUST_CERTS env variable for unsigned cert environments (http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html) 5 | # 3) restages the apps 6 | source ./commons.sh 7 | 8 | addTrustCerts() 9 | { 10 | TRUST_CERTS=`cf target | grep "api endpoint" | cut -d" " -f5| xargs` 11 | cf set-env $1 TRUST_CERTS $TRUST_CERTS 12 | cf restage $1 & 13 | } 14 | 15 | echo "Attaching apps to Spring Cloud Services, watch progress in the Service Discovery Service" 16 | 17 | file="./microServices.list" 18 | while IFS= read -r app 19 | do 20 | if [ ! "${app:0:1}" == "#" ] 21 | then 22 | app=`echo $app | cut -d "-" -f1` 23 | addTrustCerts $app 24 | sleep 4 25 | fi 26 | done < "$file" 27 | 28 | wait 29 | 30 | summaryOfApps 31 | summaryOfServices 32 | printf "\nExecuted $SCRIPTNAME in $SECONDS seconds.\n" 33 | exit 0 34 | -------------------------------------------------------------------------------- /elastic-search/es-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 #API Version of the resource 2 | kind: Service #Type of resource 3 | metadata: #Contains metadata of this resource. 4 | name: elasticsearch #Name of this resource 5 | labels: #Additional identifier to put on pods 6 | component: elasticsearch #puts component = elasticsearch 7 | spec: #Specifications of this resource 8 | type: LoadBalancer #type of service 9 | selector: #will distribute load on pods which 10 | component: elasticsearch #have label `component = elasticsearch` 11 | ports: #Port on which LoadBalancer will listen 12 | - name: http #Name given to port 13 | port: 9200 #Port number 14 | protocol: TCP #Protocol supported 15 | - name: transport #Name given to port 16 | port: 9300 #Port number 17 | protocol: TCP #Protocol supported 18 | -------------------------------------------------------------------------------- /quotes-service/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | #pivotal: 2 | # quotes: 3 | # quote_url: https://api.iextrading.com/1.0/stock/{symbol}/quote 4 | # quotes_url: https://api.iextrading.com/1.0/stock/market/batch?symbols={symbols}&types=quote 5 | # companies_url: http://dev.markitondemand.com/Api/v2/Lookup/json?input={name} 6 | pivotal: 7 | quotes: 8 | quote_url: https://cloud.iexapis.com/v1/stock/{symbol}/quote/?token=sk_a66da9dad6114f43b94f53d5d19cf927 9 | quotes_url: https://cloud.iexapis.com/v1/stock/market/batch?symbols={symbols}&types=quote&token=sk_a66da9dad6114f43b94f53d5d19cf927 10 | companies_url: http://dev.markitondemand.com/MODApis/Api/v2/Lookup/json?input={name} 11 | 12 | logging: 13 | level: 14 | org: 15 | apache: 16 | http: debug 17 | hystrix: 18 | metrics: 19 | enabled: false 20 | spring: 21 | sleuth: 22 | stream: 23 | enabled: false 24 | cloud: 25 | discovery: 26 | enabled: false 27 | service-registry: 28 | auto-registration: 29 | enabled: false 30 | -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/domain/AccountTypeConverter.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.accounts.domain; 2 | 3 | import javax.persistence.AttributeConverter; 4 | import javax.persistence.Converter; 5 | 6 | /** 7 | * Converts between AccountType enum to databse persistence value. 8 | * 9 | * @author David Ferreira Pinto 10 | * 11 | */ 12 | @Converter 13 | public class AccountTypeConverter implements 14 | AttributeConverter { 15 | 16 | @Override 17 | public String convertToDatabaseColumn(AccountType type) { 18 | switch (type) { 19 | case CURRENT: 20 | return "C"; 21 | case SAVINGS: 22 | return "S"; 23 | default: 24 | throw new IllegalArgumentException("Unknown" + type); 25 | } 26 | } 27 | 28 | @Override 29 | public AccountType convertToEntityAttribute(String dbData) { 30 | switch (dbData) { 31 | case "C": 32 | return AccountType.CURRENT; 33 | case "S": 34 | return AccountType.SAVINGS; 35 | default: 36 | throw new IllegalArgumentException("Unknown" + dbData); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /discoveryServer/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.5.10.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}" 10 | } 11 | } 12 | 13 | apply plugin: 'eclipse' 14 | apply plugin: 'java' 15 | apply plugin: 'org.springframework.boot' 16 | 17 | jar { 18 | baseName = 'registry' 19 | version = '' 20 | } 21 | 22 | eclipse { 23 | jdt { 24 | sourceCompatibility = 1.8 25 | targetCompatibility = 1.8 26 | } 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | } 32 | 33 | description = "Registry server for micro services" 34 | dependencies { 35 | compile('org.springframework.cloud:spring-cloud-starter-netflix-eureka-server') 36 | testCompile('org.springframework.boot:spring-boot-starter-test') 37 | } 38 | 39 | dependencyManagement { 40 | imports { 41 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:Edgware.SR2" 42 | } 43 | } 44 | 45 | task wrapper(type: Wrapper) { 46 | gradleVersion = '4.6' 47 | } 48 | -------------------------------------------------------------------------------- /configServer/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.5.10.RELEASE' 4 | springCloudStarterParentTrain = 'Camden.SR6' 5 | } 6 | repositories { 7 | mavenCentral() 8 | } 9 | dependencies { 10 | classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}" 11 | } 12 | } 13 | 14 | apply plugin: 'eclipse' 15 | apply plugin: 'java' 16 | apply plugin: 'org.springframework.boot' 17 | 18 | jar { 19 | baseName = 'configServer' 20 | version = '' 21 | } 22 | 23 | eclipse { 24 | jdt { 25 | sourceCompatibility = 1.8 26 | targetCompatibility = 1.8 27 | } 28 | } 29 | 30 | repositories { 31 | mavenCentral() 32 | } 33 | 34 | description = "config server for micro services" 35 | 36 | dependencyManagement { 37 | imports { 38 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:Edgware.SR2" 39 | } 40 | } 41 | dependencies { 42 | compile "org.springframework.cloud:spring-cloud-starter-config" 43 | compile "org.springframework.cloud:spring-cloud-config-server" 44 | } 45 | task wrapper(type: Wrapper) { 46 | gradleVersion = '4.6' 47 | } 48 | -------------------------------------------------------------------------------- /user-service/src/main/java/io/pivotal/user/exception/AuthenticationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.pivotal.user.exception; 17 | 18 | /** 19 | * AuthenticationException should be thrown whenever a login attempt fails to 20 | * find the user 21 | * 22 | * @author Brian Dussault 23 | */ 24 | 25 | @SuppressWarnings("serial") 26 | public class AuthenticationException extends RuntimeException { 27 | 28 | public AuthenticationException(String message) { 29 | super(message); 30 | } 31 | } -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/exception/AuthenticationException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.pivotal.accounts.exception; 17 | 18 | /** 19 | * AuthenticationException should be thrown whenever a login attempt fails to 20 | * find the user 21 | * 22 | * @author Brian Dussault 23 | */ 24 | 25 | @SuppressWarnings("serial") 26 | public class AuthenticationException extends RuntimeException { 27 | 28 | public AuthenticationException(String message) { 29 | super(message); 30 | } 31 | } -------------------------------------------------------------------------------- /elastic-search/readme.md: -------------------------------------------------------------------------------- 1 | # Background 2 | This was adapted from https://medium.appbase.io/deploy-elasticsearch-with-kubernetes-on-aws-in-10-steps-7913b607abda. The changes were to add a persistent volumen claim for vspherevolumes and to utilize a different container image that uses elasticsearch 2.4. 3 | 4 | # Deploy 5 | ``` 6 | kubectl apply -f vsphere-volume-sc-fast.yaml 7 | kubectl apply -f es-statefulset.yaml 8 | kubectl apply -f es-svc.yaml 9 | ``` 10 | 11 | # Test 12 | Get the IP address and get the http and native ports 13 | ``` 14 | kubectl get nodes -o wide 15 | export ES_HOST= 16 | kubectl get svc 17 | export ES_HTTP_PORT= 18 | export ES_PORT= 19 | ``` 20 | Access elastic search and see basic output 21 | ``` 22 | http $ES_HOST:$ES_HTTP_PORT 23 | ``` 24 | Index a document 25 | ``` 26 | http POST $ES_HOST:$ES_HTTP_PORT/trader/trades symbol=MS 27 | ``` 28 | Search the index 29 | ``` 30 | http $ES_HOST:$ES_HTTP_PORT/trader/_search 31 | ``` 32 | 33 | # Cleanup 34 | ``` 35 | kubectl delete -f es-statefulset.yaml 36 | kubectl delete -f es-svc.yaml 37 | kubectl delete -f vsphere-volume-sc-fast.yaml 38 | ``` 39 | -------------------------------------------------------------------------------- /user-service/src/main/java/io/pivotal/user/exception/NoRecordsFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.pivotal.user.exception; 17 | 18 | /** 19 | * NoRecordsFoundException should be thrown whenever an entity is not 20 | * found via the repositories finder method. This exception is thrown from the controller 21 | * 22 | * @author Brian Dussault 23 | */ 24 | 25 | @SuppressWarnings("serial") 26 | public class NoRecordsFoundException extends RuntimeException { 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /accounts-service/src/main/java/io/pivotal/accounts/exception/NoRecordsFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.pivotal.accounts.exception; 17 | 18 | /** 19 | * NoRecordsFoundException should be thrown whenever an entity is not 20 | * found via the repositories finder method. This exception is thrown from the controller 21 | * 22 | * @author Brian Dussault 23 | */ 24 | 25 | @SuppressWarnings("serial") 26 | public class NoRecordsFoundException extends RuntimeException { 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/gateway-service.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | cloud: 3 | gateway: 4 | discovery: 5 | locator: 6 | enabled: true 7 | routes: 8 | - id: quotes-service 9 | uri: lb://quotes-service 10 | predicates: 11 | - Path=/quotes/** 12 | filters: 13 | - RewritePath=/quotes/(?.*), /$\{path} 14 | - id: accounts-service 15 | uri: lb://accounts-service 16 | predicates: 17 | - Path=/accounts/** 18 | filters: 19 | - RewritePath=/accounts/(?.*), /$\{path} 20 | - id: user-service 21 | uri: lb://user-service 22 | predicates: 23 | - Path=/user/** 24 | filters: 25 | - RewritePath=/user/(?.*), /$\{path} 26 | - id: portfolio-service 27 | uri: lb://portfolio-service 28 | predicates: 29 | - Path=/portfolio/** 30 | filters: 31 | - RewritePath=/portfolio/(?.*), /$\{path} 32 | - id: analytics-service 33 | uri: lb://analytics-service 34 | predicates: 35 | - Path=/analytics/** 36 | filters: 37 | - RewritePath=/analytics/(?.*), /$\{path} 38 | -------------------------------------------------------------------------------- /zipkin-server/src/main/java/zipkin2/server/internal/InternalZipkinConfiguration.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin2.server.internal; 15 | 16 | import org.springframework.context.annotation.Configuration; 17 | import org.springframework.context.annotation.Import; 18 | import zipkin2.server.internal.brave.TracingConfiguration; 19 | 20 | @Configuration 21 | @Import({ 22 | ZipkinServerConfiguration.class, 23 | TracingConfiguration.class, 24 | ZipkinQueryApiV2.class, 25 | ZipkinHttpCollector.class, 26 | MetricsHealthController.class 27 | }) 28 | public class InternalZipkinConfiguration { 29 | } 30 | -------------------------------------------------------------------------------- /zipkin-server/src/main/java/zipkin2/server/internal/EnableZipkinServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin2.server.internal; 15 | 16 | import java.lang.annotation.Documented; 17 | import java.lang.annotation.ElementType; 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | import java.lang.annotation.Target; 21 | import org.springframework.context.annotation.Import; 22 | 23 | @Target(ElementType.TYPE) 24 | @Retention(RetentionPolicy.RUNTIME) 25 | @Documented 26 | @Import(InternalZipkinConfiguration.class) 27 | public @interface EnableZipkinServer { 28 | 29 | } 30 | -------------------------------------------------------------------------------- /e2e-tests/src/test/java/e2e/E2EBase.java: -------------------------------------------------------------------------------- 1 | package e2e; 2 | 3 | import com.github.javafaker.Faker; 4 | import com.jayway.restassured.RestAssured; 5 | import com.jayway.restassured.filter.log.ErrorLoggingFilter; 6 | import com.jayway.restassured.filter.log.RequestLoggingFilter; 7 | import com.jayway.restassured.filter.log.ResponseLoggingFilter; 8 | import org.junit.Before; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Value; 11 | import org.springframework.boot.SpringBootConfiguration; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | 15 | @RunWith(SpringRunner.class) 16 | @SpringBootTest() 17 | @SpringBootConfiguration 18 | public class E2EBase { 19 | 20 | @Value("${application.url:http://localhost:8085}") 21 | String applicationUrl; 22 | 23 | Faker faker = Faker.instance(); 24 | 25 | @Before 26 | public void setUp() throws Exception { 27 | 28 | RestAssured.baseURI = this.applicationUrl; 29 | RestAssured.useRelaxedHTTPSValidation(); 30 | RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter(), new ErrorLoggingFilter()); 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /analytics-service/src/main/java/io/pivotal/analytics/service/AnalyticsService.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.service; 2 | 3 | import io.pivotal.analytics.entity.Trade; 4 | import io.pivotal.analytics.repository.TradeRepository; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.cloud.context.config.annotation.RefreshScope; 10 | import org.springframework.data.domain.PageRequest; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | 15 | @Service 16 | @RefreshScope 17 | public class AnalyticsService { 18 | private static final Logger logger = LoggerFactory 19 | .getLogger(AnalyticsService.class); 20 | 21 | @Autowired 22 | TradeRepository repository; 23 | 24 | @Value("${pivotal.accountsService.name}") 25 | protected String accountsService; 26 | 27 | public List getTrades(String symbol) { 28 | 29 | logger.debug("Getting trades for symbol: " + symbol); 30 | List trades = repository.findBySymbolOrderByCompletiondateDesc(symbol, new PageRequest(0, 20)).getContent(); 31 | return trades; 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /turbineServer/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '1.5.10.RELEASE' 4 | springCloudStarterParentTrain = 'Edgware.SR2' 5 | } 6 | repositories { 7 | mavenCentral() 8 | } 9 | dependencies { classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}" } 10 | } 11 | 12 | apply plugin: 'eclipse' 13 | apply plugin: 'java' 14 | apply plugin: 'org.springframework.boot' 15 | 16 | jar { 17 | baseName = 'turbineServer' 18 | version = '' 19 | } 20 | 21 | eclipse { 22 | jdt { 23 | sourceCompatibility = 1.8 24 | targetCompatibility = 1.8 25 | } 26 | } 27 | 28 | repositories { 29 | mavenCentral() 30 | } 31 | 32 | description = "config server for micro services" 33 | 34 | dependencyManagement { 35 | imports { mavenBom "org.springframework.cloud:spring-cloud-starter-parent:${springCloudStarterParentTrain}" } 36 | } 37 | dependencies { 38 | compile "org.springframework.boot:spring-boot-starter-web" 39 | compile "org.springframework.boot:spring-boot-starter-actuator" 40 | 41 | compile "org.springframework.cloud:spring-cloud-starter-netflix-turbine" 42 | compile "org.springframework.cloud:spring-cloud-starter-netflix-hystrix-dashboard" 43 | } 44 | task wrapper(type: Wrapper) { gradleVersion = '4.6' } 45 | -------------------------------------------------------------------------------- /analytics-scdf-sink/src/main/java/io/pivotal/analytics/configuration/EsSinkProperties.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.configuration; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | import org.springframework.validation.annotation.Validated; 5 | 6 | import javax.validation.constraints.NotBlank; 7 | 8 | 9 | @ConfigurationProperties("es-sink") 10 | @Validated 11 | public class EsSinkProperties { 12 | 13 | /** 14 | * Elasticsearch cluster name. 15 | */ 16 | private String clusterName = "elasticsearch"; 17 | 18 | /** 19 | * Elasticsearch host name. 20 | */ 21 | private String host = "localhost"; 22 | 23 | /** 24 | * Elasticsearch native port. 25 | */ 26 | private String port = "9300"; 27 | 28 | @NotBlank 29 | public String getClusterName() { 30 | return clusterName; 31 | } 32 | 33 | public void setClusterName(String clusterName) { 34 | this.clusterName = clusterName; 35 | } 36 | 37 | @NotBlank 38 | public String getHost() { 39 | return host; 40 | } 41 | 42 | public void setHost(String host) { 43 | this.host = host; 44 | } 45 | 46 | @NotBlank 47 | public String getPort() { 48 | return port; 49 | } 50 | 51 | public void setPort(String port) { 52 | this.port = port; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /discoveryServer/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: eureka-server 4 | profiles.active: local 5 | eureka: 6 | instance: 7 | hostname: ${vcap.application.uris[0]:localhost} 8 | metadataMap: 9 | instanceId: ${spring.application.name}:${vcap.application.instance_index:${server.port}} 10 | enableSelfPreservation: false 11 | # client: 12 | # registerWithEureka: false 13 | # fetchRegistry: false 14 | server: 15 | waitTimeInMsWhenSyncEmpty: 0 16 | logging: 17 | pattern: 18 | console: "%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(%5p) %clr(${PID:- }){magenta} %clr(---){faint} %clr([trace=%X{X-Trace-Id:-},span=%X{X-Span-Id:-}]){yellow} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%replace(%xException){'\n','\u2028'}%nopex%n" 19 | level: 20 | com.netflix: FATAL 21 | org.springframework.cloud: WARN 22 | --- 23 | spring: 24 | profiles: local 25 | eureka: 26 | client: 27 | serviceUrl: 28 | defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 29 | server: 30 | port: ${PORT:8761} 31 | --- 32 | spring: 33 | profiles: cloud 34 | eureka: 35 | instance: 36 | nonSecurePort: 80 37 | #server: 38 | # port: ${vcap.application.port:80} 39 | --- 40 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/trade.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Spring Trader 7 |
8 | 9 | 10 |
11 | 12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/domain/AuthenticationRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.pivotal.web.domain; 17 | 18 | /** 19 | * AuthenticationRequest 20 | * @author Brian Dussault 21 | */ 22 | public class AuthenticationRequest { 23 | private String username; 24 | private String password; 25 | 26 | public String getUsername() { 27 | return username; 28 | } 29 | 30 | public void setUsername(String username) { 31 | this.username = username; 32 | } 33 | 34 | public String getPassword() { 35 | return password; 36 | } 37 | 38 | public void setPassword(String password) { 39 | this.password = password; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /cf-SpringBootTrader-config/quotes-service.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: quotes-service 4 | #pivotal: 5 | # quotes: 6 | # quote_url: https://api.iextrading.com/1.0/stock/{symbol}/quote 7 | # quotes_url: https://api.iextrading.com/1.0/stock/market/batch?symbols={symbols}&types=quote 8 | # companies_url: http://dev.markitondemand.com/MODApis/Api/v2/Lookup/json?input={name} 9 | 10 | #pivotal: 11 | # quotes: 12 | # quote_url: https://cloud.iexapis.com/v1/stock/{symbol}/quote/?token={token} 13 | # quotes_url: https://cloud.iexapis.com/v1/stock/market/batch?symbols={symbols}&types=quote&token={token} 14 | # quotes_token: ${iex_token} 15 | # companies_url: http://dev.markitondemand.com/MODApis/Api/v2/Lookup/json?input={name} 16 | 17 | pivotal: 18 | quotes: 19 | quote_url: https://cloud.iexapis.com/v1/stock/{symbol}/quote/?token=sk_a66da9dad6114f43b94f53d5d19cf927 20 | quotes_url: https://cloud.iexapis.com/v1/stock/market/batch?symbols={symbols}&types=quote&token=sk_a66da9dad6114f43b94f53d5d19cf927 21 | companies_url: http://dev.markitondemand.com/MODApis/Api/v2/Lookup/json?input={name} 22 | 23 | #curl 'https://cloud.iexapis.com/v1/stock/market/batch?symbols=PVTL,AAPL&types=quote&token={sk_a66da9dad6114f43b94f53d5d19cf927}' 24 | #curl 'https://cloud.iexapis.com/v1/stock/pvtl/quote/?token={sk_a66da9dad6114f43b94f53d5d19cf927}' -------------------------------------------------------------------------------- /docs/lab_zipkin.md: -------------------------------------------------------------------------------- 1 | # Zipkin Lab 2 | Spring Sleuth can integrate with Zipkin to send trace/span data. Then use Zipkin server to search and view trace/span data. 3 | In this lab, integration is done via HTTP and configured to send 100% of trace data. 4 | 5 | # Zipkin Server 6 | The Spring Cloud Zipkin server has been deprecated, so we will use the zipkin-server app from 7 | zipkin source itself. A fork of that repo was brought into this repo within the sub-directory 8 | zipkin-server. Minor updates were made so that the server would register with the Spring Cloud Discovery Server 9 | and a cloud foundry manifest was added. 10 | 11 | # Build Zipkin Server 12 | Build the binary... 13 | ``` 14 | cd zipkin-server 15 | mvn clean package -DskipTests 16 | ``` 17 | # Deploy to Cloud Foundry 18 | ``` 19 | cd zipkin-server 20 | cf push 21 | ``` 22 | 23 | # Try it out 24 | 25 | 1. Log into the pivotal bank web and follow the [user acceptance test](lab_manual_test.md) 26 | 2. Access the zipkin app, and search for recent spans 27 | 28 | # Deploy to Locally 29 | ``` 30 | cd zipkin-server 31 | java -jar target/zipkin.jar 32 | ``` 33 | 34 | # Reference 35 | - [zipkin-server on github](https://github.com/openzipkin/zipkin/tree/master/zipkin-server) 36 | - [Spring Sleuth Integration with Zipkin](https://cloud.spring.io/spring-cloud-sleuth/single/spring-cloud-sleuth.html#_sleuth_with_zipkin_via_http) -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/fragments/user_fragment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 |

User Statistics

7 |
8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 |
Full Nameuser
User ID / Emailuser
Creation Datetoday
Total Logins0
Session Creation Datetoday
31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/static/css/style.css: -------------------------------------------------------------------------------- 1 | a { 2 | cursor: pointer; 3 | } 4 | body { 5 | background-color: #ecefef; 6 | padding-top:110px; 7 | } 8 | #nc-loading .logo, #nc-loading .loading { 9 | margin: auto; 10 | } 11 | #nc-loading .loading { 12 | margin-top: 20px; 13 | } 14 | .loading { 15 | background:url(../images/loading.gif) no-repeat; 16 | width: 32px; 17 | height: 32px; 18 | } 19 | 20 | .btn-success { 21 | background-color: #138078; 22 | border-color: #333333; 23 | } 24 | .btn-success:hover, .btn-success:focus, .btn-success:active, .btn-success.active { 25 | background-color: #0F635D; 26 | border-color: #333333; 27 | } 28 | .container-with-min-width { 29 | min-width: 1000px; 30 | } 31 | .panel-with-min-width { 32 | min-width: 800px; 33 | } 34 | .panel-default>.panel-heading { 35 | background-color: #138078; 36 | } 37 | .panel-title { 38 | color: white; 39 | } 40 | 41 | .completed { 42 | padding:2px 5px; 43 | background:#5daf1b; 44 | color:#ffffff; 45 | border-radius:3px; 46 | } 47 | .uncompleted { 48 | padding:2px 5px; 49 | background:#a09f9f; 50 | color:#ffffff; 51 | border-radius:3px; 52 | } 53 | 54 | #market-carousel { 55 | height: 300px; 56 | } 57 | 58 | .carousel-indicators li { 59 | background-color: #000; 60 | } 61 | .carousel-indicators .active { 62 | background-color: #138078; 63 | } -------------------------------------------------------------------------------- /zipkin-server/src/main/resources/banner.txt: -------------------------------------------------------------------------------- 1 | ******** 2 | ** ** 3 | * * 4 | ** ** 5 | ** ** 6 | ** ** 7 | ** ** 8 | ******** 9 | **** 10 | **** 11 | **** **** 12 | ****** **** *** 13 | **************************************************************************** 14 | ******* **** *** 15 | **** **** 16 | ** 17 | ** 18 | 19 | 20 | ***** ** ***** ** ** ** ** ** 21 | ** ** ** * *** ** **** ** 22 | ** ** ***** **** ** ** *** 23 | ****** ** ** ** ** ** ** ** 24 | 25 | ${AnsiColor.GREEN}:: Powered by Spring Boot :: ${AnsiStyle.FAINT}${AnsiColor.BLACK}${spring-boot.formatted-version}${AnsiStyle.NORMAL} 26 | -------------------------------------------------------------------------------- /portfolio-service/src/main/java/io/pivotal/portfolio/service/PortfolioRepositoryService.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio.service; 2 | 3 | import brave.ScopedSpan; 4 | import brave.Span; 5 | import brave.Tracer; 6 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 7 | import io.pivotal.portfolio.domain.Order; 8 | import io.pivotal.portfolio.repository.OrderRepository; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | 12 | import java.util.List; 13 | 14 | @Service 15 | public class PortfolioRepositoryService { 16 | 17 | private Tracer tracer; 18 | private OrderRepository repository; 19 | 20 | @Autowired 21 | public PortfolioRepositoryService(Tracer tracer, OrderRepository repository) { 22 | this.tracer = tracer; 23 | this.repository = repository; 24 | } 25 | 26 | @HystrixCommand( 27 | commandKey = "portfolio-service.getOrderFromDB", 28 | groupKey = "portfolio-service.getOrderFromDB", 29 | threadPoolKey = "portfolio-service.getOrderFromDB") 30 | List getOrders(String userId) { 31 | 32 | Span newSpan = this.tracer.nextSpan().name("retrieveUserId"); 33 | 34 | List orders = repository.findByUserId(userId); 35 | try{ 36 | return repository.findByUserId(userId); 37 | } finally { 38 | newSpan.finish(); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /docs/lab_configserver.md: -------------------------------------------------------------------------------- 1 | # Creating the Configuration service. 2 | 3 | All our microservices will retrieve their configuration from a Configuration service. We will use the Configuration service provided by 4 | the [Spring Cloud Services for PCF](https://network.pivotal.io/products/p-spring-cloud-services). 5 | 6 | Underneath the covers, this discovery service is implemented using the [Spring Cloud Config](http://cloud.spring.io/spring-cloud-config/). 7 | 8 | ### Exercise 9 | 10 | 1. Log in to the Apps Manager through your browser. The URL will be: `https://console./` 11 | 12 | Go the *Marketplace* and choose a *Config Server for Pivotal Cloud Foundry*. 13 | 14 | When prompted for the name of the service, insert **"config-server"** and bind it to the space you are using to deploy your applications. 15 | 16 | Add the following json for further configuration: 17 | 18 | ```json 19 | {"git":{"uri":"https://github.com/Pivotal-Field-Engineering/pivotal-bank-demo.git","searchPaths":"cf-SpringBootTrader-config","label":"master"}} 20 | ``` 21 | 22 | > You can pick any name of the service, however, the service is already specified in the manifest files, so it is easier to re-use that name. If you do modify the name, ensure you modify it in the manifest files as well. 23 | 24 | # Summary 25 | The config server dashboard can be accessed on the link provided in the console UI. Find the config server service you created and click on Manage. 26 | 27 | You can now move on to [pushing the quote service](lab_pushquote.md) 28 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/security/LogoutSuccessHandler.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.security; 2 | 3 | import io.pivotal.web.service.UserService; 4 | 5 | import java.io.IOException; 6 | import java.util.Enumeration; 7 | 8 | import javax.servlet.ServletException; 9 | import javax.servlet.http.HttpServletRequest; 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.security.core.Authentication; 16 | import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler; 17 | import org.springframework.stereotype.Component; 18 | 19 | @Component 20 | public class LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler { 21 | private static final Logger logger = LoggerFactory 22 | .getLogger(LogoutSuccessHandler.class); 23 | @Autowired 24 | private UserService service; 25 | 26 | public LogoutSuccessHandler() { 27 | super(); 28 | } 29 | // Just for setting the default target URL 30 | public LogoutSuccessHandler(String defaultTargetURL) { 31 | this.setDefaultTargetUrl(defaultTargetURL); 32 | } 33 | 34 | @Override 35 | public void onLogoutSuccess(HttpServletRequest request, 36 | HttpServletResponse response, Authentication authentication) 37 | throws IOException, ServletException { 38 | 39 | service.logout(authentication.getPrincipal().toString()); 40 | super.onLogoutSuccess(request, response, authentication); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/accounts.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Spring Trader - Accounts 7 |
8 | 9 | 10 | 11 | 12 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 32 |
33 | 34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /docs/lab_registryserver.md: -------------------------------------------------------------------------------- 1 | # Creating the discovery service. 2 | 3 | All our microservices will connect to a Service Registry. We will use the Discovery service provided by the [Spring Cloud Services for PCF](https://network.pivotal.io/products/p-spring-cloud-services). 4 | 5 | Underneath the covers, this discovery service is implemented using the [Spring Cloud Netflix - Eureka](http://cloud.spring.io/spring-cloud-netflix/). 6 | 7 | As such, all we have to do to implement a discovery service is to create a service instance. 8 | 9 | ### Exercise 10 | 11 | 1. Log in to the Apps Manager through your browser. The URL will be: `https://console./` 12 | 13 | Go the *Marketplace* and choose a *Service Registry for Pivotal Cloud Foundry*. 14 | 15 | When prompted for the name of the service, insert **"discovery-service"** and bind it to the space you are using to deploy your applications. 16 | 17 | > You can pick any name of the service, however, the service is already specified in the manifest files, so it is easier to re-use that name. If you do modify the name, ensure you modify it in the manifest files as well. 18 | 19 | # Summary 20 | 21 | The registry server has a UI that can be accessed on the link provided in the console UI. Find the discovery service you created and click on **Manage**. 22 | 23 | If you deployed your own Discovery service or are running it locally, you can also access the UI by going to the deployed application's URL. 24 | 25 | You can now move on to [Creating the Circuit Breaker Dashboard](lab_circuitbreaker.md) 26 | -------------------------------------------------------------------------------- /analytics-scdf-sink/src/main/java/io/pivotal/analytics/configuration/SinkConfiguration.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.configuration; 2 | 3 | import io.pivotal.analytics.entity.Trade; 4 | import io.pivotal.analytics.repository.TradeRepository; 5 | import org.apache.commons.logging.Log; 6 | import org.apache.commons.logging.LogFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.cloud.stream.annotation.EnableBinding; 9 | import org.springframework.cloud.stream.messaging.Sink; 10 | import org.springframework.integration.annotation.ServiceActivator; 11 | import org.springframework.util.LinkedCaseInsensitiveMap; 12 | import org.springframework.util.StringUtils; 13 | 14 | import java.math.BigDecimal; 15 | import java.text.ParseException; 16 | import java.text.SimpleDateFormat; 17 | import java.util.Date; 18 | 19 | @EnableBinding(Sink.class) 20 | public class SinkConfiguration { 21 | private static final Log logger = LogFactory.getLog(SinkConfiguration.class); 22 | 23 | @Autowired 24 | TradeRepository tradeRepository; 25 | 26 | @ServiceActivator(inputChannel=Sink.INPUT) 27 | public void loggerSink(Trade trade) { 28 | 29 | // sample input message {orderid=32772, accountid=1, completiondate=2018-06-25 18:37:00.0, currency=USD, orderfee=10.50, ordertype=0, price=24.80, quantity=15, symbol=PVTL, userid=nfoles, tag=null} 30 | 31 | logger.info("found order: " + trade.toString()); 32 | 33 | // date format; 2018-06-25 18:37:00.0 34 | 35 | tradeRepository.save(trade); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/portfolio.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Spring Trader - Portfolio 7 |
8 | 9 | 10 | 11 | 12 | 15 | 16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | 24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 32 |
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /zipkin-server/src/main/java/zipkin/server/ZipkinServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin.server; 15 | 16 | import org.springframework.boot.autoconfigure.SpringBootApplication; 17 | import org.springframework.boot.builder.SpringApplicationBuilder; 18 | import zipkin2.server.internal.EnableZipkinServer; 19 | import zipkin2.server.internal.RegisterZipkinHealthIndicators; 20 | 21 | @SpringBootApplication 22 | @EnableZipkinServer 23 | public class ZipkinServer { 24 | static { 25 | // Make sure java.util.logging goes to log4j2 26 | // https://docs.spring.io/spring-boot/docs/current/reference/html/howto-logging.html#howto-configure-log4j-for-logging 27 | System.setProperty("java.util.logging.manager", "org.apache.logging.log4j.jul.LogManager"); 28 | } 29 | 30 | public static void main(String[] args) { 31 | new SpringApplicationBuilder(ZipkinServer.class) 32 | .listeners(new RegisterZipkinHealthIndicators()) 33 | .properties("spring.config.name=zipkin-server").run(args); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /docs/lab_local.md: -------------------------------------------------------------------------------- 1 | # Running Pivotal Bank Locally 2 | 3 | You can run pivotal bank locally and get full functionality with some modified circuit breaker dashboard experience. 4 | The **key** is ensuring that each of the dependencies are running. 5 | 6 | ## Common Dependencies 7 | 8 | All services depend on a config server and discovery server. Run the following commands in separate terminal windows. 9 | The discovery server has configurations specific for running locally 10 | 11 | 1. Config Server (runs on localhost:8888) 12 | You can test it out by accessing http://localhost:8888/quotes-service/local. The configuration 13 | of this config server watches the local file system where cf-SpringBootTRADER-config is. So to have your changes 14 | take affect, you only have to edit the file. No need to commit if you are just playing around. 15 | ```bash 16 | cd configServer 17 | ./gradlew bootRun 18 | ``` 19 | 20 | 2. Discovery Server (runs on localhost:8761) 21 | You can test it out by accessing http://localhost:8761/ 22 | ```bash 23 | cd configServer 24 | ./gradlew bootRun 25 | 26 | ``` 27 | 28 | ## Services 29 | In order to run the services, you will need to launch the following in separate terminal windows 30 | ``` 31 | cd 32 | SPRING_PROFILES_ACTIVE=local ./gradlew bootRun 33 | ``` 34 | Use the following for dependencies: 35 | - quotes: http://localhost:8083 , no dependencies 36 | - accounts: http://localhost:8082 , no dependencies 37 | - user: http://localhost:8084 , no dependencies 38 | - portfolio: http://localhost:8081 , depends on quotes and accounts 39 | - web: http://localhost:8080 , depends on portfolio, users, quotes, and accounts -------------------------------------------------------------------------------- /e2e-tests/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | io.pivotal.pivotalbank 7 | e2e-tests 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | 12 | org.springframework.boot 13 | spring-boot-starter-parent 14 | 2.0.3.RELEASE 15 | 16 | 17 | 18 | 19 | UTF-8 20 | UTF-8 21 | 1.8 22 | 23 | 24 | 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-test 29 | test 30 | 31 | 32 | 33 | com.jayway.restassured 34 | rest-assured 35 | 2.9.0 36 | test 37 | 38 | 39 | 40 | com.github.javafaker 41 | javafaker 42 | 0.15 43 | test 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /zipkin-server/src/it/execjar/src/test/java/zipkin/execjar/DoesntCrashWhenKafkaBrokerIsDownTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin.execjar; 15 | 16 | import java.io.IOException; 17 | import java.net.HttpURLConnection; 18 | import java.net.URI; 19 | import org.junit.Rule; 20 | import org.junit.Test; 21 | 22 | import static org.junit.Assert.assertEquals; 23 | import static org.junit.Assert.fail; 24 | 25 | public class DoesntCrashWhenKafkaBrokerIsDownTest { 26 | 27 | @Rule 28 | public ExecJarRule zipkin = new ExecJarRule() 29 | .putEnvironment("KAFKA_BOOTSTRAP_SERVERS", "idontexist"); 30 | 31 | @Test 32 | public void startsButReturnsFailedHealthCheck() { 33 | try { 34 | HttpURLConnection connection = (HttpURLConnection) 35 | URI.create("http://localhost:" + zipkin.port() + "/health").toURL() 36 | .openConnection(); 37 | 38 | assertEquals(503, connection.getResponseCode()); 39 | } catch (RuntimeException | IOException e) { 40 | fail(String.format("unexpected error!%s%n%s", e.getMessage(), zipkin.consoleOutput())); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /docs/lab_scale.md: -------------------------------------------------------------------------------- 1 | # Scaling the services. 2 | Within **Cloud Foundry** the concept of scalability can mean different things: 3 | - scaling the amount of resources available to the platform to run applications instances - as well as other platform components - [Scaling CF](http://docs.pivotal.io/pivotalcf/concepts/high-availability.html). 4 | - increasing memory of each application instance ([vertical scaling](http://docs.pivotal.io/pivotalcf/devguide/deploy-apps/cf-scale.html#vertical)). 5 | - horizontally scaling the application ([horizontal scaling](http://docs.pivotal.io/pivotalcf/devguide/deploy-apps/cf-scale.html#horizontal)). 6 | 7 | One of the benefits of a micro service architecture is that each service can be scaled independently. This means that if the quote service is under stress (CPU,memory), it can be scaled up independently from the other services. The platform will automatically load balance the requests across the available instances. 8 | 9 | ### Exercise 10 | 1. Scale the Quote service to two instances using either the UI or the CLI. 11 | 12 | 2. Monitor the logs of the quote service application, either via the [CLI](http://docs.pivotal.io/pivotalcf/devguide/deploy-apps/streaming-logs.html#view) or the UI. 13 | 14 | 3. Use the REST api of the quote service to retrieve quotes, for example: 15 | 16 | `curl http:///v1/quotes?q=EMC` 17 | 18 | or put the URL in your browser window. 19 | 20 | How do the logs show which instance of the application is actually servicing the request? 21 | 22 | How far can you scale the quote service? what is the limitation? 23 | 24 | # Summary 25 | 26 | What happened in the registry server when you scale up? 27 | 28 | Move on to the [next lab](lab_bluegreen.md) 29 | -------------------------------------------------------------------------------- /docs/lab_spring_cloud_gateway.md: -------------------------------------------------------------------------------- 1 | # Spring Cloud Gateway 2 | [Spring Cloud Gateway](https://cloud.spring.io/spring-cloud-gateway/) provides simple and effective ways to route to your api 3 | and provide facility for cross cutting concerns. 4 | 5 | In this lab, we will deploy an gateway in front of our various microservice apis. This provides a consistent entry point 6 | for the api. Then we will run an automated end to end test that targets the gateway. 7 | 8 | # Build and Deploy the Gateway 9 | You can explore the code of the gateway-service. You will notice that it is very light. It includes dependencies for 10 | actuator, zipkin, and spring cloud services just like our other microservices. The primary dependency is the 11 | spring-cloud-starter-gateway which includes the key components of the gateway. The code simply defines our application 12 | and includes security configuration to expose the actuator endpoints. 13 | 14 | The gateway configuration is stored in our configuration git repo identifying each route, it's downstream target, 15 | its predicate and filter. Here we refer to the downstream target using the logical identifier of managed by the 16 | discovery server. Spring Cloud Gateway is quite extensible and additional filters could be added. 17 | 18 | ``` 19 | cd gateway-service 20 | ./gradlew build 21 | cf push 22 | ``` 23 | 24 | Copy the generated URL for the gateway service for use in the end to end tests. 25 | 26 | # Run the end to end tests 27 | An end 2 end test suite exists at /e2e-tests/. This runs junit tests targeting the application gateway and exercise 28 | each of the microservices behind the gateway. 29 | 30 | ``` 31 | cd e2e-tests 32 | APPLICATION_URL= mvn verify 33 | 34 | ``` 35 | -------------------------------------------------------------------------------- /zipkin-server/src/it/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 17 | 18 | 19 | 20 | it-repo 21 | 22 | true 23 | 24 | 25 | 26 | local.central 27 | @localRepositoryUrl@ 28 | 29 | true 30 | 31 | 32 | true 33 | 34 | 35 | 36 | 37 | 38 | local.central 39 | @localRepositoryUrl@ 40 | 41 | true 42 | 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /quotes-service/src/main/java/io/pivotal/quotes/domain/QuoteMapper.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package io.pivotal.quotes.domain; 5 | 6 | import java.util.Date; 7 | 8 | /** 9 | * Singleton Class to map between quote objects as returned by different public quotes URLS 10 | * 11 | * @author Sufyaan Kazi 12 | */ 13 | public class QuoteMapper { 14 | public static QuoteMapper INSTANCE = new QuoteMapper(); 15 | 16 | private QuoteMapper() { 17 | super(); 18 | } 19 | 20 | public Quote mapFromIexQuote(IexQuote iexQuote) { 21 | if (iexQuote == null) { 22 | return null; 23 | } 24 | 25 | Quote mappedQuote = new Quote(); 26 | mappedQuote.setSymbol(iexQuote.getSymbol()); 27 | mappedQuote.setName(iexQuote.getCompanyName()); 28 | mappedQuote.setOpen(iexQuote.getOpen()); 29 | mappedQuote.setHigh(iexQuote.getHigh()); 30 | mappedQuote.setLow(iexQuote.getLow()); 31 | mappedQuote.setChange(iexQuote.getChange()); 32 | mappedQuote.setChangePercent(iexQuote.getChangePercent().floatValue()); 33 | mappedQuote.setMarketCap(iexQuote.getMarketCap().floatValue()); 34 | if ("Previous close".equals(iexQuote.getLatestSource())) { 35 | mappedQuote.setLastPrice(iexQuote.getClose()); 36 | mappedQuote.setTimestamp(new Date(iexQuote.getCloseTime())); 37 | } else { 38 | mappedQuote.setLastPrice(iexQuote.getLatestPrice()); 39 | mappedQuote.setTimestamp(new Date(iexQuote.getLatestUpdate())); 40 | } 41 | mappedQuote.setStatus("SUCCESS"); 42 | mappedQuote.setVolume((int) Math.round(iexQuote.getAvgTotalVolume().doubleValue())); 43 | 44 | return mappedQuote; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /analytics-service/src/main/java/io/pivotal/analytics/controller/AnalyticsController.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.controller; 2 | 3 | import io.pivotal.analytics.entity.Trade; 4 | import io.pivotal.analytics.service.AnalyticsService; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpHeaders; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.http.ResponseEntity; 11 | import org.springframework.web.bind.annotation.PathVariable; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import java.util.List; 17 | 18 | @RestController 19 | public class AnalyticsController { 20 | 21 | private static final Logger logger = LoggerFactory 22 | .getLogger(AnalyticsController.class); 23 | 24 | @Autowired 25 | private AnalyticsService service; 26 | 27 | @RequestMapping(value = "/analytics/trades/{symbol}", method = RequestMethod.GET) 28 | public ResponseEntity> getTrades(@PathVariable("symbol") final String symbol) { 29 | 30 | logger.debug("AnalyticsController: Retrieving trades for symbol:" + symbol); 31 | List trades = service.getTrades(symbol); 32 | logger.debug("AnalyticsController: Retrieved trades for symbol:" + symbol); 33 | return new ResponseEntity>(trades, getNoCacheHeaders(), HttpStatus.OK); 34 | 35 | } 36 | 37 | private HttpHeaders getNoCacheHeaders() { 38 | HttpHeaders responseHeaders = new HttpHeaders(); 39 | responseHeaders.set("Cache-Control", "no-cache"); 40 | return responseHeaders; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /quotes-service/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.3.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'eclipse' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | bootJar { 19 | baseName = 'quotes' 20 | version = "" // omit the version from the war file name 21 | } 22 | 23 | description = "Micro-service to retrieve up to date quotes" 24 | sourceCompatibility = 1.8 25 | targetCompatibility = 1.8 26 | 27 | repositories { 28 | mavenCentral() 29 | } 30 | 31 | ext { 32 | springCloudServicesVersion = '2.0.1.RELEASE' 33 | springCloudVersion = 'Finchley.RELEASE' 34 | } 35 | 36 | dependencies { 37 | 38 | compile "org.springframework.boot:spring-boot-starter-web" 39 | compile "org.springframework.boot:spring-boot-starter-actuator" 40 | 41 | compile "org.springframework.cloud:spring-cloud-starter-zipkin" 42 | 43 | compileOnly "org.projectlombok:lombok" 44 | 45 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-config-client" 46 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry" 47 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker" 48 | 49 | testCompile "org.springframework.boot:spring-boot-starter-test" 50 | 51 | } 52 | 53 | dependencyManagement { 54 | imports { 55 | mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}" 56 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 57 | } 58 | } -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/service/AnalyticsService.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.service; 2 | 3 | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 4 | import io.pivotal.web.domain.Quote; 5 | import io.pivotal.web.domain.Trade; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.beans.factory.annotation.Value; 10 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 11 | import org.springframework.cloud.context.config.annotation.RefreshScope; 12 | import org.springframework.stereotype.Service; 13 | import org.springframework.web.client.RestTemplate; 14 | 15 | import java.util.*; 16 | 17 | 18 | @Service 19 | @RefreshScope 20 | public class AnalyticsService { 21 | private static final Logger logger = LoggerFactory 22 | .getLogger(AnalyticsService.class); 23 | 24 | @Autowired 25 | @LoadBalanced 26 | private RestTemplate restTemplate; 27 | 28 | @Value("${pivotal.downstream-protocol:http}") 29 | protected String downstreamProtocol; 30 | 31 | @Value("${pivotal.analyticsService.name}") 32 | private String analyticsService; 33 | 34 | @HystrixCommand(fallbackMethod = "getAnalyticsFallback") 35 | public List getTrades(String symbol) { 36 | logger.debug("Fetching trades: " + symbol); 37 | Trade[] tradesArr = restTemplate.getForObject(downstreamProtocol + "://" + analyticsService + "/analytics/trades/{symbol}", Trade[].class, symbol); 38 | List trades = Arrays.asList(tradesArr); 39 | logger.debug("Found " + trades.size() + " trades"); 40 | return trades; 41 | } 42 | 43 | private List getAnalyticsFallback(String symbol) { 44 | logger.warn("Falling back due to error."); 45 | 46 | return new ArrayList(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /zipkin-server/src/main/java/zipkin2/server/internal/RegisterZipkinHealthIndicators.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin2.server.internal; 15 | 16 | import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 17 | import org.springframework.boot.context.event.ApplicationReadyEvent; 18 | import org.springframework.context.ApplicationEvent; 19 | import org.springframework.context.ApplicationListener; 20 | import zipkin2.Component; 21 | 22 | /** Makes sure all zipkin components end up in the /health endpoint. */ 23 | // This is an application listener to ensure the graph is fully constructed before doing health 24 | public final class RegisterZipkinHealthIndicators implements ApplicationListener { 25 | 26 | @Override 27 | public void onApplicationEvent(ApplicationEvent event) { 28 | if (!(event instanceof ApplicationReadyEvent)) return; 29 | ConfigurableListableBeanFactory beanFactory = 30 | ((ApplicationReadyEvent) event).getApplicationContext().getBeanFactory(); 31 | ZipkinHealthIndicator healthIndicator = beanFactory.getBean(ZipkinHealthIndicator.class); 32 | for (Component component : beanFactory.getBeansOfType(Component.class).values()) { 33 | healthIndicator.addComponent(component); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /user-service/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.3.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'eclipse' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | bootJar { 19 | baseName = 'user' 20 | version = "" 21 | } 22 | 23 | description = "Micro-service to deal with accounts and user logins" 24 | sourceCompatibility = 1.8 25 | targetCompatibility = 1.8 26 | 27 | repositories { 28 | mavenCentral() 29 | } 30 | 31 | ext { 32 | springCloudServicesVersion = '2.0.1.RELEASE' 33 | springCloudVersion = 'Finchley.RELEASE' 34 | } 35 | 36 | dependencies { 37 | 38 | compile "org.springframework.boot:spring-boot-starter-web" 39 | compile "org.springframework.boot:spring-boot-starter-actuator" 40 | compile "org.springframework.boot:spring-boot-starter-data-jpa" 41 | 42 | compile "org.springframework.cloud:spring-cloud-starter-zipkin" 43 | 44 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-config-client" 45 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry" 46 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker" 47 | 48 | runtime "org.hsqldb:hsqldb" 49 | 50 | testCompile "org.springframework.boot:spring-boot-starter-test" 51 | testCompile "junit:junit" 52 | testRuntime "com.jayway.jsonpath:json-path" 53 | 54 | } 55 | 56 | dependencyManagement { 57 | imports { 58 | mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}" 59 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 60 | } 61 | } -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | Spring Trader 8 | 9 |
10 | 11 | 12 | 13 |
14 | 16 |
17 | 19 | 20 |
21 |
22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 |
30 | 31 |
32 |
33 |
34 |
35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /zipkin-server/src/main/java/zipkin/server/EnableZipkinServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin.server; 15 | 16 | import java.lang.annotation.Documented; 17 | import java.lang.annotation.ElementType; 18 | import java.lang.annotation.Retention; 19 | import java.lang.annotation.RetentionPolicy; 20 | import java.lang.annotation.Target; 21 | import org.springframework.context.annotation.Import; 22 | import zipkin2.server.internal.InternalZipkinConfiguration; 23 | 24 | /** 25 | * @deprecated Custom servers are possible, but not supported by the community. Please use our 26 | * default server build first. If you 27 | * find something missing, please gitter us about 28 | * it before making a custom server. 29 | * 30 | *

If you decide to make a custom server, you accept responsibility for troubleshooting your 31 | * build or configuration problems, even if such problems are a reaction to a change made by the 32 | * OpenZipkin maintainers. In other words, custom servers are possible, but not supported. 33 | */ 34 | @Target(ElementType.TYPE) 35 | @Retention(RetentionPolicy.RUNTIME) 36 | @Documented 37 | @Import(InternalZipkinConfiguration.class) 38 | @Deprecated 39 | public @interface EnableZipkinServer { 40 | 41 | } 42 | -------------------------------------------------------------------------------- /portfolio-service/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.3.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'eclipse' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | bootJar { 19 | baseName = 'portfolio' 20 | version = "" // omit the version from the war file name 21 | } 22 | 23 | 24 | description = "Micro-service to manage portfolios" 25 | sourceCompatibility = 1.8 26 | targetCompatibility = 1.8 27 | 28 | repositories { 29 | mavenCentral() 30 | } 31 | 32 | ext { 33 | springCloudServicesVersion = '2.0.1.RELEASE' 34 | springCloudVersion = 'Finchley.RELEASE' 35 | } 36 | 37 | dependencies { 38 | 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | compile "org.springframework.boot:spring-boot-starter-data-jpa" 42 | 43 | compile "org.springframework.cloud:spring-cloud-starter-zipkin" 44 | 45 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-config-client" 46 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry" 47 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker" 48 | 49 | runtime "org.hsqldb:hsqldb" 50 | 51 | testCompile "org.springframework.boot:spring-boot-starter-test" 52 | testCompile "junit:junit" 53 | testRuntime "com.jayway.jsonpath:json-path" 54 | 55 | } 56 | 57 | dependencyManagement { 58 | imports { 59 | mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}" 60 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /web-ui/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.3.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'eclipse' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | bootJar { 19 | baseName = 'web' 20 | version = "" // omit the version from the war file name 21 | } 22 | 23 | description = "Web interface to the springboot set of services" 24 | sourceCompatibility = 1.8 25 | targetCompatibility = 1.8 26 | 27 | repositories { 28 | mavenCentral() 29 | } 30 | 31 | ext { 32 | springCloudServicesVersion = '2.0.1.RELEASE' 33 | springCloudVersion = 'Finchley.RELEASE' 34 | } 35 | 36 | dependencies { 37 | 38 | compile "org.springframework.boot:spring-boot-starter-web" 39 | compile "org.springframework.boot:spring-boot-starter-actuator" 40 | compile "org.springframework.boot:spring-boot-starter-thymeleaf" 41 | compile "org.springframework.boot:spring-boot-starter-security" 42 | compile "org.thymeleaf.extras:thymeleaf-extras-springsecurity4" 43 | 44 | compile "org.springframework.cloud:spring-cloud-starter-zipkin" 45 | 46 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-config-client" 47 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry" 48 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker" 49 | 50 | testCompile "org.springframework.boot:spring-boot-starter-test" 51 | testCompile "junit:junit" 52 | 53 | } 54 | 55 | dependencyManagement { 56 | imports { 57 | mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}" 58 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 59 | } 60 | } -------------------------------------------------------------------------------- /accounts-service/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.3.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'eclipse' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | bootJar { 19 | baseName = 'accounts' 20 | version = "" // omit the version from the war file name 21 | } 22 | 23 | description = "Micro-service to deal with accounts and user logins" 24 | sourceCompatibility = 1.8 25 | targetCompatibility = 1.8 26 | 27 | repositories { 28 | mavenCentral() 29 | } 30 | 31 | ext { 32 | springCloudServicesVersion = '2.0.1.RELEASE' 33 | springCloudVersion = 'Finchley.RELEASE' 34 | } 35 | 36 | dependencies { 37 | 38 | compile "org.springframework.boot:spring-boot-starter-web" 39 | compile "org.springframework.boot:spring-boot-starter-actuator" 40 | compile "org.springframework.boot:spring-boot-starter-data-jpa" 41 | 42 | compile "org.springframework.cloud:spring-cloud-starter-zipkin" 43 | 44 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-config-client" 45 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry" 46 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker" 47 | 48 | runtime "org.hsqldb:hsqldb" 49 | 50 | testCompile "org.springframework.boot:spring-boot-starter-test" 51 | testCompile "junit:junit" 52 | testRuntime "com.jayway.jsonpath:json-path" 53 | 54 | } 55 | 56 | dependencyManagement { 57 | imports { 58 | mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}" 59 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /analytics-service/src/test/java/io/pivotal/analytics/AnalyticsServiceTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics; 2 | 3 | import io.pivotal.analytics.entity.Trade; 4 | import io.pivotal.analytics.repository.TradeRepository; 5 | import io.pivotal.analytics.service.AnalyticsService; 6 | import org.junit.After; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | 15 | import java.math.BigDecimal; 16 | import java.util.Date; 17 | import java.util.List; 18 | 19 | import static org.hamcrest.MatcherAssert.assertThat; 20 | import static org.hamcrest.Matchers.greaterThan; 21 | 22 | @RunWith(SpringRunner.class) 23 | @SpringBootTest(classes = AnalyticsApplication.class) 24 | public class AnalyticsServiceTest { 25 | 26 | @Autowired 27 | AnalyticsService service; 28 | 29 | @Autowired 30 | private ElasticsearchTemplate esTemplate; 31 | 32 | @Autowired 33 | private TradeRepository repository; 34 | 35 | @Before 36 | public void before() { 37 | esTemplate.deleteIndex(Trade.class); 38 | esTemplate.createIndex(Trade.class); 39 | esTemplate.putMapping(Trade.class); 40 | esTemplate.refresh(Trade.class); 41 | 42 | Trade trade = new Trade(); 43 | trade.setUserid("nfoles"); 44 | trade.setSymbol("PVTL"); 45 | trade.setQuantity(100); 46 | trade.setPrice(BigDecimal.valueOf(24.78)); 47 | trade.setCompletiondate(new Date()); 48 | repository.save(trade); 49 | 50 | } 51 | 52 | @After 53 | public void teardown() { 54 | esTemplate.deleteIndex(Trade.class); 55 | } 56 | 57 | @Test 58 | public void testFindByTitle() { 59 | 60 | List bySymbol = service.getTrades("PVTL"); 61 | assertThat(bySymbol.size(), greaterThan(0)); 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /analytics-scdf-sink/src/main/java/io/pivotal/analytics/configuration/EsConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.configuration; 2 | 3 | import org.elasticsearch.client.Client; 4 | import org.elasticsearch.client.transport.TransportClient; 5 | import org.elasticsearch.common.settings.Settings; 6 | import org.elasticsearch.common.transport.InetSocketTransportAddress; 7 | import org.elasticsearch.transport.client.PreBuiltTransportClient; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | import org.springframework.data.elasticsearch.core.ElasticsearchOperations; 13 | import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 14 | import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; 15 | 16 | import java.net.InetAddress; 17 | 18 | @Configuration 19 | @EnableConfigurationProperties(EsSinkProperties.class) 20 | @EnableElasticsearchRepositories(basePackages = "io.pivotal.analytics.repository") 21 | public class EsConfig { 22 | 23 | 24 | @Autowired 25 | private EsSinkProperties properties; 26 | 27 | 28 | @Bean 29 | public Client client() throws Exception { 30 | 31 | Settings esSettings = Settings.builder() 32 | .put("cluster.name", properties.getClusterName()) 33 | .build(); 34 | 35 | TransportClient client = new PreBuiltTransportClient(esSettings) 36 | .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(properties.getHost()), Integer.parseInt(properties.getPort()))); 37 | 38 | return client; 39 | 40 | } 41 | 42 | @Bean 43 | public ElasticsearchOperations elasticsearchTemplate() throws Exception { 44 | return new ElasticsearchTemplate(client()); 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /quotes-service/src/main/java/io/pivotal/quotes/domain/IexQuote.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.quotes.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.math.BigDecimal; 9 | 10 | @Data 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @JsonIgnoreProperties(ignoreUnknown = true) 14 | public class IexQuote { 15 | private String symbol; 16 | private String companyName; 17 | private String primaryExchange; 18 | private String calculationPrice; 19 | private BigDecimal open; 20 | private Long openTime; 21 | private BigDecimal close; 22 | private Long closeTime; 23 | private BigDecimal high; 24 | private BigDecimal low; 25 | private BigDecimal latestPrice; 26 | private String latestSource; 27 | private String latestTime; 28 | private Long latestUpdate; 29 | private BigDecimal latestVolume; 30 | private BigDecimal iexRealtimePrice; 31 | private String iexRealtimeSize; 32 | private String iexLastUpdated; 33 | private BigDecimal delayedPrice; 34 | private Long delayedPriceTime; 35 | private String extendedPrice; 36 | private String extendedChange; 37 | private BigDecimal extendedChangePercent; 38 | private Long extendedPriceTime; 39 | private String previousClose; 40 | private BigDecimal previousVolume; 41 | private BigDecimal change; 42 | private BigDecimal changePercent; 43 | private String volume; 44 | private BigDecimal iexMarketPercent; 45 | private String iexVolume; 46 | private BigDecimal avgTotalVolume; 47 | private BigDecimal iexBidPrice; 48 | private String iexBidSize; 49 | private BigDecimal iexAskPrice; 50 | private String iexAskSize; 51 | private BigDecimal marketCap; 52 | private String peRatio; 53 | private BigDecimal week52High; 54 | private BigDecimal week52Low; 55 | private BigDecimal ytdChange; 56 | private Long lastTradeTime; 57 | private String isUSMarketOpen; 58 | } -------------------------------------------------------------------------------- /analytics-service/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.3.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 10 | } 11 | } 12 | 13 | apply plugin: 'java' 14 | apply plugin: 'eclipse' 15 | apply plugin: 'org.springframework.boot' 16 | apply plugin: 'io.spring.dependency-management' 17 | 18 | bootJar { 19 | baseName = 'analytics' 20 | version = "" // omit the version from the war file name 21 | } 22 | 23 | description = "Micro-service to access analytics" 24 | sourceCompatibility = 1.8 25 | targetCompatibility = 1.8 26 | 27 | repositories { 28 | mavenCentral() 29 | } 30 | 31 | ext { 32 | springCloudServicesVersion = '2.0.1.RELEASE' 33 | springCloudVersion = 'Finchley.RELEASE' 34 | elasticsearchVersion = "5.6.4" 35 | } 36 | ext['elasticsearch.version'] = '5.6.4' 37 | 38 | 39 | dependencies { 40 | 41 | compile "org.springframework.boot:spring-boot-starter-web" 42 | compile "org.springframework.boot:spring-boot-starter-actuator" 43 | compile "org.springframework.boot:spring-boot-starter-data-elasticsearch" 44 | 45 | compile("org.elasticsearch.client:transport:${elasticsearchVersion}") { 46 | exclude group: "commons-logging", module: "commons-logging" 47 | } 48 | 49 | compile "org.springframework.cloud:spring-cloud-starter-zipkin" 50 | 51 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-config-client" 52 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry" 53 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker" 54 | 55 | testCompile "org.springframework.boot:spring-boot-starter-test" 56 | 57 | } 58 | 59 | dependencyManagement { 60 | imports { 61 | mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}" 62 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /zipkin-server/src/main/java/zipkin2/server/internal/ZipkinHealthIndicator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin2.server.internal; 15 | 16 | import org.springframework.boot.actuate.health.CompositeHealthIndicator; 17 | import org.springframework.boot.actuate.health.Health; 18 | import org.springframework.boot.actuate.health.HealthAggregator; 19 | import org.springframework.boot.actuate.health.HealthIndicator; 20 | import zipkin2.CheckResult; 21 | import zipkin2.Component; 22 | 23 | final class ZipkinHealthIndicator extends CompositeHealthIndicator { 24 | 25 | ZipkinHealthIndicator(HealthAggregator healthAggregator) { 26 | super(healthAggregator); 27 | } 28 | 29 | void addComponent(Component component) { 30 | String healthName = component.getClass().getSimpleName(); 31 | healthName = healthName.replace("AutoValue_", ""); 32 | addHealthIndicator(healthName, new ComponentHealthIndicator(component)); 33 | } 34 | 35 | static final class ComponentHealthIndicator implements HealthIndicator { 36 | final Component component; 37 | 38 | ComponentHealthIndicator(Component component) { 39 | this.component = component; 40 | } 41 | 42 | /** synchronized to prevent overlapping requests to a storage backend */ 43 | @Override 44 | public synchronized Health health() { 45 | CheckResult result = component.check(); 46 | return result.ok() ? Health.up().build() : Health.down((Exception) result.error()).build(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /gateway-service/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext { 3 | springBootVersion = '2.0.4.RELEASE' 4 | } 5 | repositories { 6 | mavenCentral() 7 | maven { url "https://repo.spring.io/snapshot" } 8 | maven { url "https://repo.spring.io/milestone" } 9 | } 10 | dependencies { 11 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") 12 | } 13 | } 14 | 15 | apply plugin: 'java' 16 | apply plugin: 'eclipse' 17 | apply plugin: 'org.springframework.boot' 18 | apply plugin: 'io.spring.dependency-management' 19 | 20 | bootJar { 21 | baseName = 'gateway' 22 | version = "" // omit the version from the jar file name 23 | } 24 | 25 | sourceCompatibility = 1.8 26 | 27 | repositories { 28 | mavenCentral() 29 | maven { url "https://repo.spring.io/snapshot" } 30 | maven { url "https://repo.spring.io/milestone" } 31 | } 32 | 33 | ext { 34 | springCloudServicesVersion = '2.0.1.RELEASE' 35 | springCloudVersion = 'Finchley.RELEASE' 36 | } 37 | 38 | dependencies { 39 | 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // 2.0.1 has not been released yet and has a fix to be able handle processing downstream responses that don't set content type 43 | compile('org.springframework.cloud:spring-cloud-starter-gateway') { 44 | exclude group: "org.springframework.cloud", module: "spring-cloud-gateway-core" 45 | } 46 | compile('org.springframework.cloud:spring-cloud-gateway-core:2.0.1.BUILD-SNAPSHOT') 47 | 48 | compile "org.springframework.cloud:spring-cloud-starter-zipkin" 49 | 50 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-config-client" 51 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-service-registry" 52 | compile "io.pivotal.spring.cloud:spring-cloud-services-starter-circuit-breaker" 53 | 54 | testCompile('org.springframework.boot:spring-boot-starter-test') 55 | 56 | } 57 | 58 | dependencyManagement { 59 | imports { 60 | mavenBom "io.pivotal.spring.cloud:spring-cloud-services-dependencies:${springCloudServicesVersion}" 61 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /docs/lab_c2c_networking.md: -------------------------------------------------------------------------------- 1 | # Container to Container Networking and SCS Discovery Server 2 | 3 | ## Background 4 | By default, apps register themselves with the discovery server based upon their route URI and port. 5 | This means that any service to service communication is going to leave the foundation and go back in through 6 | the go router. In order to leverage container to container networking you must do two things. 7 | 8 | 1. Specify registration method for the app to be [direct](http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html#register-using-c2c), 9 | instead of the default `route`. 10 | 11 | ``` 12 | spring.cloud.services.registrationMethod = direct 13 | ``` 14 | 15 | 2. [Add a networking policy](http://docs.pivotal.io/spring-cloud-services/1-5/common/service-registry/writing-client-applications.html#consume-using-c2c) 16 | to allow access from the calling app to the registered app 17 | 18 | ``` 19 | cf add-network-policy gateway --destination-app quotes 20 | ``` 21 | 22 | ## Prerequisites 23 | This lab leverages the spring cloud gateway. Setup the gateway first following the [gateway lab](lab_spring_cloud_gateway.md). 24 | 25 | ## Lab 26 | 1. Update the registrationMethod configuration for quotes service by editing quotes-services-cloud.yml and pushing your commit 27 | 28 | 2. Restart quotes service 29 | ``` 30 | cf restart quotes 31 | ``` 32 | 3. View the discover service's management page and notice that the quote-service URL is an IP address, while the others are the route. 33 | 34 | 4. Access the quote service through the gateway 35 | ``` 36 | http /quotes/v1/quotes?q=PVTL 37 | ``` 38 | Notice that the request fails with 500 error. If you looked at the gateway logs, it would say it could not make a connection 39 | 40 | 5. Apply the network policy 41 | >Note: your user account must have network.admin or network.write scopes within UAA 42 | ``` 43 | cf add-network-policy gateway --destination-app quotes 44 | ``` 45 | 46 | 6. Retest the quote service through the gateway 47 | ``` 48 | http /quotes/v1/quotes?q=PVTL 49 | ``` 50 | Now it is successful! 51 | -------------------------------------------------------------------------------- /zipkin-server/src/test/java/zipkin/server/ITEnableZipkinServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin.server; 15 | 16 | import java.io.IOException; 17 | import okhttp3.OkHttpClient; 18 | import okhttp3.Request; 19 | import okhttp3.Response; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.springframework.beans.factory.annotation.Value; 23 | import org.springframework.boot.autoconfigure.SpringBootApplication; 24 | import org.springframework.boot.test.context.SpringBootTest; 25 | import org.springframework.test.context.junit4.SpringRunner; 26 | 27 | import static org.assertj.core.api.Assertions.assertThat; 28 | 29 | @SpringBootTest( 30 | classes = CustomServer.class, 31 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 32 | properties = "spring.config.name=zipkin-server" 33 | ) 34 | @RunWith(SpringRunner.class) 35 | public class ITEnableZipkinServer { 36 | 37 | @Value("${local.server.port}") int zipkinPort; 38 | 39 | OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build(); 40 | 41 | @Test public void writeSpans_noContentTypeIsJson() throws Exception { 42 | Response response = get("/api/v2/services"); 43 | 44 | assertThat(response.code()) 45 | .isEqualTo(200); 46 | } 47 | 48 | Response get(String path) throws IOException { 49 | return client.newCall(new Request.Builder() 50 | .url("http://localhost:" + zipkinPort + path) 51 | .build()).execute(); 52 | } 53 | } 54 | @SpringBootApplication 55 | @EnableZipkinServer 56 | class CustomServer { 57 | 58 | } 59 | -------------------------------------------------------------------------------- /docs/lab_bluegreen.md: -------------------------------------------------------------------------------- 1 | # Zero downtime deployments. 2 | 3 | One of the benefits of a microservice architecture is the ability to upgrade each service individually. However, for continuous operations, we would like no downtime during the upgrade as well as the ability to test the new version and be able to rollback in case the new version doesn't *cut the mustard*. This can be accomplished with the platform. 4 | 5 | In this lab, you will be mimicking upgrading the quote service. 6 | 7 | ### Exercise 8 | 9 | 1. Rename the existing application. 10 | ``` 11 | cf rename quotes quotes-venerable 12 | ``` 13 | 14 | 2. Push the updated application. 15 | > What happens in the registry service UI after you pushed the application? 16 | 17 | 3. Use the CLI or UI to delete the old version of the quote service whilst making requests on the UI of the application. 18 | 19 | 20 | # Blue/green deployments. 21 | 22 | In the [Creating the discovery service](lab_registryserver.md) lab we discussed an alternative approach for microservices to bind to each other. In this approach, we cannot rely on the registry service to give us the zero downtime deployments. Even in the registry service approach, we may want to upgrade the registry server itself in which case we can employ the Blue/Green deployment technique. 23 | 24 | In order to minimise downtime as new versions of the software is created and released, **Cloud Foundry** provides a technique to deploy these new versions/releases without incurring downtime. This technique is called [Blue/Green deployment](http://docs.pivotal.io/pivotalcf/devguide/deploy-apps/blue-green.html) 25 | 26 | In fact, the technique is very powerful, as it allows multiple versions of the application to be deployed and either serving requests or not serving requests (or even serving requests but not on the production route.) 27 | 28 | The procedure is very simple: 29 | 30 | * push the new version of the application with a new name and a new route. 31 | * test the new version under the new route. 32 | * if successful, bind the old route or production route to the new version. 33 | * unbind the route from the old version. 34 | * the old version can remain running until it is certain a rollback will not be necessary and then removed. 35 | -------------------------------------------------------------------------------- /zipkin-server/src/it/execjar/src/test/java/zipkin/execjar/DoesntCrashWhenCassandraIsDownTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin.execjar; 15 | 16 | import java.io.IOException; 17 | import java.net.HttpURLConnection; 18 | import java.net.URI; 19 | import org.junit.Rule; 20 | import org.junit.Test; 21 | 22 | import static org.junit.Assert.assertEquals; 23 | import static org.junit.Assert.fail; 24 | 25 | public class DoesntCrashWhenCassandraIsDownTest { 26 | 27 | @Rule 28 | public ExecJarRule zipkin = new ExecJarRule() 29 | .putEnvironment("STORAGE_TYPE", "cassandra") 30 | .putEnvironment("CASSANDRA_CONTACT_POINTS", "idontexist"); 31 | 32 | @Test 33 | public void startsButReturns500QueryingStorage() { 34 | try { 35 | HttpURLConnection connection = (HttpURLConnection) 36 | URI.create("http://localhost:" + zipkin.port() + "/api/v2/services").toURL() 37 | .openConnection(); 38 | 39 | assertEquals(500, connection.getResponseCode()); 40 | } catch (RuntimeException | IOException e) { 41 | fail(String.format("unexpected error!%s%n%s", e.getMessage(), zipkin.consoleOutput())); 42 | } 43 | } 44 | 45 | @Test 46 | public void startsButReturnsFailedHealthCheck() { 47 | try { 48 | HttpURLConnection connection = (HttpURLConnection) 49 | URI.create("http://localhost:" + zipkin.port() + "/health").toURL() 50 | .openConnection(); 51 | 52 | assertEquals(503, connection.getResponseCode()); 53 | } catch (RuntimeException | IOException e) { 54 | fail(String.format("unexpected error!%s%n%s", e.getMessage(), zipkin.consoleOutput())); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/security/CustomAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.security; 2 | 3 | import io.pivotal.web.domain.AuthenticationRequest; 4 | import io.pivotal.web.service.UserService; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.security.authentication.AuthenticationProvider; 12 | import org.springframework.security.authentication.BadCredentialsException; 13 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 14 | import org.springframework.security.core.Authentication; 15 | import org.springframework.security.core.AuthenticationException; 16 | import org.springframework.security.core.GrantedAuthority; 17 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 18 | import org.springframework.stereotype.Component; 19 | import org.springframework.web.client.HttpServerErrorException; 20 | 21 | @Component 22 | public class CustomAuthenticationProvider implements AuthenticationProvider { 23 | 24 | @Autowired 25 | private UserService service; 26 | 27 | @Override 28 | public Authentication authenticate(Authentication authentication) 29 | throws AuthenticationException { 30 | String name = authentication.getName(); 31 | String password = authentication.getCredentials().toString(); 32 | AuthenticationRequest request = new AuthenticationRequest(); 33 | request.setUsername(name); 34 | request.setPassword(password); 35 | try { 36 | Map params = service.login(request); 37 | if (params != null) { 38 | List grantedAuths = new ArrayList<>(); 39 | grantedAuths.add(new SimpleGrantedAuthority("USER")); 40 | Authentication auth = new UsernamePasswordAuthenticationToken( 41 | name, password, grantedAuths); 42 | return auth; 43 | } else { 44 | throw new BadCredentialsException("Username not found"); 45 | } 46 | } catch (HttpServerErrorException e) { 47 | throw new BadCredentialsException("Login failed!"); 48 | } 49 | } 50 | 51 | @Override 52 | public boolean supports(Class authentication) { 53 | return authentication.equals(UsernamePasswordAuthenticationToken.class); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /web-ui/src/main/resources/templates/fragments/analytics_fragment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

5 |
6 |
7 |
9 |
10 | 12 |
13 |   14 | 15 |
16 |
17 |
18 |
19 | 20 | 21 |
22 |
23 |
24 |
25 |

List of Trades Matching Symbol

26 |
27 |
28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 |
Order IdSymbolQuantityPriceCompletion DateUser IdAccount Id
orderidsymbolquantitypricecompletiondateuseridaccountid
53 |
54 |
55 |
56 |
57 |
58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /analytics-scdf-sink/src/test/java/io/pivotal/analytics/TradeServiceTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics; 2 | 3 | import io.pivotal.analytics.Application; 4 | import io.pivotal.analytics.entity.Trade; 5 | import org.junit.After; 6 | import org.junit.Before; 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 12 | import org.springframework.test.context.TestPropertySource; 13 | import org.springframework.test.context.junit4.SpringRunner; 14 | import io.pivotal.analytics.repository.TradeRepository; 15 | 16 | import java.math.BigDecimal; 17 | 18 | import static org.hamcrest.CoreMatchers.equalTo; 19 | import static org.hamcrest.CoreMatchers.is; 20 | import static org.hamcrest.MatcherAssert.assertThat; 21 | import static org.junit.Assert.assertNotNull; 22 | import static org.junit.Assert.assertNull; 23 | 24 | @RunWith(SpringRunner.class) 25 | @SpringBootTest(classes = Application.class) 26 | @TestPropertySource(locations="classpath:application-test.properties") 27 | public class TradeServiceTest { 28 | 29 | @Autowired 30 | private TradeRepository repository; 31 | 32 | @Autowired 33 | private ElasticsearchTemplate esTemplate; 34 | 35 | @Before 36 | public void before() { 37 | esTemplate.deleteIndex(Trade.class); 38 | esTemplate.createIndex(Trade.class); 39 | esTemplate.putMapping(Trade.class); 40 | esTemplate.refresh(Trade.class); 41 | } 42 | 43 | @After 44 | public void tearDown() throws Exception { 45 | esTemplate.deleteIndex(Trade.class); 46 | } 47 | 48 | @Test 49 | public void testSave() { 50 | 51 | Trade trade = new Trade(); 52 | trade.setOrderid(1); 53 | trade.setPrice(BigDecimal.valueOf(31.21)); 54 | trade.setSymbol("MS"); 55 | Trade testTrade = repository.save(trade); 56 | 57 | assertNotNull(testTrade.getId()); 58 | assertThat(testTrade.getOrderid(), equalTo(trade.getOrderid())); 59 | assertThat(testTrade.getSymbol(), equalTo(trade.getSymbol())); 60 | assertThat(testTrade.getPrice(), equalTo(trade.getPrice())); 61 | 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/domain/CompanyInfo.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * Represents company information. 7 | * 8 | * @author dpinto 9 | * 10 | */ 11 | public class CompanyInfo { 12 | /* 13 | * { 14 | "Symbol":"NFLX", 15 | "Name":"Netflix Inc", 16 | "Exchange":"NASDAQ" 17 | } 18 | */ 19 | @JsonProperty("Symbol") 20 | private String symbol; 21 | @JsonProperty("Name") 22 | private String name; 23 | @JsonProperty("Exchange") 24 | private String exchange; 25 | 26 | public String getSymbol() { 27 | return symbol; 28 | } 29 | public void setSymbol(String symbol) { 30 | this.symbol = symbol; 31 | } 32 | public String getName() { 33 | return name; 34 | } 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | public String getExchange() { 39 | return exchange; 40 | } 41 | public void setExchange(String exchange) { 42 | this.exchange = exchange; 43 | } 44 | @Override 45 | public String toString() { 46 | StringBuilder builder = new StringBuilder(); 47 | builder.append("CompanyInfo [symbol=").append(symbol).append(", name=") 48 | .append(name).append(", exchange=").append(exchange) 49 | .append("]"); 50 | return builder.toString(); 51 | } 52 | @Override 53 | public int hashCode() { 54 | final int prime = 31; 55 | int result = 1; 56 | result = prime * result 57 | + ((exchange == null) ? 0 : exchange.hashCode()); 58 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 59 | result = prime * result + ((symbol == null) ? 0 : symbol.hashCode()); 60 | return result; 61 | } 62 | @Override 63 | public boolean equals(Object obj) { 64 | if (this == obj) 65 | return true; 66 | if (obj == null) 67 | return false; 68 | if (getClass() != obj.getClass()) 69 | return false; 70 | CompanyInfo other = (CompanyInfo) obj; 71 | if (exchange == null) { 72 | if (other.exchange != null) 73 | return false; 74 | } else if (!exchange.equals(other.exchange)) 75 | return false; 76 | if (name == null) { 77 | if (other.name != null) 78 | return false; 79 | } else if (!name.equals(other.name)) 80 | return false; 81 | if (symbol == null) { 82 | if (other.symbol != null) 83 | return false; 84 | } else if (!symbol.equals(other.symbol)) 85 | return false; 86 | return true; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /analytics-service/src/main/java/io/pivotal/analytics/config/EsConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.analytics.config; 2 | 3 | import org.elasticsearch.client.Client; 4 | import org.elasticsearch.client.transport.TransportClient; 5 | import org.elasticsearch.common.settings.Settings; 6 | import org.elasticsearch.common.transport.InetSocketTransportAddress; 7 | import org.springframework.boot.context.properties.ConfigurationProperties; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.data.elasticsearch.core.ElasticsearchOperations; 11 | import org.elasticsearch.transport.client.PreBuiltTransportClient; 12 | import org.springframework.data.elasticsearch.core.ElasticsearchTemplate; 13 | import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories; 14 | 15 | import java.net.InetAddress; 16 | 17 | @Configuration 18 | @ConfigurationProperties("vcap.services.es.credentials") 19 | @EnableElasticsearchRepositories(basePackages = "io.pivotal.analytics.repository") 20 | public class EsConfig { 21 | 22 | private String host; 23 | 24 | public String getHost() { 25 | return host; 26 | } 27 | 28 | public void setHost(String host) { 29 | this.host = host; 30 | } 31 | 32 | public int getPort() { 33 | return port; 34 | } 35 | 36 | public void setPort(int port) { 37 | this.port = port; 38 | } 39 | 40 | public String getClusterName() { 41 | return clusterName; 42 | } 43 | 44 | public void setClusterName(String clusterName) { 45 | this.clusterName = clusterName; 46 | } 47 | 48 | private int port; 49 | 50 | private String clusterName; 51 | 52 | @Bean 53 | public Client client() throws Exception { 54 | 55 | Settings esSettings = Settings.builder() 56 | .put("cluster.name", clusterName) 57 | .build(); 58 | 59 | TransportClient client = new PreBuiltTransportClient(esSettings) 60 | .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), port)); 61 | 62 | return client; 63 | 64 | } 65 | 66 | @Bean 67 | public ElasticsearchOperations elasticsearchTemplate() throws Exception { 68 | return new ElasticsearchTemplate(client()); 69 | } 70 | 71 | } -------------------------------------------------------------------------------- /zipkin-server/src/test/java/zipkin2/server/internal/ITZipkinServerQueryDisabled.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin2.server.internal; 15 | 16 | import java.io.IOException; 17 | import okhttp3.OkHttpClient; 18 | import okhttp3.Request; 19 | import okhttp3.Response; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.springframework.beans.factory.annotation.Value; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | import org.springframework.test.context.junit4.SpringRunner; 25 | import zipkin.server.ZipkinServer; 26 | 27 | import static org.assertj.core.api.Assertions.assertThat; 28 | 29 | /** 30 | * Collector-only builds should be able to disable the query (and indirectly the UI), so that 31 | * associated assets 404 vs throw exceptions. 32 | */ 33 | @SpringBootTest( 34 | classes = ZipkinServer.class, 35 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 36 | properties = { 37 | "spring.config.name=zipkin-server", 38 | "zipkin.query.enabled=false", 39 | "zipkin.ui.enabled=false" 40 | } 41 | ) 42 | @RunWith(SpringRunner.class) 43 | public class ITZipkinServerQueryDisabled { 44 | @Value("${local.server.port}") int zipkinPort; 45 | OkHttpClient client = new OkHttpClient.Builder().followRedirects(false).build(); 46 | 47 | @Test public void queryRelatedEndpoints404() throws Exception { 48 | assertThat(get("/api/v2/traces").code()).isEqualTo(404); 49 | assertThat(get("/index.html").code()).isEqualTo(404); 50 | 51 | // but other endpoints are ok 52 | assertThat(get("/health").isSuccessful()).isTrue(); 53 | } 54 | 55 | private Response get(String path) throws IOException { 56 | return client.newCall(new Request.Builder() 57 | .url("http://localhost:" + zipkinPort + path) 58 | .build()).execute(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /user-service/src/main/java/io/pivotal/user/domain/AuthenticationRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package io.pivotal.user.domain; 17 | 18 | /** 19 | * Represents an authentication request object. 20 | * 21 | * Used to make login requests. 22 | * 23 | * @author David Ferreira Pinto 24 | */ 25 | public class AuthenticationRequest { 26 | private String username; 27 | private String password; 28 | 29 | public String getUsername() { 30 | return username; 31 | } 32 | 33 | public void setUsername(String username) { 34 | this.username = username; 35 | } 36 | 37 | public String getPassword() { 38 | return password; 39 | } 40 | 41 | public void setPassword(String password) { 42 | this.password = password; 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | final int prime = 31; 48 | int result = 1; 49 | result = prime * result + ((password == null) ? 0 : password.hashCode()); 50 | result = prime * result + ((username == null) ? 0 : username.hashCode()); 51 | return result; 52 | } 53 | 54 | @Override 55 | public boolean equals(Object obj) { 56 | if (this == obj) 57 | return true; 58 | if (obj == null) 59 | return false; 60 | if (getClass() != obj.getClass()) 61 | return false; 62 | AuthenticationRequest other = (AuthenticationRequest) obj; 63 | if (password == null) { 64 | if (other.password != null) 65 | return false; 66 | } else if (!password.equals(other.password)) 67 | return false; 68 | if (username == null) { 69 | if (other.username != null) 70 | return false; 71 | } else if (!username.equals(other.username)) 72 | return false; 73 | return true; 74 | } 75 | 76 | @Override 77 | public String toString() { 78 | return "AuthenticationRequest [username=" + username + ", password=" + password + "]"; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /zipkin-server/src/it/execjar/src/test/java/zipkin/execjar/StrictTraceIdFalseTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015-2018 The OpenZipkin Authors 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the License 10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11 | * or implied. See the License for the specific language governing permissions and limitations under 12 | * the License. 13 | */ 14 | package zipkin.execjar; 15 | 16 | import java.io.IOException; 17 | import java.util.Collections; 18 | import okhttp3.MediaType; 19 | import okhttp3.OkHttpClient; 20 | import okhttp3.Request; 21 | import okhttp3.RequestBody; 22 | import okhttp3.Response; 23 | import org.junit.Rule; 24 | import org.junit.Test; 25 | import zipkin2.Endpoint; 26 | import zipkin2.Span; 27 | import zipkin2.codec.SpanBytesDecoder; 28 | import zipkin2.codec.SpanBytesEncoder; 29 | 30 | import static org.junit.Assert.assertEquals; 31 | 32 | public class StrictTraceIdFalseTest { 33 | OkHttpClient client = new OkHttpClient(); 34 | 35 | @Rule 36 | public ExecJarRule zipkin = new ExecJarRule() 37 | .putEnvironment("STRICT_TRACE_ID", "false"); 38 | 39 | @Test 40 | public void canSearchByLower64Bits() throws IOException { 41 | Span span = Span.newBuilder().traceId("463ac35c9f6413ad48485a3953bb6124").id("a") 42 | .name("test-span") 43 | .localEndpoint(Endpoint.newBuilder().serviceName("foo-service").build()) 44 | .addAnnotation(System.currentTimeMillis() * 1000L, "hello").build(); 45 | 46 | byte[] spansInJson = SpanBytesEncoder.JSON_V2.encodeList(Collections.singletonList(span)); 47 | 48 | client.newCall(new Request.Builder() 49 | .url("http://localhost:" + zipkin.port() + "/api/v2/spans") 50 | .post(RequestBody.create(MediaType.parse("application/json"), spansInJson)).build()) 51 | .execute(); 52 | 53 | Response response = client.newCall(new Request.Builder() 54 | .url("http://localhost:" + zipkin.port() + "/api/v2/trace/" + span.traceId()) 55 | .build()).execute(); 56 | 57 | assertEquals(span, SpanBytesDecoder.JSON_V2.decodeList(response.body().bytes()).get(0)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /portfolio-service/src/test/java/io/pivotal/portfolio/service/QuoteRemoteCallServiceTest.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.portfolio.service; 2 | 3 | import io.pivotal.portfolio.PortfolioApplication; 4 | import io.pivotal.portfolio.config.ServiceTestConfiguration; 5 | import io.pivotal.portfolio.domain.Quote; 6 | import org.junit.Before; 7 | import org.junit.Ignore; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.mockito.InjectMocks; 11 | import org.mockito.Mock; 12 | import org.mockito.MockitoAnnotations; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.beans.factory.annotation.Value; 15 | import org.springframework.boot.test.context.SpringBootTest; 16 | import org.springframework.test.context.junit4.SpringRunner; 17 | import org.springframework.web.client.RestTemplate; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertNotEquals; 21 | import static org.mockito.Mockito.when; 22 | 23 | 24 | @RunWith(SpringRunner.class) 25 | @SpringBootTest(classes = PortfolioApplication.class) 26 | public class QuoteRemoteCallServiceTest { 27 | 28 | @Value("${pivotal.quotesService.name}") 29 | private String quotesURI; 30 | 31 | @Autowired 32 | @InjectMocks 33 | QuoteRemoteCallService service; 34 | 35 | @Mock 36 | RestTemplate restTemplate; 37 | 38 | @Before 39 | public void setup() { 40 | MockitoAnnotations.initMocks(this); 41 | } 42 | 43 | /* 44 | * resttemplate not being injected into service thus cannot test success of hystrix 45 | */ 46 | @Test 47 | @Ignore 48 | public void doGetQuote() { 49 | when(restTemplate.getForObject("http://" + quotesURI + "/quote/{symbol}", Quote.class, ServiceTestConfiguration.SYMBOL)).thenReturn(ServiceTestConfiguration.quote()); 50 | Quote quote = service.getQuote(ServiceTestConfiguration.SYMBOL); 51 | assertEquals(ServiceTestConfiguration.quote(),quote); 52 | } 53 | @Test 54 | public void doGetQuoteFailure() { 55 | when(restTemplate.getForObject("http://" + quotesURI + "/quote/{symbol}", Quote.class, ServiceTestConfiguration.SYMBOL)).thenThrow(new RuntimeException("Deliberately throwing an exception 1")); 56 | 57 | Quote quote = service.getQuote(ServiceTestConfiguration.SYMBOL); 58 | assertNotEquals(ServiceTestConfiguration.quote(),quote); 59 | Quote emptyQuote = new Quote(); 60 | emptyQuote.setSymbol(ServiceTestConfiguration.SYMBOL); 61 | emptyQuote.setStatus("FAILED"); 62 | assertEquals(emptyQuote,quote); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/config/WebSecurityConfig.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.config; 2 | 3 | import io.pivotal.web.security.CustomAuthenticationProvider; 4 | import io.pivotal.web.security.CustomCredentialsService; 5 | import io.pivotal.web.security.LogoutSuccessHandler; 6 | 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 11 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 12 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 13 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 14 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 15 | 16 | @Configuration 17 | @EnableWebSecurity 18 | public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 19 | 20 | @Autowired 21 | private CustomCredentialsService customCredentialsService; 22 | 23 | @Autowired 24 | private CustomAuthenticationProvider customAuthenticationProvider; 25 | 26 | @Autowired 27 | private LogoutSuccessHandler logoutSuccessHandler; 28 | 29 | @Override 30 | protected void configure(HttpSecurity http) throws Exception { 31 | http 32 | .authorizeRequests() 33 | .antMatchers("/", "/registration","/hystrix.stream").permitAll() 34 | .requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll() 35 | .anyRequest().authenticated() 36 | .and() 37 | .formLogin() 38 | .loginPage("/login") 39 | .loginProcessingUrl("/login") 40 | .permitAll() 41 | .and() 42 | .logout() 43 | .logoutSuccessHandler(logoutSuccessHandler) 44 | .permitAll(); 45 | } 46 | @Override 47 | public void configure(WebSecurity web) throws Exception { 48 | web 49 | .ignoring() 50 | .antMatchers("/webjars/**") 51 | .antMatchers("/images/**").antMatchers("/css/**").antMatchers("/js/**"); 52 | } 53 | 54 | @Autowired 55 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 56 | auth.authenticationProvider(customAuthenticationProvider); 57 | auth.userDetailsService(customCredentialsService); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /web-ui/src/main/java/io/pivotal/web/service/UserService.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.web.service; 2 | 3 | import java.util.Map; 4 | 5 | import io.pivotal.web.domain.AuthenticationRequest; 6 | import io.pivotal.web.domain.User; 7 | 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 13 | import org.springframework.cloud.context.config.annotation.RefreshScope; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.stereotype.Service; 16 | import org.springframework.web.client.RestTemplate; 17 | 18 | @Service 19 | @RefreshScope 20 | public class UserService { 21 | private static final Logger logger = LoggerFactory 22 | .getLogger(UserService.class); 23 | 24 | @Autowired 25 | @LoadBalanced 26 | private RestTemplate restTemplate; 27 | 28 | @Value("${pivotal.userService.name}") 29 | private String userService; 30 | 31 | @Value("${pivotal.downstream-protocol:http}") 32 | protected String downstreamProtocol; 33 | 34 | public void createUser(User user) { 35 | logger.debug("Creating user with userId: " + user.getUserid()); 36 | logger.debug(user.toString()); 37 | String status = restTemplate.postForObject(downstreamProtocol + "://" + userService + "/users/", user, String.class); 38 | logger.info("Status from registering account for "+ user.getUserid()+ " is " + status); 39 | } 40 | 41 | public Map login(AuthenticationRequest request){ 42 | logger.debug("logging in with userId:" + request.getUsername()); 43 | @SuppressWarnings("unchecked") 44 | Map result = (Map) restTemplate.postForObject(downstreamProtocol + "://" + userService + "/login/".toString(), request, Map.class); 45 | return result; 46 | } 47 | 48 | public User getUser(String user) { 49 | logger.debug("Looking for user with user name: " + user); 50 | 51 | User account = restTemplate.getForObject(downstreamProtocol + "://" + userService + "/users/{user}", User.class, user); 52 | logger.debug("Got user: " + account); 53 | return account; 54 | } 55 | 56 | public void logout(String user) { 57 | logger.debug("logging out user with userId: " + user); 58 | 59 | ResponseEntity response = restTemplate.getForEntity(downstreamProtocol + "://" + userService + "/logout/{user}", String.class, user); 60 | logger.debug("Logout response: " + response.getStatusCode()); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /quotes-service/src/main/java/io/pivotal/quotes/domain/CompanyInfo.java: -------------------------------------------------------------------------------- 1 | package io.pivotal.quotes.domain; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** 6 | * Represents company information. 7 | * 8 | * { 9 | * "Symbol":"NFLX", 10 | * "Name":"Netflix Inc", 11 | * "Exchange":"NASDAQ" 12 | * } 13 | * 14 | * @author David Ferreira Pinto 15 | * 16 | */ 17 | public class CompanyInfo implements Comparable { 18 | 19 | @JsonProperty("Symbol") 20 | private String symbol; 21 | @JsonProperty("Name") 22 | private String name; 23 | @JsonProperty("Exchange") 24 | private String exchange; 25 | 26 | public String getSymbol() { 27 | return symbol; 28 | } 29 | public void setSymbol(String symbol) { 30 | this.symbol = symbol; 31 | } 32 | public String getName() { 33 | return name; 34 | } 35 | public void setName(String name) { 36 | this.name = name; 37 | } 38 | public String getExchange() { 39 | return exchange; 40 | } 41 | public void setExchange(String exchange) { 42 | this.exchange = exchange; 43 | } 44 | @Override 45 | public String toString() { 46 | StringBuilder builder = new StringBuilder(); 47 | builder.append("CompanyInfo [symbol=").append(symbol).append(", name=") 48 | .append(name).append(", exchange=").append(exchange) 49 | .append("]"); 50 | return builder.toString(); 51 | } 52 | @Override 53 | public int compareTo(CompanyInfo o) { 54 | if(o == null){ 55 | return -1; 56 | } 57 | return this.getSymbol().compareTo(o.getSymbol()); 58 | } 59 | @Override 60 | public int hashCode() { 61 | final int prime = 31; 62 | int result = 1; 63 | result = prime * result + ((exchange == null) ? 0 : exchange.hashCode()); 64 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 65 | result = prime * result + ((symbol == null) ? 0 : symbol.hashCode()); 66 | return result; 67 | } 68 | @Override 69 | public boolean equals(Object obj) { 70 | if (this == obj) 71 | return true; 72 | if (obj == null) 73 | return false; 74 | if (getClass() != obj.getClass()) 75 | return false; 76 | CompanyInfo other = (CompanyInfo) obj; 77 | if (exchange == null) { 78 | if (other.exchange != null) 79 | return false; 80 | } else if (!exchange.equals(other.exchange)) 81 | return false; 82 | if (name == null) { 83 | if (other.name != null) 84 | return false; 85 | } else if (!name.equals(other.name)) 86 | return false; 87 | if (symbol == null) { 88 | if (other.symbol != null) 89 | return false; 90 | } else if (!symbol.equals(other.symbol)) 91 | return false; 92 | return true; 93 | } 94 | } 95 | --------------------------------------------------------------------------------