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