private void onFindPrimaryShardSuccess(
      PrimaryShardInfo primaryShardInfo,
      TransactionProxy parent,
      String shardName,
      TransactionContextWrapper transactionContextWrapper) {
    if (LOG.isDebugEnabled()) {
      LOG.debug(
          "Tx {}: Found primary {} for shard {}",
          parent.getIdentifier(),
          primaryShardInfo.getPrimaryShardActor(),
          shardName);
    }

    updateShardInfo(shardName, primaryShardInfo);

    try {
      TransactionContext localContext = maybeCreateLocalTransactionContext(parent, shardName);
      if (localContext != null) {
        transactionContextWrapper.executePriorTransactionOperations(localContext);
      } else {
        RemoteTransactionContextSupport remote =
            new RemoteTransactionContextSupport(transactionContextWrapper, parent, shardName);
        remote.setPrimaryShard(
            primaryShardInfo.getPrimaryShardActor(), primaryShardInfo.getPrimaryShardVersion());
      }
    } finally {
      onTransactionContextCreated(parent.getIdentifier());
    }
  }
  final TransactionContextWrapper newTransactionContextWrapper(
      final TransactionProxy parent, final String shardName) {
    final TransactionContextWrapper transactionContextWrapper =
        new TransactionContextWrapper(parent.getIdentifier(), actorContext);

    Future<PrimaryShardInfo> findPrimaryFuture =
        findPrimaryShard(shardName, parent.getIdentifier());
    if (findPrimaryFuture.isCompleted()) {
      Try<PrimaryShardInfo> maybe = findPrimaryFuture.value().get();
      if (maybe.isSuccess()) {
        onFindPrimaryShardSuccess(maybe.get(), parent, shardName, transactionContextWrapper);
      } else {
        onFindPrimaryShardFailure(
            maybe.failed().get(), parent, shardName, transactionContextWrapper);
      }
    } else {
      findPrimaryFuture.onComplete(
          new OnComplete<PrimaryShardInfo>() {
            @Override
            public void onComplete(
                final Throwable failure, final PrimaryShardInfo primaryShardInfo) {
              if (failure == null) {
                onFindPrimaryShardSuccess(
                    primaryShardInfo, parent, shardName, transactionContextWrapper);
              } else {
                onFindPrimaryShardFailure(failure, parent, shardName, transactionContextWrapper);
              }
            }
          },
          actorContext.getClientDispatcher());
    }

    return transactionContextWrapper;
  }
  private void onFindPrimaryShardFailure(
      Throwable failure,
      TransactionProxy parent,
      String shardName,
      TransactionContextWrapper transactionContextWrapper) {
    LOG.debug(
        "Tx {}: Find primary for shard {} failed", parent.getIdentifier(), shardName, failure);

    try {
      transactionContextWrapper.executePriorTransactionOperations(
          new NoOpTransactionContext(failure, parent.getIdentifier()));
    } finally {
      onTransactionContextCreated(parent.getIdentifier());
    }
  }
  private TransactionContext maybeCreateLocalTransactionContext(
      final TransactionProxy parent, final String shardName) {
    final LocalTransactionFactory local = knownLocal.get(shardName);
    if (local != null) {
      if (LOG.isDebugEnabled()) {
        LOG.debug(
            "Tx {} - Creating local component for shard {} using factory {}",
            parent.getIdentifier(),
            shardName,
            local);
      }

      try {
        return createLocalTransactionContext(local, parent);
      } catch (Exception e) {
        return new NoOpTransactionContext(e, parent.getIdentifier());
      }
    }

    return null;
  }
  private static TransactionContext createLocalTransactionContext(
      final LocalTransactionFactory factory, final TransactionProxy parent) {

    switch (parent.getType()) {
      case READ_ONLY:
        final DOMStoreReadTransaction readOnly =
            factory.newReadOnlyTransaction(parent.getIdentifier());
        return new LocalTransactionContext(readOnly, parent.getIdentifier(), factory) {
          @Override
          protected DOMStoreWriteTransaction getWriteDelegate() {
            throw new UnsupportedOperationException();
          }

          @Override
          protected DOMStoreReadTransaction getReadDelegate() {
            return readOnly;
          }
        };
      case READ_WRITE:
        final DOMStoreReadWriteTransaction readWrite =
            factory.newReadWriteTransaction(parent.getIdentifier());
        return new LocalTransactionContext(readWrite, parent.getIdentifier(), factory) {
          @Override
          protected DOMStoreWriteTransaction getWriteDelegate() {
            return readWrite;
          }

          @Override
          protected DOMStoreReadTransaction getReadDelegate() {
            return readWrite;
          }
        };
      case WRITE_ONLY:
        final DOMStoreWriteTransaction writeOnly =
            factory.newWriteOnlyTransaction(parent.getIdentifier());
        return new LocalTransactionContext(writeOnly, parent.getIdentifier(), factory) {
          @Override
          protected DOMStoreWriteTransaction getWriteDelegate() {
            return writeOnly;
          }

          @Override
          protected DOMStoreReadTransaction getReadDelegate() {
            throw new UnsupportedOperationException();
          }
        };
      default:
        throw new IllegalArgumentException("Invalid transaction type: " + parent.getType());
    }
  }