
io.inverno.mod.http.server.ResponseBody Maven / Gradle / Ivy
/*
* Copyright 2020 Jeremy KUHN
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.inverno.mod.http.server;
import io.inverno.mod.http.base.OutboundData;
import io.netty.buffer.ByteBuf;
import org.reactivestreams.Publisher;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
/**
*
* Represents the payload body of a server response in a server exchange.
*
*
*
* The response body basically provides multiple ways to produce the response payload.
*
*
* @author Jeremy Kuhn
* @since 1.0
*
* @see Response
*/
public interface ResponseBody {
/**
*
* Transforms the payload publisher.
*
*
*
* This can be used in an exchange interceptor in order to decorate response data publisher.
*
*
* @param transformer a request payload publisher transformer
*
* @return the request body
*
* @throws IllegalArgumentException if data were already sent to the recipient
*/
ResponseBody transform(Function, Publisher> transformer) throws IllegalArgumentException;
/**
*
* Produces an empty payload.
*
*
*
* If a payload has already been provided this method does nothing.
*
*
*
* A typical usage is:
*
*
* {@code
* exchange.response().body().empty();
* }
*/
void empty();
/**
*
* Returns a raw payload producer.
*
*
*
* A typical usage is:
*
*
* {@code
* exchange.response().body().raw().stream(
* Flux.just(
* Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Hello ", Charsets.DEFAULT)),
* Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("World!", Charsets.DEFAULT))
* )
* );
* }
*
* @return a raw payload producer
*/
OutboundData raw();
/**
*
* Returns a string payload producer.
*
*
*
* A typical usage is:
*
*
* {@code
* exchange.response().body().string().stream(
* Flux.just(
* Unpooled.unreleasableBuffer("Hello "),
* Unpooled.unreleasableBuffer("World!")
* )
* );
* }
*
* @param the type of char sequence
*
* @return a string payload producer
*/
OutboundData string();
/**
*
* Returns a resource payload producer.
*
*
*
* A typical usage is:
*
*
* {@code
* ResourceService resourceService = ...
* exchange.response().body().resource().value(resourceService.get("file:/path/to/resource");
* }
*
* @return a resource payload producer
*/
ResponseBody.Resource resource();
/**
*
* Returns a server-sent events payload producer as defined by Server-Sent Events.
*
*
*
* A typical usage is:
*
*
* {@code
* exchange.response().body().sse().from(
* (events, data) -> Flux.interval(Duration.ofSeconds(1))
* .map(seq -> events.create(event -> event
* .id(Long.toString(seq))
* .event("seq")
* .value(Unpooled.unreleasableBuffer(Unpooled.copiedBuffer("Event #" + seq, Charsets.DEFAULT)))
* )
* )
* );
* }
*
* @return a server-sent events payload producer
*/
ResponseBody.Sse, ResponseBody.Sse.EventFactory>> sse();
/**
*
* Returns a server-sent events payload producer as defined by Server-Sent Events.
*
*
*
* A typical usage is:
*
*
* {@code
* exchange.response().body().sseString().from(
* (events, data) -> Flux.interval(Duration.ofSeconds(1))
* .map(seq -> events.create(event -> event
* .id(Long.toString(seq))
* .event("seq")
* .value("Event #" + seq, Charsets.DEFAULT))
* )
* )
* );
* }
*
* @param The type of char sequence
*
* @return a server-sent events payload producer
*/
ResponseBody.Sse, ResponseBody.Sse.EventFactory>> sseString();
/**
*
* A resource payload producer.
*
*
* @author Jeremy Kuhn
* @since 1.0
*/
interface Resource {
/**
*
* Sets the specified resource in the response payload.
*
*
*
* This method tries to determine the content type of the specified resource in
* which case the content type header is set in the response.
*
*
* @param resource a resource
*
* @throws IllegalStateException if data were already sent to the recipient
*/
void value(io.inverno.mod.base.resource.Resource resource) throws IllegalStateException;
}
/**
*
* A server-sent events payload producer as defined by
* Server-Sent Events.
*
*
* @author Jeremy Kuhn
* @since 1.0
*
* @param the type of data sent in the event
* @param the server-sent event type
* @param the server-sent event factory
*/
interface Sse, C extends ResponseBody.Sse.EventFactory> {
/**
*
* Sets the server-sent events stream in the specified consumer using the server-sent event factory to create events and the server-sent
* events producer to sets the stream of events.
*
*
* @param data a function in which server-sent events stream must be set
*/
void from(BiConsumer> data);
/**
*
* Represents a server-sent event.
*
*
* @author Jeremy Kuhn
* @since 1.0
*
* @param the type of data sent in the event
*/
interface Event extends OutboundData {
/**
*
* Sets the event id.
*
*
* @param id an id
*
* @return the event
*/
ResponseBody.Sse.Event id(String id);
/**
*
* Sets the event comment.
*
*
* @param comment a comment
*
* @return the event
*/
ResponseBody.Sse.Event comment(String comment);
/**
*
* Sets the type of event.
*
*
* @param event an event type
*
* @return the event
*/
ResponseBody.Sse.Event event(String event);
}
/**
*
* A server-sent event factory is used to create server-sent events.
*
*
* @author Jeremy Kuhn
* @since 1.0
*
* @param the type of data sent in the event data
* @param the server-sent event type
*/
@FunctionalInterface
interface EventFactory> {
/**
*
* Creates a server-sent event with the specified configurer.
*
*
* @param configurer a server-sent event configurer
*
* @return a new server-sent event
*/
B create(Consumer configurer);
/**
*
* Creates an empty server-sent event.
*
*
* @return a new server-sent event
*/
default B create() {
return this.create(event -> {});
}
}
}
}