package io.micronaut.web.router.version;
import io.micronaut.context.annotation.Requires;
import io.micronaut.core.util.ArgumentUtils;
import io.micronaut.core.version.annotation.Version;
import io.micronaut.http.HttpRequest;
import io.micronaut.web.router.UriRouteMatch;
import io.micronaut.web.router.filter.RouteMatchFilter;
import io.micronaut.web.router.version.resolution.RequestVersionResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import edu.umd.cs.findbugs.annotations.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;
@Singleton
@Requires(beans = RoutesVersioningConfiguration.class)
public class RouteVersionFilter implements RouteMatchFilter {
private static final Logger LOG = LoggerFactory.getLogger(RouteVersionFilter.class);
private final List<RequestVersionResolver> resolvingStrategies;
private final DefaultVersionProvider defaultVersionProvider;
@Inject
public RouteVersionFilter(List<RequestVersionResolver> resolvingStrategies,
@Nullable DefaultVersionProvider defaultVersionProvider) {
this.resolvingStrategies = resolvingStrategies;
this.defaultVersionProvider = defaultVersionProvider;
}
@Override
public <T, R> Predicate<UriRouteMatch<T, R>> filter(HttpRequest<?> request) {
ArgumentUtils.requireNonNull("request", request);
if (resolvingStrategies == null || resolvingStrategies.isEmpty()) {
return match -> true;
}
Optional<String> defaultVersion = defaultVersionProvider == null ? Optional.empty() : Optional.of(defaultVersionProvider.resolveDefaultVersion());
Optional<String> version = resolvingStrategies.stream()
.map(strategy -> strategy.resolve(request).orElse(null))
.filter(Objects::nonNull)
.findFirst();
return match -> {
Optional<String> routeVersion = getVersion(match);
if (routeVersion.isPresent()) {
String resolvedVersion = version.orElse(defaultVersion.orElse(null));
if (resolvedVersion == null) {
if (LOG.isDebugEnabled()) {
LOG.debug("Route specifies a version {} and no version information resolved for request to URI {}", routeVersion.get(), request.getUri());
}
return true;
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Route specifies a version {} and the version {} was resolved for request to URI {}", routeVersion.get(), resolvedVersion, request.getUri());
}
return resolvedVersion.equals(routeVersion.get());
}
} else {
if (version.isPresent()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Route does not specify a version but the version {} was resolved for request to URI {}", version.get(), request.getUri());
}
return false;
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Route does not specify a version and no version was resolved for request to URI {}", request.getUri());
}
return true;
}
}
};
}
private <T, R> Optional<String> getVersion(UriRouteMatch<T, R> routeMatch) {
return routeMatch.getExecutableMethod().stringValue(Version.class);
}
}