001/*
002 * Copyright 2022-2026 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 org.jspecify.annotations.NonNull;
020
021import java.lang.reflect.Method;
022import java.util.Optional;
023import java.util.Set;
024
025import static java.util.Objects.requireNonNull;
026
027/**
028 * Contract for matching incoming HTTP requests with appropriate <em>Resource Methods</em> (Java methods to invoke to handle requests).
029 * <p>
030 * 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}, ...
031 * <p>
032 * Standard threadsafe implementations can be acquired via these factory methods:
033 * <ul>
034 *   <li>{@link #fromClasspathIntrospection()} (examines an annotation-processor-generated lookup table of Java {@link Method} declarations with corresponding HTTP method annotations)</li>
035 *   <li>{@link #fromClasses(Set)} (examines methods within the hardcoded set of classes)</li>
036 *   <li>{@link #fromMethods(Set)} (examines the hardcoded set of methods)</li>
037 * </ul>
038 * <p>
039 * It is likely that one or more of the above implementations is sufficient for your application and test suite.
040 * <p>
041 * 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>.
042 *
043 * @author <a href="https://www.revetkn.com">Mark Allen</a>
044 */
045public interface ResourceMethodResolver {
046        /**
047         * Given an HTTP request, provide a matching <em>Resource Method</em> to invoke.
048         * <p>
049         * An unmatched <em>Resource Method</em> generally indicates an {@code HTTP 404}.
050         *
051         * @param request    the HTTP request
052         * @param serverType the type of server that's handling the request
053         * @return the matching <em>Resource Method</em>, or {@link Optional#empty()} if no match was found
054         */
055        @NonNull
056        Optional<ResourceMethod> resourceMethodForRequest(@NonNull Request request,
057                                                                                                                                                                                                                @NonNull ServerType serverType);
058
059        /**
060         * Vends the set of all <em>Resource Methods</em> registered in the system.
061         *
062         * @return the set of all <em>Resource Methods</em> in the system
063         */
064        @NonNull
065        Set<@NonNull ResourceMethod> getResourceMethods();
066
067        /**
068         * 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.
069         * <p>
070         * This implementation requires that your application be compiled with the {@link SokletProcessor} annotation processor, as shown below:
071         * <p>
072         * <pre>javac -parameters -processor com.soklet.SokletProcessor ...[rest of javac command elided]</pre>
073         * <p>
074         * The returned instance is guaranteed to be a JVM-wide singleton.
075         *
076         * @return a {@code ResourceMethodResolver} which performs classpath introspection against the annotation processor's lookup table
077         */
078        @NonNull
079        static ResourceMethodResolver fromClasspathIntrospection() {
080                return DefaultResourceMethodResolver.fromClasspathIntrospection();
081        }
082
083        /**
084         * Acquires a threadsafe {@link ResourceMethodResolver} implementation which locates <em>Resource Methods</em> by examining the provided {@code classes}.
085         * <p>
086         * This method is guaranteed to return a new instance.
087         *
088         * @param classes the classes to inspect for <em>Resource Methods</em>
089         * @return a {@code ResourceMethodResolver} backed by the given {@code classes}
090         */
091        @NonNull
092static ResourceMethodResolver fromClasses(@NonNull Set<@NonNull Class<?>> classes) {
093        requireNonNull(classes);
094        return DefaultResourceMethodResolver.fromClasses(classes);
095}
096
097        /**
098         * Acquires a threadsafe {@link ResourceMethodResolver} implementation which locates <em>Resource Methods</em> by examining the provided {@code methods}.
099         * <p>
100         * This method is guaranteed to return a new instance.
101         *
102         * @param methods the methods to inspect for <em>Resource Method</em> annotations
103         * @return a {@code ResourceMethodResolver} backed by the given {@code methods}
104         */
105        @NonNull
106static ResourceMethodResolver fromMethods(@NonNull Set<@NonNull Method> methods) {
107        requireNonNull(methods);
108        return DefaultResourceMethodResolver.fromMethods(methods);
109}
110}