Skip to content

Commit d710ff7

Browse files
committed
swagger documentation added
1 parent 86a0074 commit d710ff7

11 files changed

+168
-63
lines changed

pom.xml

+12
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@
2323

2424
<dependencies>
2525

26+
<!-- swagger deps -->
27+
<dependency>
28+
<groupId>io.springfox</groupId>
29+
<artifactId>springfox-swagger2</artifactId>
30+
<version>2.9.2</version>
31+
</dependency>
32+
<dependency>
33+
<groupId>io.springfox</groupId>
34+
<artifactId>springfox-swagger-ui</artifactId>
35+
<version>2.7.0</version>
36+
</dependency>
37+
2638
<!-- Guava deps -->
2739
<dependency>
2840
<groupId>com.google.guava</groupId>
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,32 @@
11
package com.kamisarau.shopsimulation.config;
22

3+
import org.springframework.context.annotation.Bean;
4+
import org.springframework.context.annotation.Configuration;
5+
import springfox.documentation.builders.ApiInfoBuilder;
6+
import springfox.documentation.builders.PathSelectors;
7+
import springfox.documentation.builders.RequestHandlerSelectors;
8+
import springfox.documentation.service.ApiInfo;
9+
import springfox.documentation.service.Contact;
10+
import springfox.documentation.spi.DocumentationType;
11+
import springfox.documentation.spring.web.plugins.Docket;
12+
import springfox.documentation.swagger2.annotations.EnableSwagger2;
13+
14+
@Configuration
15+
@EnableSwagger2
316
public class SwaggerConf {
4-
}
17+
@Bean
18+
public Docket api() {
19+
return new Docket(DocumentationType.SWAGGER_2)
20+
.select()
21+
.apis(RequestHandlerSelectors.any())
22+
.paths(PathSelectors.any())
23+
.build().apiInfo(apiEndPointsInfo());
24+
}
25+
26+
private ApiInfo apiEndPointsInfo() {
27+
return new ApiInfoBuilder().title("Spring REST custom auth API")
28+
.description("Shop Simulation System")
29+
.contact(new Contact("Kamisarau Anton", "www.github.com/bn1knb", "[email protected]"))
30+
.build();
31+
}
32+
}

src/main/java/com/kamisarau/shopsimulation/controller/LogsController.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.kamisarau.shopsimulation.controller;
22

33
import com.kamisarau.shopsimulation.service.LogServiceStrategy;
4+
import io.swagger.annotations.Api;
5+
import io.swagger.annotations.ApiParam;
46
import org.springframework.core.io.ByteArrayResource;
57
import org.springframework.core.io.Resource;
68
import org.springframework.http.MediaType;
@@ -16,11 +18,17 @@
1618

