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.reactive; 018 019import java.util.concurrent.*; 020 021/** 022 * SPI that bridges a third-party reactive return type to one of the two JDK-native shapes that the 023 * {@link ReactiveResponseProcessor} understands: a {@link CompletionStage} (single value) or a 024 * {@link java.util.concurrent.Flow.Publisher Flow.Publisher} (a stream of values). 025 * 026 * <h5 class='topic'>Why this exists</h5> 027 * <p> 028 * The opt-in {@code juneau-rest-server-reactive} module handles {@link java.util.concurrent.Flow.Publisher Flow.Publisher} 029 * (and, via the existing {@code AsyncResponseProcessor}, {@link CompletionStage}) using only JDK APIs — 030 * no external dependency. Libraries such as Project Reactor ({@code Mono} / {@code Flux}), RxJava 3 031 * ({@code Single} / {@code Maybe} / {@code Flowable} / {@code Observable}), and the 032 * Reactive-Streams {@code org.reactivestreams.Publisher} are NOT on the core classpath. The opt-in 033 * {@code juneau-rest-server-reactive-reactor} module ships {@code ReactiveStreamsAdapter} implementations that 034 * convert those types into the JDK-native shapes, so the streaming / buffering / SSE / NDJSON plumbing 035 * is implemented exactly once in the core. 036 * 037 * <h5 class='topic'>Registration</h5> 038 * <p> 039 * Adapters are discovered via the JDK {@link java.util.ServiceLoader} mechanism. A bridge module (or a 040 * consumer who wants a custom adapter) ships a 041 * {@code META-INF/services/ReactiveStreamsAdapter} file listing the 042 * implementation class names. The {@link ReactiveResponseProcessor} loads the providers once (lazily, 043 * at first use) and skips any provider whose backing library is absent from the runtime classpath 044 * (a {@link NoClassDefFoundError} / {@link java.util.ServiceConfigurationError} on instantiation is swallowed). 045 * This means a single {@code juneau-rest-server-reactive-reactor} jar can declare Reactor, RxJava, and 046 * Reactive-Streams adapters while the consumer pulls only the {@code provided}-scope libraries they 047 * actually want. 048 * 049 * @see ReactiveResponseProcessor 050 * @see Adaptation 051 * @since 10.0.0 052 */ 053public interface ReactiveStreamsAdapter { 054 055 /** 056 * Returns whether this adapter recognizes the supplied return value. 057 * 058 * <p> 059 * Implementations must return {@code false} (rather than throw) for values they do not handle, and 060 * must be cheap to call — this is invoked on the response hot path for every non-null handler 061 * return value once at least one adapter is registered. 062 * 063 * @param value The {@code @RestOp} handler return value. Never {@code null}. 064 * @return {@code true} if {@link #adapt(Object)} can convert this value. 065 */ 066 boolean canAdapt(Object value); 067 068 /** 069 * Converts the supplied reactive value to a JDK-native {@link Adaptation}. 070 * 071 * <p> 072 * Only called when {@link #canAdapt(Object)} returned {@code true} for the same value. 073 * 074 * @param value The reactive value to adapt. Never {@code null}. 075 * @return The adapted single-value or streaming shape. Never {@code null}. 076 */ 077 Adaptation adapt(Object value); 078}