// Path: src/ledgermonolith/src/main/java/anthos/samples/bankofanthos/ledgermonolith/ExceptionMessages.java
// public static final String EXCEPTION_MESSAGE_DUPLICATE_TRANSACTION =
//         "duplicate transaction uuid";
// 
// Path: src/ledgermonolith/src/main/java/anthos/samples/bankofanthos/ledgermonolith/ExceptionMessages.java
// public static final String EXCEPTION_MESSAGE_INSUFFICIENT_BALANCE =
//         "insufficient balance";
// 
// Path: src/ledgermonolith/src/main/java/anthos/samples/bankofanthos/ledgermonolith/ExceptionMessages.java
// public static final String
//         EXCEPTION_MESSAGE_WHEN_AUTHORIZATION_HEADER_NULL =
//         "HTTP request 'Authorization' header is null";


import static anthos.samples.bankofanthos.ledgermonolith.ExceptionMessages.EXCEPTION_MESSAGE_DUPLICATE_TRANSACTION;
import static anthos.samples.bankofanthos.ledgermonolith.ExceptionMessages.EXCEPTION_MESSAGE_INSUFFICIENT_BALANCE;
import static anthos.samples.bankofanthos.ledgermonolith.ExceptionMessages.EXCEPTION_MESSAGE_WHEN_AUTHORIZATION_HEADER_NULL;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
import java.util.Deque;
import java.util.concurrent.ExecutionException;
import org.springframework.web.bind.annotation.PathVariable;
            @RequestHeader("Authorization") String bearerToken,
            @RequestBody Transaction transaction) {
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            bearerToken = bearerToken.split("Bearer ")[1];
        }
        try {
            if (bearerToken == null) {
                LOGGER.error("Transaction submission failed: "
                    + "Authorization header null");
                throw new IllegalArgumentException(
                        EXCEPTION_MESSAGE_WHEN_AUTHORIZATION_HEADER_NULL);
            }
            final DecodedJWT jwt = this.verifier.verify(bearerToken);

            // Check against cache for duplicate transactions
            if (this.ledgerWriterCache.asMap().containsKey(transaction.getRequestUuid())) {
                throw new IllegalStateException(
                        EXCEPTION_MESSAGE_DUPLICATE_TRANSACTION);
            }

            // validate transaction
            transactionValidator.validateTransaction(localRoutingNum,
                    jwt.getClaim(JWT_ACCOUNT_KEY).asString(), transaction);
            // Ensure sender balance can cover transaction.
            if (transaction.getFromRoutingNum().equals(localRoutingNum)) {
                Long balance = getAvailableBalance(transaction.getFromAccountNum());
                if (balance < transaction.getAmount()) {
                    LOGGER.error("Transaction submission failed: "
                        + "Insufficient balance");
                    throw new IllegalStateException(
// Path: src/ledgermonolith/src/main/java/anthos/samples/bankofanthos/ledgermonolith/ExceptionMessages.java
// public static final String EXCEPTION_MESSAGE_DUPLICATE_TRANSACTION =
//         "duplicate transaction uuid";
// 
// Path: src/ledgermonolith/src/main/java/anthos/samples/bankofanthos/ledgermonolith/ExceptionMessages.java
// public static final String EXCEPTION_MESSAGE_INSUFFICIENT_BALANCE =
//         "insufficient balance";
// 
// Path: src/ledgermonolith/src/main/java/anthos/samples/bankofanthos/ledgermonolith/ExceptionMessages.java
// public static final String
//         EXCEPTION_MESSAGE_WHEN_AUTHORIZATION_HEADER_NULL =
//         "HTTP request 'Authorization' header is null";


// Path: src/ledgermonolith/src/main/java/anthos/samples/bankofanthos/ledgermonolith/LedgerMonolithController.java
import static anthos.samples.bankofanthos.ledgermonolith.ExceptionMessages.EXCEPTION_MESSAGE_DUPLICATE_TRANSACTION;
import static anthos.samples.bankofanthos.ledgermonolith.ExceptionMessages.EXCEPTION_MESSAGE_INSUFFICIENT_BALANCE;
import static anthos.samples.bankofanthos.ledgermonolith.ExceptionMessages.EXCEPTION_MESSAGE_WHEN_AUTHORIZATION_HEADER_NULL;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.LoadingCache;
import com.google.common.util.concurrent.UncheckedExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import java.util.Collection;
import java.util.Deque;
import java.util.concurrent.ExecutionException;
import org.springframework.web.bind.annotation.PathVariable;

            @RequestHeader("Authorization") String bearerToken,
            @RequestBody Transaction transaction) {
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            bearerToken = bearerToken.split("Bearer ")[1];
        }
        try {
            if (bearerToken == null) {
                LOGGER.error("Transaction submission failed: "
                    + "Authorization header null");
                throw new IllegalArgumentException(
                        EXCEPTION_MESSAGE_WHEN_AUTHORIZATION_HEADER_NULL);
            }
            final DecodedJWT jwt = this.verifier.verify(bearerToken);

            // Check against cache for duplicate transactions
            if (this.ledgerWriterCache.asMap().containsKey(transaction.getRequestUuid())) {
                throw new IllegalStateException(
                        EXCEPTION_MESSAGE_DUPLICATE_TRANSACTION);
            }

            // validate transaction
            transactionValidator.validateTransaction(localRoutingNum,
                    jwt.getClaim(JWT_ACCOUNT_KEY).asString(), transaction);
            // Ensure sender balance can cover transaction.
            if (transaction.getFromRoutingNum().equals(localRoutingNum)) {
                Long balance = getAvailableBalance(transaction.getFromAccountNum());
                if (balance < transaction.getAmount()) {
                    LOGGER.error("Transaction submission failed: "
                        + "Insufficient balance");
                    throw new IllegalStateException(
                            EXCEPTION_MESSAGE_INSUFFICIENT_BALANCE);