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}