public void setSource(final TransactionSource source) {

    TransactionReference tx = transactions.get();
    if (tx != null) {
      tx.setSource(source);
    }
  }
  public TransactionSource getSource() {

    TransactionReference tx = transactions.get();
    if (tx != null) {

      return tx.getSource();
    }

    return null;
  }
  public TransactionCommand beginTx() {

    final DatabaseService graphDb = (DatabaseService) arguments.get("graphDb");
    TransactionReference tx = transactions.get();

    if (tx == null) {

      // start new transaction
      tx = new TransactionReference(graphDb.beginTx());

      queues.set(new ModificationQueue());
      buffers.set(new ErrorBuffer());
      transactions.set(tx);
      currentCommand.set(this);
    }

    // increase depth
    tx.begin();

    return this;
  }
  public ModificationQueue finishTx() {

    final TransactionReference tx = transactions.get();
    ModificationQueue modificationQueue = null;

    if (tx != null) {

      if (tx.isToplevel()) {

        modificationQueue = queues.get();

        final Set<String> synchronizationKeys = modificationQueue.getSynchronizationKeys();

        // cleanup
        queues.remove();
        buffers.remove();
        currentCommand.remove();
        transactions.remove();

        try {
          tx.close();

        } catch (Throwable t) {
          t.printStackTrace();

        } finally {

          // release semaphores as the transaction is now finished
          semaphore.release(synchronizationKeys); // careful: this can be null
        }

      } else {

        tx.end();
      }
    }

    return modificationQueue;
  }
  public void commitTx(final boolean doValidation) throws FrameworkException {

    final TransactionReference tx = transactions.get();
    if (tx != null && tx.isToplevel()) {

      final ModificationQueue modificationQueue = queues.get();
      final ErrorBuffer errorBuffer = buffers.get();

      // 0.5: let transaction listeners examine (and prevent?) commit
      for (final StructrTransactionListener listener : listeners) {
        listener.beforeCommit(
            securityContext, modificationQueue.getModificationEvents(), tx.getSource());
      }

      // 1. do inner callbacks (may cause transaction to fail)
      if (doValidation) {

        if (!modificationQueue.doInnerCallbacks(securityContext, errorBuffer)) {

          tx.failure();
          throw new FrameworkException(
              422, "Unable to commit transaction, validation failed", errorBuffer);
        }

        // 1.5: execute validatable post-transaction action
        if (!modificationQueue.doPostProcessing(securityContext, errorBuffer)) {

          tx.failure();
          throw new FrameworkException(
              422, "Unable to commit transaction, transaction post processing failed", errorBuffer);
        }
      }

      // 2. fetch all types of entities modified in this tx
      Set<String> synchronizationKeys = modificationQueue.getSynchronizationKeys();

      // we need to protect the validation and indexing part of every transaction
      // from being entered multiple times in the presence of validators
      // 3. acquire semaphores for each modified type
      try {
        semaphore.acquire(synchronizationKeys);
      } catch (InterruptedException iex) {
        return;
      }

      // finally, do validation under the protection of the semaphores for each type
      if (!modificationQueue.doValidation(securityContext, errorBuffer, doValidation)) {

        tx.failure();

        // create error
        throw new FrameworkException(
            422, "Unable to commit transaction, validation failed", errorBuffer);
      }

      try {
        tx.success();

      } catch (Throwable t) {
        t.printStackTrace();
      }
    }
  }