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.core;
018
019import javax.annotation.Nonnull;
020import javax.annotation.Nullable;
021import javax.annotation.concurrent.ThreadSafe;
022import java.lang.reflect.Method;
023import java.util.Objects;
024
025import static java.lang.String.format;
026import static java.util.Objects.requireNonNull;
027
028/**
029 * Represents a <em>Resource Method</em>, which is a Java {@link Method} invoked by Soklet to handle an HTTP request.
030 * <p>
031 * See <a href="https://www.soklet.com/docs/request-handling">https://www.soklet.com/docs/request-handling</a> for details.
032 *
033 * @author <a href="https://www.revetkn.com">Mark Allen</a>
034 */
035@ThreadSafe
036public class ResourceMethod {
037        @Nonnull
038        private final HttpMethod httpMethod;
039        @Nonnull
040        private final ResourcePathDeclaration resourcePathDeclaration;
041        @Nonnull
042        private final Method method;
043        @Nonnull
044        private final Boolean serverSentEventSource;
045
046        /**
047         * Vends a <em>Resource Method</em> given its unique components.
048         *
049         * @param httpMethod            an HTTP method
050         * @param resourcePathDeclaration          an HTTP path which might contain placeholders, e.g. {@code /example/{exampleId}}
051         * @param method                a Java method to invoke for the combination of HTTP method and resource path
052         * @param serverSentEventSource is this <em>Resource Method</em> configured as a server-sent event source?
053         * @return a <em>Resource Method</em> for the supplied components
054         */
055        @Nonnull
056        public static ResourceMethod withComponents(@Nonnull HttpMethod httpMethod,
057                                                                                                                                                                                        @Nonnull ResourcePathDeclaration resourcePathDeclaration,
058                                                                                                                                                                                        @Nonnull Method method,
059                                                                                                                                                                                        @Nonnull Boolean serverSentEventSource) {
060                requireNonNull(httpMethod);
061                requireNonNull(resourcePathDeclaration);
062                requireNonNull(method);
063                requireNonNull(serverSentEventSource);
064
065                return new ResourceMethod(httpMethod, resourcePathDeclaration, method, serverSentEventSource);
066        }
067
068        protected ResourceMethod(@Nonnull HttpMethod httpMethod,
069                                                                                                         @Nonnull ResourcePathDeclaration resourcePathDeclaration,
070                                                                                                         @Nonnull Method method,
071                                                                                                         @Nonnull Boolean serverSentEventSource) {
072                requireNonNull(httpMethod);
073                requireNonNull(resourcePathDeclaration);
074                requireNonNull(method);
075                requireNonNull(serverSentEventSource);
076
077                this.httpMethod = httpMethod;
078                this.resourcePathDeclaration = resourcePathDeclaration;
079                this.method = method;
080                this.serverSentEventSource = serverSentEventSource;
081        }
082
083        @Override
084        public String toString() {
085                return format("%s{httpMethod=%s, resourcePathDeclaration=%s, method=%s, serverSentEventSource=%s}", getClass().getSimpleName(),
086                                getHttpMethod(), getResourcePath(), getMethod(), isServerSentEventSource());
087        }
088
089        @Override
090        public boolean equals(@Nullable Object object) {
091                if (this == object)
092                        return true;
093
094                if (!(object instanceof ResourceMethod resourceMethod))
095                        return false;
096
097                return Objects.equals(getHttpMethod(), resourceMethod.getHttpMethod())
098                                && Objects.equals(getResourcePath(), resourceMethod.getResourcePath())
099                                && Objects.equals(getMethod(), resourceMethod.getMethod())
100                                && Objects.equals(isServerSentEventSource(), resourceMethod.isServerSentEventSource());
101        }
102
103        @Override
104        public int hashCode() {
105                return Objects.hash(getHttpMethod(), getResourcePath(), getMethod(), isServerSentEventSource());
106        }
107
108        /**
109         * Returns the HTTP method for this <em>Resource Method</em>.
110         *
111         * @return the HTTP method
112         */
113        @Nonnull
114        public HttpMethod getHttpMethod() {
115                return this.httpMethod;
116        }
117
118        /**
119         * Returns the HTTP path for this <em>Resource Method</em>, which might contain placeholders - for example, {@code /example/{exampleId}}.
120         *
121         * @return the HTTP path
122         */
123        @Nonnull
124        public ResourcePathDeclaration getResourcePath() {
125                return this.resourcePathDeclaration;
126        }
127
128        /**
129         * Returns the Java method to invoke for the combination of HTTP method and resource path.
130         *
131         * @return the Java method to invoke
132         */
133        @Nonnull
134        public Method getMethod() {
135                return this.method;
136        }
137
138        /**
139         * Returns whether or not this <em>Resource Method</em> functions as a Server-Sent Event Source.
140         *
141         * @return {@code true} if this <em>Resource Method</em> functions as a Server-Sent Event Source, {@code false} otherwise
142         */
143        @Nonnull
144        public Boolean isServerSentEventSource() {
145                return this.serverSentEventSource;
146        }
147}