├── confsvr ├── src │ └── main │ │ ├── resources │ │ ├── bootstrap.yml │ │ ├── config │ │ │ ├── organizationservice │ │ │ │ └── organizationservice.yml │ │ │ └── licensingservice │ │ │ │ ├── licensingservice-dev.yml │ │ │ │ ├── licensingservice.yml │ │ │ │ └── licensingservice-prod.yml │ │ └── application.yml │ │ ├── java │ │ └── com │ │ │ └── thoughtmechanix │ │ │ └── confsvr │ │ │ └── ConfigServerApplication.java │ │ └── docker │ │ ├── Dockerfile │ │ └── run.sh ├── .gitignore └── pom.xml ├── organization-service ├── src │ └── main │ │ ├── resources │ │ ├── bootstrap.yml │ │ ├── application.yml │ │ └── schema.sql │ │ ├── docker │ │ ├── Dockerfile │ │ └── run.sh │ │ └── java │ │ └── com │ │ └── thoughtmechanix │ │ └── organization │ │ ├── repository │ │ └── OrganizationRepository.java │ │ ├── Application.java │ │ ├── services │ │ └── OrganizationService.java │ │ ├── model │ │ └── Organization.java │ │ └── controllers │ │ └── OrganizationServiceController.java └── pom.xml ├── licensing-service ├── src │ └── main │ │ ├── resources │ │ ├── application.yml │ │ ├── bootstrap.yml │ │ └── schema.sql │ │ ├── docker │ │ ├── Dockerfile │ │ └── run.sh │ │ └── java │ │ └── com │ │ └── thoughtmechanix │ │ └── licenses │ │ ├── config │ │ └── ServiceConfig.java │ │ ├── repository │ │ └── LicenseRepository.java │ │ ├── clients │ │ ├── OrganizationFeignClient.java │ │ ├── OrganizationRestTemplateClient.java │ │ └── OrganizationDiscoveryClient.java │ │ ├── controllers │ │ ├── ToolsController.java │ │ └── LicenseServiceController.java │ │ ├── Application.java │ │ ├── model │ │ ├── Organization.java │ │ └── License.java │ │ └── services │ │ ├── DiscoveryService.java │ │ └── LicenseService.java └── pom.xml ├── eurekasvr ├── src │ └── main │ │ ├── docker │ │ ├── Dockerfile │ │ └── run.sh │ │ ├── resources │ │ └── application.yml │ │ └── java │ │ └── com │ │ └── thoughtmechanix │ │ └── eurekasvr │ │ └── EurekaServerApplication.java └── pom.xml ├── .gitignore ├── pom.xml ├── .travis.yml ├── docker └── common │ └── docker-compose.yml └── README.md /confsvr/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: configserver 4 | 5 | -------------------------------------------------------------------------------- /confsvr/src/main/resources/config/organizationservice/organizationservice.yml: -------------------------------------------------------------------------------- 1 | example.organization.property: "I AM THE DEFAULT ORGANIZATION SERVICE" 2 | -------------------------------------------------------------------------------- /confsvr/.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | #* 3 | *# 4 | .#* 5 | .classpath 6 | .project 7 | .settings 8 | .springBeans 9 | .gradle 10 | build 11 | bin 12 | /target/ 13 | git.properties 14 | .idea 15 | *.iml 16 | .factorypath 17 | -------------------------------------------------------------------------------- /organization-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: organizationservice 4 | profiles: 5 | active: 6 | default 7 | cloud: 8 | config: 9 | enabled: true 10 | -------------------------------------------------------------------------------- /licensing-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | instance: 3 | preferIpAddress: true 4 | client: 5 | registerWithEureka: true 6 | fetchRegistry: true 7 | serviceUrl: 8 | defaultZone: http://localhost:8761/eureka/ 9 | -------------------------------------------------------------------------------- /organization-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | 2 | eureka: 3 | instance: 4 | preferIpAddress: true 5 | client: 6 | registerWithEureka: true 7 | fetchRegistry: true 8 | serviceUrl: 9 | defaultZone: http://localhost:8761/eureka/ 10 | 11 | -------------------------------------------------------------------------------- /eurekasvr/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | RUN apk update && apk upgrade && apk add netcat-openbsd 3 | RUN mkdir -p /usr/local/eurekaserver 4 | ADD @project.build.finalName@.jar /usr/local/eurekaserver/ 5 | ADD run.sh run.sh 6 | RUN chmod +x run.sh 7 | CMD ./run.sh 8 | -------------------------------------------------------------------------------- /licensing-service/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | RUN apk update && apk upgrade && apk add netcat-openbsd 3 | RUN mkdir -p /usr/local/licensingservice 4 | ADD @project.build.finalName@.jar /usr/local/licensingservice/ 5 | ADD run.sh run.sh 6 | RUN chmod +x run.sh 7 | CMD ./run.sh 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Java class files 2 | *.class 3 | 4 | # Eclipse project files 5 | .classpath 6 | .project 7 | .settings/ 8 | 9 | # Intellij project files 10 | *.iml 11 | *.ipr 12 | *.iws 13 | .idea/ 14 | 15 | .DS_Store/ 16 | /target 17 | 18 | /target 19 | /target/ 20 | **/target/ 21 | 22 | .DS_Store 23 | -------------------------------------------------------------------------------- /licensing-service/src/main/resources/bootstrap.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: licensingservice 4 | profiles: 5 | active: 6 | default 7 | cloud: 8 | config: 9 | enabled: true 10 | # discovery: 11 | # enabled: true 12 | # serviceId: configserver 13 | -------------------------------------------------------------------------------- /organization-service/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | RUN apk update && apk upgrade && apk add netcat-openbsd 3 | RUN mkdir -p /usr/local/organizationservice 4 | ADD @project.build.finalName@.jar /usr/local/organizationservice/ 5 | ADD run.sh run.sh 6 | RUN chmod +x run.sh 7 | CMD ./run.sh 8 | -------------------------------------------------------------------------------- /eurekasvr/src/main/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "********************************************************" 3 | echo "Starting the Eureka Server" 4 | echo "********************************************************" 5 | java -Djava.security.egd=file:/dev/./urandom -jar /usr/local/eurekaserver/@project.build.finalName@.jar 6 | -------------------------------------------------------------------------------- /eurekasvr/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #Default port is 8761 2 | server: 3 | port: 8761 4 | 5 | eureka: 6 | client: 7 | registerWithEureka: false 8 | fetchRegistry: false 9 | server: 10 | waitTimeInMsWhenSyncEmpty: 5 11 | serviceUrl: 12 | defaultZone: http://localhost:8761 13 | 14 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/config/ServiceConfig.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.config; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | public class ServiceConfig{ 8 | 9 | @Value("${example.property}") 10 | private String exampleProperty=""; 11 | 12 | public String getExampleProperty(){ 13 | return exampleProperty; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /confsvr/src/main/java/com/thoughtmechanix/confsvr/ConfigServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.confsvr; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.config.server.EnableConfigServer; 6 | 7 | @SpringBootApplication 8 | @EnableConfigServer 9 | public class ConfigServerApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ConfigServerApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/thoughtmechanix/organization/repository/OrganizationRepository.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.organization.repository; 2 | 3 | import com.thoughtmechanix.organization.model.Organization; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface OrganizationRepository extends CrudRepository { 11 | public Organization findById(String organizationId); 12 | } 13 | -------------------------------------------------------------------------------- /eurekasvr/src/main/java/com/thoughtmechanix/eurekasvr/EurekaServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.eurekasvr; 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 EurekaServerApplication { 10 | public static void main(String[] args) { 11 | SpringApplication.run(EurekaServerApplication.class, args); 12 | } 13 | } -------------------------------------------------------------------------------- /confsvr/src/main/resources/config/licensingservice/licensingservice-dev.yml: -------------------------------------------------------------------------------- 1 | spring.jpa.database: "POSTGRESQL" 2 | spring.datasource.platform: "postgres" 3 | spring.jpa.show-sql: "true" 4 | spring.database.driverClassName: "org.postgresql.Driver" 5 | spring.datasource.url: "jdbc:postgresql://192.168.99.100:5432/eagle_eye_dev" 6 | spring.datasource.username: "postgres_dev" 7 | spring.datasource.password: "p0stgr@s_dev" 8 | spring.datasource.testWhileIdle: "true" 9 | spring.datasource.validationQuery: "SELECT 1" 10 | spring.jpa.properties.hibernate.dialect: "org.hibernate.dialect.PostgreSQLDialect" 11 | -------------------------------------------------------------------------------- /confsvr/src/main/resources/config/licensingservice/licensingservice.yml: -------------------------------------------------------------------------------- 1 | example.property: "I AM THE DEFAULT" 2 | spring.jpa.database: "POSTGRESQL" 3 | spring.datasource.platform: "postgres" 4 | spring.jpa.show-sql: "true" 5 | spring.database.driverClassName: "org.postgresql.Driver" 6 | spring.datasource.url: "jdbc:postgresql://192.168.99.100:5432/eagle_eye_local" 7 | spring.datasource.username: "postgres" 8 | spring.datasource.password: "p0stgr@s" 9 | spring.datasource.testWhileIdle: "true" 10 | spring.datasource.validationQuery: "SELECT 1" 11 | spring.jpa.properties.hibernate.dialect: "org.hibernate.dialect.PostgreSQLDialect" -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/repository/LicenseRepository.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.repository; 2 | 3 | import com.thoughtmechanix.licenses.model.License; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface LicenseRepository extends CrudRepository { 11 | public List findByOrganizationId(String organizationId); 12 | public License findByOrganizationIdAndLicenseId(String organizationId,String licenseId); 13 | } 14 | -------------------------------------------------------------------------------- /confsvr/src/main/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | RUN apk update && apk upgrade && apk add netcat-openbsd && apk add curl 3 | RUN mkdir -p /usr/local/configserver 4 | RUN cd /tmp/ && \ 5 | curl -k -LO "http://download.oracle.com/otn-pub/java/jce/8/jce_policy-8.zip" -H 'Cookie: oraclelicense=accept-securebackup-cookie' && \ 6 | unzip jce_policy-8.zip && \ 7 | rm jce_policy-8.zip && \ 8 | yes |cp -v /tmp/UnlimitedJCEPolicyJDK8/*.jar /usr/lib/jvm/java-1.8-openjdk/jre/lib/security/ 9 | ADD @project.build.finalName@.jar /usr/local/configserver/ 10 | ADD run.sh run.sh 11 | RUN chmod +x run.sh 12 | CMD ./run.sh 13 | -------------------------------------------------------------------------------- /confsvr/src/main/resources/config/licensingservice/licensingservice-prod.yml: -------------------------------------------------------------------------------- 1 | example.property: "I AM A PROD PROPERTY OVERRIDE" 2 | spring.jpa.database: "POSTGRESQL" 3 | spring.datasource.platform: "postgres" 4 | spring.jpa.show-sql: "true" 5 | spring.database.driverClassName: "org.postgresql.Driver" 6 | spring.datasource.url: "jdbc:postgresql://192.168.99.100:5432/eagle_eye_prod" 7 | spring.datasource.username: "postgres_prod" 8 | spring.datasource.password: "p0stgr@s_prod" 9 | spring.datasource.testWhileIdle: "true" 10 | spring.datasource.validationQuery: "SELECT 1" 11 | spring.jpa.properties.hibernate.dialect: "org.hibernate.dialect.PostgreSQLDialect" -------------------------------------------------------------------------------- /confsvr/src/main/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "********************************************************" 4 | echo "Waiting for the eureka server to start on port $EUREKASERVER_PORT" 5 | echo "********************************************************" 6 | while ! `nc -z eurekaserver $EUREKASERVER_PORT`; do sleep 3; done 7 | echo ">>>>>>>>>>>> Eureka Server has started" 8 | 9 | echo "********************************************************" 10 | echo "Starting Configuration Service with Eureka Endpoint: $EUREKASERVER_URI"; 11 | echo "********************************************************" 12 | java -Djava.security.egd=file:/dev/./urandom -Deureka.client.serviceUrl.defaultZone=$EUREKASERVER_URI -jar /usr/local/configserver/@project.build.finalName@.jar 13 | -------------------------------------------------------------------------------- /organization-service/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS organizations; 2 | 3 | CREATE TABLE organizations ( 4 | organization_id VARCHAR(100) PRIMARY KEY NOT NULL, 5 | name TEXT NOT NULL, 6 | contact_name TEXT NOT NULL, 7 | contact_email TEXT NOT NULL, 8 | contact_phone TEXT NOT NULL); 9 | 10 | 11 | INSERT INTO organizations (organization_id, name, contact_name, contact_email, contact_phone) 12 | VALUES ('e254f8c-c442-4ebe-a82a-e2fc1d1ff78a', 'customer-crm-co', 'Mark Balster', 'mark.balster@custcrmco.com', '823-555-1212'); 13 | 14 | INSERT INTO organizations (organization_id, name, contact_name, contact_email, contact_phone) 15 | VALUES ('442adb6e-fa58-47f3-9ca2-ed1fecdfe86c', 'HR-PowerSuite', 'Doug Drewry','doug.drewry@hr.com', '920-555-1212'); 16 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/clients/OrganizationFeignClient.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.clients; 2 | 3 | 4 | import com.thoughtmechanix.licenses.model.Organization; 5 | import org.springframework.cloud.netflix.feign.FeignClient; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestMethod; 9 | 10 | @FeignClient("organizationservice") 11 | public interface OrganizationFeignClient { 12 | @RequestMapping( 13 | method= RequestMethod.GET, 14 | value="/v1/organizations/{organizationId}", 15 | consumes="application/json") 16 | Organization getOrganization(@PathVariable("organizationId") String organizationId); 17 | } 18 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/thoughtmechanix/organization/Application.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.organization; 2 | 3 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 7 | import org.springframework.cloud.context.config.annotation.RefreshScope; 8 | import org.springframework.cloud.netflix.eureka.EnableEurekaClient; 9 | import org.springframework.cloud.netflix.feign.EnableFeignClients; 10 | 11 | 12 | @SpringBootApplication 13 | @EnableEurekaClient 14 | //@EnableFeignClients 15 | public class Application { 16 | public static void main(String[] args) { 17 | SpringApplication.run(Application.class, args); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/controllers/ToolsController.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.controllers; 2 | 3 | import com.thoughtmechanix.licenses.services.DiscoveryService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestMethod; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | @RequestMapping(value="v1/tools") 13 | public class ToolsController { 14 | @Autowired 15 | private DiscoveryService discoveryService; 16 | 17 | @RequestMapping(value="/eureka/services",method = RequestMethod.GET) 18 | public List getEurekaServices() { 19 | 20 | return discoveryService.getEurekaServices(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/Application.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.client.discovery.EnableDiscoveryClient; 6 | import org.springframework.cloud.netflix.feign.EnableFeignClients; 7 | import org.springframework.cloud.client.loadbalancer.LoadBalanced; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.web.client.RestTemplate; 10 | import java.util.Collections; 11 | import java.util.List; 12 | 13 | @SpringBootApplication 14 | @EnableDiscoveryClient 15 | @EnableFeignClients 16 | public class Application { 17 | 18 | @LoadBalanced 19 | @Bean 20 | public RestTemplate getRestTemplate(){ 21 | return new RestTemplate(); 22 | } 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(Application.class, args); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/clients/OrganizationRestTemplateClient.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.clients; 2 | 3 | import com.thoughtmechanix.licenses.model.Organization; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.http.HttpMethod; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.stereotype.Component; 8 | import org.springframework.web.client.RestTemplate; 9 | 10 | @Component 11 | public class OrganizationRestTemplateClient { 12 | @Autowired 13 | RestTemplate restTemplate; 14 | 15 | public Organization getOrganization(String organizationId){ 16 | ResponseEntity restExchange = 17 | restTemplate.exchange( 18 | "http://organizationservice/v1/organizations/{organizationId}", 19 | HttpMethod.GET, 20 | null, Organization.class, organizationId); 21 | 22 | return restExchange.getBody(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/thoughtmechanix/organization/services/OrganizationService.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.organization.services; 2 | 3 | import com.thoughtmechanix.organization.model.Organization; 4 | import com.thoughtmechanix.organization.repository.OrganizationRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.UUID; 9 | 10 | @Service 11 | public class OrganizationService { 12 | @Autowired 13 | private OrganizationRepository orgRepository; 14 | 15 | public Organization getOrg(String organizationId) { 16 | return orgRepository.findById(organizationId); 17 | } 18 | 19 | public void saveOrg(Organization org){ 20 | org.setId( UUID.randomUUID().toString()); 21 | 22 | orgRepository.save(org); 23 | 24 | } 25 | 26 | public void updateOrg(Organization org){ 27 | orgRepository.save(org); 28 | } 29 | 30 | public void deleteOrg(Organization org){ 31 | orgRepository.delete( org.getId()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/model/Organization.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.model; 2 | 3 | public class Organization { 4 | String id; 5 | String name; 6 | String contactName; 7 | String contactEmail; 8 | String contactPhone; 9 | 10 | 11 | public String getId() { 12 | return id; 13 | } 14 | 15 | 16 | public void setId(String id) { 17 | this.id = id; 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | public void setName(String name) { 25 | this.name = name; 26 | } 27 | 28 | public String getContactName() { 29 | return contactName; 30 | } 31 | 32 | public void setContactName(String contactName) { 33 | this.contactName = contactName; 34 | } 35 | 36 | public String getContactEmail() { 37 | return contactEmail; 38 | } 39 | 40 | public void setContactEmail(String contactEmail) { 41 | this.contactEmail = contactEmail; 42 | } 43 | 44 | public String getContactPhone() { 45 | return contactPhone; 46 | } 47 | 48 | public void setContactPhone(String contactPhone) { 49 | this.contactPhone = contactPhone; 50 | } 51 | 52 | 53 | } -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/services/DiscoveryService.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.services; 2 | 3 | 4 | import com.thoughtmechanix.licenses.model.Organization; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.cloud.client.ServiceInstance; 7 | import org.springframework.cloud.client.discovery.DiscoveryClient; 8 | import org.springframework.http.HttpMethod; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.web.client.RestTemplate; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.Random; 16 | 17 | @Service 18 | public class DiscoveryService { 19 | @Autowired 20 | RestTemplate restTemplate; 21 | 22 | @Autowired 23 | private DiscoveryClient discoveryClient; 24 | 25 | public List getEurekaServices(){ 26 | List services = new ArrayList(); 27 | 28 | discoveryClient.getServices().forEach(serviceName -> { 29 | discoveryClient.getInstances(serviceName).forEach(instance->{ 30 | services.add( String.format("%s:%s",serviceName,instance.getUri())); 31 | }); 32 | }); 33 | 34 | return services; 35 | } 36 | 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /licensing-service/src/main/resources/schema.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS licenses; 2 | 3 | CREATE TABLE licenses ( 4 | license_id VARCHAR(100) PRIMARY KEY NOT NULL, 5 | organization_id TEXT NOT NULL, 6 | license_type TEXT NOT NULL, 7 | product_name TEXT NOT NULL, 8 | license_max INT NOT NULL, 9 | license_allocated INT, 10 | comment VARCHAR(100)); 11 | 12 | 13 | INSERT INTO licenses (license_id, organization_id, license_type, product_name, license_max, license_allocated) 14 | VALUES ('f3831f8c-c338-4ebe-a82a-e2fc1d1ff78a', 'e254f8c-c442-4ebe-a82a-e2fc1d1ff78a', 'user','CustomerPro', 100,5); 15 | INSERT INTO licenses (license_id, organization_id, license_type, product_name, license_max, license_allocated) 16 | VALUES ('t9876f8c-c338-4abc-zf6a-ttt1', 'e254f8c-c442-4ebe-a82a-e2fc1d1ff78a', 'user','suitability-plus', 200,189); 17 | INSERT INTO licenses (license_id, organization_id, license_type, product_name, license_max, license_allocated) 18 | VALUES ('38777179-7094-4200-9d61-edb101c6ea84', '442adb6e-fa58-47f3-9ca2-ed1fecdfe86c', 'user','HR-PowerSuite', 100,4); 19 | INSERT INTO licenses (license_id, organization_id, license_type, product_name, license_max, license_allocated) 20 | VALUES ('08dbe05-606e-4dad-9d33-90ef10e334f9', '442adb6e-fa58-47f3-9ca2-ed1fecdfe86c', 'core-prod','WildCat Application Gateway', 16,16); -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.thoughtmechanix 6 | 0.0.1-SNAPSHOT 7 | tmx-parent-pom 8 | pom 9 | 10 | thoughtmechanix-parent-pom 11 | Parent Pom for the thoughtmechanix project 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 1.4.4.RELEASE 17 | 18 | 19 | confsvr 20 | licensing-service 21 | organization-service 22 | eurekasvr 23 | 24 | 25 | 26 | 27 | com.spotify 28 | docker-maven-plugin 29 | 0.4.10 30 | 31 | java 32 | example 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /confsvr/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | # 2 | # This is the core configuration for service. I have two examples here: 3 | # 4 | # - A configuration service which completelty loads the configuration for the services 5 | # from the local file server of the config service. This should only be used for 6 | # demonstration purposes or for a small application with a limited number of services. 7 | # 8 | # - A configuraton service that uses a git-based repository to read the files from 9 | # 10 | 11 | 12 | #################################### 13 | server: 14 | port: 8888 15 | spring: 16 | cloud: 17 | config: 18 | discovery: 19 | enabled: true 20 | server: 21 | encrypt.enabled: false 22 | git: 23 | uri: https://github.com/carnellj/config-repo/ 24 | searchPaths: licensingservice,organizationservice 25 | username: native-cloud-apps 26 | password: 0ffended 27 | 28 | 29 | #### 30 | #Classpath and file-based solution 31 | #### 32 | 33 | #server: 34 | # port: 8888 35 | #spring: 36 | # profiles: 37 | # active: native 38 | # cloud: 39 | # config: 40 | # server: 41 | # native: 42 | # searchLocations: file:///confsvr/src/main/resources/config/licensingservice, 43 | # file://confsvr/src/main/resources/config/organizationservice 44 | ## #searchLocations: classpath:config/,classpath:config/licensingservice 45 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/clients/OrganizationDiscoveryClient.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.clients; 2 | 3 | 4 | import com.thoughtmechanix.licenses.model.Organization; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.cloud.client.ServiceInstance; 7 | import org.springframework.cloud.client.discovery.DiscoveryClient; 8 | import org.springframework.http.HttpMethod; 9 | import org.springframework.http.ResponseEntity; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.client.RestTemplate; 12 | 13 | import java.util.List; 14 | 15 | @Component 16 | public class OrganizationDiscoveryClient { 17 | 18 | @Autowired 19 | private DiscoveryClient discoveryClient; 20 | 21 | public Organization getOrganization(String organizationId) { 22 | RestTemplate restTemplate = new RestTemplate(); 23 | List instances = discoveryClient.getInstances("organizationservice"); 24 | 25 | if (instances.size()==0) return null; 26 | String serviceUri = String.format("%s/v1/organizations/%s",instances.get(0).getUri().toString(), organizationId); 27 | 28 | ResponseEntity< Organization > restExchange = 29 | restTemplate.exchange( 30 | serviceUri, 31 | HttpMethod.GET, 32 | null, Organization.class, organizationId); 33 | 34 | return restExchange.getBody(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /organization-service/src/main/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "********************************************************" 4 | echo "Waiting for the eureka server to start on port $EUREKASERVER_PORT" 5 | echo "********************************************************" 6 | while ! `nc -z eurekaserver $EUREKASERVER_PORT`; do sleep 3; done 7 | echo "******* Eureka Server has started" 8 | 9 | 10 | echo "********************************************************" 11 | echo "Waiting for the database server to start on port $DATABASESERVER_PORT" 12 | echo "********************************************************" 13 | while ! `nc -z database $DATABASESERVER_PORT`; do sleep 3; done 14 | echo "******** Database Server has started " 15 | 16 | echo "********************************************************" 17 | echo "Waiting for the configuration server to start on port $CONFIGSERVER_PORT" 18 | echo "********************************************************" 19 | while ! `nc -z configserver $CONFIGSERVER_PORT`; do sleep 3; done 20 | echo "******* Configuration Server has started" 21 | 22 | echo "********************************************************" 23 | echo "Starting Organization Service " 24 | echo "********************************************************" 25 | java -Djava.security.egd=file:/dev/./urandom -Dserver.port=$SERVER_PORT \ 26 | -Deureka.client.serviceUrl.defaultZone=$EUREKASERVER_URI \ 27 | -Dspring.cloud.config.uri=$CONFIGSERVER_URI \ 28 | -Dspring.profiles.active=$PROFILE \ 29 | -jar /usr/local/organizationservice/@project.build.finalName@.jar 30 | -------------------------------------------------------------------------------- /licensing-service/src/main/docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | getPort() { 3 | echo $1 | cut -d : -f 3 | xargs basename 4 | } 5 | 6 | echo "********************************************************" 7 | echo "Waiting for the eureka server to start on port $EUREKASERVER_PORT" 8 | echo "********************************************************" 9 | while ! `nc -z eurekaserver $EUREKASERVER_PORT`; do sleep 3; done 10 | echo "******* Eureka Server has started" 11 | 12 | 13 | echo "********************************************************" 14 | echo "Waiting for the database server to start on port $DATABASESERVER_PORT" 15 | echo "********************************************************" 16 | while ! `nc -z database $DATABASESERVER_PORT`; do sleep 3; done 17 | echo "******** Database Server has started " 18 | 19 | echo "********************************************************" 20 | echo "Waiting for the configuration server to start on port $CONFIGSERVER_PORT" 21 | echo "********************************************************" 22 | while ! `nc -z configserver $CONFIGSERVER_PORT`; do sleep 3; done 23 | echo "******* Configuration Server has started" 24 | 25 | 26 | echo "********************************************************" 27 | echo "Starting License Server with Configuration Service via Eureka : $EUREKASERVER_URI" ON PORT: $SERVER_PORT; 28 | echo "********************************************************" 29 | java -Djava.security.egd=file:/dev/./urandom -Dserver.port=$SERVER_PORT \ 30 | -Deureka.client.serviceUrl.defaultZone=$EUREKASERVER_URI \ 31 | -Dspring.cloud.config.uri=$CONFIGSERVER_URI \ 32 | -Dspring.profiles.active=$PROFILE -jar /usr/local/licensingservice/@project.build.finalName@.jar 33 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/thoughtmechanix/organization/model/Organization.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.organization.model; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | @Entity 9 | @Table(name = "organizations") 10 | public class Organization { 11 | @Id 12 | @Column(name = "organization_id", nullable = false) 13 | String id; 14 | 15 | @Column(name = "name", nullable = false) 16 | String name; 17 | 18 | @Column(name = "contact_name", nullable = false) 19 | String contactName; 20 | 21 | @Column(name = "contact_email", nullable = false) 22 | String contactEmail; 23 | 24 | @Column(name = "contact_phone", nullable = false) 25 | String contactPhone; 26 | 27 | 28 | public String getId() { 29 | return id; 30 | } 31 | 32 | 33 | public void setId(String id) { 34 | this.id = id; 35 | } 36 | 37 | public String getName() { 38 | return name; 39 | } 40 | 41 | public void setName(String name) { 42 | this.name = name; 43 | } 44 | 45 | public String getContactName() { 46 | return contactName; 47 | } 48 | 49 | public void setContactName(String contactName) { 50 | this.contactName = contactName; 51 | } 52 | 53 | public String getContactEmail() { 54 | return contactEmail; 55 | } 56 | 57 | public void setContactEmail(String contactEmail) { 58 | this.contactEmail = contactEmail; 59 | } 60 | 61 | public String getContactPhone() { 62 | return contactPhone; 63 | } 64 | 65 | public void setContactPhone(String contactPhone) { 66 | this.contactPhone = contactPhone; 67 | } 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /organization-service/src/main/java/com/thoughtmechanix/organization/controllers/OrganizationServiceController.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.organization.controllers; 2 | 3 | 4 | import com.thoughtmechanix.organization.model.Organization; 5 | import com.thoughtmechanix.organization.services.OrganizationService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.web.bind.annotation.RestController; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.PathVariable; 13 | import org.springframework.web.bind.annotation.ResponseStatus; 14 | 15 | @RestController 16 | @RequestMapping(value="v1/organizations") 17 | public class OrganizationServiceController { 18 | @Autowired 19 | private OrganizationService orgService; 20 | 21 | 22 | @RequestMapping(value="/{organizationId}",method = RequestMethod.GET) 23 | public Organization getOrganization( @PathVariable("organizationId") String organizationId) { 24 | return orgService.getOrg(organizationId); 25 | } 26 | 27 | @RequestMapping(value="/{organizationId}",method = RequestMethod.PUT) 28 | public void updateOrganization( @PathVariable("organizationId") String orgId, @RequestBody Organization org) { 29 | orgService.updateOrg( org ); 30 | } 31 | 32 | @RequestMapping(value="/{organizationId}",method = RequestMethod.POST) 33 | public void saveOrganization(@RequestBody Organization org) { 34 | orgService.saveOrg( org ); 35 | } 36 | 37 | @RequestMapping(value="/{organizationId}",method = RequestMethod.DELETE) 38 | @ResponseStatus(HttpStatus.NO_CONTENT) 39 | public void deleteOrganization( @PathVariable("orgId") String orgId, @RequestBody Organization org) { 40 | orgService.deleteOrg( org ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | cache: 3 | directories: 4 | - $HOME/.m2 5 | jdk: 6 | - oraclejdk8 7 | sudo: required 8 | services: 9 | - docker 10 | notifications: 11 | slack: teamcarnell:zhTADgjsb7yJ5RPEd7LPNFwI 12 | email: 13 | - carnell28@gmail.com 14 | on_success: always 15 | on_failure: always 16 | env: 17 | global: 18 | - secure: i70vpTdFrFSR9sa7Me7S2a3HwiAFe0ZmNfF+odCSNcx6vfSPgYOXtKrKgRVw+HGrIW6+OSQylMjqbhTHoDG0zTwkk774r2YMQ6DINisihmPySZfNgwaEGP8A0CMgHEdbC+uKva0ySZMa9pz0Cs6jUzSBACIP38WrYj7lW8Z5advSTmqGU0V9uGHdS46B9CtkVEbSsC2O9yK1BFyBZwMaPf5xdwLi2ByFMtBa3KWHfoP52jHwGQQWGIkgtM18ObpTzO0BZs20osOU4YKxkj3bcQV5ggi3uxpFdoOmo+oxWpu8eMLHjqClFm7XGj6BFnR2oqcDQJsh5aiQACqcWhSdF4csBy0n574/+Ne+dP/lzdwcHqlG+HbNNQ2nO85MzB9IU0PS/xd880121kLc4lviGQEYk6vn7gAoha/+uoZhb0ZjwEenGupsu+/p0DCzX7IkenOYNxqf4Z9eRpU7mHVODBLJr0bCDcbvsbnO9n4kX1VO5mu0ChMi1ZAhKSbcnoApqMyQGCS2f6rFeGqyt/V0KhMpeU7TKTX7E3WVRLlLY82RHdw5lTRiphv9anA3ItqybboX/3PUmGEVdNUUON/nGqW0mg5GTyXRz1zUOvaRPbyjI0sD3Yi9Ae9HSiDr1uC9w+4mkkD4M2tcXOw1wUIFYKOBclxvN7DOJ5i7JDPC94s= 19 | - secure: FGP5X6tkLjJR8LyM/A2QnoYNXCrUxYB316o5EzOraOcMu0A07c+5rFVQyZSmvim14+PBgRDzpqK5ZNWfhAZPlgzHo+kxLSf7I4WZnVZlQABb3+jNOaAIl4C0Ow1HQQ0J6JerSQlekYcUp/PROoEhD4UR7x0RrVapdYvOLmmzRLp84bjY8xwkI84j8xYRIJKp0lZcdzfl8Q1JVV43k+aeWVR8Z3vpCd6/tqk+X+ffBkYaU5SoL5ak/JxS20tBXt2M0gPWUu1MwIaPrsYUYiN2rBXvU+rOHLuW1IegQGTPtfJ/tRAhJuF1nCU6GwpRKp7k6YYYnBARiwtGl1p2HmCsjY5Pp9gsCjVCQNzhOyioNtsgwJRcp640pr2FJo5so3BeTr+RG4QfRfl96M3DXJb12Zy0sFkc2//hmLc1qKGw3GoN0/Y5OAmKptmSgHmCSviwapVXWPzAfb4YW/6dha6x5LkqhApEGREVxZWTazTHN25HlZYju5jCvgi9hE+Arsu03pyDOCpiGXq7DzuSkNYsGPTvQN9wWfZoSkl/v5jIG88UPCY3InpawG+3xOykFw9HuEY/x09t7ev2BaRsOrYVLZL8foVeaWswkfnoBxSfsr+q5BHm2KxsTmgHvx4MR4jaiPnCb/n9nVrdQEU0Bo+eBUq+lDxQvZf6ozv1HrqQk+c= 20 | script: 21 | - docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD 22 | - mvn clean package docker:build 23 | - docker push johncarnell/tmx-licensing-service:chapter4 24 | - docker push johncarnell/tmx-organization-service:chapter4 25 | - docker push johncarnell/tmx-confsvr:chapter4 26 | - docker push johncarnell/tmx-eurekasvr:chapter4 27 | -------------------------------------------------------------------------------- /docker/common/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2' 2 | services: 3 | eurekaserver: 4 | image: johncarnell/tmx-eurekasvr:chapter4 5 | ports: 6 | - "8761:8761" 7 | configserver: 8 | image: johncarnell/tmx-confsvr:chapter4 9 | ports: 10 | - "8888:8888" 11 | environment: 12 | EUREKASERVER_URI: "http://eurekaserver:8761/eureka/" 13 | EUREKASERVER_PORT: "8761" 14 | ENCRYPT_KEY: "IMSYMMETRIC" 15 | # configserver2: 16 | # image: johncarnell/tmx-confsvr:chapter4 17 | # ports: 18 | # - "8889:8889" 19 | # links: 20 | # - "eurekaserver:eurekaserver" 21 | # environment: 22 | # EUREKASERVER_URI: "http://eurekaserver:8761/eureka/" 23 | # EUREKASERVER_PORT:8761 24 | # ENCRYPT_KEY: "IMSYMMETRIC" 25 | database: 26 | image: postgres:9.5 27 | ports: 28 | - "5432:5432" 29 | environment: 30 | - POSTGRES_USER=postgres 31 | - POSTGRES_PASSWORD=p0stgr@s 32 | - POSTGRES_DB=eagle_eye_local 33 | licensingservice: 34 | image: johncarnell/tmx-licensing-service:chapter4 35 | ports: 36 | - "8080:8080" 37 | environment: 38 | PROFILE: "default" 39 | SERVER_PORT: "8080" 40 | CONFIGSERVER_URI: "http://configserver:8888" 41 | EUREKASERVER_URI: "http://eurekaserver:8761/eureka/" 42 | EUREKASERVER_PORT: "8761" 43 | CONFIGSERVER_PORT: "8888" 44 | DATABASESERVER_PORT: "5432" 45 | ENCRYPT_KEY: "IMSYMMETRIC" 46 | organizationservice: 47 | image: johncarnell/tmx-organization-service:chapter4 48 | ports: 49 | - "8085:8085" 50 | environment: 51 | PROFILE: "default" 52 | SERVER_PORT: "8085" 53 | CONFIGSERVER_URI: "http://configserver:8888" 54 | EUREKASERVER_URI: "http://eurekaserver:8761/eureka/" 55 | EUREKASERVER_PORT: "8761" 56 | CONFIGSERVER_PORT: "8888" 57 | DATABASESERVER_PORT: "5432" 58 | ENCRYPT_KEY: "IMSYMMETRIC" 59 | organizationservice2: 60 | image: johncarnell/tmx-organization-service:chapter4 61 | ports: 62 | - "8086:8086" 63 | environment: 64 | PROFILE: "default" 65 | SERVER_PORT: "8085" 66 | CONFIGSERVER_URI: "http://configserver:8888" 67 | EUREKASERVER_URI: "http://eurekaserver:8761/eureka/" 68 | EUREKASERVER_PORT: "8761" 69 | CONFIGSERVER_PORT: "8888" 70 | DATABASESERVER_PORT: "5432" 71 | ENCRYPT_KEY: "IMSYMMETRIC" 72 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/controllers/LicenseServiceController.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.controllers; 2 | 3 | import com.thoughtmechanix.licenses.model.License; 4 | import com.thoughtmechanix.licenses.services.LicenseService; 5 | import com.thoughtmechanix.licenses.config.ServiceConfig; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.RequestBody; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.web.bind.annotation.RestController; 11 | import org.springframework.web.bind.annotation.RequestMethod; 12 | import org.springframework.web.bind.annotation.PathVariable; 13 | import org.springframework.web.bind.annotation.ResponseStatus; 14 | 15 | import java.util.List; 16 | 17 | @RestController 18 | @RequestMapping(value="v1/organizations/{organizationId}/licenses") 19 | public class LicenseServiceController { 20 | @Autowired 21 | private LicenseService licenseService; 22 | 23 | @Autowired 24 | private ServiceConfig serviceConfig; 25 | 26 | @RequestMapping(value="/",method = RequestMethod.GET) 27 | public List getLicenses( @PathVariable("organizationId") String organizationId) { 28 | 29 | return licenseService.getLicensesByOrg(organizationId); 30 | } 31 | 32 | @RequestMapping(value="/{licenseId}",method = RequestMethod.GET) 33 | public License getLicenses( @PathVariable("organizationId") String organizationId, 34 | @PathVariable("licenseId") String licenseId) { 35 | 36 | return licenseService.getLicense(organizationId, licenseId, ""); 37 | } 38 | 39 | @RequestMapping(value="/{licenseId}/{clientType}",method = RequestMethod.GET) 40 | public License getLicensesWithClient( @PathVariable("organizationId") String organizationId, 41 | @PathVariable("licenseId") String licenseId, 42 | @PathVariable("clientType") String clientType) { 43 | 44 | return licenseService.getLicense(organizationId,licenseId, clientType); 45 | } 46 | 47 | @RequestMapping(value="{licenseId}",method = RequestMethod.PUT) 48 | public void updateLicenses( @PathVariable("licenseId") String licenseId, @RequestBody License license) { 49 | licenseService.updateLicense(license); 50 | } 51 | 52 | @RequestMapping(value="/",method = RequestMethod.POST) 53 | public void saveLicenses(@RequestBody License license) { 54 | licenseService.saveLicense(license); 55 | } 56 | 57 | @RequestMapping(value="{licenseId}",method = RequestMethod.DELETE) 58 | @ResponseStatus(HttpStatus.NO_CONTENT) 59 | public void deleteLicenses( @PathVariable("licenseId") String licenseId, @RequestBody License license) { 60 | licenseService.deleteLicense(license); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | Welcome to Spring Microservices in Action, Chapter 4. Chapter 4 builds on the material from Chapter 3 and introduces the concept of service registration and discovery patterns using Spring Cloud and Netflix's Eureka server. Using service discovery, you will be able to add and remove service instances without the clients having to know the physical locations of the service. 3 | 4 | By the time you are done reading this chapter you will have built and/or deployed: 5 | 6 | 1. A Spring Cloud Config server that is deployed as Docker container and can manage a services configuration information using a file system or GitHub-based repository. 7 | 2. A Eureka server running as a Spring-Cloud based service. This service will allow multiple service instances to register with it. Clients that need to call a service will use Eureka to lookup the physical location of the target service. 8 | 2. A organization service that will manage organization data used within EagleEye. 9 | 3. A licensing service that will manage licensing data used within EagleEye. 10 | 4. A Postgres SQL database used to hold the data for these two services. 11 | 12 | # Software needed 13 | 1. Apache Maven (http://maven.apache.org). I used version 3.3.9 of the Maven. I chose Maven because, while other build tools like Gradle are extremely popular, Maven is still the pre-dominate build tool in use in the Java ecosystem. All of the code examples in this book have been compiled with Java version 1.8. 14 | 2. Docker (http://docker.com). I built the code examples in this book using Docker V1.12 and above. I am taking advantage of the embedded DNS server in Docker that came out in release V1.11. New Docker releases are constantly coming out so it's release version you are using may change on a regular basis. 15 | 3. Git Client (http://git-scm.com). All of the source code for this book is stored in a GitHub repository. For the book, I used version 2.8.4 of the git client. 16 | 17 | # Building the Docker Images for Chapter 4 18 | To build the code examples for Chapter 4 as a docker image, open a command-line window change to the directory where you have downloaded the chapter 4 source code. 19 | 20 | Run the following maven command. This command will execute the [Spotify docker plugin](https://github.com/spotify/docker-maven-plugin) defined in the pom.xml file. 21 | 22 | **mvn clean package docker:build** 23 | 24 | Running the above command at the root of the project directory will build all of the projects. If everything builds successfully you should see a message indicating that the build was successful. 25 | 26 | # Running the services in Chapter 3 27 | 28 | Now we are going to use docker-compose to start the actual image. To start the docker image, 29 | change to the directory containing your chapter 4 source code. Issue the following docker-compose command: 30 | 31 | **docker-compose -f docker/common/docker-compose.yml up** 32 | 33 | If everything starts correctly you should see a bunch of Spring Boot information fly by on standard out. At this point all of the services needed for the chapter code examples will be running. 34 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/services/LicenseService.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.services; 2 | 3 | import com.thoughtmechanix.licenses.clients.OrganizationDiscoveryClient; 4 | import com.thoughtmechanix.licenses.clients.OrganizationFeignClient; 5 | import com.thoughtmechanix.licenses.clients.OrganizationRestTemplateClient; 6 | import com.thoughtmechanix.licenses.config.ServiceConfig; 7 | import com.thoughtmechanix.licenses.model.License; 8 | import com.thoughtmechanix.licenses.model.Organization; 9 | import com.thoughtmechanix.licenses.repository.LicenseRepository; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.List; 14 | import java.util.UUID; 15 | 16 | @Service 17 | public class LicenseService { 18 | 19 | @Autowired 20 | private LicenseRepository licenseRepository; 21 | 22 | @Autowired 23 | ServiceConfig config; 24 | 25 | 26 | @Autowired 27 | OrganizationFeignClient organizationFeignClient; 28 | 29 | @Autowired 30 | OrganizationRestTemplateClient organizationRestClient; 31 | 32 | @Autowired 33 | OrganizationDiscoveryClient organizationDiscoveryClient; 34 | 35 | 36 | private Organization retrieveOrgInfo(String organizationId, String clientType){ 37 | Organization organization = null; 38 | 39 | switch (clientType) { 40 | case "feign": 41 | System.out.println("I am using the feign client"); 42 | organization = organizationFeignClient.getOrganization(organizationId); 43 | break; 44 | case "rest": 45 | System.out.println("I am using the rest client"); 46 | organization = organizationRestClient.getOrganization(organizationId); 47 | break; 48 | case "discovery": 49 | System.out.println("I am using the discovery client"); 50 | organization = organizationDiscoveryClient.getOrganization(organizationId); 51 | break; 52 | default: 53 | organization = organizationRestClient.getOrganization(organizationId); 54 | } 55 | 56 | return organization; 57 | } 58 | 59 | public License getLicense(String organizationId,String licenseId, String clientType) { 60 | License license = licenseRepository.findByOrganizationIdAndLicenseId(organizationId, licenseId); 61 | 62 | Organization org = retrieveOrgInfo(organizationId, clientType); 63 | 64 | return license 65 | .withOrganizationName( org.getName()) 66 | .withContactName( org.getContactName()) 67 | .withContactEmail( org.getContactEmail() ) 68 | .withContactPhone( org.getContactPhone() ) 69 | .withComment(config.getExampleProperty()); 70 | } 71 | 72 | public List getLicensesByOrg(String organizationId){ 73 | return licenseRepository.findByOrganizationId( organizationId ); 74 | } 75 | 76 | public void saveLicense(License license){ 77 | license.withId( UUID.randomUUID().toString()); 78 | 79 | licenseRepository.save(license); 80 | 81 | } 82 | 83 | public void updateLicense(License license){ 84 | licenseRepository.save(license); 85 | } 86 | 87 | public void deleteLicense(License license){ 88 | licenseRepository.delete( license.getLicenseId()); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /eurekasvr/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.thoughtmechanix 6 | eurekasvr 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Eureka Server 11 | Eureka Server demo project 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 1.4.4.RELEASE 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-dependencies 23 | Camden.SR5 24 | pom 25 | import 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-starter-eureka-server 34 | 35 | 36 | 37 | 38 | 39 | UTF-8 40 | com.thoughtmechanix.eurekasvr.EurekaServerApplication 41 | 1.8 42 | johncarnell/tmx-eurekasvr 43 | chapter4 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | maven-resources-plugin 52 | 53 | 54 | copy-resources 55 | 56 | validate 57 | 58 | copy-resources 59 | 60 | 61 | ${basedir}/target/dockerfile 62 | 63 | 64 | src/main/docker 65 | true 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | com.spotify 74 | docker-maven-plugin 75 | 0.4.10 76 | 77 | ${docker.image.name}:${docker.image.tag} 78 | ${basedir}/target/dockerfile 79 | 80 | 81 | / 82 | ${project.build.directory} 83 | ${project.build.finalName}.jar 84 | 85 | 86 | 87 | 88 | 89 | org.springframework.boot 90 | spring-boot-maven-plugin 91 | 92 | 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /confsvr/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.thoughtmechanix 6 | configurationserver 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Config Server 11 | Config Server demo project 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 1.4.4.RELEASE 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-dependencies 23 | Camden.SR5 24 | pom 25 | import 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.cloud 33 | spring-cloud-config-server 34 | 35 | 36 | 37 | org.springframework.cloud 38 | spring-cloud-starter-config 39 | 40 | 41 | 42 | org.springframework.cloud 43 | spring-cloud-starter-eureka 44 | 45 | 46 | 47 | 48 | 49 | UTF-8 50 | com.thoughtmechanix.confsvr.ConfigServerApplication 51 | 1.8 52 | johncarnell/tmx-confsvr 53 | chapter4 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | maven-resources-plugin 62 | 63 | 64 | copy-resources 65 | 66 | validate 67 | 68 | copy-resources 69 | 70 | 71 | ${basedir}/target/dockerfile 72 | 73 | 74 | src/main/docker 75 | true 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | com.spotify 84 | docker-maven-plugin 85 | 0.4.10 86 | 87 | ${docker.image.name}:${docker.image.tag} 88 | ${basedir}/target/dockerfile 89 | 90 | 91 | / 92 | ${project.build.directory} 93 | ${project.build.finalName}.jar 94 | 95 | 96 | 97 | 98 | 99 | org.springframework.boot 100 | spring-boot-maven-plugin 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /licensing-service/src/main/java/com/thoughtmechanix/licenses/model/License.java: -------------------------------------------------------------------------------- 1 | package com.thoughtmechanix.licenses.model; 2 | 3 | 4 | import javax.persistence.Column; 5 | import javax.persistence.Entity; 6 | import javax.persistence.Id; 7 | import javax.persistence.Table; 8 | import javax.persistence.Transient; 9 | 10 | @Entity 11 | @Table(name = "licenses") 12 | public class License{ 13 | @Id 14 | @Column(name = "license_id", nullable = false) 15 | private String licenseId; 16 | 17 | @Column(name = "organization_id", nullable = false) 18 | private String organizationId; 19 | 20 | @Transient 21 | private String organizationName =""; 22 | 23 | @Transient 24 | private String contactName =""; 25 | 26 | @Transient 27 | private String contactPhone =""; 28 | 29 | @Transient 30 | private String contactEmail =""; 31 | 32 | @Column(name = "product_name", nullable = false) 33 | private String productName; 34 | 35 | @Column(name = "license_type", nullable = false) 36 | private String licenseType; 37 | 38 | @Column(name = "license_max", nullable = false) 39 | private Integer licenseMax; 40 | 41 | @Column(name = "license_allocated", nullable = false) 42 | private Integer licenseAllocated; 43 | 44 | @Column(name="comment") 45 | private String comment; 46 | 47 | 48 | public Integer getLicenseMax() { 49 | return licenseMax; 50 | } 51 | 52 | public void setLicenseMax(Integer licenseMax) { 53 | this.licenseMax = licenseMax; 54 | } 55 | 56 | public Integer getLicenseAllocated() { 57 | return licenseAllocated; 58 | } 59 | 60 | public void setLicenseAllocated(Integer licenseAllocated) { 61 | this.licenseAllocated = licenseAllocated; 62 | } 63 | 64 | 65 | public String getLicenseId() { 66 | return licenseId; 67 | } 68 | 69 | public void setLicenseId(String licenseId) { 70 | this.licenseId = licenseId; 71 | } 72 | 73 | public String getOrganizationId() { 74 | return organizationId; 75 | } 76 | 77 | public void setOrganizationId(String organizationId) { 78 | this.organizationId = organizationId; 79 | } 80 | 81 | public String getProductName() { 82 | return productName; 83 | } 84 | 85 | public void setProductName(String productName) { 86 | this.productName = productName; 87 | } 88 | 89 | public String getLicenseType() { 90 | return licenseType; 91 | } 92 | 93 | public void setLicenseType(String licenseType) { 94 | this.licenseType = licenseType; 95 | } 96 | 97 | public String getComment() { 98 | return comment; 99 | } 100 | 101 | public void setComment(String comment) { 102 | this.comment = comment; 103 | } 104 | 105 | public String getOrganizationName() { 106 | return organizationName; 107 | } 108 | 109 | public void setOrganizationName(String organizationName) { 110 | this.organizationName = organizationName; 111 | } 112 | 113 | public String getContactName() { 114 | return contactName; 115 | } 116 | 117 | public void setContactName(String contactName) { 118 | this.contactName = contactName; 119 | } 120 | 121 | public String getContactPhone() { 122 | return contactPhone; 123 | } 124 | 125 | public void setContactPhone(String contactPhone) { 126 | this.contactPhone = contactPhone; 127 | } 128 | 129 | public String getContactEmail() { 130 | return contactEmail; 131 | } 132 | 133 | public void setContactEmail(String contactEmail) { 134 | this.contactEmail = contactEmail; 135 | } 136 | 137 | public License withId(String id){ 138 | this.setLicenseId(id); 139 | return this; 140 | } 141 | 142 | public License withOrganizationId(String organizationId){ 143 | this.setOrganizationId(organizationId); 144 | return this; 145 | } 146 | 147 | public License withProductName(String productName){ 148 | this.setProductName(productName); 149 | return this; 150 | } 151 | 152 | public License withLicenseType(String licenseType){ 153 | this.setLicenseType(licenseType); 154 | return this; 155 | } 156 | 157 | public License withLicenseMax(Integer licenseMax){ 158 | this.setLicenseMax(licenseMax); 159 | return this; 160 | } 161 | 162 | public License withLicenseAllocated(Integer licenseAllocated){ 163 | this.setLicenseAllocated(licenseAllocated); 164 | return this; 165 | } 166 | 167 | public License withComment(String comment){ 168 | this.setComment(comment); 169 | return this; 170 | } 171 | 172 | public License withOrganizationName(String organizationName){ 173 | this.setOrganizationName(organizationName); 174 | return this; 175 | } 176 | 177 | public License withContactName(String contactName){ 178 | this.setContactName(contactName); 179 | return this; 180 | } 181 | 182 | public License withContactPhone(String contactPhone){ 183 | this.setContactPhone(contactPhone); 184 | return this; 185 | } 186 | 187 | public License withContactEmail(String contactEmail){ 188 | this.setContactEmail(contactEmail); 189 | return this; 190 | } 191 | 192 | 193 | 194 | 195 | } 196 | -------------------------------------------------------------------------------- /organization-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.thoughtmechanix 6 | organization-service 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Eagle Eye Organization Service 11 | Organization Service 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 1.4.4.RELEASE 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-dependencies 23 | Camden.SR5 24 | pom 25 | import 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-data-jpa 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-web 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-actuator 42 | 43 | 44 | 45 | org.springframework.cloud 46 | spring-cloud-starter-config 47 | 48 | 49 | 50 | org.springframework.cloud 51 | spring-cloud-starter-eureka 52 | 53 | 54 | 55 | org.springframework.cloud 56 | spring-cloud-config-client 57 | 58 | 59 | com.h2database 60 | h2 61 | 62 | 63 | 64 | postgresql 65 | postgresql 66 | 9.1-901.jdbc4 67 | 68 | 69 | org.springframework.security 70 | spring-security-rsa 71 | 72 | 73 | 74 | 75 | UTF-8 76 | 1.8 77 | UTF-8 78 | com.thoughtmechanix.organization.Application 79 | johncarnell/tmx-organization-service 80 | chapter4 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | maven-resources-plugin 89 | 90 | 91 | copy-resources 92 | 93 | validate 94 | 95 | copy-resources 96 | 97 | 98 | ${basedir}/target/dockerfile 99 | 100 | 101 | src/main/docker 102 | true 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | com.spotify 111 | docker-maven-plugin 112 | 0.4.10 113 | 114 | ${docker.image.name}:${docker.image.tag} 115 | ${basedir}/target/dockerfile 116 | 117 | 118 | / 119 | ${project.build.directory} 120 | ${project.build.finalName}.jar 121 | 122 | 123 | 124 | 125 | 126 | org.springframework.boot 127 | spring-boot-maven-plugin 128 | 129 | 130 | org.springframework.boot 131 | spring-boot-starter-aop 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /licensing-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | 5 | com.thoughtmechanix 6 | licensing-service 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | Eagle Eye Licensing Service 11 | Licensing Service 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-parent 16 | 1.4.4.RELEASE 17 | 18 | 19 | 20 | 21 | org.springframework.cloud 22 | spring-cloud-dependencies 23 | Camden.SR5 24 | pom 25 | import 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-data-jpa 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-web 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-starter-actuator 43 | 44 | 45 | 46 | org.springframework.cloud 47 | spring-cloud-starter-eureka 48 | 49 | 50 | 51 | org.springframework.cloud 52 | spring-cloud-starter-feign 53 | 54 | 55 | 56 | org.springframework.cloud 57 | spring-cloud-starter-config 58 | 59 | 60 | 61 | org.springframework.cloud 62 | spring-cloud-config-client 63 | 64 | 65 | 66 | com.h2database 67 | h2 68 | 69 | 70 | 71 | postgresql 72 | postgresql 73 | 9.1-901.jdbc4 74 | 75 | 76 | org.springframework.security 77 | spring-security-rsa 78 | 79 | 80 | 81 | 82 | UTF-8 83 | 1.8 84 | UTF-8 85 | com.thoughtmechanix.licenses.Application 86 | johncarnell/tmx-licensing-service 87 | chapter4 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | maven-resources-plugin 96 | 97 | 98 | copy-resources 99 | 100 | validate 101 | 102 | copy-resources 103 | 104 | 105 | ${basedir}/target/dockerfile 106 | 107 | 108 | src/main/docker 109 | true 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | com.spotify 118 | docker-maven-plugin 119 | 0.4.10 120 | 121 | ${docker.image.name}:${docker.image.tag} 122 | ${basedir}/target/dockerfile 123 | 124 | 125 | / 126 | ${project.build.directory} 127 | ${project.build.finalName}.jar 128 | 129 | 130 | 131 | 132 | 133 | org.springframework.boot 134 | spring-boot-maven-plugin 135 | 136 | 137 | 138 | 139 | --------------------------------------------------------------------------------