All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.transaction.reactive.TransactionContextManager Maven / Gradle / Ivy

There is a newer version: 6.2.0
Show newest version
/*
 * Copyright 2002-2023 the original author or authors.
 *
 * 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
 *
 *      https://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.springframework.transaction.reactive;

import java.util.ArrayDeque;
import java.util.function.Function;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.context.Context;

import org.springframework.transaction.NoTransactionException;

/**
 * Delegate to register and obtain transactional contexts.
 *
 * 

Typically used by components that intercept or orchestrate transactional flows * such as AOP interceptors or transactional operators. * * @author Mark Paluch * @since 5.2 * @see TransactionSynchronization */ public abstract class TransactionContextManager { private TransactionContextManager() { } /** * Obtain the current {@link TransactionContext} from the subscriber context or the * transactional context holder. Context retrieval fails with NoTransactionException * if no context or context holder is registered. * @return the current {@link TransactionContext} * @throws NoTransactionException if no TransactionContext was found in the * subscriber context or no context found in a holder */ public static Mono currentContext() { return Mono.deferContextual(ctx -> { if (ctx.hasKey(TransactionContext.class)) { return Mono.just(ctx.get(TransactionContext.class)); } if (ctx.hasKey(TransactionContextHolder.class)) { TransactionContextHolder holder = ctx.get(TransactionContextHolder.class); if (holder.hasContext()) { return Mono.just(holder.currentContext()); } } return Mono.error(new NoTransactionInContextException()); }); } /** * Create a {@link TransactionContext} and register it in the subscriber {@link Context}. * @return functional context registration. * @throws IllegalStateException if a transaction context is already associated. * @see Mono#contextWrite(Function) * @see Flux#contextWrite(Function) */ public static Function createTransactionContext() { return context -> context.put(TransactionContext.class, new TransactionContext()); } /** * Return a {@link Function} to create or associate a new {@link TransactionContext}. * Interaction with transactional resources through * {@link TransactionSynchronizationManager} requires a TransactionContext * to be registered in the subscriber context. * @return functional context registration. */ public static Function getOrCreateContext() { return context -> { TransactionContextHolder holder = context.get(TransactionContextHolder.class); if (holder.hasContext()) { return context.put(TransactionContext.class, holder.currentContext()); } return context.put(TransactionContext.class, holder.createContext()); }; } /** * Return a {@link Function} to create or associate a new * {@link TransactionContextHolder}. Creation and release of transactions * within a reactive flow requires a mutable holder that follows a top to * down execution scheme. Reactor's subscriber context follows a down to top * approach regarding mutation visibility. * @return functional context registration. */ public static Function getOrCreateContextHolder() { return context -> { if (!context.hasKey(TransactionContextHolder.class)) { return context.put(TransactionContextHolder.class, new TransactionContextHolder(new ArrayDeque<>())); } return context; }; } /** * Stackless variant of {@link NoTransactionException} for reactive flows. */ @SuppressWarnings("serial") private static class NoTransactionInContextException extends NoTransactionException { public NoTransactionInContextException() { super("No transaction in context"); } @Override public synchronized Throwable fillInStackTrace() { // stackless exception return this; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy