Skip to content

Commit c7cafeb

Browse files
committed
deleting everything
1 parent 1930a8d commit c7cafeb

File tree

23 files changed

+399
-0
lines changed

23 files changed

+399
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.example.api.composite;
2+
3+
import java.util.List;
4+
5+
public class ProductAggregate {
6+
private final int productId;
7+
private final String name;
8+
private final int weight;
9+
private final List<RecommendationSummary> recommendations;
10+
private final List<ReviewSummary> reviews;
11+
private final ServiceAddresses serviceAddresses;
12+
13+
public ProductAggregate(
14+
int productId,
15+
String name,
16+
int weight,
17+
List<RecommendationSummary> recommendations,
18+
List<ReviewSummary> reviews,
19+
ServiceAddresses serviceAddresses) {
20+
21+
this.productId = productId;
22+
this.name = name;
23+
this.weight = weight;
24+
this.recommendations = recommendations;
25+
this.reviews = reviews;
26+
this.serviceAddresses = serviceAddresses;
27+
}
28+
29+
public int getProductId() {
30+
return productId;
31+
}
32+
33+
public String getName() {
34+
return name;
35+
}
36+
37+
public int getWeight() {
38+
return weight;
39+
}
40+
41+
public List<RecommendationSummary> getRecommendations() {
42+
return recommendations;
43+
}
44+
45+
public List<ReviewSummary> getReviews() {
46+
return reviews;
47+
}
48+
49+
public ServiceAddresses getServiceAddresses() {
50+
return serviceAddresses;
51+
}
52+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package com.example.api.composite;
2+
3+
import io.swagger.v3.oas.annotations.Operation;
4+
import io.swagger.v3.oas.annotations.responses.ApiResponse;
5+
import io.swagger.v3.oas.annotations.responses.ApiResponses;
6+
import io.swagger.v3.oas.annotations.tags.Tag;
7+
import org.springframework.web.bind.annotation.GetMapping;
8+
import org.springframework.web.bind.annotation.PathVariable;
9+
10+
@Tag(name = "ProductComposite", description = "REST API for composite product information.")
11+
public interface ProductCompositeService {
12+
13+
@Operation(
14+
summary =
15+
"${api.product-composite.get-composite-product.description}",
16+
description =
17+
"${api.product-composite.get-composite-product.notes}")
18+
@ApiResponses(value = {
19+
@ApiResponse(responseCode = "200", description =
20+
"${api.responseCodes.ok.description}"),
21+
@ApiResponse(responseCode = "400", description =
22+
"${api.responseCodes.badRequest.description}"),
23+
@ApiResponse(responseCode = "404", description =
24+
"${api.responseCodes.notFound.description}"),
25+
@ApiResponse(responseCode = "422", description =
26+
"${api.responseCodes.unprocessableEntity.description}")
27+
})
28+
29+
/**
30+
* Sample usage: "curl $HOST:$PORT/product-composite/1".
31+
*
32+
* @param productId Id of the product
33+
* @return the composite product info, if found, else null
34+
*/
35+
@GetMapping(
36+
value = "/product-composite/{productId}",
37+
produces = "application/json")
38+
ProductAggregate getProduct(@PathVariable int productId);
39+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.example.api.composite;
2+
3+
public class RecommendationSummary {
4+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.example.api.composite;
2+
3+
public class ReviewSummary {
4+
5+
private final int reviewId;
6+
private final String author;
7+
private final String subject;
8+
9+
public ReviewSummary(int reviewId, String author, String subject) {
10+
this.reviewId = reviewId;
11+
this.author = author;
12+
this.subject = subject;
13+
}
14+
15+
public int getReviewId() {
16+
return reviewId;
17+
}
18+
19+
public String getAuthor() {
20+
return author;
21+
}
22+
23+
public String getSubject() {
24+
return subject;
25+
}
26+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.example.api.composite;
2+
3+
public class ServiceAddresses {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.examole.api.exceptions;
2+
3+
public class InvalidInputException {
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.example.api.exceptions;
2+
3+
public class NotFoundException {
4+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package com.example.microservices.composite.product.services;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import java.io.IOException;
5+
import java.util.ArrayList;
6+
import java.util.List;
7+
import java.util.Objects;
8+
9+
import org.slf4j.Logger;
10+
import org.slf4j.LoggerFactory;
11+
import org.springframework.beans.factory.annotation.Autowired;
12+
import org.springframework.beans.factory.annotation.Value;
13+
import org.springframework.core.ParameterizedTypeReference;
14+
import org.springframework.http.HttpStatus;
15+
import org.springframework.stereotype.Component;
16+
import org.springframework.web.client.HttpClientErrorException;
17+
import org.springframework.web.client.RestTemplate;
18+
import com.example.api.core.product.Product;
19+
import com.example.api.core.product.ProductService;
20+
import com.example.api.core.recommendation.Recommendation;
21+
import com.example.api.core.recommendation.RecommendationService;
22+
import com.example.api.core.review.Review;
23+
import com.example.api.core.review.ReviewService;
24+
import com.example.api.exceptions.InvalidInputException;
25+
import com.example.api.exceptions.NotFoundException;
26+
import com.example.util.http.HttpErrorInfo;
27+
28+
import static org.springframework.http.HttpMethod.GET;
29+
30+
@Component
31+
public class ProductCompositeIntegration implements ProductService, RecommendationService, ReviewService {
32+
33+
private static final Logger LOG = LoggerFactory.getLogger(ProductCompositeIntegration.class);
34+
35+
private final RestTemplate restTemplate;
36+
private final ObjectMapper mapper;
37+
38+
private final String productServiceUrl;
39+
private final String recommendationServiceUrl;
40+
private final String reviewServiceUrl;
41+
42+
@Autowired
43+
public ProductCompositeIntegration(
44+
RestTemplate restTemplate,
45+
ObjectMapper mapper,
46+
@Value("${app.product-service.host}") String productServiceHost,
47+
@Value("${app.product-service.port}") int productServicePort,
48+
@Value("${app.recommendation-service.host}") String recommendationServiceHost,
49+
@Value("${app.recommendation-service.port}") int recommendationServicePort,
50+
@Value("${app.review-service.host}") String reviewServiceHost,
51+
@Value("${app.review-service.port}") int reviewServicePort) {
52+
53+
this.restTemplate = restTemplate;
54+
this.mapper = mapper;
55+
56+
productServiceUrl = "http://" + productServiceHost + ":" + productServicePort + "/product/";
57+
recommendationServiceUrl = "http://" + recommendationServiceHost + ":" + recommendationServicePort + "/recommendation?productId=";
58+
reviewServiceUrl = "http://" + reviewServiceHost + ":" + reviewServicePort + "/review?productId=";
59+
}
60+
61+
public Product getProduct(int productId) {
62+
63+
try {
64+
String url = productServiceUrl + productId;
65+
LOG.debug("Will call getProduct API on URL: {}", url);
66+
67+
Product product = restTemplate.getForObject(url, Product.class);
68+
assert product != null;
69+
LOG.debug("Found a product with id: {}", product.getProductId());
70+
71+
return product;
72+
73+
} catch (HttpClientErrorException ex) {
74+
75+
switch (Objects.requireNonNull(HttpStatus.resolve(ex.getStatusCode().value()))) {
76+
case NOT_FOUND:
77+
throw new NotFoundException(getErrorMessage(ex));
78+
79+
case UNPROCESSABLE_ENTITY:
80+
throw new InvalidInputException(getErrorMessage(ex));
81+
82+
default:
83+
LOG.warn("Got an unexpected HTTP error: {}, will rethrow it", ex.getStatusCode());
84+
LOG.warn("Error body: {}", ex.getResponseBodyAsString());
85+
throw ex;
86+
}
87+
}
88+
}
89+
90+
private String getErrorMessage(HttpClientErrorException ex) {
91+
try {
92+
return mapper.readValue(ex.getResponseBodyAsString(), HttpErrorInfo.class).getMessage();
93+
} catch (IOException ioex) {
94+
return ex.getMessage();
95+
}
96+
}
97+
98+
public List<Recommendation> getRecommendations(int productId) {
99+
try {
100+
String url = recommendationServiceUrl + productId;
101+
102+
LOG.debug("Will call getRecommendations API on URL: {}", url);
103+
List<Recommendation> recommendations = restTemplate
104+
.exchange(url, GET, null, new ParameterizedTypeReference<List<Recommendation>>() {})
105+
.getBody();
106+
107+
assert recommendations != null;
108+
LOG.debug("Found {} recommendations for a product with id: {}", recommendations.size(), productId);
109+
return recommendations;
110+
111+
} catch (Exception ex) {
112+
LOG.warn("Got an exception while requesting recommendations, return zero recommendations: {}", ex.getMessage());
113+
return new ArrayList<>();
114+
}
115+
}
116+
117+
public List<Review> getReviews(int productId) {
118+
119+
try {
120+
String url = reviewServiceUrl + productId;
121+
122+
LOG.debug("Will call getReviews API on URL: {}", url);
123+
List<Review> reviews = restTemplate
124+
.exchange(url, GET, null, new ParameterizedTypeReference<List<Review>>() {})
125+
.getBody();
126+
127+
LOG.debug("Found {} reviews for a product with id: {}", reviews.size(), productId);
128+
return reviews;
129+
130+
} catch (Exception ex) {
131+
LOG.warn("Got an exception while requesting reviews, return zero reviews: {}", ex.getMessage());
132+
return new ArrayList<>();
133+
}
134+
}
135+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package com.example.microservices.composite.product.service;
2+
3+
import java.util.List;
4+
import java.util.stream.Collectors;
5+
6+
import com.example.api.composite.*;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.web.bind.annotation.RestController;
9+
import com.example.api.core.product.Product;
10+
import com.example.api.core.recommendation.Recommendation;
11+
import com.example.api.core.review.Review;
12+
import com.example.api.exceptions.NotFoundException;
13+
import com.example.util.http.ServiceUtil;
14+
15+
@RestController
16+
public class ProductCompositeServiceImpl implements ProductCompositeService {
17+
18+
private ServiceUtil serviceUtil;
19+
private ProductCompositeIntegration integration;
20+
21+
@Autowired
22+
public ProductCompositeServiceImpl(
23+
ServiceUtil serviceUtil, ProductCompositeIntegration integration) {
24+
25+
this.serviceUtil = serviceUtil;
26+
this.integration = integration;
27+
}
28+
29+
@Override
30+
public ProductAggregate getProduct(int productId) {
31+
32+
Product product = integration.getProduct(productId);
33+
if (product == null) {
34+
throw new NotFoundException("No product found for productId: " + productId);
35+
}
36+
37+
List<Recommendation> recommendations = integration.getRecommendations(productId);
38+
39+
List<Review> reviews = integration.getReviews(productId);
40+
41+
return createProductAggregate(product, recommendations, reviews, serviceUtil.getServiceAddress());
42+
}
43+
44+
private ProductAggregate createProductAggregate(
45+
Product product,
46+
List<Recommendation> recommendations,
47+
List<Review> reviews,
48+
String serviceAddress) {
49+
50+
// 1. Setup product info
51+
int productId = product.getProductId();
52+
String name = product.getName();
53+
int weight = product.getWeight();
54+
55+
// 2. Copy summary recommendation info, if available
56+
List<RecommendationSummary> recommendationSummaries =
57+
(recommendations == null) ? null : recommendations.stream()
58+
.map(r -> new RecommendationSummary(r.getRecommendationId(), r.getAuthor(), r.getRate()))
59+
.collect(Collectors.toList());
60+
61+
// 3. Copy summary review info, if available
62+
List<ReviewSummary> reviewSummaries =
63+
(reviews == null) ? null : reviews.stream()
64+
.map(r -> new ReviewSummary(r.getReviewId(), r.getAuthor(), r.getSubject()))
65+
.collect(Collectors.toList());
66+
67+
// 4. Create info regarding the involved microservices addresses
68+
String productAddress = product.getServiceAddress();
69+
String reviewAddress = (reviews != null && !reviews.isEmpty()) ? reviews.get(0).getServiceAddress() : "";
70+
String recommendationAddress = (recommendations != null && !recommendations.isEmpty()) ? recommendations.get(0).getServiceAddress() : "";
71+
ServiceAddresses serviceAddresses = new ServiceAddresses(serviceAddress, productAddress, reviewAddress, recommendationAddress);
72+
73+
return new ProductAggregate(productId, name, weight, recommendationSummaries, reviewSummaries, serviceAddresses);
74+
}
75+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package com.example.microservices.core.product.persistence;
2+
3+
public class ProductEntity {
4+
}

0 commit comments

Comments
 (0)