1719
@RestController
1820
@RequestMapping("/logs")
21+
@Api(value = "Get logs here")
1922
public class LogsController {
2023

2124
@GetMapping(produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
22-
public ResponseEntity<Resource> getLogs(@RequestParam(defaultValue = "all", required = false) String type,
23-
@RequestParam(required = false) Date date) {
25+
public ResponseEntity<Resource> getLogs(
26+
@ApiParam(name = "type", value = "type of logs (eg. shelf, merchandise, storage, product) " +
27+
"default: all")
28+
@RequestParam(defaultValue = "all", required = false) String type,
29+
@ApiParam(name = "date", value = "get logs by requested date")
30+
@RequestParam(required = false) Date date) {
31+
2432
LogServiceStrategy logServiceStrategy = choose(type);
2533
ByteArrayResource resource = new ByteArrayResource(logServiceStrategy.getLogs(date));
2634
return ResponseEntity.ok()

src/main/java/com/kamisarau/shopsimulation/controller/PriceHistoryController.java

+14-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.kamisarau.shopsimulation.controller;
22

33
import com.kamisarau.shopsimulation.model.WrappedProduct;
4+
import io.swagger.annotations.*;
45
import org.hibernate.envers.AuditReader;
56
import org.hibernate.envers.AuditReaderFactory;
67
import org.hibernate.envers.query.AuditEntity;
@@ -14,14 +15,24 @@
1415

1516
@RestController
1617
@RequestMapping("/history")
18+
@Api(value = "Get price history here")
1719
public class PriceHistoryController {
1820
@PersistenceContext
1921
EntityManager entityManager;
2022

2123
@GetMapping("/{name}")
22-
public ResponseEntity<List<WrappedProduct>> getHistory(@PathVariable String name,
23-
@RequestParam(required = false) Integer page,
24-
@RequestParam(required = false) Integer size) {
24+
@ApiOperation(value = "Get price history of choosen product")
25+
@ApiResponses(value = {
26+
@ApiResponse(code = 200, message = "History has been shown"),
27+
@ApiResponse(code = 404, message = "No History found")
28+
})
29+
public ResponseEntity<List<WrappedProduct>> getHistory(
30+
@ApiParam(name = "name", value = "name of product (eg. orange, cheese, apple")
31+
@PathVariable String name,
32+
@ApiParam(name = "page", value = "page number")
33+
@RequestParam(required = false) Integer page,
34+
@ApiParam(name = "size", value = "number of results per page")
35+
@RequestParam(required = false) Integer size) {
2536

2637
int limit = (size == null) ? 10 : size;
2738
int first = (page == null) ? 0 : page * limit + 1;

src/main/java/com/kamisarau/shopsimulation/controller/StartEmulation.java

+8-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import com.kamisarau.shopsimulation.model.Shelf;
44
import com.kamisarau.shopsimulation.service.Randomiser;
5+
import io.swagger.annotations.Api;
6+
import io.swagger.annotations.ApiParam;
57
import org.springframework.beans.factory.annotation.Autowired;
68
import org.springframework.http.HttpStatus;
79
import org.springframework.http.ResponseEntity;
@@ -14,18 +16,22 @@
1416

1517
@RestController
1618
@RequestMapping("/start")
19+
@Api(value = "Start simulation here")
1720
public class StartEmulation {
1821
private static final Random RANDOM = new Random();
1922
private Randomiser randomiser;
23+
private Shelf shelf = new Shelf().setHeight(RANDOM.nextInt(100)).setWidth(RANDOM.nextInt(100));
2024

2125
@Autowired
2226
public StartEmulation(Randomiser randomiser) {
2327
this.randomiser = randomiser;
2428
}
2529

2630
@GetMapping
27-
public ResponseEntity start(@RequestParam(defaultValue = "10", required = false) int number) {
28-
Shelf shelf = new Shelf().setHeight(RANDOM.nextInt(100)).setWidth(RANDOM.nextInt(100));
31+
public ResponseEntity start(
32+
@ApiParam(name = "number", value = "number of random operations (default is 10)")
33+
@RequestParam(defaultValue = "10", required = false) int number) {
34+
2935

3036
randomiser.populateStorageWithProducts();
3137
randomiser.doRandomOperations(number, shelf);

src/main/java/com/kamisarau/shopsimulation/service/WrappedProductService.java

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
@Service
88
public interface WrappedProductService {
9+
void remove(WrappedProduct wrappedProduct);
10+
911
WrappedProduct setPrice(WrappedProduct product, double price);
1012

1113
WrappedProduct setCategory(WrappedProduct product, Category category);

src/main/java/com/kamisarau/shopsimulation/service/impl/MerchandiseServiceImpl.java

+79-46
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.kamisarau.shopsimulation.service.impl;
22

3+
import com.google.common.collect.ImmutableList;
34
import com.kamisarau.shopsimulation.model.Category;
45
import com.kamisarau.shopsimulation.model.Product;
56
import com.kamisarau.shopsimulation.model.Shelf;
@@ -12,8 +13,8 @@
1213
import org.springframework.beans.factory.annotation.Autowired;
1314
import org.springframework.stereotype.Service;
1415

15-
import java.util.ArrayList;
16-
import java.util.List;
16+
import java.util.*;
17+
import java.util.stream.Collectors;
1718

1819
@Service
1920
@Slf4j
@@ -22,18 +23,20 @@ public class MerchandiseServiceImpl implements MerchandiseService {
2223
private StorageService storageService;
2324
private ShelfService shelfService;
2425

25-
26-
//TODO add try catch blocks to prevent NoProductFound crash
26+
//TODO add try catch blocks to prevent NoProductFound crash
2727
@Autowired
28-
public MerchandiseServiceImpl(WrappedProductService wrappedProductService, StorageService storageService, ShelfService shelfService) {
28+
public MerchandiseServiceImpl(WrappedProductService wrappedProductService,
29+
StorageService storageService, ShelfService shelfService) {
2930
this.wrappedProductService = wrappedProductService;
3031
this.storageService = storageService;
3132
this.shelfService = shelfService;
3233
}
3334

3435
@Override
3536
public boolean isProductBiggerThanShelf(WrappedProduct product, Shelf shelf) {
36-
log.info("Checking if product is bigger than shelf size: {}", shelf.getHeight() * shelf.getWidth() < product.getHeight() * product.getWidth());
37+
log.info("Checking if product is bigger than shelf size: {}",
38+
(shelf.getHeight() * shelf.getWidth() < product.getHeight() * product.getWidth()) ||
39+
(shelf.getWidth() < product.getWidth()) || (shelf.getHeight() < product.getHeight()));
3740

3841
if (shelf.getHeight() * shelf.getWidth() < product.getHeight() * product.getWidth()) {
3942
return true;
@@ -44,16 +47,10 @@ public boolean isProductBiggerThanShelf(WrappedProduct product, Shelf shelf) {
4447
@Override
4548
public boolean storeOnShelf(WrappedProduct product, Shelf shelf) {
4649

47-
if (product.getWidth() < product.getHeight()) {
48-
log.info("Rotating product: {} so the width: {} wiil be bigger than height: {}", product.getName(), product.getWidth(), product.getHeight());
49-
50-
int temp = product.getWidth();
51-
product.setWidth(product.getHeight());
52-
product.setHeight(temp);
53-
}
50+
rotateProduct(product);
5451

5552
if (isProductBiggerThanShelf(product, shelf)) {
56-
log.warn("Given product is bigger than shelf size, exiting...");
53+
log.warn("Given product is bigger than shelf size, bringing back...");
5754

5855
return false;
5956
}
@@ -65,43 +62,18 @@ public boolean storeOnShelf(WrappedProduct product, Shelf shelf) {
6562
return true;
6663
}
6764

68-
List<WrappedProduct> copyWithNewItem = new ArrayList<>(shelf.getProducts());
69-
copyWithNewItem.add(product);
70-
log.debug("Creting the copy: {} of products on the shelf: {}", copyWithNewItem, shelf);
71-
72-
int x = 1;
73-
int y = 1;
74-
int shelfLevel = 0;
75-
76-
for (WrappedProduct storedItem : copyWithNewItem) {
77-
78-
log.debug("Shelflevel is: {}", shelfLevel);
79-
80-
if (shelf.getHeight() < shelfLevel + storedItem.getHeight()) {
81-
log.debug("Product: {} doesnt fit, exiting...", storedItem);
82-
return false;
83-
}
84-
85-
if (shelf.getWidth() + 1 < x + storedItem.getWidth()) {
86-
log.debug("Moving position to the {}, {}", 1, shelfLevel);
87-
y = shelfLevel;
88-
x = 1;
89-
}
65+
List<WrappedProduct> copyWithNewItem = ImmutableList.<WrappedProduct>builder()
66+
.addAll(shelf.getProducts())
67+
.add(product).build();
9068

91-
if (storedItem.getHeight() > shelfLevel - y) {
92-
log.debug("Setting shelflevel to: {}", y + storedItem.getHeight());
93-
shelfLevel = y + storedItem.getHeight();
94-
}
69+
log.debug("Creting the copy: {} of products on the shelf: {}", copyWithNewItem, shelf.getId());
9570

96-
log.debug("Setting final position on: {}, {}", x, y);
97-
storedItem.setX(x);
98-
storedItem.setY(y);
99-
100-
x += storedItem.getWidth();
71+
if (doShelfAlgorithm(shelf, copyWithNewItem).isEmpty()) {
72+
return false;
10173
}
10274

10375
shelfService.storeProduct(copyWithNewItem, shelf);
104-
log.info("Shelf: {} has: {} products", shelf, shelf.getProducts().size());
76+
log.info("Shelf: {} has: {} products", shelf.getId(), shelf.getProducts().size());
10577
log.info("Shelf index is: {}%", getShelfCapacityIndex(shelf));
10678
return true;
10779
}
@@ -149,6 +121,8 @@ public WrappedProduct prepare(Product product) {
149121

150122
@Override
151123
public Product prepare(WrappedProduct wrappedProduct) {
124+
wrappedProductService.remove(wrappedProduct);
125+
152126
return new Product()
153127
.setName(wrappedProduct.getName())
154128
.setHeight(wrappedProduct.getHeight())
@@ -161,4 +135,63 @@ private double getShelfCapacityIndex(Shelf shelf) {
161135

162136
return sumOfProductsParams / (shelf.getHeight() * shelf.getWidth()) * 100;
163137
}
138+
139+
private void rotateProduct(WrappedProduct product) {
140+
if (product.getWidth() < product.getHeight()) {
141+
log.info("Rotating product: {} so the width: {} wiil be bigger than height: {}",
142+
product.getName(), product.getWidth(), product.getHeight());
143+
144+
int temp = product.getWidth();
145+
product.setWidth(product.getHeight());
146+
product.setHeight(temp);
147+
}
148+
}
149+
150+
/**
151+
* NFDH (Next Fit Decreasing High) packing algorithm
152+
*
153+
* @param shelf shelf to use as storage to calculate wether products fit or not
154+
* @param products list of products to store
155+
* <p>
156+
* x,y - bottom-left point of the product to be set after its located on the shelf
157+
* @return null if one of the products doesn't fit
158+
*/
159+
private List<WrappedProduct> doShelfAlgorithm(Shelf shelf, List<? extends WrappedProduct> products) {
160+
List<WrappedProduct> productsWithSortedHeight = products.stream()
161+
.sorted(Comparator.comparingInt(WrappedProduct::getHeight).reversed())
162+
.collect(Collectors.toList());
163+
164+
int x = 1;
165+
int y = 1;
166+
int shelfLevel = 0;
167+
168+
for (WrappedProduct storedItem : productsWithSortedHeight) {
169+
170+
log.debug("Shelflevel is: {}", shelfLevel);
171+
172+
if (shelf.getHeight() < shelfLevel + storedItem.getHeight()) {
173+
log.debug("Product: {} doesnt fit, exiting...", storedItem);
174+
return Collections.emptyList();
175+
}
176+
177+
if (shelf.getWidth() + 1 < x + storedItem.getWidth()) {
178+
log.debug("Moving position to the {}, {}", 1, shelfLevel);
179+
y = shelfLevel;
180+
x = 1;
181+
}
182+
183+
if (storedItem.getHeight() > shelfLevel - y) {
184+
log.debug("Setting shelflevel to: {}", y + storedItem.getHeight());
185+
shelfLevel = y + storedItem.getHeight();
186+
}
187+
188+
log.debug("Setting final position on: {}, {}", x, y);
189+
storedItem.setX(x);
190+
storedItem.setY(y);
191+
192+
x += storedItem.getWidth();
193+
}
194+
195+
return productsWithSortedHeight;
196+
}
164197
}

src/main/java/com/kamisarau/shopsimulation/service/impl/RandomiserImpl.java

+3
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ public void doRandomOperations(int n, Shelf shelf) {
7979

8080
merchandiseService.bringProductToStorage(prepared);
8181

82+
if (shelf.getProducts().isEmpty()) continue;
83+
8284
String[] names = shelf.getProducts().stream().map(WrappedProduct::getName).toArray(String[]::new);
85+
8386
Product removedFromShelf = merchandiseService.prepare(
8487
merchandiseService.removeFromShelf(names[RANDOM.nextInt(names.length)], shelf)
8588
);

src/main/java/com/kamisarau/shopsimulation/service/impl/ShelfServiceImpl.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public WrappedProduct storeProduct(WrappedProduct product, Shelf shelf) {
6565
shelf.store(product);
6666
shelfRepository.save(shelf);
6767

68-
log.info("Storing: {}\n on shelf: {}", product.getName(), shelf);
68+
log.info("Storing: {} on shelf: {}", product.getName(), shelf.getId());
6969

7070
return product;
7171
}
@@ -77,7 +77,7 @@ public List<WrappedProduct> storeProduct(List<WrappedProduct> products, Shelf sh
7777
products.forEach(shelf::store);
7878
shelfRepository.save(shelf);
7979

80-
log.info("Storing: {}\n on shelf: {}",
80+
log.info("Storing: {} on shelf: {}",
8181
products.stream().collect(Collectors.groupingBy(WrappedProduct::getName)), shelf.getId());
8282

8383
return products;

src/main/java/com/kamisarau/shopsimulation/service/impl/WrappedProductServiceImpl.java

+5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ public WrappedProductServiceImpl(WrappedProductRepository wrappedProductReposito
1818
this.wrappedProductRepository = wrappedProductRepository;
1919
}
2020

21+
@Override
22+
public void remove(WrappedProduct wrappedProduct) {
23+
wrappedProductRepository.delete(wrappedProduct);
24+
}
25+
2126
@Override
2227
public WrappedProduct setPrice(WrappedProduct product, double price) {
2328
log.info("Setting price: {} for product: {}", price, product.getName());

0 commit comments

Comments
 (0)