diff --git a/src/main/java/com/restful_spring/rest_interceptor/RestInterceptor.java b/src/main/java/com/restful_spring/rest_interceptor/RestInterceptor.java new file mode 100644 index 0000000..bfbe2d4 --- /dev/null +++ b/src/main/java/com/restful_spring/rest_interceptor/RestInterceptor.java @@ -0,0 +1,33 @@ +package com.restful_spring.rest_interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.List; +import org.springframework.web.cors.CorsUtils; +import org.springframework.web.servlet.HandlerInterceptor; + +public abstract class RestInterceptor implements HandlerInterceptor { + + protected List restfulPatterns = List.of(); + + @Override + public final boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + if (isPreFlightRequest(request) || shouldSkip(request)) { + return true; + } + return doInternal(request, response, handler); + } + + private boolean isPreFlightRequest(final HttpServletRequest request) { + return CorsUtils.isPreFlightRequest(request); + } + + private boolean shouldSkip(final HttpServletRequest request) { + return this.restfulPatterns.stream() + .noneMatch(pattern -> pattern.matches(request)); + } + + protected boolean doInternal(HttpServletRequest request, HttpServletResponse response, Object handler) { + return true; + } +} diff --git a/src/main/java/com/restful_spring/rest_interceptor/RestInterceptorRegistration.java b/src/main/java/com/restful_spring/rest_interceptor/RestInterceptorRegistration.java new file mode 100644 index 0000000..b4d6266 --- /dev/null +++ b/src/main/java/com/restful_spring/rest_interceptor/RestInterceptorRegistration.java @@ -0,0 +1,37 @@ +package com.restful_spring.rest_interceptor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class RestInterceptorRegistration { + + private final RestInterceptor restInterceptor; + private int order = 0; + + public RestInterceptorRegistration(RestInterceptor restInterceptor) { + this.restInterceptor = restInterceptor; + } + + public RestInterceptorRegistration addRestfulPatterns(RestfulPattern... restfulPatterns) { + return addRestfulPatterns(List.of(restfulPatterns)); + } + + public RestInterceptorRegistration addRestfulPatterns(Collection restfulPatterns) { + restInterceptor.restfulPatterns = new ArrayList<>(restfulPatterns); + return this; + } + + public RestInterceptorRegistration order(int order) { + this.order = order; + return this; + } + + protected RestInterceptor getRestInterceptor() { + return restInterceptor; + } + + protected int getOrder() { + return order; + } +} diff --git a/src/main/java/com/restful_spring/rest_interceptor/RestInterceptorRegistry.java b/src/main/java/com/restful_spring/rest_interceptor/RestInterceptorRegistry.java new file mode 100644 index 0000000..f3297a9 --- /dev/null +++ b/src/main/java/com/restful_spring/rest_interceptor/RestInterceptorRegistry.java @@ -0,0 +1,34 @@ +package com.restful_spring.rest_interceptor; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; + +public class RestInterceptorRegistry { + + private final InterceptorRegistry registry; + private final List registrations = new ArrayList<>(); + + public RestInterceptorRegistry(InterceptorRegistry registry) { + this.registry = registry; + } + + public RestInterceptorRegistration addInterceptor(RestInterceptor restInterceptor) { + RestInterceptorRegistration registration = new RestInterceptorRegistration(restInterceptor); + registrations.add(registration); + return registration; + } + + public void build() { + this.registrations.forEach(registration -> { + RestInterceptor restInterceptor = registration.getRestInterceptor(); + + registry.addInterceptor(restInterceptor) + .addPathPatterns(restInterceptor.restfulPatterns.stream() + .map(RestfulPattern::getPath) + .collect(Collectors.toList())) + .order(registration.getOrder()); + }); + } +} diff --git a/src/main/java/com/restful_spring/rest_interceptor/RestfulPattern.java b/src/main/java/com/restful_spring/rest_interceptor/RestfulPattern.java new file mode 100644 index 0000000..40fabd0 --- /dev/null +++ b/src/main/java/com/restful_spring/rest_interceptor/RestfulPattern.java @@ -0,0 +1,137 @@ +package com.restful_spring.rest_interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import org.springframework.http.HttpMethod; +import org.springframework.web.util.UriTemplate; + +public class RestfulPattern { + + private final UriTemplate path; + private final Set methods; + + private RestfulPattern(final UriTemplate path, final Set methods) { + this.path = path; + this.methods = methods; + } + + public static RestfulPattern of(final String path, final Collection methods) { + return new RestfulPattern(new UriTemplate(path), new HashSet<>(methods)); + } + + public static RestfulPattern of(final String path, final HttpMethod method) { + return new RestfulPattern(new UriTemplate(path), Set.of(method)); + } + + public static RestfulPatternBuilder builder() { + return new RestfulPatternBuilder(); + } + + public boolean matches(final HttpServletRequest request) { + return methods.contains(HttpMethod.valueOf(request.getMethod())) && path.matches(request.getRequestURI()); + } + + public String getPath() { + return path.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof RestfulPattern that)) { + return false; + } + + if (!methods.equals(that.methods)) { + return false; + } + return Objects.equals(path, that.path) && Objects.equals(methods, that.methods); + } + + @Override + public int hashCode() { + int result = methods.hashCode(); + result = 31 * result + (path != null ? path.hashCode() : 0); + return result; + } + + @Override + public String toString() { + return "RestfulPattern{" + + "methods=" + methods + + ", path=" + path.toString() + + '}'; + } + + public static class RestfulPatternBuilder { + + private final Set methods; + private UriTemplate path; + + public RestfulPatternBuilder() { + this.path = new UriTemplate("/**"); + this.methods = new HashSet<>(); + } + + public RestfulPatternBuilder path(String path) { + this.path = new UriTemplate(path); + return this; + } + + public RestfulPatternBuilder get() { + this.methods.add(HttpMethod.GET); + return this; + } + + public RestfulPatternBuilder post() { + this.methods.add(HttpMethod.POST); + return this; + } + + public RestfulPatternBuilder put() { + this.methods.add(HttpMethod.PUT); + return this; + } + + public RestfulPatternBuilder delete() { + this.methods.add(HttpMethod.DELETE); + return this; + } + + public RestfulPatternBuilder patch() { + this.methods.add(HttpMethod.PATCH); + return this; + } + + public RestfulPatternBuilder trace() { + this.methods.add(HttpMethod.TRACE); + return this; + } + + public RestfulPatternBuilder options() { + this.methods.add(HttpMethod.OPTIONS); + return this; + } + + public RestfulPatternBuilder head() { + this.methods.add(HttpMethod.HEAD); + return this; + } + + public RestfulPatternBuilder all() { + return get().post().put().delete().patch().trace().options().head(); + } + + public RestfulPattern build() { + if (methods.isEmpty()) { + return new RestfulPattern(path, Set.of(HttpMethod.values())); + } + return new RestfulPattern(path, methods); + } + } +}