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 com.google.common.annotations.Beta; 027import jakarta.annotation.Nonnull; 028import jakarta.annotation.Nullable; 029import org.springframework.transaction.annotation.Isolation; 030import org.springframework.transaction.annotation.Propagation; 031import org.springframework.transaction.support.TransactionCallback; 032import org.springframework.transaction.support.TransactionOperations; 033 034import java.util.List; 035import java.util.concurrent.Callable; 036import java.util.stream.Stream; 037 038/** 039 * This class is used to execute code within the context of a database transaction, 040 * just like Spring's {@link org.springframework.transaction.support.TransactionTemplate} 041 * but with more functionality. It can auto-execute code upon rollback, it translates 042 * specific exceptions, and it stores transaction context in a ThreadLocal. 043 */ 044public interface IHapiTransactionService { 045 046 /** 047 * Fluent builder for creating a transactional callback 048 * <p> 049 * Method chain must end with a call to {@link IExecutionBuilder#execute(Runnable)} or one of the other 050 * overloads of <code>task(...)</code> 051 * </p> 052 */ 053 IExecutionBuilder withRequest(@Nullable RequestDetails theRequestDetails); 054 055 /** 056 * Fluent builder for internal system requests with no external 057 * requestdetails associated 058 */ 059 IExecutionBuilder withSystemRequest(); 060 061 /** 062 * Fluent builder for internal system requests with no external 063 * {@link RequestDetails} associated and a pre-specified partition ID. 064 * This method is sugar for 065 * <pre> 066 * withSystemRequest() 067 * .withRequestPartitionId(thePartitionId); 068 * </pre> 069 * 070 * @since 6.6.0 071 */ 072 default IExecutionBuilder withSystemRequestOnPartition(RequestPartitionId theRequestPartitionId) { 073 return withSystemRequest().withRequestPartitionId(theRequestPartitionId); 074 } 075 076 /** 077 * Convenience for TX working with non-partitioned entities. 078 */ 079 default IExecutionBuilder withSystemRequestOnDefaultPartition() { 080 return withSystemRequestOnPartition(RequestPartitionId.defaultPartition()); 081 } 082 083 /** 084 * @deprecated It is highly recommended to use {@link #withRequest(RequestDetails)} instead of this method, for increased visibility. 085 */ 086 @Deprecated(since = "6.10") 087 <T> T withRequest( 088 @Nullable RequestDetails theRequestDetails, 089 @Nullable TransactionDetails theTransactionDetails, 090 @Nonnull Propagation thePropagation, 091 @Nonnull Isolation theIsolation, 092 @Nonnull ICallable<T> theCallback); 093 094 /** 095 * Are two RequestPartitionId values compatible within the same transaction? 096 * <p> 097 * This is an experimental API, subject to change in a future release. 098 * </p> 099 * 100 * @since 7.4.0 101 */ 102 @Beta 103 default boolean isCompatiblePartition( 104 RequestPartitionId theRequestPartitionId, RequestPartitionId theOtherRequestPartitionId) { 105 return true; 106 } 107 108 interface IExecutionBuilder extends TransactionOperations { 109 110 IExecutionBuilder withIsolation(Isolation theIsolation); 111 112 IExecutionBuilder withTransactionDetails(TransactionDetails theTransactionDetails); 113 114 IExecutionBuilder withPropagation(Propagation thePropagation); 115 116 IExecutionBuilder withRequestPartitionId(RequestPartitionId theRequestPartitionId); 117 118 IExecutionBuilder readOnly(); 119 120 IExecutionBuilder onRollback(Runnable theOnRollback); 121 122 void execute(Runnable theTask); 123 124 <T> T execute(Callable<T> theTask); 125 126 <T> T execute(@Nonnull TransactionCallback<T> callback); 127 128 /** 129 * Read query path. 130 */ 131 default <T> T read(Callable<T> theCallback) { 132 return execute(theCallback); 133 } 134 135 /** 136 * Search for open Stream. 137 * The Stream may not be readable outside an outermost transaction. 138 */ 139 default <T> Stream<T> search(Callable<Stream<T>> theCallback) { 140 return execute(theCallback); 141 } 142 143 /** 144 * Search for concrete List. 145 */ 146 default <T> List<T> searchList(Callable<List<T>> theCallback) { 147 return execute(theCallback); 148 } 149 } 150}