001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.rest.server.mcp;
018
019
020import java.util.*;
021
022import org.apache.juneau.commons.inject.*;
023import static org.apache.juneau.commons.utils.Shorts.*;
024
025/**
026 * Handler for a single MCP resource template.
027 *
028 * <p>
029 * Implementations declare a {@link #descriptor() descriptor} (the {@link McpResourceTemplateSpec} returned by
030 * {@code resources/templates/list}), a {@link #read(String, Map, BeanStore) read} body invoked when this
031 * template is selected for a matching {@code resources/read} request, and an optional
032 * {@link #completer(String) completer} for one of the template's declared variables.
033 *
034 * <p>
035 * A registration whose {@link #descriptor() descriptor}.{@code uriTemplate} is not one of
036 * {@link McpUriTemplateMatcher}'s reverse-matchable forms remains listable and completable but is never
037 * selected for a template-backed read. Use {@link McpServerConfig#addResourceTemplate(McpResourceTemplateSpec...)}
038 * to register a listing-only template without implementing this interface.
039 *
040 * <p>
041 * Use {@link #of(McpResourceTemplateSpec, ReadFunction)} for the common case of wiring both
042 * {@link #descriptor()} and {@link #read(String, Map, BeanStore)} in a single expression.
043 */
044public interface McpResourceTemplateHandler {
045
046   /**
047    * A three-argument function from ({@code uri}, {@code variables}, {@code ctx}) to a
048    * {@link McpResourceOutcome}, matching {@link #read(String, Map, BeanStore)}'s signature.
049    *
050    * <p>
051    * A dedicated functional interface rather than {@link java.util.function.BiFunction} because
052    * {@code read(...)} takes three parameters, not two.
053    */
054   @FunctionalInterface
055   interface ReadFunction {
056      /**
057       * Reads the resource body for a concrete URI matched against the template.
058       *
059       * @param uri The original concrete URI from the {@code resources/read} request.
060       * @param variables An immutable, insertion-ordered map of the template's declared variables to their
061       *    decoded values, captured from {@code uri}.
062       * @param ctx Per-request bean store. Never {@code null}.
063       * @return The resource contents, or {@code null} if this template does not serve {@code uri}.
064       */
065      McpResourceOutcome read(String uri, Map<String,String> variables, BeanStore ctx);
066   }
067
068   /**
069    * Builds a handler from a fixed descriptor and a {@code read} lambda.
070    *
071    * <p>
072    * The sanctioned one-expression path for registering a resource template: wires both
073    * {@link #descriptor()} and {@link #read(String, Map, BeanStore)} from a single call.
074    *
075    * @param descriptor The static descriptor returned from every {@link #descriptor()} call. Must not be
076    *    <jk>null</jk> and must carry a non-blank {@link McpResourceTemplateSpec#getUriTemplate() uriTemplate}
077    *    (routing and {@code completion/complete} both match on it, so a templateless registration would be
078    *    silently unreachable). Must not be <jk>null</jk>.
079    * @param read The read body, invoked with the concrete URI, its captured template variables, and the
080    *    per-request bean store. Must not be <jk>null</jk>.
081    * @return A new handler wiring both. Never <jk>null</jk>.
082    */
083   static McpResourceTemplateHandler of(McpResourceTemplateSpec descriptor, ReadFunction read) {
084      reqnn("descriptor", descriptor);
085      reqnb("descriptor.getUriTemplate()", descriptor.getUriTemplate());
086      reqnn("read", read);
087      return new McpResourceTemplateHandler() {
088         @Override public McpResourceTemplateSpec descriptor() {
089            return descriptor;
090         }
091
092         @Override public McpResourceOutcome read(String uri, Map<String,String> variables, BeanStore ctx) {
093            return read.read(uri, variables, ctx);
094         }
095      };
096   }
097
098   /**
099    * Returns the static descriptor for this resource template.
100    *
101    * <p>
102    * The {@link McpResourceTemplateSpec#getUriTemplate() uriTemplate} value is used by the bound
103    * {@link McpRevision} to route incoming {@code resources/read} requests and by {@code completion/complete}
104    * to identify this template, so each handler in an {@link McpServerConfig} must use a unique template
105    * string.
106    *
107    * @return The resource-template descriptor. Never {@code null}.
108    */
109   McpResourceTemplateSpec descriptor();
110
111   /**
112    * Reads the resource body for a concrete URI matched against this template.
113    *
114    * @param uri The original concrete URI from the {@code resources/read} request.
115    * @param variables An immutable, insertion-ordered map of this template's declared variables to their
116    *    decoded values, captured from {@code uri}.
117    * @param ctx Per-request bean store. Never {@code null}.
118    * @return The resource contents, or {@code null} if this template does not serve {@code uri}, which is
119    *    reported as resource-not-found. A {@code null} result never falls through to a less-specific template.
120    */
121   McpResourceOutcome read(String uri, Map<String,String> variables, BeanStore ctx);
122
123   /**
124    * Returns the completer for one of this template's declared variables.
125    *
126    * @param variableName The variable name from a {@code completion/complete} request.
127    * @return The completer for that variable, or {@code null} if none is registered. Callers must treat an
128    *    undeclared variable name as having no completer regardless of what this method returns.
129    */
130   default McpCompleter completer(String variableName) {
131      return null;
132   }
133}