From 0f8a0ce76ef86f801c7302c198c44aa2e59e5d13 Mon Sep 17 00:00:00 2001 From: Milen Dyankov Date: Sun, 8 Mar 2015 20:23:23 +0100 Subject: [PATCH] Created catalog microservice demo based on Spring Boot --- catalog-microservice/.gitignore | 1 + catalog-microservice/pom.xml | 69 +++++++++++++ .../com/forest/micro/catalog/CatalogApp.java | 17 ++++ .../micro/catalog/CategoryEndpoint.java | 68 +++++++++++++ .../forest/micro/catalog/ProductEndpoint.java | 81 ++++++++++++++++ .../micro/catalog/model/CategoryObject.java | 29 ++++++ .../micro/catalog/model/ProductObject.java | 49 ++++++++++ .../micro/catalog/wiring/CategoryManager.java | 21 ++++ .../micro/catalog/wiring/CategoryStorage.java | 66 +++++++++++++ .../micro/catalog/wiring/ProductManager.java | 20 ++++ .../micro/catalog/wiring/ProductStorage.java | 97 +++++++++++++++++++ .../src/main/resources/application.properties | 5 + pom.xml | 1 + stats/jdepend.sh | 3 +- 14 files changed, 526 insertions(+), 1 deletion(-) create mode 100644 catalog-microservice/.gitignore create mode 100644 catalog-microservice/pom.xml create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/CatalogApp.java create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/CategoryEndpoint.java create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/ProductEndpoint.java create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/model/CategoryObject.java create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/model/ProductObject.java create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/CategoryManager.java create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/CategoryStorage.java create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/ProductManager.java create mode 100644 catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/ProductStorage.java create mode 100644 catalog-microservice/src/main/resources/application.properties diff --git a/catalog-microservice/.gitignore b/catalog-microservice/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/catalog-microservice/.gitignore @@ -0,0 +1 @@ +/target diff --git a/catalog-microservice/pom.xml b/catalog-microservice/pom.xml new file mode 100644 index 0000000..434c993 --- /dev/null +++ b/catalog-microservice/pom.xml @@ -0,0 +1,69 @@ + + 4.0.0 + + org.glassfish.javaeetutorial + dukes-forest + 7.0.6-SNAPSHOT + + catalog-microservice + Catalog microservice + + + + + org.springframework.boot + spring-boot-starter-web + 1.2.2.RELEASE + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-undertow + 1.2.2.RELEASE + + + + org.glassfish.javaeetutorial + usecases-catalog + 7.0.6-SNAPSHOT + + + + org.jsondoc + spring-boot-starter-jsondoc + 1.1.12 + + + org.jsondoc + jsondoc-ui-webjar + 1.1.12 + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + + \ No newline at end of file diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/CatalogApp.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/CatalogApp.java new file mode 100644 index 0000000..bebfd54 --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/CatalogApp.java @@ -0,0 +1,17 @@ +package com.forest.micro.catalog; + +import org.jsondoc.spring.boot.starter.EnableJSONDoc; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; + +@EnableAutoConfiguration +@ComponentScan +@EnableJSONDoc +public class CatalogApp { + + public static void main(String[] args) throws Exception { + SpringApplication.run(CatalogApp.class, args); + } + +} diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/CategoryEndpoint.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/CategoryEndpoint.java new file mode 100644 index 0000000..9a376ed --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/CategoryEndpoint.java @@ -0,0 +1,68 @@ +package com.forest.micro.catalog; + +import java.util.List; + +import org.jsondoc.core.annotation.Api; +import org.jsondoc.core.annotation.ApiAuthNone; +import org.jsondoc.core.annotation.ApiBodyObject; +import org.jsondoc.core.annotation.ApiMethod; +import org.jsondoc.core.annotation.ApiPathParam; +import org.jsondoc.core.annotation.ApiResponseObject; +import org.jsondoc.core.annotation.ApiVersion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; + +import com.forest.micro.catalog.model.CategoryObject; +import com.forest.micro.catalog.wiring.CategoryManager; +import com.forest.model.Category; + +@RestController +@Api(name = "Category", description = "Methods for managing categories") +@ApiVersion(since = "1.0") +@ApiAuthNone +public class CategoryEndpoint { + + private CategoryManager categoryManager; + + @Autowired + public CategoryEndpoint(CategoryManager categoryManager) { + this.categoryManager = categoryManager; + } + + @ApiMethod(produces = "application/json", description = "Get a list of all categories") + @ApiResponseObject + @RequestMapping("/cetegories") + List getCategories() { + return categoryManager.getAll(); + } + + @ApiMethod(produces = "application/json", description = "Returns a caregory with given id") + @ApiResponseObject + @RequestMapping(value = "/category/{id}", produces = "application/json") + CategoryObject getCategory( + @PathVariable("id") @ApiPathParam(description = "The id of the category") int id) { + return (CategoryObject) categoryManager.getCategory(id); + } + + @ApiMethod(produces = "application/json", description = "Creates new category") + @ApiResponseObject + @RequestMapping(method = RequestMethod.POST, value = "/category", consumes = "application/json") + void addCategory(@RequestBody @ApiBodyObject CategoryObject category) { + categoryManager.createCategory(category); + } + + @ApiMethod(produces = "application/json", description = "Updates existing category") + @ApiResponseObject + @RequestMapping(method = RequestMethod.PUT, value = "/category/{id}", consumes = "application/json") + void updateCategory( + @PathVariable("id") @ApiPathParam(description = "The id of the category") int id, + @RequestBody @ApiBodyObject CategoryObject category) { + + category.setId(id); + categoryManager.updateCategory(category); + } +} diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/ProductEndpoint.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/ProductEndpoint.java new file mode 100644 index 0000000..37e479f --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/ProductEndpoint.java @@ -0,0 +1,81 @@ +package com.forest.micro.catalog; + +import java.util.List; + +import org.jsondoc.core.annotation.Api; +import org.jsondoc.core.annotation.ApiAuthNone; +import org.jsondoc.core.annotation.ApiBodyObject; +import org.jsondoc.core.annotation.ApiMethod; +import org.jsondoc.core.annotation.ApiPathParam; +import org.jsondoc.core.annotation.ApiQueryParam; +import org.jsondoc.core.annotation.ApiResponseObject; +import org.jsondoc.core.annotation.ApiVersion; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import com.forest.micro.catalog.model.ProductObject; +import com.forest.micro.catalog.wiring.ProductManager; +import com.forest.model.Product; + +@RestController +@Api(name = "Product", description = "Methods for managing products") +@ApiVersion(since = "1.0") +@ApiAuthNone +public class ProductEndpoint { + + private ProductManager productManager; + + @Autowired + public ProductEndpoint(ProductManager productManager) { + this.productManager = productManager; + } + + @ApiMethod(produces = "application/json", description = "Get a list of all products") + @ApiResponseObject + @RequestMapping("/products") + List getProducts() { + return productManager.getAll(); + } + + @ApiMethod(produces = "application/json", description = "Returns a product with given id") + @ApiResponseObject + @RequestMapping(value = "/product/{id}", produces = "application/json") + ProductObject getProduct( + @PathVariable("id") @ApiPathParam(description = "The id of the product") int id) { + return (ProductObject) productManager.getProduct(id); + } + + @ApiMethod(produces = "application/json", description = "Creates new product") + @ApiResponseObject + @RequestMapping(method = RequestMethod.POST, value = "/product", consumes = "application/json") + void addProduct(@RequestBody @ApiBodyObject ProductObject product) { + productManager.createProduct(product); + } + + @ApiMethod(produces = "application/json", description = "Updates existing product") + @ApiResponseObject + @RequestMapping(method = RequestMethod.PUT, value = "/product/{id}", consumes = "application/json") + void updateProduct( + @PathVariable("id") @ApiPathParam(description = "The id of the product") int id, + @RequestBody @ApiBodyObject ProductObject product) { + + product.setId(id); + productManager.updateProduct(product); + } + + @ApiMethod(produces = "application/json", description = "Gets products in given category") + @ApiResponseObject + @RequestMapping(method = RequestMethod.GET, value = "/category/{id}/products", produces = "application/json") + List getProductInCategory( + @PathVariable("id") @ApiPathParam(description = "The id of the category") int id, + @RequestParam(defaultValue = "0", required = false) @ApiQueryParam(name = "from", defaultvalue = "0", required = false) int from, + @RequestParam(defaultValue = "10", required = false) @ApiQueryParam(name = "to", defaultvalue = "10", required = false) int to) { + + return productManager.getProductsInCategory(id, from, to); + } +} diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/model/CategoryObject.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/model/CategoryObject.java new file mode 100644 index 0000000..ff34a11 --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/model/CategoryObject.java @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. + * + * You may not modify, use, reproduce, or distribute this software except in + * compliance with the terms of the License at: + * http://java.net/projects/javaeetutorial/pages/BerkeleyLicense + */ +package com.forest.micro.catalog.model; + +import javax.xml.bind.annotation.XmlRootElement; + +import org.jsondoc.core.annotation.ApiObject; +import org.jsondoc.core.annotation.ApiObjectField; + +import com.forest.model.Category; + +@ApiObject(name = "Category", description = "Category") +@XmlRootElement +public class CategoryObject extends Category { + + private static final long serialVersionUID = -5400424750505982222L; + + @ApiObjectField(description = "Category name", required = true) + protected String name; + + @ApiObjectField(description = "Tags") + protected String tags; + +} diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/model/ProductObject.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/model/ProductObject.java new file mode 100644 index 0000000..9b8f4b4 --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/model/ProductObject.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. + * + * You may not modify, use, reproduce, or distribute this software except in + * compliance with the terms of the License at: + * http://java.net/projects/javaeetutorial/pages/BerkeleyLicense + */ +package com.forest.micro.catalog.model; + +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlTransient; + +import org.jsondoc.core.annotation.ApiObject; +import org.jsondoc.core.annotation.ApiObjectField; + +import com.forest.model.Category; +import com.forest.model.Product; + +@ApiObject (name="Product", description="Product") +@XmlRootElement +public class ProductObject extends Product { + + private static final long serialVersionUID = -9109112921000514199L; + + + @ApiObjectField(description="Product name", required=true) + protected String name; + + @ApiObjectField(description="Product price") + protected double price; + + @ApiObjectField(description="Product description") + protected String description; + + @XmlTransient + protected Category category; + + @ApiObjectField(description="Category to add to") + protected Integer categoryId; + + public Integer getCategoryId() { + return categoryId; + } + + public void setCategoryId(Integer categoryId) { + this.categoryId = categoryId; + } + +} diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/CategoryManager.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/CategoryManager.java new file mode 100644 index 0000000..843fb8f --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/CategoryManager.java @@ -0,0 +1,21 @@ +package com.forest.micro.catalog.wiring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.forest.usecase.catalog.AbstractBaseCategoryManager; +import com.forest.usecase.catalog.persistence.CategoryPersistence; + + +@Component +public class CategoryManager extends AbstractBaseCategoryManager { + + @Autowired + private CategoryPersistence categoryPersistence; + + @Override + protected CategoryPersistence getCategoryPersistence() { + return categoryPersistence; + } + +} diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/CategoryStorage.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/CategoryStorage.java new file mode 100644 index 0000000..fa7efb0 --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/CategoryStorage.java @@ -0,0 +1,66 @@ +package com.forest.micro.catalog.wiring; + +import java.util.LinkedList; +import java.util.List; +import java.util.TreeMap; + +import org.springframework.stereotype.Component; + +import com.forest.model.Category; +import com.forest.usecase.catalog.persistence.CategoryPersistence; + +@Component +public class CategoryStorage implements CategoryPersistence { + + /* + * In-memory storage (for demo purpose ONLY) !!! + */ + private static final TreeMap categoryById = new TreeMap(); + private static int idGenerator = 1; + + @Override + public void createCategory(Category category) { + category.setId(idGenerator++); + categoryById.put(category.getId(), category); + } + + @Override + public void updateCategory(Category category) { + if (categoryById.containsKey(category.getId())) { + categoryById.put(category.getId(), category); + } + } + + @Override + public void removeCategory(Category category) { + categoryById.remove(category.getId()); + } + + @Override + public Category getCategory(int id) { + return categoryById.get(id); + } + + @Override + public int count() { + return categoryById.size(); + } + + @Override + public List findAll() { + return new LinkedList(categoryById.values()); + } + + @Override + public List findRange(int... range) { + fixRange(range, categoryById.size()); + return new LinkedList(categoryById.subMap(range[0], range[1]).values()); + } + + private void fixRange(int[] range, int size) { + if (range[0] < 0) range[0] = 0; + if (range[0] > size) range[0] = size; + if (range[1] < range[0]) range[1] = range[0]; + if (range[1] > size) range[1] = size; + } +} diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/ProductManager.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/ProductManager.java new file mode 100644 index 0000000..18d9f1c --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/ProductManager.java @@ -0,0 +1,20 @@ +package com.forest.micro.catalog.wiring; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.forest.usecase.catalog.AbstractBaseProductManager; +import com.forest.usecase.catalog.persistence.ProductPersistence; + +@Component +public class ProductManager extends AbstractBaseProductManager { + + @Autowired + private ProductPersistence productPersistence; + + @Override + protected ProductPersistence getProductPersistence() { + return productPersistence; + } + +} diff --git a/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/ProductStorage.java b/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/ProductStorage.java new file mode 100644 index 0000000..f8dc0ec --- /dev/null +++ b/catalog-microservice/src/main/java/com/forest/micro/catalog/wiring/ProductStorage.java @@ -0,0 +1,97 @@ +package com.forest.micro.catalog.wiring; + +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +import java.util.TreeMap; + +import org.springframework.stereotype.Component; + +import com.forest.micro.catalog.model.ProductObject; +import com.forest.model.Product; +import com.forest.usecase.catalog.persistence.ProductPersistence; + +@Component +public class ProductStorage implements ProductPersistence { + + /* + * In-memory storage (for demo purpose ONLY) !!! + */ + private static final TreeMap productsById = new TreeMap(); + private static final TreeMap> productsByCategory = new TreeMap>(); + private static int idGenerator = 1; + + @Override + public void createProduct(Product product) { + product.setId(idGenerator++); + productsById.put(product.getId(), product); + updateCategory(product); + } + + @Override + public void updateProduct(Product product) { + if (productsById.containsKey(product.getId())) { + productsById.put(product.getId(), product); + updateCategory(product); + } + } + + @Override + public void removeProduct(Product product) { + productsById.remove(product.getId()); + productsByCategory.get(product.getCategory().getId()).remove(product); + } + + @Override + public Product getProduct(int id) { + return productsById.get(id); + } + + @Override + public int count() { + return productsById.size(); + } + + @Override + public List findAll() { + return new LinkedList(productsById.values()); + } + + @Override + public List findRange(int... range) { + fixRange(range, productsById.size()); + return new LinkedList(productsById.subMap(range[0], range[1]) + .values()); + } + + @Override + public List findByCategory(int[] range, int categoryId) { + List products = productsByCategory.get(categoryId); + if (products != null) { + fixRange(range, products.size()); + return products.subList(range[0], range[1]); + } + return Collections.emptyList(); + } + + private void fixRange(int[] range, int size) { + if (range[0] < 0) range[0] = 0; + if (range[0] > size) range[0] = size; + if (range[1] < range[0]) range[1] = range[0]; + if (range[1] > size) range[1] = size; + } + + private void updateCategory(Product product) { + ProductObject productObject = (ProductObject) product; + Integer categoryId = productObject.getCategoryId(); + if (categoryId != null) { + List products = productsByCategory.get(categoryId); + if (products == null) { + products = new LinkedList(); + productsByCategory.put(categoryId, products); + } + products.add(product); + } + } + +} diff --git a/catalog-microservice/src/main/resources/application.properties b/catalog-microservice/src/main/resources/application.properties new file mode 100644 index 0000000..e5a37ff --- /dev/null +++ b/catalog-microservice/src/main/resources/application.properties @@ -0,0 +1,5 @@ +jsondoc.version=1.0 +jsondoc.basePath=http://localhost:9000/ +jsondoc.packages[0]=com.forest.micro + +server.port=9000 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4e0abd7..de1116b 100644 --- a/pom.xml +++ b/pom.xml @@ -72,6 +72,7 @@ jpa-persistence jee-apps usecases + catalog-microservice diff --git a/stats/jdepend.sh b/stats/jdepend.sh index a2202c8..1eaf0b6 100755 --- a/stats/jdepend.sh +++ b/stats/jdepend.sh @@ -15,7 +15,8 @@ com.forest.shipment.wiring,\ com.forest.shipment.ui,\ com.forest.payment.services,\ com.forest.persistence,\ -com.forest.model" +com.forest.model,\ +org.springframework.boot" mkdir -p $REPORT_DIR