code: public void abort(TransactionFailureException cause) throws TransactionFailureException {
      if (currentTx == null) {
        // might be called by some generic exception handler even though already aborted/finished - we allow that
        return;
      }
      try {
        boolean success = true;
        for (TransactionAware txAware : txAwares) {
          try {
            if (!txAware.rollbackTx()) {
              success = false;
            }
          } catch (Throwable e) {
            String message = String.format("Unable to roll back changes in transaction-aware '%s' for transaction %d. ",
                                           txAware.getTransactionAwareName(), currentTx.getTransactionId());
            LOG.warn(message, e);
            if (cause == null) {
              cause = new TransactionFailureException(message, e);
            }
            success = false;
          }
        }
        if (success) {
          txClient.abort(currentTx);
        } else {
          txClient.invalidate(currentTx.getTransactionId());
        }
        if (cause != null) {
          throw cause;
        }
      } finally {
        currentTx = null;
      }
    }
docs: Aborts the given transaction, and rolls back all data set changes. If rollback fails,
  the transaction is invalidated. If an exception is caught during rollback, the exception
  is rethrown wrapped into a TransactionFailureException, after all remaining TransactionAwares have
  completed rollback. If an existing exception is passed in, that exception is thrown in either
  case, whether the rollback is successful or not. In other words, this method always throws the
  first exception that it encounters.
  @param cause the original exception that caused the abort
  @throws TransactionFailureException for any exception that is encountered.