001/*
002 * Copyright 2015-2022 Transmogrify LLC, 2022-2026 Revetware LLC.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.pyranid;
018
019import org.jspecify.annotations.NonNull;
020import org.jspecify.annotations.Nullable;
021
022import javax.annotation.concurrent.Immutable;
023import java.util.Optional;
024
025import static java.util.Objects.requireNonNull;
026
027/**
028 * Immutable observation of one completed transaction boundary, after cleanup and post-transaction hooks.
029 * <p>
030 * The database result and the invocation failure describe different facts: a committed transaction can still fail
031 * during cleanup or a post-transaction hook. A normal rollback-only return has no failure. Nested independent
032 * transactions have separate completions even when the same failure escapes both boundaries.
033 * <p>
034 * The failure is the original throwable reference, not an immutable copy of that throwable.
035 *
036 * @since 4.8.0
037 */
038@Immutable
039public final class TransactionCompletion {
040        @NonNull
041        private final Long transactionId;
042        @Nullable
043        private final Long enclosingTransactionId;
044        @NonNull
045        private final TransactionResult result;
046        @Nullable
047        private final Throwable failure;
048
049        TransactionCompletion(@NonNull Long transactionId, @Nullable Long enclosingTransactionId,
050                        @NonNull TransactionResult result, @Nullable Throwable failure) {
051                this.transactionId = requireNonNull(transactionId);
052                this.enclosingTransactionId = enclosingTransactionId;
053                this.result = requireNonNull(result);
054                this.failure = failure;
055        }
056
057        /**
058         * Gets this boundary's identifier. IDs correlate transactions within the process, not durable business operations.
059         *
060         * @return transaction identifier
061         */
062        @NonNull
063        public Long getTransactionId() {
064                return this.transactionId;
065        }
066
067        /**
068         * Gets the identifier of the ambient transaction when this boundary started, including a different database's
069         * transaction when an independent nested transaction was started explicitly.
070         *
071         * @return enclosing transaction identifier, if any
072         */
073        @NonNull
074        public Optional<Long> getEnclosingTransactionId() {
075                return Optional.ofNullable(this.enclosingTransactionId);
076        }
077
078        /**
079         * Gets this boundary's database outcome. Scopes without physical JDBC work retain their logical commit or rollback
080         * result. This result does not describe the outcome of independently completed nested transactions.
081         *
082         * @return transaction result
083         */
084        @NonNull
085        public TransactionResult getResult() {
086                return this.result;
087        }
088
089        /**
090         * Gets the exact throwable propagated by this invocation, including suppressed cleanup and hook failures.
091         * The throwable may subsequently gain suppressed failures as it crosses enclosing transaction boundaries.
092         *
093         * @return invocation failure, or empty for a normal return
094         */
095        @NonNull
096        public Optional<Throwable> getFailure() {
097                return Optional.ofNullable(this.failure);
098        }
099}