initial commit
This commit is contained in:
		
							parent
							
								
									119344f0e2
								
							
						
					
					
						commit
						ea807acdba
					
				
							
								
								
									
										42
									
								
								kubernetes/productcatalogue-service.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								kubernetes/productcatalogue-service.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | --- | ||||||
|  | apiVersion: v1 | ||||||
|  | kind: Service | ||||||
|  | metadata: | ||||||
|  |   name: productcatalogue | ||||||
|  |   labels: | ||||||
|  |     app: productcatalogue | ||||||
|  | spec: | ||||||
|  |   type: NodePort | ||||||
|  |   selector: | ||||||
|  |     app: productcatalogue | ||||||
|  |   ports: | ||||||
|  |   - protocol: TCP | ||||||
|  |     port: 8020 | ||||||
|  |     name: http | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | apiVersion: apps/v1 | ||||||
|  | kind: Deployment | ||||||
|  | metadata: | ||||||
|  |   name: productcatalogue | ||||||
|  | spec: | ||||||
|  |   selector: | ||||||
|  |     matchLabels: | ||||||
|  |       app: productcatalogue | ||||||
|  |   replicas: 1 | ||||||
|  |   template: | ||||||
|  |     metadata: | ||||||
|  |       labels: | ||||||
|  |         app: productcatalogue | ||||||
|  |     spec: | ||||||
|  |       containers: | ||||||
|  |       - name: productcatalogue | ||||||
|  |         image: danielbryantuk/djproductcatalogue:latest | ||||||
|  |         ports: | ||||||
|  |         - containerPort: 8020 | ||||||
|  |         livenessProbe: | ||||||
|  |           httpGet: | ||||||
|  |             path: /healthcheck | ||||||
|  |             port: 8025 | ||||||
|  |           initialDelaySeconds: 30 | ||||||
|  |           timeoutSeconds: 1 | ||||||
							
								
								
									
										42
									
								
								kubernetes/shopfront-service.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								kubernetes/shopfront-service.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | --- | ||||||
|  | apiVersion: v1 | ||||||
|  | kind: Service | ||||||
|  | metadata: | ||||||
|  |   name: shopfront | ||||||
|  |   labels: | ||||||
|  |     app: shopfront | ||||||
|  | spec: | ||||||
|  |   type: NodePort | ||||||
|  |   selector: | ||||||
|  |     app: shopfront | ||||||
|  |   ports: | ||||||
|  |   - protocol: TCP | ||||||
|  |     port: 8010 | ||||||
|  |     name: http | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | apiVersion: apps/v1 | ||||||
|  | kind: Deployment | ||||||
|  | metadata: | ||||||
|  |   name: shopfront | ||||||
|  | spec: | ||||||
|  |   selector: | ||||||
|  |     matchLabels: | ||||||
|  |       app: shopfront | ||||||
|  |   replicas: 1 | ||||||
|  |   template: | ||||||
|  |     metadata: | ||||||
|  |       labels: | ||||||
|  |         app: shopfront | ||||||
|  |     spec: | ||||||
|  |       containers: | ||||||
|  |       - name: djshopfront | ||||||
|  |         image: danielbryantuk/djshopfront:latest | ||||||
|  |         ports: | ||||||
|  |         - containerPort: 8010 | ||||||
|  |         livenessProbe: | ||||||
|  |           httpGet: | ||||||
|  |             path: /health | ||||||
|  |             port: 8010 | ||||||
|  |           initialDelaySeconds: 30 | ||||||
|  |           timeoutSeconds: 1 | ||||||
							
								
								
									
										43
									
								
								kubernetes/stockmanager-service.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								kubernetes/stockmanager-service.yaml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | --- | ||||||
|  | apiVersion: v1 | ||||||
|  | kind: Service | ||||||
|  | metadata: | ||||||
|  |   name: stockmanager | ||||||
|  |   labels: | ||||||
|  |     app: stockmanager | ||||||
|  | spec: | ||||||
|  |   type: NodePort | ||||||
|  |   selector: | ||||||
|  |     app: stockmanager | ||||||
|  |   ports: | ||||||
|  |   - protocol: TCP | ||||||
|  |     port: 8030 | ||||||
|  |     name: http | ||||||
|  | 
 | ||||||
|  | --- | ||||||
|  | apiVersion: apps/v1 | ||||||
|  | kind: Deployment | ||||||
|  | metadata: | ||||||
|  |   name: stockmanager | ||||||
|  | spec: | ||||||
|  |   spec: | ||||||
|  |   selector: | ||||||
|  |     matchLabels: | ||||||
|  |       app: stockmanager | ||||||
|  |   replicas: 1 | ||||||
|  |   template: | ||||||
|  |     metadata: | ||||||
|  |       labels: | ||||||
|  |         app: stockmanager | ||||||
|  |     spec: | ||||||
|  |       containers: | ||||||
|  |       - name: stockmanager | ||||||
|  |         image: danielbryantuk/djstockmanager:latest | ||||||
|  |         ports: | ||||||
|  |         - containerPort: 8030 | ||||||
|  |         livenessProbe: | ||||||
|  |           httpGet: | ||||||
|  |             path: /health | ||||||
|  |             port: 8030 | ||||||
|  |           initialDelaySeconds: 30 | ||||||
|  |           timeoutSeconds: 1 | ||||||
							
								
								
									
										5
									
								
								productcatalogue/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								productcatalogue/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | FROM openjdk:8-jre | ||||||
|  | ADD target/productcatalogue-0.0.1-SNAPSHOT.jar app.jar | ||||||
|  | ADD product-catalogue.yml app-config.yml | ||||||
|  | EXPOSE 8020 | ||||||
|  | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","app.jar", "server", "app-config.yml"] | ||||||
							
								
								
									
										9
									
								
								productcatalogue/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								productcatalogue/README.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | |||||||
|  | product-catalogue | ||||||
|  | ================= | ||||||
|  | 
 | ||||||
|  | java -jar target/product-1.0-SNAPSHOT.jar server product-catalogue.yml | ||||||
|  | 
 | ||||||
|  | docker build -t danielbryantuk/product . | ||||||
|  | docker run -p 9010:9010 -p 9011:9011 -d danielbryantuk/product | ||||||
|  | 
 | ||||||
|  | Update | ||||||
							
								
								
									
										79
									
								
								productcatalogue/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								productcatalogue/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,79 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||||
