# 가드가 자기 존재 이유로 적는 것
  IdempotencyCapabilityGuard.java:9 /**
  IdempotencyCapabilityGuard.java:10  * The preconditions a mutation must meet before any SQL runs.
  IdempotencyCapabilityGuard.java:11  *
  IdempotencyCapabilityGuard.java:12  * <p>Its own type because these are three separate questions — is the schema sanctioned, is there a
  IdempotencyCapabilityGuard.java:13  * transaction, is it <em>this</em> 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  * <p>The difference shows up in an application with two data sources: a mutation issued inside the
  IdempotencyCapabilityGuard.java:19  * <em>other</em> 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    * <p>{@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)) {
