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 static java.util.Objects.requireNonNull;
022
023/**
024 * Contract for generating {@link Request} identifiers of a particular type (for example, sequential {@link Long} values, random {@link java.util.UUID}s, etc.)
025 * <p>
026 * Useful for incorporating request data in nonlocal deployment environments (e.g. a tracing header like <a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-request-tracing.html" target="_blank">{@code X-Amzn-Trace-Id}</a>).
027 * <p>
028 * Implementations may or may not guarantee uniqueness, ordering, or repeatability of generated identifiers. Callers should not assume any such guarantees unless documented by the implementation.
029 * <p>
030 * Standard threadsafe implementations can be acquired via these factory methods:
031 * <ul>
032 *   <li>{@link #defaultInstance()}</li>
033 *   <li>{@link #defaultSessionInstance()}</li>
034 *   <li>{@link #fromPrefix(String)}</li>
035 * </ul>
036 *
037 * @param <T> the type of identifier produced
038 * @author <a href="https://www.revetkn.com">Mark Allen</a>
039 */
040@FunctionalInterface
041public interface IdGenerator<T> {
042        /**
043         * Generates an identifier for the given {@link Request}.
044         * <p>
045         * Implementations may choose different strategies (sequential, random, host-based, etc.)
046         * and are not required to guarantee uniqueness unless explicitly documented.
047         * <p>
048         * Implementations may choose to incorporate request data (e.g. a tracing header like {@code X-Amzn-Trace-Id}).
049         *
050         * @param request the request for which an identifier is being generated
051         * @return the generated identifier (never {@code null})
052         */
053        @NonNull
054        T generateId(@NonNull Request request);
055
056        /**
057         * Acquires a threadsafe {@link IdGenerator} with a best-effort local IP prefix.
058         * <p>
059         * This method is guaranteed to return a new instance.
060         *
061         * @return an {@code IdGenerator} with default settings
062         */
063        @NonNull
064        static IdGenerator<String> defaultInstance() {
065                return DefaultIdGenerator.defaultInstance();
066        }
067
068        /**
069         * Acquires a threadsafe, cryptographically strong session identifier generator.
070         * <p>
071         * This implementation is intended for protocol session identifiers such as MCP
072         * {@code MCP-Session-Id} values, where IDs must be globally unique, unguessable,
073         * and safe to include in HTTP header values.
074         * <p>
075         * Generated IDs contain only URL-safe visible ASCII characters.
076         *
077         * @return an {@code IdGenerator} suitable for session identifiers
078         */
079        @NonNull
080        static IdGenerator<String> defaultSessionInstance() {
081                return DefaultSessionIdGenerator.defaultInstance();
082        }
083
084
085        /**
086         * Acquires a threadsafe {@link IdGenerator} with the given prefix.
087         * <p>
088         * This method is guaranteed to return a new instance.
089         *
090         * @param prefix a string to prepend to the generated numeric ID
091         * @return an {@code IdGenerator} configured with the given prefix
092         */
093        @NonNull
094        static IdGenerator<String> fromPrefix(@NonNull String prefix) {
095                requireNonNull(prefix);
096                return DefaultIdGenerator.fromPrefix(prefix);
097        }
098}