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/**
020 * Per-subscription queue handle minted by an {@link McpSubscriptionBroker}.
021 *
022 * <p>
023 * Deliberately named differently from the client-facing {@code McpSubscriptionHandle} (a distinct type in a
024 * separate client module/package): this is the server-side, broker-internal handle a v2 dispatch branch
025 * drains via {@link #take()} to serialize change events onto its own stream.
026 *
027 * <p>
028 * Owns its own bounded, drop-oldest queue — it does <b>not</b> reuse
029 * {@code org.apache.juneau.rest.server.sse.SseSubscription}, whose constructor and {@code offer(...)} method
030 * are package-private to a different package. Only one thread should call {@link #take()} concurrently on a
031 * given instance (matching the production single-pump-per-subscription usage): {@link #close()}'s contract
032 * of interrupting a blocked {@link #take()} tracks a single in-flight taker thread.
033 */
034public interface McpSubscription extends AutoCloseable {
035
036   /**
037    * The subscription identifier (the originating {@code subscriptions/listen} request's JSON-RPC id).
038    *
039    * @return The identifier. Never {@code null} or empty.
040    */
041   String getId();
042
043   /**
044    * The honored filter this subscription was registered with.
045    *
046    * @return The filter. Never {@code null}.
047    */
048   McpSubscriptionFilter getFilter();
049
050   /**
051    * Blocks until the next matching change event is available.
052    *
053    * <p>
054    * Calling this on a subscription that is already closed throws {@link InterruptedException} immediately
055    * rather than blocking — load-bearing behavior for a pump's graceful-completion path, which relies on a
056    * closed-before-called {@link #take()} failing fast instead of hanging forever waiting for an event that
057    * will never arrive.
058    *
059    * @return The next event.
060    * @throws InterruptedException If the wait was interrupted, including by a concurrent {@link #close()},
061    *    or if this subscription was already closed before this call.
062    */
063   McpChangeEvent take() throws InterruptedException;
064
065   /**
066    * Returns whether this subscription has been closed.
067    *
068    * @return {@code true} if closed.
069    */
070   boolean isClosed();
071
072   /**
073    * Closes this subscription: idempotent, deregisters from the broker that minted it, and interrupts a
074    * thread currently blocked in {@link #take()}.
075    */
076   @Override
077   void close();
078}