# 가드가 자기 존재 이유로 적는 것 IdempotencyCapabilityGuard.java:9 /** IdempotencyCapabilityGuard.java:10 * The preconditions a mutation must meet before any SQL runs. IdempotencyCapabilityGuard.java:11 * IdempotencyCapabilityGuard.java:12 *

Its own type because these are three separate questions — is the schema sanctioned, is there a IdempotencyCapabilityGuard.java:13 * transaction, is it this store's transaction — and the store answered the third one IdempotencyCapabilityGuard.java:14 * wrongly. It checked that the thread had an active read-write transaction, which is true whenever IdempotencyCapabilityGuard.java:15 * any transaction is open on any data source; the sibling outbox and inbox adapters check {@code IdempotencyCapabilityGuard.java:16 * hasResource(dataSource)}, which is the question that actually matters. IdempotencyCapabilityGuard.java:17 * IdempotencyCapabilityGuard.java:18 *

The difference shows up in an application with two data sources: a mutation issued inside the IdempotencyCapabilityGuard.java:19 * other one's transaction passed the old check, ran against this store's connection IdempotencyCapabilityGuard.java:20 * outside any transaction, and committed independently of the work it was supposed to be atomic IdempotencyCapabilityGuard.java:21 * with. IdempotencyCapabilityGuard.java:22 */ IdempotencyCapabilityGuard.java:23 final class IdempotencyCapabilityGuard { # 그 데이터소스 필드는 어떻게 들어오는가 IdempotencyCapabilityGuard.java:28 private final JdbcOperations jdbc; IdempotencyCapabilityGuard.java:29 private final DataSource dataSource; IdempotencyCapabilityGuard.java:30 private final String activeCapabilitySql; IdempotencyCapabilityGuard.java:31 IdempotencyCapabilityGuard.java:32 private volatile boolean postgreSqlConfirmed; IdempotencyCapabilityGuard.java:33 IdempotencyCapabilityGuard.java:34 IdempotencyCapabilityGuard( IdempotencyCapabilityGuard.java:35 JdbcOperations jdbc, DataSource dataSource, String activeCapabilitySql) { IdempotencyCapabilityGuard.java:36 this.jdbc = Objects.requireNonNull(jdbc, "jdbc"); IdempotencyCapabilityGuard.java:37 this.dataSource = dataSource; IdempotencyCapabilityGuard.java:38 this.activeCapabilitySql = Objects.requireNonNull(activeCapabilitySql, "activeCapabilitySql"); IdempotencyCapabilityGuard.java:39 } # 세 번째 질문을 지금 어떻게 묻는가 IdempotencyCapabilityGuard.java:87 /** IdempotencyCapabilityGuard.java:88 * Fails closed unless this store's own data source is enlisted in a read-write transaction. IdempotencyCapabilityGuard.java:89 * IdempotencyCapabilityGuard.java:90 * @throws IllegalStateException naming which of the three conditions failed IdempotencyCapabilityGuard.java:91 */ IdempotencyCapabilityGuard.java:92 void requirePrimaryWriteTransaction() { IdempotencyCapabilityGuard.java:93 if (!TransactionSynchronizationManager.isActualTransactionActive()) { IdempotencyCapabilityGuard.java:94 throw new IllegalStateException( IdempotencyCapabilityGuard.java:95 "owner-safe idempotency mutation requires an active primary transaction"); IdempotencyCapabilityGuard.java:96 } IdempotencyCapabilityGuard.java:97 if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { IdempotencyCapabilityGuard.java:98 throw new IllegalStateException( IdempotencyCapabilityGuard.java:99 "owner-safe idempotency mutation requires a read-write transaction"); IdempotencyCapabilityGuard.java:100 } IdempotencyCapabilityGuard.java:101 if (dataSource != null && !TransactionSynchronizationManager.hasResource(dataSource)) { IdempotencyCapabilityGuard.java:102 // The exact check the outbox and inbox adapters already make. Without it, a transaction on IdempotencyCapabilityGuard.java:103 // another data source satisfied the guard while this store's work committed on its own. IdempotencyCapabilityGuard.java:104 throw new IllegalStateException( IdempotencyCapabilityGuard.java:105 "owner-safe idempotency mutation requires a transaction bound to this store's data" IdempotencyCapabilityGuard.java:106 + " source; the active transaction belongs to another one"); IdempotencyCapabilityGuard.java:107 } IdempotencyCapabilityGuard.java:108 } IdempotencyCapabilityGuard.java:109 } # 그 필드 값을 정하는 곳 PostgreSqlOwnerSafeIdempotencyStore.java:84 public PostgreSqlOwnerSafeIdempotencyStore(JdbcOperations jdbc) { PostgreSqlOwnerSafeIdempotencyStore.java:85 this(jdbc, new SecureRandom()); PostgreSqlOwnerSafeIdempotencyStore.java:86 } PostgreSqlOwnerSafeIdempotencyStore.java:87 PostgreSqlOwnerSafeIdempotencyStore.java:88 PostgreSqlOwnerSafeIdempotencyStore(JdbcOperations jdbc, SecureRandom secureRandom) { PostgreSqlOwnerSafeIdempotencyStore.java:89 Objects.requireNonNull(jdbc, "jdbc"); PostgreSqlOwnerSafeIdempotencyStore.java:90 this.secureRandom = Objects.requireNonNull(secureRandom, "secureRandom"); PostgreSqlOwnerSafeIdempotencyStore.java:91 this.guard = new IdempotencyCapabilityGuard(jdbc, dataSourceOf(jdbc), ACTIVE_CAPABILITY_SQL); PostgreSqlOwnerSafeIdempotencyStore.java:92 this.rows = new IdempotencyRowMapper(jdbc); PostgreSqlOwnerSafeIdempotencyStore.java:93 this.claims = new IdempotencyClaimGateway(jdbc); PostgreSqlOwnerSafeIdempotencyStore.java:94 this.transitions = new IdempotencyTransitionGateway(jdbc); PostgreSqlOwnerSafeIdempotencyStore.java:95 } PostgreSqlOwnerSafeIdempotencyStore.java:96 PostgreSqlOwnerSafeIdempotencyStore.java:97 /** PostgreSqlOwnerSafeIdempotencyStore.java:98 * The data source behind this store's operations, when it can be determined. PostgreSqlOwnerSafeIdempotencyStore.java:99 * PostgreSqlOwnerSafeIdempotencyStore.java:100 *

{@code JdbcTemplate} knows its own; a hand-rolled {@code JdbcOperations} may not. The guard PostgreSqlOwnerSafeIdempotencyStore.java:101 * treats an unknown data source as "cannot check", which is weaker than the outbox adapter's PostgreSqlOwnerSafeIdempotencyStore.java:102 * exact check and still stronger than what was here before — but it is the honest answer when the PostgreSqlOwnerSafeIdempotencyStore.java:103 * collaborator genuinely cannot be identified. PostgreSqlOwnerSafeIdempotencyStore.java:104 */ PostgreSqlOwnerSafeIdempotencyStore.java:105 private static javax.sql.DataSource dataSourceOf(JdbcOperations jdbc) { PostgreSqlOwnerSafeIdempotencyStore.java:106 return jdbc instanceof org.springframework.jdbc.core.JdbcTemplate template PostgreSqlOwnerSafeIdempotencyStore.java:107 ? template.getDataSource() PostgreSqlOwnerSafeIdempotencyStore.java:108 : null; PostgreSqlOwnerSafeIdempotencyStore.java:109 } # 이 저장소를 만드는 자리 전부와 각각이 넘기는 것 postgresqlIntegrationTest · PostgreSqlIdempotencyIntegrationTest.java:61 store = new PostgreSqlOwnerSafeIdempotencyStore(jdbc); test · OwnerSafeIdempotencyPreconditionTest.java:47 new PostgreSqlOwnerSafeIdempotencyStore(jdbc); main · PostgreSqlIdempotencyProviderConfig.java:60 return new PostgreSqlOwnerSafeIdempotencyStore(jdbc); 그 자리들이 넘기는 JdbcOperations 의 출처 : PostgreSqlIdempotencyProviderConfig.java:55 * @param jdbc the primary {@code JdbcOperations}; the store's transaction guard identifies its PostgreSqlIdempotencyProviderConfig.java:56 * data source from it so a transaction opened on a different one cannot pass PostgreSqlIdempotencyProviderConfig.java:57 */ PostgreSqlIdempotencyProviderConfig.java:58 @Bean PostgreSqlIdempotencyProviderConfig.java:59 IdempotencyStorePortV2 postgreSqlOwnerSafeIdempotencyStore(JdbcOperations jdbc) { PostgreSqlIdempotencyProviderConfig.java:60 return new PostgreSqlOwnerSafeIdempotencyStore(jdbc); PostgreSqlIdempotencyProviderConfig.java:61 } PostgreSqlIdempotencyProviderConfig.java:62 OwnerSafeIdempotencyPreconditionTest.java:44 OwnerSafeIdempotencyPreconditionTest.java:45 private final JdbcOperations jdbc = mock(JdbcOperations.class); OwnerSafeIdempotencyPreconditionTest.java:46 private final PostgreSqlOwnerSafeIdempotencyStore store = OwnerSafeIdempotencyPreconditionTest.java:47 new PostgreSqlOwnerSafeIdempotencyStore(jdbc); OwnerSafeIdempotencyPreconditionTest.java:48 저장소에 JdbcOperations 구현이나 JdbcTemplate 하위 클래스가 있는가 : 0 건 # 세 번째 검사를 덮는 시험이 있는가 IdempotencyCapabilityGuard.java:106: + " source; the active transaction belongs to another one"); 전제 시험이 단언하는 것 : OwnerSafeIdempotencyPreconditionTest.java:50 void clearTransactionState() { OwnerSafeIdempotencyPreconditionTest.java:57 void aClaimWithNoTransactionIsRefused() { OwnerSafeIdempotencyPreconditionTest.java:67 void aClaimAgainstAnotherVendorIsRefused() throws Exception { OwnerSafeIdempotencyPreconditionTest.java:81 void aClaimAgainstAnUnsanctionedStreamIsRefused() throws Exception { # 가드를 부르는 자리 main · IdempotencyCapabilityGuard.java:55 void requireActiveCapability() { main · IdempotencyCapabilityGuard.java:92 void requirePrimaryWriteTransaction() { main · PostgreSqlOwnerSafeIdempotencyStore.java:122 requirePrimaryWriteTransaction(); main · PostgreSqlOwnerSafeIdempotencyStore.java:123 requireActiveCapability(); main · PostgreSqlOwnerSafeIdempotencyStore.java:176 requirePrimaryWriteTransaction(); main · PostgreSqlOwnerSafeIdempotencyStore.java:211 requirePrimaryWriteTransaction(); main · PostgreSqlOwnerSafeIdempotencyStore.java:255 requirePrimaryWriteTransaction(); main · PostgreSqlOwnerSafeIdempotencyStore.java:303 requirePrimaryWriteTransaction(); main · PostgreSqlOwnerSafeIdempotencyStore.java:360 requirePrimaryWriteTransaction(); main · PostgreSqlOwnerSafeIdempotencyStore.java:502 private void requireActiveCapability() { main · PostgreSqlOwnerSafeIdempotencyStore.java:503 guard.requireActiveCapability(); main · PostgreSqlOwnerSafeIdempotencyStore.java:506 private void requirePrimaryWriteTransaction() { main · PostgreSqlOwnerSafeIdempotencyStore.java:507 guard.requirePrimaryWriteTransaction(); main · PostgreSqlSameStoreInboxAdapter.java:227 requireActiveCapability(); main · PostgreSqlSameStoreInboxAdapter.java:494 private void requireActiveCapability() { main · PostgreSqlImmutableOutboxAppendAdapter.java:166 requireActiveCapability(); main · PostgreSqlImmutableOutboxAppendAdapter.java:312 private void requireActiveCapability() { # 형제 어댑터는 같은 질문을 어떻게 묻고 데이터소스를 어떻게 받는가 PostgreSqlImmutableOutboxAppendAdapter : PostgreSqlImmutableOutboxAppendAdapter.java:149 private final DataSource dataSource; PostgreSqlImmutableOutboxAppendAdapter.java:153 public PostgreSqlImmutableOutboxAppendAdapter(DataSource dataSource) { PostgreSqlImmutableOutboxAppendAdapter.java:158 this.dataSource = Objects.requireNonNull(dataSource, "dataSource"); PostgreSqlImmutableOutboxAppendAdapter.java:320 private void requireSameResourcePrimaryWriteTransaction() { PostgreSqlImmutableOutboxAppendAdapter.java:321 if (!TransactionSynchronizationManager.isActualTransactionActive()) { PostgreSqlImmutableOutboxAppendAdapter.java:325 if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) { PostgreSqlImmutableOutboxAppendAdapter.java:328 if (!TransactionSynchronizationManager.hasResource(dataSource)) { PostgreSqlSameStoreInboxAdapter : PostgreSqlSameStoreInboxAdapter.java:199 private final DataSource dataSource; PostgreSqlSameStoreInboxAdapter.java:204 public PostgreSqlSameStoreInboxAdapter(DataSource dataSource) { PostgreSqlSameStoreInboxAdapter.java:210 this.dataSource = Objects.requireNonNull(dataSource, "dataSource"); PostgreSqlSameStoreInboxAdapter.java:502 private void requireSameResourcePrimaryWriteTransaction() { PostgreSqlSameStoreInboxAdapter.java:503 if (!TransactionSynchronizationManager.isActualTransactionActive() PostgreSqlSameStoreInboxAdapter.java:504 || TransactionSynchronizationManager.isCurrentTransactionReadOnly() PostgreSqlSameStoreInboxAdapter.java:505 || !TransactionSynchronizationManager.hasResource(dataSource)) {