001/*
002 * Copyright 2022-2025 Revetware LLC.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.soklet;
018
019import javax.annotation.Nonnull;
020import java.lang.reflect.Method;
021import java.util.Optional;
022import java.util.Set;
023
024import static java.util.Objects.requireNonNull;
025
026/**
027 * Contract for matching incoming HTTP requests with appropriate <em>Resource Methods</em> (Java methods to invoke to handle requests).
028 * <p>
029 * A <em>Resource Method</em> is a Java {@link Method} with an HTTP method annotation applied, e.g. {@link com.soklet.annotation.GET}, {@link com.soklet.annotation.POST}, {@link com.soklet.annotation.ServerSentEventSource}, ...
030 * <p>
031 * Standard threadsafe implementations can be acquired via these factory methods:
032 * <ul>
033 *   <li>{@link #fromClasspathIntrospection()} (examines an annotation-processor-generated lookup table of Java {@link Method} declarations with corresponding HTTP method annotations)</li>
034 *   <li>{@link #withClasses(Set)} (examines methods within the hardcoded set of classes)</li>
035 *   <li>{@link #withMethods(Set)} (examines the hardcoded set of methods)</li>
036 * </ul>
037 * <p>
038 * It is likely that one or more of the above implementations is sufficient for your application and test suite.
039 * <p>
040 * However, should a custom implementation be necessary, documentation is available at <a href="https://www.soklet.com/docs/request-handling#resource-method-resolution">https://www.soklet.com/docs/request-handling#resource-method-resolution</a>.
041 *
042 * @author <a href="https://www.revetkn.com">Mark Allen</a>
043 */
044public interface ResourceMethodResolver {
045        /**
046         * Given an HTTP request, provide a matching <em>Resource Method</em> to invoke.
047         * <p>
048         * An unmatched <em>Resource Method</em> generally indicates an {@code HTTP 404}.
049         *
050         * @param request    the HTTP request
051         * @param serverType the type of server that's handling the request
052         * @return the matching <em>Resource Method</em>, or {@link Optional#empty()} if no match was found
053         */
054        @Nonnull
055        Optional<ResourceMethod> resourceMethodForRequest(@Nonnull Request request,
056                                                                                                                                                                                                                @Nonnull ServerType serverType);
057
058        /**
059         * Vends the set of all <em>Resource Methods</em> registered in the system.
060         *
061         * @return the set of all <em>Resource Methods</em> in the system
062         */
063        @Nonnull
064        Set<ResourceMethod> getResourceMethods();
065
066        /**
067         * Acquires a threadsafe {@link ResourceMethodResolver} implementation which locates <em>Resource Methods</em> by examining a lookup table of Java {@link Method} declarations that are annotated with {@link com.soklet.annotation.GET}, {@link com.soklet.annotation.POST}, {@link com.soklet.annotation.ServerSentEventSource}, etc.
068         * <p>
069         * This implementation requires that your application be compiled with the {@link SokletProcessor} annotation processor, as shown below:
070         * <p>
071         * <pre>javac -parameters -processor com.soklet.SokletProcessor ...[rest of javac command elided]</pre>
072         * <p>
073         * The returned instance is guaranteed to be a JVM-wide singleton.
074         *
075         * @return a {@code ResourceMethodResolver} which performs classpath introspection against the annotation processor's lookup table
076         */
077        @Nonnull
078        static ResourceMethodResolver fromClasspathIntrospection() {
079                return DefaultResourceMethodResolver.fromClasspathIntrospection();
080        }
081
082        /**
083         * Acquires a threadsafe {@link ResourceMethodResolver} implementation which locates <em>Resource Methods</em> by examining the provided {@code classes}.
084         * <p>
085         * This method is guaranteed to return a new instance.
086         *
087         * @param classes the classes to inspect for <em>Resource Methods</em>
088         * @return a {@code ResourceMethodResolver} backed by the given {@code classes}
089         */
090        @Nonnull
091        static ResourceMethodResolver withClasses(@Nonnull Set<Class<?>> classes) {
092                requireNonNull(classes);
093                return DefaultResourceMethodResolver.withClasses(classes);
094        }
095
096        /**
097         * Acquires a threadsafe {@link ResourceMethodResolver} implementation which locates <em>Resource Methods</em> by examining the provided {@code methods}.
098         * <p>
099         * This method is guaranteed to return a new instance.
100         *
101         * @param methods the methods to inspect for <em>Resource Method</em> annotations
102         * @return a {@code ResourceMethodResolver} backed by the given {@code methods}
103         */
104        @Nonnull
105        static ResourceMethodResolver withMethods(@Nonnull Set<Method> methods) {
106                requireNonNull(methods);
107                return DefaultResourceMethodResolver.withMethods(methods);
108        }
109}