ImdbRestService.java
package org.xandercat.pmdb.service;
import java.util.Arrays;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Invocation.Builder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.GenericType;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.xandercat.pmdb.dto.Movie;
import org.xandercat.pmdb.dto.imdb.MovieDetailsRequest;
import org.xandercat.pmdb.dto.imdb.MovieDetails;
import org.xandercat.pmdb.dto.imdb.MovieDetailsWrapper;
import org.xandercat.pmdb.dto.imdb.ResponseType;
import org.xandercat.pmdb.dto.imdb.SearchRequest;
import org.xandercat.pmdb.dto.imdb.SearchResult;
import org.xandercat.pmdb.exception.ServiceLimitExceededException;
import org.xandercat.pmdb.exception.WebServicesException;
import org.xandercat.pmdb.util.format.FormatUtil;
import org.xandercat.pmdb.ws.ClientQueryParamMarshaller;
@Component
public class ImdbRestService implements ImdbSearchService {
private static final Logger LOGGER = LogManager.getLogger(ImdbRestService.class);
private static final int MAX_ATTRIBUTE_VALUE_LENGTH = 400;
private static final String IMDB_URL_BASE = "https://www.imdb.com/title/";
@Value("${imdb.rapidapi.host.url}")
private String hostUrl;
@Value("${imdb.rapidapi.host.header.key}")
private String hostHeaderKey;
@Value("${imdb.rapidapi.host.header.value}")
private String hostHeaderValue;
@Value("${imdb.rapidapi.key.header.key}")
private String apiKeyHeaderKey;
@Value("${imdb.rapidapi.key.header.value}")
private String apiKeyHeaderValue;
@Value("${imdb.calls.per.day.maximum}")
private int maxServiceCallsPerDay;
@Autowired
private Client restClient;
@Autowired
private ClientQueryParamMarshaller clientQueryParamMarshaller;
@Autowired
private ApplicationService applicationService;
private Builder builder(Object request) {
WebTarget webTarget = restClient.target(hostUrl);
webTarget = clientQueryParamMarshaller.queryParams(webTarget, request);
return webTarget.request()
.header(hostHeaderKey, hostHeaderValue)
.header(apiKeyHeaderKey, apiKeyHeaderValue);
}
public SearchResult searchImdb(SearchRequest request) throws WebServicesException, ServiceLimitExceededException {
int serviceCalls = applicationService.getImdbServiceCallCount();
if (serviceCalls >= maxServiceCallsPerDay) {
throw new ServiceLimitExceededException(serviceCalls, maxServiceCallsPerDay);
} else {
applicationService.incrementImdbServiceCallCount();
}
if (FormatUtil.isBlank(request.getTitle())) {
throw new IllegalArgumentException("Title is required.");
}
request.setResponseType(ResponseType.XML);
request.setTitle(request.getTitle().replaceAll("[\\u0091\\u0092]", "'")); // for clients that insist on using curly quotes that would cause search to fail
try {
return builder(request).get(new GenericType<SearchResult>() {});
} catch (Exception e) {
throw new WebServicesException(e);
}
}
@Override
public MovieDetails getMovieDetails(MovieDetailsRequest request) throws WebServicesException, ServiceLimitExceededException {
int serviceCalls = applicationService.getImdbServiceCallCount();
if (serviceCalls >= maxServiceCallsPerDay) {
throw new ServiceLimitExceededException(serviceCalls, maxServiceCallsPerDay);
} else {
applicationService.incrementImdbServiceCallCount();
}
request.setResponseType(ResponseType.XML);
MovieDetailsWrapper movieDetailsWrapper = null;
try {
movieDetailsWrapper = builder(request).get(new GenericType<MovieDetailsWrapper>() {});
} catch (Exception e) {
throw new WebServicesException(e);
}
return movieDetailsWrapper.getMovieDetails();
}
private void setAttribute(Movie movie, ImdbAttribute imdbAttribute, String value) {
if (FormatUtil.isNotBlank(value)) {
if (value.length() > MAX_ATTRIBUTE_VALUE_LENGTH) {
value = value.substring(0, MAX_ATTRIBUTE_VALUE_LENGTH);
}
movie.addAttribute(imdbAttribute.getKey(), value);
}
}
@Override
public void addImdbAttributes(Movie movie, MovieDetails movieDetails) {
if (FormatUtil.isBlank(movie.getTitle())) {
// only add title if it doesn't already have one; this allows custom names for pre-existing movies
movie.setTitle(movieDetails.getTitle());
}
setAttribute(movie, ImdbAttribute.YEAR, movieDetails.getYear());
setAttribute(movie, ImdbAttribute.GENRE, movieDetails.getGenre());
setAttribute(movie, ImdbAttribute.RATED, movieDetails.getRated());
setAttribute(movie, ImdbAttribute.PLOT, movieDetails.getPlot());
setAttribute(movie, ImdbAttribute.ACTORS, movieDetails.getActors());
setAttribute(movie, ImdbAttribute.DIRECTOR, movieDetails.getDirector());
setAttribute(movie, ImdbAttribute.AWARDS, movieDetails.getAwards());
setAttribute(movie, ImdbAttribute.IMDB_ID, movieDetails.getImdbId());
if (FormatUtil.isNotBlank(movieDetails.getImdbId())) {
setAttribute(movie, ImdbAttribute.IMDB_URL, IMDB_URL_BASE + movieDetails.getImdbId());
}
setAttribute(movie, ImdbAttribute.IMDB_RATING, movieDetails.getImdbRating());
setAttribute(movie, ImdbAttribute.IMDB_VOTES, movieDetails.getImdbVotes());
setAttribute(movie, ImdbAttribute.LANGUAGE, movieDetails.getLanguage());
setAttribute(movie, ImdbAttribute.METASCORE, movieDetails.getMetascore());
setAttribute(movie, ImdbAttribute.POSTER, movieDetails.getPoster());
setAttribute(movie, ImdbAttribute.RELEASED, movieDetails.getReleased());
setAttribute(movie, ImdbAttribute.RUNTIME, movieDetails.getRuntime());
setAttribute(movie, ImdbAttribute.TYPE, movieDetails.getType());
setAttribute(movie, ImdbAttribute.COUNTRY, movieDetails.getCountry());
}
@Override
public void removeImdbAttributes(Movie movie) {
Arrays.stream(ImdbAttribute.values()).forEach(imdbAttribute -> movie.removeAttribute(imdbAttribute.getKey()));
}
}