|  |          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||||
|  |     <modelVersion>4.0.0</modelVersion> | ||||||
|  | 
 | ||||||
|  |     <groupId>uk.co.danielbryant.djshopping</groupId> | ||||||
|  |     <artifactId>productcatalogue</artifactId> | ||||||
|  |     <version>0.0.1-SNAPSHOT</version> | ||||||
|  | 
 | ||||||
|  |     <properties> | ||||||
|  |         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||||
|  |         <dropwizard.version>1.3.27</dropwizard.version> | ||||||
|  |         <guice.version>4.2.3</guice.version> | ||||||
|  |     </properties> | ||||||
|  | 
 | ||||||
|  |     <dependencies> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>io.dropwizard</groupId> | ||||||
|  |             <artifactId>dropwizard-core</artifactId> | ||||||
|  |             <version>${dropwizard.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.google.inject</groupId> | ||||||
|  |             <artifactId>guice</artifactId> | ||||||
|  |             <version>${guice.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |     </dependencies> | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     <build> | ||||||
|  |         <plugins> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.apache.maven.plugins</groupId> | ||||||
|  |                 <artifactId>maven-compiler-plugin</artifactId> | ||||||
|  |                 <configuration> | ||||||
|  |                     <source>1.8</source> | ||||||
|  |                     <target>1.8</target> | ||||||
|  |                 </configuration> | ||||||
|  |             </plugin> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.apache.maven.plugins</groupId> | ||||||
|  |                 <artifactId>maven-shade-plugin</artifactId> | ||||||
|  |                 <version>1.6</version> | ||||||
|  |                 <configuration> | ||||||
|  |                     <createDependencyReducedPom>true</createDependencyReducedPom> | ||||||
|  |                     <filters> | ||||||
|  |                         <filter> | ||||||
|  |                             <artifact>*:*</artifact> | ||||||
|  |                             <excludes> | ||||||
|  |                                 <exclude>META-INF/*.SF</exclude> | ||||||
|  |                                 <exclude>META-INF/*.DSA</exclude> | ||||||
|  |                                 <exclude>META-INF/*.RSA</exclude> | ||||||
|  |                             </excludes> | ||||||
|  |                         </filter> | ||||||
|  |                     </filters> | ||||||
|  |                 </configuration> | ||||||
|  |                 <executions> | ||||||
|  |                     <execution> | ||||||
|  |                         <phase>package</phase> | ||||||
|  |                         <goals> | ||||||
|  |                             <goal>shade</goal> | ||||||
|  |                         </goals> | ||||||
|  |                         <configuration> | ||||||
|  |                             <transformers> | ||||||
|  |                                 <transformer | ||||||
|  |                                         implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/> | ||||||
|  |                                 <transformer | ||||||
|  |                                         implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> | ||||||
|  |                                     <mainClass>uk.co.danielbryant.djshopping.productcatalogue.ProductServiceApplication</mainClass> | ||||||
|  |                                 </transformer> | ||||||
|  |                             </transformers> | ||||||
|  |                         </configuration> | ||||||
|  |                     </execution> | ||||||
|  |                 </executions> | ||||||
|  |             </plugin> | ||||||
|  |         </plugins> | ||||||
|  |     </build> | ||||||
|  | </project> | ||||||
							
								
								
									
										10
									
								
								productcatalogue/product-catalogue.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								productcatalogue/product-catalogue.yml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | version: 1.0-SNAPSHOT | ||||||
|  |   | ||||||
|  | 
 | ||||||
|  | server: | ||||||
|  |   applicationConnectors: | ||||||
|  |   - type: http | ||||||
|  |     port: 8020 | ||||||
|  |   adminConnectors: | ||||||
|  |   - type: http | ||||||
|  |     port: 8025 | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.productcatalogue; | ||||||
|  | 
 | ||||||
|  | import com.google.inject.Guice; | ||||||
|  | import com.google.inject.Injector; | ||||||
|  | import io.dropwizard.Application; | ||||||
|  | import io.dropwizard.setup.Bootstrap; | ||||||
|  | import io.dropwizard.setup.Environment; | ||||||
|  | import uk.co.danielbryant.djshopping.productcatalogue.healthchecks.BasicHealthCheck; | ||||||
|  | import uk.co.danielbryant.djshopping.productcatalogue.configuration.ProductServiceConfiguration; | ||||||
|  | import uk.co.danielbryant.djshopping.productcatalogue.resources.ProductResource; | ||||||
|  | 
 | ||||||
|  | public class ProductServiceApplication extends Application<ProductServiceConfiguration> { | ||||||
|  |     public static void main(String[] args) throws Exception { | ||||||
|  |         new ProductServiceApplication().run(args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public String getName() { | ||||||
|  |         return "product-list-service"; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void initialize(Bootstrap<ProductServiceConfiguration> bootstrap) { | ||||||
|  |         // nothing to do yet | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public void run(ProductServiceConfiguration config, | ||||||
|  |                     Environment environment) { | ||||||
|  |         final BasicHealthCheck healthCheck = new BasicHealthCheck(config.getVersion()); | ||||||
|  |         environment.healthChecks().register("template", healthCheck); | ||||||
|  | 
 | ||||||
|  |         Injector injector = Guice.createInjector(); | ||||||
|  |         environment.jersey().register(injector.getInstance(ProductResource.class)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.productcatalogue.configuration; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | import io.dropwizard.Configuration; | ||||||
|  | import org.hibernate.validator.constraints.NotEmpty; | ||||||
|  | 
 | ||||||
|  | public class ProductServiceConfiguration extends Configuration { | ||||||
|  | 
 | ||||||
|  |     @NotEmpty | ||||||
|  |     private String version; | ||||||
|  | 
 | ||||||
|  |     @JsonProperty | ||||||
|  |     public String getVersion() { | ||||||
|  |         return version; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JsonProperty | ||||||
|  |     public void setVersion(String version) { | ||||||
|  |         this.version = version; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,17 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.productcatalogue.healthchecks; | ||||||
|  | 
 | ||||||
|  | import com.codahale.metrics.health.HealthCheck; | ||||||
|  | 
 | ||||||
|  | public class BasicHealthCheck extends HealthCheck { | ||||||
|  | 
 | ||||||
|  |     private final String version; | ||||||
|  | 
 | ||||||
|  |     public BasicHealthCheck(String version) { | ||||||
|  |         this.version = version; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     protected Result check() throws Exception { | ||||||
|  |         return Result.healthy("Ok with version: " + version); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,43 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.productcatalogue.model; | ||||||
|  | 
 | ||||||
|  | import com.fasterxml.jackson.annotation.JsonProperty; | ||||||
|  | 
 | ||||||
|  | import java.math.BigDecimal; | ||||||
|  | 
 | ||||||
|  | public class Product { | ||||||
|  |     private String id; | ||||||
|  |     private String name; | ||||||
|  |     private String description; | ||||||
|  |     private BigDecimal price; | ||||||
|  | 
 | ||||||
|  |     public Product() { | ||||||
|  |         // Needed for Jackson deserialization | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Product(String id, String name, String description, BigDecimal price) { | ||||||
|  |         this.id = id; | ||||||
|  |         this.name = name; | ||||||
|  |         this.description = description; | ||||||
|  |         this.price = price; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JsonProperty | ||||||
|  |     public String getId() { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JsonProperty | ||||||
|  |     public String getName() { | ||||||
|  |         return name; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JsonProperty | ||||||
|  |     public String getDescription() { | ||||||
|  |         return description; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @JsonProperty | ||||||
|  |     public BigDecimal getPrice() { | ||||||
|  |         return price; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,50 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.productcatalogue.resources; | ||||||
|  | 
 | ||||||
|  | import com.codahale.metrics.annotation.Timed; | ||||||
|  | import com.google.inject.Inject; | ||||||
|  | import uk.co.danielbryant.djshopping.productcatalogue.services.ProductService; | ||||||
|  | import uk.co.danielbryant.djshopping.productcatalogue.model.Product; | ||||||
|  | 
 | ||||||
|  | import javax.ws.rs.GET; | ||||||
|  | import javax.ws.rs.Path; | ||||||
|  | import javax.ws.rs.PathParam; | ||||||
|  | import javax.ws.rs.Produces; | ||||||
|  | import javax.ws.rs.core.MediaType; | ||||||
|  | import javax.ws.rs.core.Response; | ||||||
|  | import java.util.Optional; | ||||||
|  | 
 | ||||||
|  | @Path("/products") | ||||||
|  | @Produces(MediaType.APPLICATION_JSON) | ||||||
|  | public class ProductResource { | ||||||
|  | 
 | ||||||
|  |     private ProductService productService; | ||||||
|  | 
 | ||||||
|  |     @Inject | ||||||
|  |     public ProductResource(ProductService productService) { | ||||||
|  |         this.productService = productService; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Timed | ||||||
|  |     public Response getAllProducts() { | ||||||
|  |         return Response.status(200) | ||||||
|  |                 .entity(productService.getAllProducts()) | ||||||
|  |                 .build(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @GET | ||||||
|  |     @Timed | ||||||
|  |     @Path("{id}") | ||||||
|  |     public Response getProduct(@PathParam("id") String id) { | ||||||
|  |         Optional<Product> result = productService.getProduct(id); | ||||||
|  | 
 | ||||||
|  |         if (result.isPresent()) { | ||||||
|  |             return Response.status(Response.Status.OK) | ||||||
|  |                     .entity(result.get()) | ||||||
|  |                     .build(); | ||||||
|  |         } else { | ||||||
|  |             return Response.status(Response.Status.NOT_FOUND) | ||||||
|  |                     .build(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,28 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.productcatalogue.services; | ||||||
|  | 
 | ||||||
|  | import uk.co.danielbryant.djshopping.productcatalogue.model.Product; | ||||||
|  | 
 | ||||||
|  | import java.math.BigDecimal; | ||||||
|  | import java.util.*; | ||||||
|  | 
 | ||||||
|  | public class ProductService { | ||||||
|  | 
 | ||||||
|  |     //{productId, Product} | ||||||
|  |     private Map<String, Product> fakeProductDAO = new HashMap<>(); | ||||||
|  | 
 | ||||||
|  |     public ProductService() { | ||||||
|  |         fakeProductDAO.put("1", new Product("1", "Widget", "Premium ACME Widgets", new BigDecimal(1.20))); | ||||||
|  |         fakeProductDAO.put("2", new Product("2", "Sprocket", "Grade B sprockets", new BigDecimal(4.10))); | ||||||
|  |         fakeProductDAO.put("3", new Product("3", "Anvil", "Large Anvils", new BigDecimal(45.50))); | ||||||
|  |         fakeProductDAO.put("4", new Product("4", "Cogs", "Grade Y cogs", new BigDecimal(1.80))); | ||||||
|  |         fakeProductDAO.put("5", new Product("5", "Multitool", "Multitools", new BigDecimal(154.10))); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Product> getAllProducts() { | ||||||
|  |         return new ArrayList<>(fakeProductDAO.values()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Optional<Product> getProduct(String id) { | ||||||
|  |         return Optional.ofNullable(fakeProductDAO.get(id)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								shopfront/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								shopfront/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | FROM openjdk:8-jre | ||||||
|  | ADD target/shopfront-0.0.1-SNAPSHOT.jar app.jar | ||||||
|  | EXPOSE 8010 | ||||||
|  | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] | ||||||
							
								
								
									
										76
									
								
								shopfront/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								shopfront/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,76 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project xmlns="http://maven.apache.org/POM/4.0.0" | ||||||
|  |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||||
|  |     <modelVersion>4.0.0</modelVersion> | ||||||
|  | 
 | ||||||
|  |     <groupId>uk.co.danielbryant.djshopping</groupId> | ||||||
|  |     <artifactId>shopfront</artifactId> | ||||||
|  |     <version>0.0.1-SNAPSHOT</version> | ||||||
|  |     <packaging>jar</packaging> | ||||||
|  | 
 | ||||||
|  |     <name>shopfront</name> | ||||||
|  |     <description>Docker Java application Shopfront</description> | ||||||
|  | 
 | ||||||
|  |     <parent> | ||||||
|  |         <groupId>org.springframework.boot</groupId> | ||||||
|  |         <artifactId>spring-boot-starter-parent</artifactId> | ||||||
|  |         <version>1.5.22.RELEASE</version> | ||||||
|  |     </parent> | ||||||
|  | 
 | ||||||
|  |     <properties> | ||||||
|  |         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||||
|  |         <java.version>1.8</java.version> | ||||||
|  |     </properties> | ||||||
|  | 
 | ||||||
|  |     <dependencyManagement> | ||||||
|  |         <dependencies> | ||||||
|  |             <dependency> | ||||||
|  |                 <groupId>org.springframework.cloud</groupId> | ||||||
|  |                 <artifactId>spring-cloud-dependencies</artifactId> | ||||||
|  |                 <version>Dalston.SR5</version> | ||||||
|  |                 <type>pom</type> | ||||||
|  |                 <scope>import</scope> | ||||||
|  |             </dependency> | ||||||
|  |         </dependencies> | ||||||
|  |     </dependencyManagement> | ||||||
|  | 
 | ||||||
|  |     <dependencies> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.boot</groupId> | ||||||
|  |             <artifactId>spring-boot-starter-thymeleaf</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.boot</groupId> | ||||||
|  |             <artifactId>spring-boot-starter-actuator</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.cloud</groupId> | ||||||
|  |             <artifactId>spring-cloud-starter-hystrix</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.cloud</groupId> | ||||||
|  |             <artifactId>spring-cloud-starter-eureka</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <!-- Test --> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.boot</groupId> | ||||||
|  |             <artifactId>spring-boot-starter-test</artifactId> | ||||||
|  |             <scope>test</scope> | ||||||
|  |         </dependency> | ||||||
|  |     </dependencies> | ||||||
|  | 
 | ||||||
|  |     <build> | ||||||
|  |         <plugins> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.springframework.boot</groupId> | ||||||
|  |                 <artifactId>spring-boot-maven-plugin</artifactId> | ||||||
|  |             </plugin> | ||||||
|  | 
 | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.codehaus.mojo</groupId> | ||||||
|  |                 <artifactId>versions-maven-plugin</artifactId> | ||||||
|  |             </plugin> | ||||||
|  |         </plugins> | ||||||
|  | 
 | ||||||
|  |     </build> | ||||||
|  | </project> | ||||||
| @ -0,0 +1,21 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront; | ||||||
|  | 
 | ||||||
|  | import org.springframework.boot.SpringApplication; | ||||||
|  | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||||
|  | import org.springframework.cloud.netflix.hystrix.EnableHystrix; | ||||||
|  | import org.springframework.context.annotation.Bean; | ||||||
|  | import org.springframework.web.client.RestTemplate; | ||||||
|  | 
 | ||||||
|  | @SpringBootApplication | ||||||
|  | @EnableHystrix | ||||||
|  | public class ShopfrontApplication { | ||||||
|  | 
 | ||||||
|  |     public static void main(String[] args) { | ||||||
|  |         SpringApplication.run(ShopfrontApplication.class, args); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Bean(name = "stdRestTemplate") | ||||||
|  |     public RestTemplate getRestTemplate() { | ||||||
|  |         return new RestTemplate(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,20 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront.controllers; | ||||||
|  | 
 | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.stereotype.Controller; | ||||||
|  | import org.springframework.ui.Model; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.services.ProductService; | ||||||
|  | 
 | ||||||
|  | @Controller | ||||||
|  | public class HomeController { | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private ProductService productService; | ||||||
|  | 
 | ||||||
|  |     @RequestMapping("/") | ||||||
|  |     public String index(Model model) { | ||||||
|  |         model.addAttribute("products", productService.getProducts()); | ||||||
|  |         return "index"; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,52 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront.model; | ||||||
|  | 
 | ||||||
|  | import java.math.BigDecimal; | ||||||
|  | 
 | ||||||
|  | public class Product { | ||||||
|  |     private String id; | ||||||
|  |     private String sku; | ||||||
|  |     private String name; | ||||||
|  |     private String description; | ||||||
|  |     private BigDecimal price; | ||||||
|  |     private int amountAvailable; | ||||||
|  | 
 | ||||||
|  |     public Product(String id, String name, String description, BigDecimal price) { | ||||||
|  |         this.id = id; | ||||||
|  |         this.name = name; | ||||||
|  |         this.description = description; | ||||||
|  |         this.price = price; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Product(String id, String sku, String name, String description, BigDecimal price, int amountAvailable) { | ||||||
|  |         this.id = id; | ||||||
|  |         this.sku = sku; | ||||||
|  |         this.name = name; | ||||||
|  |         this.description = description; | ||||||
|  |         this.price = price; | ||||||
|  |         this.amountAvailable = amountAvailable; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getId() { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getSku() { | ||||||
|  |         return sku; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getName() { | ||||||
|  |         return name; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getDescription() { | ||||||
|  |         return description; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public BigDecimal getPrice() { | ||||||
|  |         return price; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getAmountAvailable() { | ||||||
|  |         return amountAvailable; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,39 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront.repo; | ||||||
|  | 
 | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.beans.factory.annotation.Qualifier; | ||||||
|  | import org.springframework.beans.factory.annotation.Value; | ||||||
|  | import org.springframework.core.ParameterizedTypeReference; | ||||||
|  | import org.springframework.http.HttpMethod; | ||||||
|  | import org.springframework.http.ResponseEntity; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.springframework.web.client.RestTemplate; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.services.dto.ProductDTO; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | @Component | ||||||
|  | public class ProductRepo { | ||||||
|  | 
 | ||||||
|  |     @Value("${productCatalogueUri}") | ||||||
|  |     private String productCatalogueUri; | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     @Qualifier(value = "stdRestTemplate") | ||||||
|  |     private RestTemplate restTemplate; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public Map<String, ProductDTO> getProductDTOs() { | ||||||
|  |         ResponseEntity<List<ProductDTO>> productCatalogueResponse = | ||||||
|  |                 restTemplate.exchange(productCatalogueUri + "/products", | ||||||
|  |                         HttpMethod.GET, null, new ParameterizedTypeReference<List<ProductDTO>>() { | ||||||
|  |                         }); | ||||||
|  |         List<ProductDTO> productDTOs = productCatalogueResponse.getBody(); | ||||||
|  | 
 | ||||||
|  |         return productDTOs.stream() | ||||||
|  |                 .collect(Collectors.toMap(ProductDTO::getId, Function.identity())); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,51 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront.repo; | ||||||
|  | 
 | ||||||
|  | import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.beans.factory.annotation.Qualifier; | ||||||
|  | import org.springframework.beans.factory.annotation.Value; | ||||||
|  | import org.springframework.core.ParameterizedTypeReference; | ||||||
|  | import org.springframework.http.HttpMethod; | ||||||
|  | import org.springframework.http.ResponseEntity; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.springframework.web.client.RestTemplate; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.services.dto.StockDTO; | ||||||
|  | 
 | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.function.Function; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | @Component | ||||||
|  | public class StockRepo { | ||||||
|  | 
 | ||||||
|  |     private static final Logger LOGGER = LoggerFactory.getLogger(StockRepo.class); | ||||||
|  | 
 | ||||||
|  |     @Value("${stockManagerUri}") | ||||||
|  |     private String stockManagerUri; | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     @Qualifier(value = "stdRestTemplate") | ||||||
|  |     private RestTemplate restTemplate; | ||||||
|  | 
 | ||||||
|  |     @HystrixCommand(fallbackMethod = "stocksNotFound") // Hystrix circuit breaker for fault-tolernace demo | ||||||
|  |     public Map<String, StockDTO> getStockDTOs() { | ||||||
|  |         LOGGER.info("getStocksDTOs"); | ||||||
|  |         ResponseEntity<List<StockDTO>> stockManagerResponse = | ||||||
|  |                 restTemplate.exchange(stockManagerUri + "/stocks", | ||||||
|  |                         HttpMethod.GET, null, new ParameterizedTypeReference<List<StockDTO>>() { | ||||||
|  |                         }); | ||||||
|  |         List<StockDTO> stockDTOs = stockManagerResponse.getBody(); | ||||||
|  | 
 | ||||||
|  |         return stockDTOs.stream() | ||||||
|  |                 .collect(Collectors.toMap(StockDTO::getProductId, Function.identity())); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Map<String, StockDTO> stocksNotFound() { | ||||||
|  |         LOGGER.info("stocksNotFound *** FALLBACK ***"); | ||||||
|  |         return Collections.EMPTY_MAP; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,22 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront.resources; | ||||||
|  | 
 | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.web.bind.annotation.RequestMapping; | ||||||
|  | import org.springframework.web.bind.annotation.RestController; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.model.Product; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.services.ProductService; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @RestController | ||||||
|  | @RequestMapping("/products") | ||||||
|  | public class ProductResource { | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private ProductService productService; | ||||||
|  | 
 | ||||||
|  |     @RequestMapping() | ||||||
|  |     public List<Product> getProducts() { | ||||||
|  |         return productService.getProducts(); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,45 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront.services; | ||||||
|  | 
 | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.model.Product; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.repo.StockRepo; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.repo.ProductRepo; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.services.dto.ProductDTO; | ||||||
|  | import uk.co.danielbryant.djshopping.shopfront.services.dto.StockDTO; | ||||||
|  | 
 | ||||||
|  | import java.util.Collections; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | 
 | ||||||
|  | @Service | ||||||
|  | public class ProductService { | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private StockRepo stockRepo; | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private ProductRepo productRepo; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  |     public List<Product> getProducts() { | ||||||
|  |         Map<String, ProductDTO> productDTOs = productRepo.getProductDTOs(); | ||||||
|  |         Map<String, StockDTO> stockDTOMap = stockRepo.getStockDTOs(); | ||||||
|  | 
 | ||||||
|  |         // Merge productDTOs and stockDTOs to a List of Products | ||||||
|  |         return productDTOs.values().stream() | ||||||
|  |                 .map(productDTO -> { | ||||||
|  |                     StockDTO stockDTO = stockDTOMap.get(productDTO.getId()); | ||||||
|  |                     if (stockDTO == null) { | ||||||
|  |                         stockDTO = StockDTO.DEFAULT_STOCK_DTO; | ||||||
|  |                     } | ||||||
|  |                     return new Product(productDTO.getId(), stockDTO.getSku(), productDTO.getName(), productDTO.getDescription(), productDTO.getPrice(), stockDTO.getAmountAvailable()); | ||||||
|  |                 }) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Product> productsNotFound() { | ||||||
|  |         return Collections.EMPTY_LIST; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,36 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront.services.dto; | ||||||
|  | 
 | ||||||
|  | import java.math.BigDecimal; | ||||||
|  | 
 | ||||||
|  | public class ProductDTO { | ||||||
|  |     private String id; | ||||||
|  |     private String name; | ||||||
|  |     private String description; | ||||||
|  |     private BigDecimal price; | ||||||
|  | 
 | ||||||
|  |     public ProductDTO() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public ProductDTO(String id, String name, String description, BigDecimal price) { | ||||||
|  |         this.id = id; | ||||||
|  |         this.name = name; | ||||||
|  |         this.description = description; | ||||||
|  |         this.price = price; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getId() { | ||||||
|  |         return id; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getName() { | ||||||
|  |         return name; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getDescription() { | ||||||
|  |         return description; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public BigDecimal getPrice() { | ||||||
|  |         return price; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront.services.dto; | ||||||
|  | 
 | ||||||
|  | public class StockDTO { | ||||||
|  |     private String productId; | ||||||
|  |     private String sku; | ||||||
|  |     private int amountAvailable; | ||||||
|  | 
 | ||||||
|  |     public static final StockDTO DEFAULT_STOCK_DTO = new StockDTO("", "default", 999); | ||||||
|  | 
 | ||||||
|  |     public StockDTO() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public StockDTO(String productId, String sku, int amountAvailable) { | ||||||
|  |         this.productId = productId; | ||||||
|  |         this.sku = sku; | ||||||
|  |         this.amountAvailable = amountAvailable; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getProductId() { | ||||||
|  |         return productId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getSku() { | ||||||
|  |         return sku; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getAmountAvailable() { | ||||||
|  |         return amountAvailable; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								shopfront/src/main/resources/application.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								shopfront/src/main/resources/application.properties
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | server.port = 8010 | ||||||
|  | productCatalogueUri = http://productcatalogue:8020 | ||||||
|  | stockManagerUri = http://stockmanager:8030 | ||||||
							
								
								
									
										90
									
								
								shopfront/src/main/resources/templates/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								shopfront/src/main/resources/templates/index.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,90 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="en" | ||||||
|  |       xmlns="http://www.w3.org/1999/xhtml" | ||||||
|  |       xmlns:th="http://www.thymeleaf.org"> | ||||||
|  | <head> | ||||||
|  |     <meta charset="utf-8"/> | ||||||
|  |     <meta http-equiv="X-UA-Compatible" content="IE=edge"/> | ||||||
|  |     <meta name="viewport" content="width=device-width, initial-scale=1"/> | ||||||
|  |     <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> | ||||||
|  | 
 | ||||||
|  |     <title>Welcome to the Docker Java Shopfront!</title> | ||||||
|  |     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | ||||||
|  |     <!-- Latest compiled and minified CSS --> | ||||||
|  |     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" | ||||||
|  |           integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"/> | ||||||
|  | 
 | ||||||
|  |     <!-- Optional theme --> | ||||||
|  |     <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" | ||||||
|  |           integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"/> | ||||||
|  | 
 | ||||||
|  |     <!-- Latest compiled and minified JavaScript --> | ||||||
|  |     <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" | ||||||
|  |             integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" | ||||||
|  |             crossorigin="anonymous"></script> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | <nav class="navbar navbar-inverse navbar-fixed-top"> | ||||||
|  |     <div class="container-fluid" style="background-color: #ff203b"> | ||||||
|  |         <div class="navbar-header"> | ||||||
|  |             <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" | ||||||
|  |                     aria-expanded="false" aria-controls="navbar"> | ||||||
|  |                 <span class="sr-only">Toggle navigation</span> | ||||||
|  |                 <span class="icon-bar"></span> | ||||||
|  |                 <span class="icon-bar"></span> | ||||||
|  |                 <span class="icon-bar"></span> | ||||||
|  |             </button> | ||||||
|  |             <a class="navbar-brand" href="#">Docker Java Shopfront</a> | ||||||
|  |         </div> | ||||||
|  |         <div id="navbar" class="navbar-collapse collapse"> | ||||||
|  |             <ul class="nav navbar-nav navbar-right"> | ||||||
|  |                 <li><a href="#">Help</a></li> | ||||||
|  |             </ul> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </nav> | ||||||
|  | 
 | ||||||
|  | <div class="container-fluid"> | ||||||
|  |     <div class="row"> | ||||||
|  |         <div class="col-sm-3 col-md-2 sidebar"> | ||||||
|  |             <ul class="nav nav-sidebar"> | ||||||
|  |                 <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li> | ||||||
|  |             </ul> | ||||||
|  |         </div> | ||||||
|  |         <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> | ||||||
|  |             <h1 class="page-header">Welcome to the Docker Java Shopfront!</h1> | ||||||
|  |             <h2 class="sub-header">Please select a product!</h2> | ||||||
|  |             <div class="table-responsive"> | ||||||
|  | 
 | ||||||
|  |                 <table class="table table-striped" id="product-table"> | ||||||
|  |                     <thead> | ||||||
|  |                     <tr> | ||||||
|  |                         <th>Product Num</th> | ||||||
|  |                         <th>SKU</th> | ||||||
|  |                         <th>Name</th> | ||||||
|  |                         <th>Description</th> | ||||||
|  |                         <th>Price £</th> | ||||||
|  |                         <th>Qty Available</th> | ||||||
|  |                     </tr> | ||||||
|  |                     </thead> | ||||||
|  |                     <tbody> | ||||||
|  |                     <tr th:each="product : ${products}"> | ||||||
|  |                         <td th:text="${product.id}">1</td> | ||||||
|  |                         <td th:text="${product.sku}">12345678</td> | ||||||
|  |                         <td th:text="${product.name}">Widget</td> | ||||||
|  |                         <td th:text="${product.description}">Widget</td> | ||||||
|  |                         <td th:text="${#numbers.formatDecimal(product.price, 0, 'COMMA', 2, 'POINT')}">1.19</td> | ||||||
|  |                         <td th:text="${product.amountAvailable}">2</td> | ||||||
|  |                     </tr> | ||||||
|  |                     </tbody> | ||||||
|  |                 </table> | ||||||
|  |             </div> | ||||||
|  |         </div> | ||||||
|  |     </div> | ||||||
|  | </div> | ||||||
|  | <!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> | ||||||
|  | <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> | ||||||
|  | <!-- Include all compiled plugins (below), or include individual files as needed --> | ||||||
|  | <script src="js/bootstrap.min.js"></script> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
| @ -0,0 +1,16 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.shopfront; | ||||||
|  | 
 | ||||||
|  | import org.junit.Test; | ||||||
|  | import org.junit.runner.RunWith; | ||||||
|  | import org.springframework.boot.test.context.SpringBootTest; | ||||||
|  | import org.springframework.test.context.junit4.SpringRunner; | ||||||
|  | 
 | ||||||
|  | @RunWith(SpringRunner.class) | ||||||
|  | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ShopfrontApplication.class) | ||||||
|  | public class ShopfrontApplicationTests { | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void contextLoads() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								stockmanager/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								stockmanager/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | |||||||
|  | FROM openjdk:8-jre | ||||||
|  | ADD target/stockmanager-0.0.1-SNAPSHOT.jar app.jar | ||||||
|  | EXPOSE 8030 | ||||||
|  | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] | ||||||
							
								
								
									
										85
									
								
								stockmanager/pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								stockmanager/pom.xml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | |||||||
|  | <?xml version="1.0" encoding="UTF-8"?> | ||||||
|  | <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||||||
|  |          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||||||
|  |     <modelVersion>4.0.0</modelVersion> | ||||||
|  | 
 | ||||||
|  |     <groupId>uk.co.danielbryant.djshopping</groupId> | ||||||
|  |     <artifactId>stockmanager</artifactId> | ||||||
|  |     <version>0.0.1-SNAPSHOT</version> | ||||||
|  |     <packaging>jar</packaging> | ||||||
|  | 
 | ||||||
|  |     <name>stockmanager</name> | ||||||
|  |     <description>Docker Java application stock manager</description> | ||||||
|  | 
 | ||||||
|  |     <parent> | ||||||
|  |         <groupId>org.springframework.boot</groupId> | ||||||
|  |         <artifactId>spring-boot-starter-parent</artifactId> | ||||||
|  |         <version>2.3.7.RELEASE</version> | ||||||
|  |     </parent> | ||||||
|  | 
 | ||||||
|  |     <properties> | ||||||
|  |         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | ||||||
|  |         <java.version>1.8</java.version> | ||||||
|  |         <cucumber.version>1.2.6</cucumber.version> | ||||||
|  |         <hamcrest-core.version>2.2</hamcrest-core.version> | ||||||
|  |     </properties> | ||||||
|  | 
 | ||||||
|  |     <dependencies> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.boot</groupId> | ||||||
|  |             <artifactId>spring-boot-starter-web</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.boot</groupId> | ||||||
|  |             <artifactId>spring-boot-starter-data-jpa</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>com.h2database</groupId> | ||||||
|  |             <artifactId>h2</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.boot</groupId> | ||||||
|  |             <artifactId>spring-boot-starter-actuator</artifactId> | ||||||
|  |         </dependency> | ||||||
|  |         <!-- Test --> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.springframework.boot</groupId> | ||||||
|  |             <artifactId>spring-boot-starter-test</artifactId> | ||||||
|  |             <scope>test</scope> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>org.hamcrest</groupId> | ||||||
|  |             <artifactId>hamcrest-core</artifactId> | ||||||
|  |             <version>${hamcrest-core.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>info.cukes</groupId> | ||||||
|  |             <artifactId>cucumber-java</artifactId> | ||||||
|  |             <version>${cucumber.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>info.cukes</groupId> | ||||||
|  |             <artifactId>cucumber-junit</artifactId> | ||||||
|  |             <version>${cucumber.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |         <dependency> | ||||||
|  |             <groupId>info.cukes</groupId> | ||||||
|  |             <artifactId>cucumber-spring</artifactId> | ||||||
|  |             <version>${cucumber.version}</version> | ||||||
|  |         </dependency> | ||||||
|  |     </dependencies> | ||||||
|  | 
 | ||||||
|  |     <build> | ||||||
|  |         <plugins> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.springframework.boot</groupId> | ||||||
|  |                 <artifactId>spring-boot-maven-plugin</artifactId> | ||||||
|  |             </plugin> | ||||||
|  |             <plugin> | ||||||
|  |                 <groupId>org.codehaus.mojo</groupId> | ||||||
|  |                 <artifactId>versions-maven-plugin</artifactId> | ||||||
|  |                 <version>2.7</version> | ||||||
|  |             </plugin> | ||||||
|  |         </plugins> | ||||||
|  |     </build> | ||||||
|  | </project> | ||||||
| @ -0,0 +1,12 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.stockmanager; | ||||||
|  | 
 | ||||||
|  | import org.springframework.boot.SpringApplication; | ||||||
|  | import org.springframework.boot.autoconfigure.SpringBootApplication; | ||||||
|  | 
 | ||||||
|  | @SpringBootApplication | ||||||
|  | public class StockManagerApplication { | ||||||
|  | 
 | ||||||
|  |     public static void main(String[] args) { | ||||||
|  |         SpringApplication.run(StockManagerApplication.class, args); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,38 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.stockmanager.config; | ||||||
|  | 
 | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.stereotype.Component; | ||||||
|  | import org.springframework.transaction.annotation.Transactional; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.model.Stock; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.repositories.StockRepository; | ||||||
|  | 
 | ||||||
|  | import javax.annotation.PostConstruct; | ||||||
|  | 
 | ||||||
|  | @Component | ||||||
|  | public class DataGenerator { | ||||||
|  | 
 | ||||||
|  |     private static final Logger LOGGER = LoggerFactory.getLogger(DataGenerator.class); | ||||||
|  | 
 | ||||||
|  |     private StockRepository stockRepository; | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     protected DataGenerator(StockRepository stockRepository) { | ||||||
|  |         this.stockRepository = stockRepository; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @PostConstruct | ||||||
|  |     @Transactional | ||||||
|  |     public void init() { | ||||||
|  |         LOGGER.info("Generating synthetic data for demonstration purposes..."); | ||||||
|  | 
 | ||||||
|  |         stockRepository.save(new Stock("1", "12345678", 5)); | ||||||
|  |         stockRepository.save(new Stock("2", "34567890", 2)); | ||||||
|  |         stockRepository.save(new Stock("3", "54326745", 999)); | ||||||
|  |         stockRepository.save(new Stock("4", "93847614", 0)); | ||||||
|  |         stockRepository.save(new Stock("5", "11856388", 1)); | ||||||
|  | 
 | ||||||
|  |         LOGGER.info("... data generation complete"); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,15 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.stockmanager.exceptions; | ||||||
|  | 
 | ||||||
|  | public class StockNotFoundException extends Exception { | ||||||
|  | 
 | ||||||
|  |     public StockNotFoundException() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public StockNotFoundException(String message) { | ||||||
|  |         super(message); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public StockNotFoundException(String message, Throwable cause) { | ||||||
|  |         super(message, cause); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,34 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.stockmanager.model; | ||||||
|  | 
 | ||||||
|  | import javax.persistence.Entity; | ||||||
|  | import javax.persistence.Id; | ||||||
|  | 
 | ||||||
|  | @Entity | ||||||
|  | public class Stock { | ||||||
|  | 
 | ||||||
|  |     @Id | ||||||
|  |     private String productId; | ||||||
|  |     private String sku; | ||||||
|  |     private int amountAvailable; | ||||||
|  | 
 | ||||||
|  |     protected Stock() { | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Stock(String productId, String sku, int amountAvailable) { | ||||||
|  |         this.productId = productId; | ||||||
|  |         this.sku = sku; | ||||||
|  |         this.amountAvailable = amountAvailable; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getProductId() { | ||||||
|  |         return productId; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getSku() { | ||||||
|  |         return sku; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public int getAmountAvailable() { | ||||||
|  |         return amountAvailable; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,7 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.stockmanager.repositories; | ||||||
|  | 
 | ||||||
|  | import org.springframework.data.repository.CrudRepository; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.model.Stock; | ||||||
|  | 
 | ||||||
|  | public interface StockRepository extends CrudRepository<Stock, String> { | ||||||
|  | } | ||||||
| @ -0,0 +1,39 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.stockmanager.resources; | ||||||
|  | 
 | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.http.HttpStatus; | ||||||
|  | import org.springframework.web.bind.annotation.*; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.exceptions.StockNotFoundException; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.model.Stock; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.services.StockService; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | @RestController | ||||||
|  | @RequestMapping("/stocks") | ||||||
|  | public class StockResource { | ||||||
|  | 
 | ||||||
|  |     private static final Logger LOGGER = LoggerFactory.getLogger(StockResource.class); | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private StockService stockService; | ||||||
|  | 
 | ||||||
|  |     @RequestMapping() | ||||||
|  |     public List<Stock> getStocks() { | ||||||
|  |         LOGGER.info("getStocks (All stocks)"); | ||||||
|  |         return stockService.getStocks(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @RequestMapping("{productId}") | ||||||
|  |     public Stock getStock(@PathVariable("productId") String productId) throws StockNotFoundException { | ||||||
|  |         LOGGER.info("getStock with productId: {}", productId); | ||||||
|  |         return stockService.getStock(productId); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @ExceptionHandler | ||||||
|  |     @ResponseStatus(HttpStatus.NOT_FOUND) | ||||||
|  |     public void handleStockNotFound(StockNotFoundException snfe) { | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,33 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.stockmanager.services; | ||||||
|  | 
 | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.stereotype.Service; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.exceptions.StockNotFoundException; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.model.Stock; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.repositories.StockRepository; | ||||||
|  | 
 | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Optional; | ||||||
|  | import java.util.stream.Collectors; | ||||||
|  | import java.util.stream.StreamSupport; | ||||||
|  | 
 | ||||||
|  | @Service | ||||||
|  | public class StockService { | ||||||
|  | 
 | ||||||
|  |     private StockRepository stockRepository; | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     public StockService(StockRepository stockRepository) { | ||||||
|  |         this.stockRepository = stockRepository; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public List<Stock> getStocks() { | ||||||
|  |         return StreamSupport.stream(stockRepository.findAll().spliterator(), false) | ||||||
|  |                 .collect(Collectors.toList()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public Stock getStock(String productId) throws StockNotFoundException { | ||||||
|  |         return stockRepository.findById(productId) | ||||||
|  |                 .orElseThrow(() -> new StockNotFoundException("Stock not found with productId: " + productId)); | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								stockmanager/src/main/resources/application.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								stockmanager/src/main/resources/application.properties
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | |||||||
|  | server.port = 8030 | ||||||
							
								
								
									
										15
									
								
								stockmanager/src/test/java/functional/FunctionalTests.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								stockmanager/src/test/java/functional/FunctionalTests.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | package functional; | ||||||
|  | 
 | ||||||
|  | import cucumber.api.CucumberOptions; | ||||||
|  | import cucumber.api.junit.Cucumber; | ||||||
|  | import org.junit.runner.RunWith; | ||||||
|  | 
 | ||||||
|  | @RunWith(Cucumber.class) | ||||||
|  | @CucumberOptions(monochrome = true, | ||||||
|  |         features = "classpath:features/", | ||||||
|  |         plugin = "html:build/reports/cucumber", | ||||||
|  |         glue = "functional", | ||||||
|  |         strict = true) | ||||||
|  | public class FunctionalTests { | ||||||
|  | 
 | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								stockmanager/src/test/java/functional/RestStepDefs.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								stockmanager/src/test/java/functional/RestStepDefs.java
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | package functional; | ||||||
|  | 
 | ||||||
|  | import cucumber.api.java.en.Given; | ||||||
|  | import cucumber.api.java.en.Then; | ||||||
|  | import cucumber.api.java.en.When; | ||||||
|  | import org.junit.runner.RunWith; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.boot.test.context.SpringBootTest; | ||||||
|  | import org.springframework.boot.test.web.client.TestRestTemplate; | ||||||
|  | import org.springframework.test.context.ContextConfiguration; | ||||||
|  | import org.springframework.test.context.junit4.SpringRunner; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.StockManagerApplication; | ||||||
|  | import uk.co.danielbryant.djshopping.stockmanager.model.Stock; | ||||||
|  | 
 | ||||||
|  | import java.util.Arrays; | ||||||
|  | import java.util.List; | ||||||
|  | 
 | ||||||
|  | import static org.hamcrest.MatcherAssert.assertThat; | ||||||
|  | import static org.hamcrest.collection.IsCollectionWithSize.hasSize; | ||||||
|  | import static org.hamcrest.core.Is.is; | ||||||
|  | 
 | ||||||
|  | @ContextConfiguration | ||||||
|  | @RunWith(SpringRunner.class) | ||||||
|  | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = StockManagerApplication.class) | ||||||
|  | public class RestStepDefs { | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private TestRestTemplate restTemplate; | ||||||
|  | 
 | ||||||
|  |     private List<Stock> stocks; | ||||||
|  | 
 | ||||||
|  |     @Given("^the application has been initialised with test data$") | ||||||
|  |     public void init() { | ||||||
|  |         //the default profile loads synthetic stocks | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @When("^the client gets all stocks$") | ||||||
|  |     public void getAllStocks() { | ||||||
|  |         Stock[] stockArray = restTemplate.getForObject("/stocks", Stock[].class); | ||||||
|  |         stocks = Arrays.asList(stockArray); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Then("^a list of (.*) stocks will be returned$") | ||||||
|  |     public void assertListOfStocksLength(int length) { | ||||||
|  |         assertThat(stocks, hasSize(length)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @Then("^the stock at index (.*) will have the sku (.*)$") | ||||||
|  |     public void assertStockHasSku(int stockIndex, String sku) { | ||||||
|  |         assertThat(stocks.get(stockIndex).getSku(), is(sku)); | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -0,0 +1,20 @@ | |||||||
|  | package uk.co.danielbryant.djshopping.stockmanager; | ||||||
|  | 
 | ||||||
|  | import org.junit.Test; | ||||||
|  | import org.junit.runner.RunWith; | ||||||
|  | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.boot.test.context.SpringBootTest; | ||||||
|  | import org.springframework.boot.test.web.client.TestRestTemplate; | ||||||
|  | import org.springframework.test.context.junit4.SpringRunner; | ||||||
|  | 
 | ||||||
|  | @RunWith(SpringRunner.class) | ||||||
|  | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = StockManagerApplication.class) | ||||||
|  | public class ShopfrontApplicationTests { | ||||||
|  | 
 | ||||||
|  |     @Autowired | ||||||
|  |     private TestRestTemplate testRestTemplate; | ||||||
|  | 
 | ||||||
|  |     @Test | ||||||
|  |     public void contextLoads() { | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								stockmanager/src/test/resources/features/Stocks.feature
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								stockmanager/src/test/resources/features/Stocks.feature
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | Feature: Retrieving Stocks | ||||||
|  | 
 | ||||||
|  |   Scenario: Should be able to get a list of all stocks | ||||||
|  |     Given the application has been initialised with test data | ||||||
|  |     When the client gets all stocks | ||||||
|  |     Then a list of 5 stocks will be returned | ||||||
|  | 
 | ||||||
|  |   Scenario: Should be able to get the correct SKU for the first stock | ||||||
|  |     Given the application has been initialised with test data | ||||||
|  |     When the client gets all stocks | ||||||
|  |     Then the stock at index 0 will have the sku 12345678 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user