org.thymeleaf.spring5.context.webflux.ReactiveDataDriverContextVariable Maven / Gradle / Ivy
Show all versions of thymeleaf-spring5 Show documentation
/*
* =============================================================================
*
* Copyright (c) 2011-2018, The THYMELEAF team (http://www.thymeleaf.org)
*
* 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 org.thymeleaf.spring5.context.webflux;
import org.reactivestreams.Publisher;
import org.springframework.core.ReactiveAdapterRegistry;
import org.thymeleaf.util.Validate;
import reactor.core.publisher.Flux;
/**
*
* Basic implementation of the {@link IReactiveDataDriverContextVariable} interface, including also
* the extensions specified in {@link IReactiveSSEDataDriverContextVariable}.
*
*
* The reactive data stream wrapped by this class will usually have the shape of an implementation of the
* {@link Publisher} interface, such as {@link reactor.core.publisher.Flux}. But other types of reactive
* artifacts are supported thanks to Spring's {@link org.springframework.core.ReactiveAdapterRegistry}
* mechanism if such adapter registry has been set in the context
* (see {@link SpringWebFluxContext#getReactiveAdapterRegistry()}).
*
*
* Data-driver context variables are required to be multi-valued.
* Being multi-valued does not mean to necessarily return more than one value,
* but simply to have the capability to do so. E.g. a {@link reactor.core.publisher.Flux} object will
* be considered multi-valued even if it publishes none or just one result, whereas a
* {@link reactor.core.publisher.Mono} object will be considered single-valued.
*
*
* Example use:
*
*
* @RequestMapping("/something")
* public String doSomething(final Model model) {
* final Publisher<Item> data = ...; // This has to be MULTI-VALUED (e.g. Flux)
* model.addAttribute("data", new ReactiveDataDriverContextVariable(data, 100));
* return "view";
* }
*
*
* And then at the template:
*
*
* <table>
* <tbody>
* <tr th:each="item : ${data}">
* <td th:text="${item}">some item...</td>
* </tr>
* </tbody>
* </table>
*
*
* For more information on the way this class would work in SSE (Server-Sent Event) scenarios, see
* {@link IReactiveSSEDataDriverContextVariable}.
*
*
* This class is NOT thread-safe. Thread-safety is not a requirement for context variables.
*
*
* @see IReactiveDataDriverContextVariable
* @see IReactiveSSEDataDriverContextVariable
*
* @author Daniel Fernández
*
* @since 3.0.3
*
*/
public class ReactiveDataDriverContextVariable implements IReactiveSSEDataDriverContextVariable {
/**
*
* Default buffer size to be applied if none is specified. Value = {@code 10}.
*
*/
public static final int DEFAULT_DATA_DRIVER_BUFFER_SIZE_ELEMENTS = 10;
/**
*
* Default value for the first event ID (for SSE scenarios). Value = {@code 0}.
*
*/
public static final long DEFAULT_FIRST_EVENT_ID = 0L;
private final Object dataStream;
private final int dataStreamBufferSizeElements;
private final String sseEventsPrefix;
private final long sseEventsFirstID;
/**
*
* Creates a new lazy context variable, wrapping a reactive asynchronous data stream.
*
*
* Buffer size will be set to {@link #DEFAULT_DATA_DRIVER_BUFFER_SIZE_ELEMENTS}.
*
*
* The specified {@code dataStream} must be adaptable to a Reactive Stream's
* {@link Publisher} by means of Spring's {@link ReactiveAdapterRegistry} mechanism. If no
* adapter has been registered for the type of the asynchronous object, and exception will be
* thrown during lazy resolution. If no adapter registry has been set into the context
* (see {@link SpringWebFluxContext#getReactiveAdapterRegistry()}) this data stream must mandatorily
* be a {@link Flux}.
*
*
* Note the specified {@code dataStream} must be multi-valued.
*
*
* Examples of supported implementations are Reactor's {@link Flux} (but not
* {@link reactor.core.publisher.Mono}), and also RxJava's {@code Observable}
* (but not {@code Single}).
*
*
* @param dataStream the asynchronous object, which must be convertible to a multi-valued {@link Publisher} by
* means of Spring's {@link ReactiveAdapterRegistry}.
*/
public ReactiveDataDriverContextVariable(final Object dataStream) {
this(dataStream, DEFAULT_DATA_DRIVER_BUFFER_SIZE_ELEMENTS, null, DEFAULT_FIRST_EVENT_ID);
}
/**
*
* Creates a new lazy context variable, wrapping a reactive asynchronous data stream and specifying a
* buffer size.
*
*
* The specified {@code dataStream} must be adaptable to a Reactive Stream's
* {@link Publisher} by means of Spring's {@link ReactiveAdapterRegistry} mechanism. If no
* adapter has been registered for the type of the asynchronous object, and exception will be
* thrown during lazy resolution. If no adapter registry has been set into the context
* (see {@link SpringWebFluxContext#getReactiveAdapterRegistry()}) this data stream must mandatorily
* be a {@link Flux}.
*
*
* Note the specified {@code dataStream} must be multi-valued.
*
*
* Examples of supported implementations are Reactor's {@link Flux} (but not
* {@link reactor.core.publisher.Mono}), and also RxJava's {@code Observable}
* (but not {@code Single}).
*
*
* @param dataStream the asynchronous object, which must be convertible to a multi-valued {@link Publisher} by
* means of Spring's {@link ReactiveAdapterRegistry}.
* @param dataStreamBufferSizeElements the buffer size to be applied (in elements).
*/
public ReactiveDataDriverContextVariable(final Object dataStream, final int dataStreamBufferSizeElements) {
this(dataStream, dataStreamBufferSizeElements, null, DEFAULT_FIRST_EVENT_ID);
}
/**
*
* Creates a new lazy context variable, wrapping a reactive asynchronous data stream and specifying a
* buffer size and a prefix for all the names and IDs of events generated from a specific SSE stream.
*
*
* The specified {@code dataStream} must be adaptable to a Reactive Stream's
* {@link Publisher} by means of Spring's {@link ReactiveAdapterRegistry} mechanism. If no
* adapter has been registered for the type of the asynchronous object, and exception will be
* thrown during lazy resolution. If no adapter registry has been set into the context
* (see {@link SpringWebFluxContext#getReactiveAdapterRegistry()}) this data stream must mandatorily
* be a {@link Flux}.
*
*
* Note the specified {@code dataStream} must be multi-valued.
*
*
* Examples of supported implementations are Reactor's {@link Flux} (but not
* {@link reactor.core.publisher.Mono}), and also RxJava's {@code Observable}
* (but not {@code Single}).
*
*
* @param dataStream the asynchronous object, which must be convertible to a multi-valued {@link Publisher} by
* means of Spring's {@link ReactiveAdapterRegistry}.
* @param dataStreamBufferSizeElements the buffer size to be applied (in elements).
* @param sseEventsPrefix the prefix to be used for event names and IDs, so that events coming from a specific
* SSE stream can be identified (if applies). Can be null.
*
* @since 3.0.8
*/
public ReactiveDataDriverContextVariable(
final Object dataStream, final int dataStreamBufferSizeElements,
final String sseEventsPrefix) {
this(dataStream, dataStreamBufferSizeElements, sseEventsPrefix, DEFAULT_FIRST_EVENT_ID);
}
/**
*
* Creates a new lazy context variable, wrapping a reactive asynchronous data stream and specifying a
* buffer size and a value for the ID of the first event generated in SSE scenarios.
*
*
* The specified {@code dataStream} must be adaptable to a Reactive Stream's
* {@link Publisher} by means of Spring's {@link ReactiveAdapterRegistry} mechanism. If no
* adapter has been registered for the type of the asynchronous object, and exception will be
* thrown during lazy resolution. If no adapter registry has been set into the context
* (see {@link SpringWebFluxContext#getReactiveAdapterRegistry()}) this data stream must mandatorily
* be a {@link Flux}.
*
*
* Note the specified {@code dataStream} must be multi-valued.
*
*
* Examples of supported implementations are Reactor's {@link Flux} (but not
* {@link reactor.core.publisher.Mono}), and also RxJava's {@code Observable}
* (but not {@code Single}).
*
*
* @param dataStream the asynchronous object, which must be convertible to a multi-valued {@link Publisher} by
* means of Spring's {@link ReactiveAdapterRegistry}.
* @param dataStreamBufferSizeElements the buffer size to be applied (in elements).
* @param sseEventsFirstID the first value to be used as event ID in SSE scenarios (if applies).
*
* @since 3.0.4
*/
public ReactiveDataDriverContextVariable(
final Object dataStream, final int dataStreamBufferSizeElements,
final long sseEventsFirstID) {
this(dataStream, dataStreamBufferSizeElements, null, sseEventsFirstID);
}
/**
*
* Creates a new lazy context variable, wrapping a reactive asynchronous data stream and specifying a
* buffer size and a value for the ID of the first event generated in SSE scenarios and a prefix for all
* the names and IDs of events generated from a specific SSE stream.
*
*
* The specified {@code dataStream} must be adaptable to a Reactive Stream's
* {@link Publisher} by means of Spring's {@link ReactiveAdapterRegistry} mechanism. If no
* adapter has been registered for the type of the asynchronous object, and exception will be
* thrown during lazy resolution. If no adapter registry has been set into the context
* (see {@link SpringWebFluxContext#getReactiveAdapterRegistry()}) this data stream must mandatorily
* be a {@link Flux}.
*
*
* Note the specified {@code dataStream} must be multi-valued.
*
*
* Examples of supported implementations are Reactor's {@link Flux} (but not
* {@link reactor.core.publisher.Mono}), and also RxJava's {@code Observable}
* (but not {@code Single}).
*
*
* @param dataStream the asynchronous object, which must be convertible to a multi-valued {@link Publisher} by
* means of Spring's {@link ReactiveAdapterRegistry}.
* @param dataStreamBufferSizeElements the buffer size to be applied (in elements).
* @param sseEventsPrefix the prefix to be used for event names and IDs, so that events coming from a specific
* SSE stream can be identified (if applies). Can be null.
* @param sseEventsFirstID the first value to be used as event ID in SSE scenarios (if applies).
*
* @since 3.0.8
*/
public ReactiveDataDriverContextVariable(
final Object dataStream, final int dataStreamBufferSizeElements,
final String sseEventsPrefix, final long sseEventsFirstID) {
super();
Validate.notNull(dataStream, "Data stream cannot be null");
Validate.isTrue(dataStreamBufferSizeElements > 0, "Data Buffer Size cannot be <= 0");
// The prefix for SSE events CAN be null
Validate.isTrue(sseEventsFirstID >= 0L, "First Event ID cannot be < 0");
this.dataStream = dataStream;
this.dataStreamBufferSizeElements = dataStreamBufferSizeElements;
this.sseEventsPrefix = sseEventsPrefix;
this.sseEventsFirstID = sseEventsFirstID;
}
@Override
public Publisher