Skip to content

Commit ac84d2d

Browse files
author
Milad Mofidi
committed
-Adding custom thread pool for async calls
-Adding a method to call each server in different threads -Adding implementation for allOf() and anyOf() methods of CompletableFuture Api -Adding MovieClient service to demonstrate different calls -Adding Movie and Review models -Adding third-party movies-restful-api.jar lib to run movie rest services, can run by:"libs/java -jar movies-restful-api.jar"
1 parent 99124a6 commit ac84d2d

File tree

9 files changed

+428
-30
lines changed

9 files changed

+428
-30
lines changed

libs/movies-restful-api.jar

38.8 MB
Binary file not shown.

pom.xml

+30
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,36 @@
5454
<scope>test</scope>
5555
</dependency>
5656

57+
<dependency>
58+
<groupId>com.fasterxml.jackson.core</groupId>
59+
<artifactId>jackson-core</artifactId>
60+
<version>2.14.1</version>
61+
</dependency>
62+
63+
<dependency>
64+
<groupId>org.springframework</groupId>
65+
<artifactId>spring-webflux</artifactId>
66+
<version>5.2.9.RELEASE</version>
67+
</dependency>
68+
69+
70+
71+
<!--<dependency>
72+
<groupId>org.springframework.boot</groupId>
73+
<artifactId>spring-boot-starter-webflux</artifactId>
74+
<version>3.0.0</version>
75+
</dependency>-->
76+
77+
78+
<!-- <dependency>
79+
<groupId>org.springframework.boot</groupId>
80+
<artifactId>spring-boot-starter-webflux</artifactId>
81+
<version>2.7.4</version>
82+
</dependency>-->
83+
84+
85+
86+
5787
</dependencies>
5888

5989
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package org.example.apiclient;
2+
3+
import org.example.domain.movie.Movie;
4+
import org.example.domain.movie.MovieInfo;
5+
import org.example.domain.movie.Review;
6+
import org.springframework.web.reactive.function.client.WebClient;
7+
import org.springframework.web.util.UriComponentsBuilder;
8+
9+
import java.util.List;
10+
import java.util.concurrent.CompletableFuture;
11+
import java.util.stream.Collectors;
12+
13+
/**
14+
* @author milad mofidi
15+
16+
* user: miladm on 2/18/2023
17+
*/
18+
public class MoviesClient
19+
{
20+
private final WebClient webClient;
21+
22+
public MoviesClient(WebClient webClient)
23+
{
24+
this.webClient = webClient;
25+
}
26+
//Implementing in blocking way
27+
public Movie retrieveMovie(Long movieInfoId){
28+
29+
var movieInfo = invokeMovieInfo(movieInfoId);
30+
var reviews =invokeReviewsService(movieInfoId);
31+
return new Movie(movieInfo, reviews);
32+
}
33+
34+
35+
//Implementing in non-blocking way
36+
public CompletableFuture<Movie> retrieveMovie_Cf_async(Long movieInfoId){
37+
38+
var movieInfo = CompletableFuture.supplyAsync( () ->invokeMovieInfo(movieInfoId)) ;
39+
var reviews =CompletableFuture.supplyAsync( () ->invokeReviewsService(movieInfoId)) ;
40+
return movieInfo
41+
.thenCombine(reviews, (movieInfoResult, reviewsResult) ->{
42+
return new Movie(movieInfoResult, reviewsResult);
43+
});
44+
45+
}
46+
//Calling traditional retrieve movie method to make list of loaded movies
47+
public List<Movie> retrieveMovies(List<Long> movieInfoIds){
48+
return movieInfoIds.stream().map(movieInfoId -> retrieveMovie(movieInfoId)).collect(Collectors.toList());
49+
}
50+
51+
//Calling completable-future retrieve movie method to make list of loaded movies using retrieveMovie_Cf_async() method
52+
public List<Movie> retrieveMovieList_Cf_async(List<Long> movieInfoIds){
53+
var movieFutures = movieInfoIds.stream().map(this::retrieveMovie_Cf_async).
54+
collect(Collectors.toList());
55+
return movieFutures.
56+
stream().
57+
map(CompletableFuture::join)
58+
.collect(Collectors.toList());
59+
}
60+
61+
//Using "allOf()" method to improve performance, this method will wait until all items get processed
62+
public List<Movie> retrieveMovieList_Cf_async_allOf(List<Long> movieInfoIds){
63+
var movieFutures = movieInfoIds.stream().map(this::retrieveMovie_Cf_async).
64+
collect(Collectors.toList());
65+
66+
var cfAllOf = CompletableFuture.allOf(movieFutures.toArray(new CompletableFuture[movieFutures.size()]));
67+
return cfAllOf.thenApply(v -> movieFutures
68+
.stream()
69+
.map(CompletableFuture::join)
70+
.collect(Collectors.toList()))
71+
.join();
72+
}
73+
74+
//Implementing the web client call in blocking way
75+
private MovieInfo invokeMovieInfo(Long movieInfoId)
76+
{
77+
var movieInfoUrlPath = "/v1/reviews?movieInfoId=2";
78+
return webClient.get().uri(movieInfoUrlPath, movieInfoId).retrieve().bodyToMono(MovieInfo.class).block();
79+
}
80+
81+
//Implementing the web client call in blocking way
82+
private List<Review> invokeReviewsService(Long movieInfoId)
83+
{
84+
///v1/reviews?movieInfoId=2
85+
var reviewUri = UriComponentsBuilder.fromUriString("/v1/reviews").queryParam("movieInfoId", movieInfoId).buildAndExpand().toString();
86+
return webClient.get().uri(reviewUri).retrieve().bodyToFlux(Review.class).collectList().block();
87+
}
88+
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.example.domain.movie;
2+
3+
4+
import lombok.AllArgsConstructor;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
import java.util.List;
9+
10+
@Data
11+
@NoArgsConstructor
12+
@AllArgsConstructor
13+
public class Movie {
14+
15+
private MovieInfo movieInfo;
16+
private List<Review> reviewList;
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package org.example.domain.movie;
2+
3+
4+
import lombok.AllArgsConstructor;
5+
import lombok.Data;
6+
import lombok.NoArgsConstructor;
7+
8+
import java.time.LocalDate;
9+
import java.util.List;
10+
11+
@Data
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
public class MovieInfo {
15+
private String movieInfoId;
16+
private String name;
17+
private Integer year;
18+
19+
private List<String> cast;
20+
private LocalDate release_date;
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.example.domain.movie;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.NoArgsConstructor;
6+
7+
@Data
8+
@NoArgsConstructor
9+
@AllArgsConstructor
10+
public class Review {
11+
12+
private String reviewId;
13+
private Long movieInfoId;
14+
private String comment;
15+
//@Min(value = 0L, message = "rating.negative : rating is negative and please pass a non-negative value")
16+
private Double rating;
17+
}

0 commit comments

Comments
 (0)