package com.atlassian.bitbucket.mesh.transaction;

import javax.annotation.Nonnull;

/**
 * Interface used for registering transaction callbacks. When a transaction completes, registered listeners are
 * first sorted by {@link #getOrder()} (ascending), and then:
 *
 * <ul>
 *     <li>if the transaction committed, {@link #afterCommit(Transaction)} is called</li>
 *     <li>{@link #afterCompletion(Transaction)} is invoked</li>
 * </ul>
 *
 * Any errors thrown by these callback methods are <em>logged but not propagated</em>.
 *
 * @see Transaction#addListener(TransactionListener)
 * @see TransactionManager#addListener(TransactionListener)
 */
public interface TransactionListener {

    /**
     * Invoked after a transaction commits.
     * <p>
     * Can perform resource cleanup <i>after</i> transaction completion.
     * <p>
     * <strong>NOTE:</strong> The transaction will have been committed already, but the transaction will still be
     * active when this method is called.
     *
     * @param transaction the transaction that has completed
     * @throws RuntimeException in case of errors; will be <em>logged but not propagated</em>
     */
    default void afterCommit(@Nonnull Transaction transaction) {
    }

    /**
     * Invoked after transaction commit/rollback.
     * <p>
     * Can perform resource cleanup <i>after</i> transaction completion.
     * <p>
     * <strong>NOTE:</strong> The transaction will have been committed or rolled back already, but the transaction
     * will still be active when this method is called.
     *
     * @param transaction the transaction that has completed
     * @throws RuntimeException in case of errors; will be <em>logged but not propagated</em>
     */
    default void afterCompletion(@Nonnull Transaction transaction) {
    }

    /**
     * Invoked when the transaction starts {@link TransactionState#COMMITTING}.
     * <p>
     * Can perform updates <i>before</i> transaction completion, e.g. publishing staged changes.
     *
     * @param transaction the transaction that is committing
     * @throws RuntimeException in case of errors; will be <em>logged but not propagated</em>
     */
    default void beforeCommit(@Nonnull Transaction transaction) {
    }

    /**
     * Return the execution order for this transaction synchronization (lower numbers are executed before higher
     * numbers).
     * <p>
     * The default is {@code 30000}. This default was chosen to allow instances to run earlier or later than
     * the default if desired.
     */
    default int getOrder() {
        return 30000;
    }
}
