+final class TransactionChainProxy extends AbstractTransactionContextFactory<LocalTransactionChain>
+ implements DOMStoreTransactionChain {
+ private abstract static class State {
+ /**
+ * Check if it is okay to allocate a new transaction.
+ * @throws IllegalStateException if a transaction may not be allocated.
+ */
+ abstract void checkReady();
+
+ /**
+ * Return the future which needs to be waited for before shard information
+ * is returned (which unblocks remote transactions).
+ * @return Future to wait for, or null of no wait is necessary
+ */
+ abstract Future<?> previousFuture();
+ }
+
+ private abstract static class Pending extends State {
+ private final TransactionIdentifier transaction;
+ private final Future<?> previousFuture;
+
+ Pending(final TransactionIdentifier transaction, final Future<?> previousFuture) {
+ this.previousFuture = previousFuture;
+ this.transaction = requireNonNull(transaction);
+ }
+
+ @Override
+ final Future<?> previousFuture() {
+ return previousFuture;
+ }
+
+ final TransactionIdentifier getIdentifier() {
+ return transaction;
+ }
+ }
+
+ private static final class Allocated extends Pending {
+ Allocated(final TransactionIdentifier transaction, final Future<?> previousFuture) {
+ super(transaction, previousFuture);
+ }
+
+ @Override
+ void checkReady() {
+ throw new IllegalStateException(String.format("Previous transaction %s is not ready yet", getIdentifier()));
+ }
+ }
+
+ private static final class Submitted extends Pending {
+ Submitted(final TransactionIdentifier transaction, final Future<?> previousFuture) {
+ super(transaction, previousFuture);
+ }
+
+ @Override
+ void checkReady() {
+ // Okay to allocate
+ }
+ }
+
+ private abstract static class DefaultState extends State {
+ @Override
+ final Future<?> previousFuture() {
+ return null;
+ }
+ }
+
+ private static final State IDLE_STATE = new DefaultState() {
+ @Override
+ void checkReady() {
+ // Okay to allocate
+ }
+ };
+
+ private static final State CLOSED_STATE = new DefaultState() {
+ @Override
+ void checkReady() {
+ throw new DOMTransactionChainClosedException("Transaction chain has been closed");
+ }
+ };
+
+ private static final Logger LOG = LoggerFactory.getLogger(TransactionChainProxy.class);
+ private static final AtomicReferenceFieldUpdater<TransactionChainProxy, State> STATE_UPDATER =
+ AtomicReferenceFieldUpdater.newUpdater(TransactionChainProxy.class, State.class, "currentState");