001/*-
002 * #%L
003 * HAPI FHIR Storage api
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.jpa.dao.tx;
021
022import ca.uhn.fhir.interceptor.model.RequestPartitionId;
023import ca.uhn.fhir.rest.api.server.RequestDetails;
024import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
025import ca.uhn.fhir.util.ICallable;
026import jakarta.annotation.Nonnull;
027import jakarta.annotation.Nullable;
028import org.springframework.transaction.annotation.Isolation;
029import org.springframework.transaction.annotation.Propagation;
030import org.springframework.transaction.support.TransactionCallback;
031import org.springframework.transaction.support.TransactionOperations;
032
033import java.util.List;
034import java.util.concurrent.Callable;
035import java.util.stream.Stream;
036
037/**
038 * This class is used to execute code within the context of a database transaction,
039 * just like Spring's {@link org.springframework.transaction.support.TransactionTemplate}
040 * but with more functionality. It can auto-execute code upon rollback, it translates
041 * specific exceptions, and it stores transaction context in a ThreadLocal.
042 */
043public interface IHapiTransactionService {
044
045        /**
046         * Fluent builder for creating a transactional callback
047         * <p>
048         * Method chain must end with a call to {@link IExecutionBuilder#execute(Runnable)} or one of the other
049         * overloads of <code>task(...)</code>
050         * </p>
051         */
052        IExecutionBuilder withRequest(@Nullable RequestDetails theRequestDetails);
053
054        /**
055         * Fluent builder for internal system requests with no external
056         * requestdetails associated
057         */
058        IExecutionBuilder withSystemRequest();
059
060        /**
061         * Fluent builder for internal system requests with no external
062         * {@link RequestDetails} associated and a pre-specified partition ID.
063         * This method is sugar for
064         * <pre>
065         *    withSystemRequest()
066         *                      .withRequestPartitionId(thePartitionId);
067         * </pre>
068         *
069         * @since 6.6.0
070         */
071        default IExecutionBuilder withSystemRequestOnPartition(RequestPartitionId theRequestPartitionId) {
072                return withSystemRequest().withRequestPartitionId(theRequestPartitionId);
073        }
074
075        /**
076         * Convenience for TX working with non-partitioned entities.
077         */
078        default IExecutionBuilder withSystemRequestOnDefaultPartition() {
079                return withSystemRequestOnPartition(RequestPartitionId.defaultPartition());
080        }
081
082        /**
083         * @deprecated It is highly recommended to use {@link #withRequest(RequestDetails)} instead of this method, for increased visibility.
084         */
085        @Deprecated(since = "6.10")
086        <T> T withRequest(
087                        @Nullable RequestDetails theRequestDetails,
088                        @Nullable TransactionDetails theTransactionDetails,
089                        @Nonnull Propagation thePropagation,
090                        @Nonnull Isolation theIsolation,
091                        @Nonnull ICallable<T> theCallback);
092
093        interface IExecutionBuilder extends TransactionOperations {
094
095                IExecutionBuilder withIsolation(Isolation theIsolation);
096
097                IExecutionBuilder withTransactionDetails(TransactionDetails theTransactionDetails);
098
099                IExecutionBuilder withPropagation(Propagation thePropagation);
100
101                IExecutionBuilder withRequestPartitionId(RequestPartitionId theRequestPartitionId);
102
103                IExecutionBuilder readOnly();
104
105                IExecutionBuilder onRollback(Runnable theOnRollback);
106
107                void execute(Runnable theTask);
108
109                <T> T execute(Callable<T> theTask);
110
111                <T> T execute(@Nonnull TransactionCallback<T> callback);
112
113                /**
114                 * Read query path.
115                 */
116                default <T> T read(Callable<T> theCallback) {
117                        return execute(theCallback);
118                }
119
120                /**
121                 * Search for open Stream.
122                 * The Stream may not be readable outside an outermost transaction.
123                 */
124                default <T> Stream<T> search(Callable<Stream<T>> theCallback) {
125                        return execute(theCallback);
126                }
127
128                /**
129                 * Search for concrete List.
130                 */
131                default <T> List<T> searchList(Callable<List<T>> theCallback) {
132                        return execute(theCallback);
133                }
134        }
135}