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
019
020import java.util.concurrent.*;
021import static org.apache.juneau.commons.utils.Shorts.*;
022
023/**
024 * The result of a {@link ReactiveStreamsAdapter#adapt(Object) ReactiveStreamsAdapter.adapt(...)} call:
025 * either a single-value {@link CompletionStage} or a multi-value
026 * {@link java.util.concurrent.Flow.Publisher Flow.Publisher}.
027 *
028 * <p>
029 * Exactly one of the two shapes is present. Single-value adaptations (e.g. Reactor {@code Mono},
030 * RxJava {@code Single} / {@code Maybe}) collapse onto the existing {@code CompletableFuture} async
031 * response path. Streaming adaptations (e.g. Reactor {@code Flux}, RxJava {@code Flowable} /
032 * {@code Observable}, a Reactive-Streams {@code Publisher}) are subscribed to and rendered as a
033 * buffered list, an SSE stream, or an NDJSON stream depending on the negotiated response media type.
034 *
035 * @see ReactiveStreamsAdapter
036 * @see ReactiveResponseProcessor
037 * @since 10.0.0
038 */
039@SuppressWarnings({
040   "java:S1452" // single() and stream() return CompletionStage<?>/Flow.Publisher<?> because the element type is erased at adaptation time.
041})
042public final class Adaptation {
043
044   private final CompletionStage<?> single;
045   private final Flow.Publisher<?> stream;
046
047   private Adaptation(CompletionStage<?> single, Flow.Publisher<?> stream) {
048      this.single = single;
049      this.stream = stream;
050   }
051
052   /**
053    * Creates a single-value adaptation backed by a {@link CompletionStage}.
054    *
055    * @param value The completion stage. Must not be {@code null}.
056    * @return A new adaptation.
057    */
058   public static Adaptation single(CompletionStage<?> value) {
059      return new Adaptation(reqnn("value", value), null);
060   }
061
062   /**
063    * Creates a streaming adaptation backed by a {@link java.util.concurrent.Flow.Publisher Flow.Publisher}.
064    *
065    * @param value The publisher. Must not be {@code null}.
066    * @return A new adaptation.
067    */
068   public static Adaptation stream(Flow.Publisher<?> value) {
069      return new Adaptation(null, reqnn("value", value));
070   }
071
072   /**
073    * Returns whether this adaptation is a multi-value stream (vs. a single value).
074    *
075    * @return {@code true} if this is a {@link java.util.concurrent.Flow.Publisher Flow.Publisher} adaptation.
076    */
077   public boolean isStream() {
078      return stream != null;
079   }
080
081   /**
082    * Returns the single-value completion stage, or {@code null} if this is a streaming adaptation.
083    *
084    * @return The completion stage, or {@code null}.
085    */
086   public CompletionStage<?> single() {
087      return single;
088   }
089
090   /**
091    * Returns the streaming publisher, or {@code null} if this is a single-value adaptation.
092    *
093    * @return The publisher, or {@code null}.
094    */
095   public Flow.Publisher<?> stream() {
096      return stream;
097   }
098}