package org.springframework.core.task;

import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrencyThrottleSupport;
import org.springframework.util.CustomizableThreadCreator;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;

/**
 * {@link TaskExecutor} implementation that fires up a new Thread for each task,
 * executing it asynchronously.
 *
 *
Supports limiting concurrent threads through the "concurrencyLimit"
 * bean property. By default, the number of concurrent threads is unlimited.
 *
 *
NOTE: This implementation does not reuse threads! Consider a
 * thread-pooling TaskExecutor implementation instead, in particular for
 * executing a large number of short-lived tasks.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see #setConcurrencyLimit
 * @see SyncTaskExecutor
 * @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
 */
@SuppressWarnings("serial")
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implements AsyncListenableTaskExecutor, Serializable {

    /**
     * Permit any number of concurrent invocations: that is, don't throttle concurrency.
     * @see ConcurrencyThrottleSupport#UNBOUNDED_CONCURRENCY
     */
    public static final int UNBOUNDED_CONCURRENCY = ConcurrencyThrottleSupport.UNBOUNDED_CONCURRENCY;

    /**
     * Switch concurrency 'off': that is, don't allow any concurrent invocations.
     * @see ConcurrencyThrottleSupport#NO_CONCURRENCY
     */
    public static final int NO_CONCURRENCY = ConcurrencyThrottleSupport.NO_CONCURRENCY;

    /**
     * Internal concurrency throttle used by this executor.
     */
    private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter();

    @Nullable
    private ThreadFactory threadFactory;

    @Nullable
    private TaskDecorator taskDecorator;

    /**
     * Create a new SimpleAsyncTaskExecutor with default thread name prefix.
     */
    public SimpleAsyncTaskExecutor() {
        super();
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given thread name prefix.
     * @param threadNamePrefix the prefix to use for the names of newly created threads
     */
    public SimpleAsyncTaskExecutor(String threadNamePrefix) {
        super(threadNamePrefix);
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given external thread factory.
     * @param threadFactory the factory to use for creating new Threads
     */
    public SimpleAsyncTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Specify an external factory to use for creating new Threads,
     * instead of relying on the local properties of this executor.
     *
You may specify an inner ThreadFactory bean or also a ThreadFactory reference
     * obtained from JNDI (on a Jakarta EE server) or some other lookup mechanism.
     * @see #setThreadNamePrefix
     * @see #setThreadPriority
     */
    public void setThreadFactory(@Nullable ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Return the external factory to use for creating new Threads, if any.
     */
    @Nullable
    public final ThreadFactory getThreadFactory() {
        return this.threadFactory;
    }

    /**
     * Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
     * about to be executed.
     *
Note that such a decorator is not necessarily being applied to the
     * user-supplied {@code Runnable}/{@code Callable} but rather to the actual
     * execution callback (which may be a wrapper around the user-supplied task).
     *
The primary use case is to set some execution context around the task's
     * invocation, or to provide some monitoring/statistics for task execution.
     *
NOTE: Exception handling in {@code TaskDecorator} implementations
     * is limited to plain {@code Runnable} execution via {@code execute} calls.
     * In case of {@code #submit} calls, the exposed {@code Runnable} will be a
     * {@code FutureTask} which does not propagate any exceptions; you might
     * have to cast it and call {@code Future#get} to evaluate exceptions.
     * @since 4.3
     */
    public final void setTaskDecorator(TaskDecorator taskDecorator) {
        this.taskDecorator = taskDecorator;
    }

    /**
     * Set the maximum number of parallel accesses allowed.
     * -1 indicates no concurrency limit at all.
     *
In principle, this limit can be changed at runtime,
     * although it is generally designed as a config time setting.
     * NOTE: Do not switch between -1 and any concrete limit at runtime,
     * as this will lead to inconsistent concurrency counts: A limit
     * of -1 effectively turns off concurrency counting completely.
     * @see #UNBOUNDED_CONCURRENCY
     */
    public void setConcurrencyLimit(int concurrencyLimit) {
        this.concurrencyThrottle.setConcurrencyLimit(concurrencyLimit);
    }

    /**
     * Return the maximum number of parallel accesses allowed.
     */
    public final int getConcurrencyLimit() {
        return this.concurrencyThrottle.getConcurrencyLimit();
    }

    /**
     * Return whether this throttle is currently active.
     * @return {@code true} if the concurrency limit for this instance is active
     * @see #getConcurrencyLimit()
     * @see #setConcurrencyLimit
     */
    public final boolean isThrottleActive() {
        return this.concurrencyThrottle.isThrottleActive();
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task) {
        execute(task, TIMEOUT_INDEFINITE);
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     *
Executes urgent tasks (with 'immediate' timeout) directly,
     * bypassing the concurrency throttle (if active). All other
     * tasks are subject to throttling.
     * @see #TIMEOUT_IMMEDIATE
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task, long startTimeout) {
        Assert.notNull(task, "Runnable must not be null");
        Runnable taskToUse = (this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
        if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
            this.concurrencyThrottle.beforeAccess();
            doExecute(new ConcurrencyThrottlingRunnable(taskToUse));
        } else {
            doExecute(taskToUse);
        }
    }

    @Override
    public Future<?> submit(Runnable task) {
        FutureTask<Object> future = new FutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        FutureTask<T> future = new FutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    /**
     * Template method for the actual execution of a task.
     *
The default implementation creates a new Thread and starts it.
     * @param task the Runnable to execute
     * @see #setThreadFactory
     * @see #createThread
     * @see java.lang.Thread#start()
     */
    protected void doExecute(Runnable task) {
        Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
        thread.start();
    }

    /**
     * Subclass of the general ConcurrencyThrottleSupport class,
     * making {@code beforeAccess()} and {@code afterAccess()}
     * visible to the surrounding class.
     */
    private static class ConcurrencyThrottleAdapter extends ConcurrencyThrottleSupport {

        @Override
        protected void beforeAccess() {
            super.beforeAccess();
        }

        @Override
        protected void afterAccess() {
            super.afterAccess();
        }
    }

    /**
     * This Runnable calls {@code afterAccess()} after the
     * target Runnable has finished its execution.
     */
    private class ConcurrencyThrottlingRunnable implements Runnable {

        private final Runnable target;

        public ConcurrencyThrottlingRunnable(Runnable target) {
            this.target = target;
        }

        @Override
        public void run() {
            try {
                this.target.run();
            } finally {
                concurrencyThrottle.afterAccess();
            }


package org.springframework.core.task;

import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrencyThrottleSupport;
import org.springframework.util.CustomizableThreadCreator;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;

/**
 * {@link TaskExecutor} implementation that fires up a new Thread for each task,
 * executing it asynchronously.
 *
 *
Supports limiting concurrent threads through the "concurrencyLimit"
 * bean property. By default, the number of concurrent threads is unlimited.
 *
 *
NOTE: This implementation does not reuse threads! Consider a
 * thread-pooling TaskExecutor implementation instead, in particular for
 * executing a large number of short-lived tasks.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see #setConcurrencyLimit
 * @see SyncTaskExecutor
 * @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
 */
@SuppressWarnings("serial")
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implements AsyncListenableTaskExecutor, Serializable {

    /**
     * Permit any number of concurrent invocations: that is, don't throttle concurrency.
     * @see ConcurrencyThrottleSupport#UNBOUNDED_CONCURRENCY
     */
    public static final int UNBOUNDED_CONCURRENCY = ConcurrencyThrottleSupport.UNBOUNDED_CONCURRENCY;

    /**
     * Switch concurrency 'off': that is, don't allow any concurrent invocations.
     * @see ConcurrencyThrottleSupport#NO_CONCURRENCY
     */
    public static final int NO_CONCURRENCY = ConcurrencyThrottleSupport.NO_CONCURRENCY;

    /**
     * Internal concurrency throttle used by this executor.
     */
    private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter();

    @Nullable
    private ThreadFactory threadFactory;

    @Nullable
    private TaskDecorator taskDecorator;

    /**
     * Create a new SimpleAsyncTaskExecutor with default thread name prefix.
     */
    public SimpleAsyncTaskExecutor() {
        super();
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given thread name prefix.
     * @param threadNamePrefix the prefix to use for the names of newly created threads
     */
    public SimpleAsyncTaskExecutor(String threadNamePrefix) {
        super(threadNamePrefix);
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given external thread factory.
     * @param threadFactory the factory to use for creating new Threads
     */
    public SimpleAsyncTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Specify an external factory to use for creating new Threads,
     * instead of relying on the local properties of this executor.
     *
You may specify an inner ThreadFactory bean or also a ThreadFactory reference
     * obtained from JNDI (on a Jakarta EE server) or some other lookup mechanism.
     * @see #setThreadNamePrefix
     * @see #setThreadPriority
     */
    public void setThreadFactory(@Nullable ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Return the external factory to use for creating new Threads, if any.
     */
    @Nullable
    public final ThreadFactory getThreadFactory() {
        return this.threadFactory;
    }

    /**
     * Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
     * about to be executed.
     *
Note that such a decorator is not necessarily being applied to the
     * user-supplied {@code Runnable}/{@code Callable} but rather to the actual
     * execution callback (which may be a wrapper around the user-supplied task).
     *
The primary use case is to set some execution context around the task's
     * invocation, or to provide some monitoring/statistics for task execution.
     *
NOTE: Exception handling in {@code TaskDecorator} implementations
     * is limited to plain {@code Runnable} execution via {@code execute} calls.
     * In case of {@code #submit} calls, the exposed {@code Runnable} will be a
     * {@code FutureTask} which does not propagate any exceptions; you might
     * have to cast it and call {@code Future#get} to evaluate exceptions.
     * @since 4.3
     */
    public final void setTaskDecorator(TaskDecorator taskDecorator) {
        this.taskDecorator = taskDecorator;
    }

    /**
     * Set the maximum number of parallel accesses allowed.
     * -1 indicates no concurrency limit at all.
     *
In principle, this limit can be changed at runtime,
     * although it is generally designed as a config time setting.
     * NOTE: Do not switch between -1 and any concrete limit at runtime,
     * as this will lead to inconsistent concurrency counts: A limit
     * of -1 effectively turns off concurrency counting completely.
     * @see #UNBOUNDED_CONCURRENCY
     */
    public void setConcurrencyLimit(int concurrencyLimit) {
        this.concurrencyThrottle.setConcurre

}

    /**
     * Return the maximum number of parallel accesses allowed.
     */
    public final int getConcurrencyLimit() {
        return this.concurrencyThrottle.getConcurrencyLimit();
    }

    /**
     * Return whether this throttle is currently active.
     * @return {@code true} if the concurrency limit for this instance is active
     * @see #getConcurrencyLimit()
     * @see #setConcurrencyLimit
     */
    public final boolean isThrottleActive() {
        return this.concurrencyThrottle.isThrottleActive();
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task) {
        execute(task, TIMEOUT_INDEFINITE);
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     *
Executes urgent tasks (with 'immediate' timeout) directly,
     * bypassing the concurrency throttle (if active). All other
     * tasks are subject to throttling.
     * @see #TIMEOUT_IMMEDIATE
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task, long startTimeout) {
        Assert.notNull(task, "Runnable must not be null");
        Runnable taskToUse = (this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
        if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
            this.concurrencyThrottle.beforeAccess();
            doExecute(new ConcurrencyThrottlingRunnable(taskToUse));
        } else {
            doExecute(taskToUse);
        }
    }

    @Override
    public Future<?> submit(Runnable task) {
        FutureTask<Object> future = new FutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        FutureTask<T> future = new FutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    /**
     * Template method for the actual execution of a task.
     *
The default implementation creates a new Thread and starts it.
     * @param task the Runnable to execute
     * @see #setThreadFactory
     * @see #createThread
     * @see java.lang.Thread#start()
     */
    protected void doExecute(Runnable task) {
        Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
        thread.start();
    }

    /**
     * Subclass of the general ConcurrencyThrottleSupport class,
     * making {@code beforeAccess()} and {@code afterAccess()}
     * visible to the surrounding class.
     */
    private static class ConcurrencyThrottleAdapter extends ConcurrencyThrottleSupport {

        @Override
        protected void beforeAccess() {
            super.beforeAccess();
        }

        @Override
        protected void afterAccess() {
            super.afterAccess();
        }
    }

    /**
     * This Runnable calls {@code afterAccess()} after the
     * target Runnable has finished its execution.
     */
    private class ConcurrencyThrottlingRunnable implements Runnable {

        private final Runnable target;

        public ConcurrencyThrottlingRunnable(Runnable target) {
            this.target = target;
        }

        @Override
        public void run() {
            try {
                this.target.run();
            } finally {
                concurrencyThrottle.afterAccess();
            }
        }
    }
}


@Override
    public void execute(Runnable task) {
        execute(task, TIMEOUT_INDEFINITE);
    }

package org.springframework.core.task;

import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrencyThrottleSupport;
import org.springframework.util.CustomizableThreadCreator;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;

/**
 * {@link TaskExecutor} implementation that fires up a new Thread for each task,
 * executing it asynchronously.
 *
 *
Supports limiting concurrent threads through the "concurrencyLimit"
 * bean property. By default, the number of concurrent threads is unlimited.
 *
 *
NOTE: This implementation does not reuse threads! Consider a
 * thread-pooling TaskExecutor implementation instead, in particular for
 * executing a large number of short-lived tasks.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see #setConcurrencyLimit
 * @see SyncTaskExecutor
 * @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
 */
@SuppressWarnings("serial")
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implements AsyncListenableTaskExecutor, Serializable {

    /**
     * Permit any number of concurrent invocations: that is, don't throttle concurrency.
     * @see ConcurrencyThrottleSupport#UNBOUNDED_CONCURRENCY
     */
    public static final int UNBOUNDED_CONCURRENCY = ConcurrencyThrottleSupport.UNBOUNDED_CONCURRENCY;

    /**
     * Switch concurrency 'off': that is, don't allow any concurrent invocations.
     * @see ConcurrencyThrottleSupport#NO_CONCURRENCY
     */
    public static final int NO_CONCURRENCY = ConcurrencyThrottleSupport.NO_CONCURRENCY;

    /**
     * Internal concurrency throttle used by this executor.
     */
    private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter();

    @Nullable
    private ThreadFactory threadFactory;

    @Nullable
    private TaskDecorator taskDecorator;

    /**
     * Create a new SimpleAsyncTaskExecutor with default thread name prefix.
     */
    public SimpleAsyncTaskExecutor() {
        super();
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given thread name prefix.
     * @param threadNamePrefix the prefix to use for the names of newly created threads
     */
    public SimpleAsyncTaskExecutor(String threadNamePrefix) {
        super(threadNamePrefix);
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given external thread factory.
     * @param threadFactory the factory to use for creating new Threads
     */
    public SimpleAsyncTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Specify an external factory to use for creating new Threads,
     * instead of relying on the local properties of this executor.
     *
You may specify an inner ThreadFactory bean or also a ThreadFactory reference
     * obtained from JNDI (on a Jakarta EE server) or some other lookup mechanism.
     * @see #setThreadNamePrefix
     * @see #setThreadPriority
     */
    public void setThreadFactory(@Nullable ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Return the external factory to use for creating new Threads, if any.
     */
    @Nullable
    public final ThreadFactory getThreadFactory() {
        return this.threadFactory;
    }

    /**
     * Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
     * about to be executed.
     *
Note that such a decorator is not necessarily being applied to the
     * user-supplied {@code Runnable}/{@code Callable} but rather to the actual
     * execution callback (which may be a wrapper around the user-supplied task).
     *
The primary use case is to set some execution context around the task's
     * invocation, or to provide some monitoring/statistics for task execution.
     *
NOTE: Exception handling in {@code TaskDecorator} implementations
     * is limited to plain {@code Runnable} execution via {@code execute} calls.
     * In case of {@code #submit} calls, the exposed {@code Runnable} will be a
     * {@code FutureTask} which does not propagate any exceptions; you might
     * have to cast it and call {@code Future#get} to evaluate exceptions.
     * @since 4.3
     */
    public final void setTaskDecorator(TaskDecorator taskDecorator) {
        this.taskDecorator = taskDecorator;
    }

    /**
     * Set the maximum number of parallel accesses allowed.
     * -1 indicates no concurrency limit at all.
     *
In principle, this limit can be changed at runtime,
     * although it is generally designed as a config time setting.
     * NOTE: Do not switch between -1 and any concrete limit at runtime,
     * as this will lead to inconsistent concurrency counts: A limit
     * of -1 effectively turns off concurrency counting completely.
     * @see #UNBOUNDED_CONCURRENCY
     */
    public void setConcurrencyLimit(int concurrencyLimit) {
        this.concurrencyThrottle.setConcurrencyLimit(concurrencyLimit);
    }

    /**
     * Return the maximum number of parallel accesses allowed.
     */
    public final int getConcurrencyLimit() {
        return this.concurrencyThrottle.getConcurrencyLimit();
    }

    /**
     * Return whether this throttle is currently active.
     * @return {@code true} if the concurrency limit for this instance is active
     * @see #getConcurrencyLimit()
     * @see #setConcurrencyLimit
     */
    public final boolean isThrottleActive() {
        return this.concurrencyThrottle.isThrottleActive();
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     * @see #doExecute(Runnable)
     */

/**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     *
Executes urgent tasks (with 'immediate' timeout) directly,
     * bypassing the concurrency throttle (if active). All other
     * tasks are subject to throttling.
     * @see #TIMEOUT_IMMEDIATE
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task, long startTimeout) {
        Assert.notNull(task, "Runnable must not be null");
        Runnable taskToUse = (this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
        if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
            this.concurrencyThrottle.beforeAccess();
            doExecute(new ConcurrencyThrottlingRunnable(taskToUse));
        } else {
            doExecute(taskToUse);
        }
    }

    @Override
    public Future<?> submit(Runnable task) {
        FutureTask<Object> future = new FutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        FutureTask<T> future = new FutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    /**
     * Template method for the actual execution of a task.
     *
The default implementation creates a new Thread and starts it.
     * @param task the Runnable to execute
     * @see #setThreadFactory
     * @see #createThread
     * @see java.lang.Thread#start()
     */
    protected void doExecute(Runnable task) {
        Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
        thread.start();
    }

    /**
     * Subclass of the general ConcurrencyThrottleSupport class,
     * making {@code beforeAccess()} and {@code afterAccess()}
     * visible to the surrounding class.
     */
    private static class ConcurrencyThrottleAdapter extends ConcurrencyThrottleSupport {

        @Override
        protected void beforeAccess() {
            super.beforeAccess();
        }

        @Override
        protected void afterAccess() {
            super.afterAccess();
        }
    }

    /**
     * This Runnable calls {@code afterAccess()} after the
     * target Runnable has finished its execution.
     */
    private class ConcurrencyThrottlingRunnable implements Runnable {

        private final Runnable target;

        public ConcurrencyThrottlingRunnable(Runnable target) {
            this.target = target;
        }

        @Override
        public void run() {
            try {
                this.target.run();
            } finally {
                concurrencyThrottle.afterAccess();
            }
        }
    }
}


if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
            this.concurrencyThrottle.beforeAccess();
            doExecute(new ConcurrencyThrottlingRunnable(taskToUse));
        } else {
            doExecute(taskToUse);
        }

package org.springframework.core.task;

import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrencyThrottleSupport;
import org.springframework.util.CustomizableThreadCreator;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;

/**
 * {@link TaskExecutor} implementation that fires up a new Thread for each task,
 * executing it asynchronously.
 *
 *
Supports limiting concurrent threads through the "concurrencyLimit"
 * bean property. By default, the number of concurrent threads is unlimited.
 *
 *
NOTE: This implementation does not reuse threads! Consider a
 * thread-pooling TaskExecutor implementation instead, in particular for
 * executing a large number of short-lived tasks.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see #setConcurrencyLimit
 * @see SyncTaskExecutor
 * @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
 */
@SuppressWarnings("serial")
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implements AsyncListenableTaskExecutor, Serializable {

    /**
     * Permit any number of concurrent invocations: that is, don't throttle concurrency.
     * @see ConcurrencyThrottleSupport#UNBOUNDED_CONCURRENCY
     */
    public static final int UNBOUNDED_CONCURRENCY = ConcurrencyThrottleSupport.UNBOUNDED_CONCURRENCY;

    /**
     * Switch concurrency 'off': that is, don't allow any concurrent invocations.
     * @see ConcurrencyThrottleSupport#NO_CONCURRENCY
     */
    public static final int NO_CONCURRENCY = ConcurrencyThrottleSupport.NO_CONCURRENCY;

    /**
     * Internal concurrency throttle used by this executor.
     */
    private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter();

    @Nullable
    private ThreadFactory threadFactory;

    @Nullable
    private TaskDecorator taskDecorator;

    /**
     * Create a new SimpleAsyncTaskExecutor with default thread name prefix.
     */
    public SimpleAsyncTaskExecutor() {
        super();
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given thread name prefix.
     * @param threadNamePrefix the prefix to use for the names of newly created threads
     */
    public SimpleAsyncTaskExecutor(String threadNamePrefix) {
        super(threadNamePrefix);
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given external thread factory.
     * @param threadFactory the factory to use for creating new Threads
     */
    public SimpleAsyncTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Specify an external factory to use for creating new Threads,
     * instead of relying on the local properties of this executor.
     *
You may specify an inner ThreadFactory bean or also a ThreadFactory reference
     * obtained from JNDI (on a Jakarta EE server) or some other lookup mechanism.
     * @see #setThreadNamePrefix
     * @see #setThreadPriority
     */
    public void setThreadFactory(@Nullable ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Return the external factory to use for creating new Threads, if any.
     */
    @Nullable
    public final ThreadFactory getThreadFactory() {
        return this.threadFactory;
    }

    /**
     * Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
     * about to be executed.
     *
Note that such a decorator is not necessarily being applied to the
     * user-supplied {@code Runnable}/{@code Callable} but rather to the actual
     * execution callback (which may be a wrapper around the user-supplied task).
     *
The primary use case is to set some execution context around the task's
     * invocation, or to provide some monitoring/statistics for task execution.
     *
NOTE: Exception handling in {@code TaskDecorator} implementations
     * is limited to plain {@code Runnable} execution via {@code execute} calls.
     * In case of {@code #submit} calls, the exposed {@code Runnable} will be a
     * {@code FutureTask} which does not propagate any exceptions; you might
     * have to cast it and call {@code Future#get} to evaluate exceptions.
     * @since 4.3
     */
    public final void setTaskDecorator(TaskDecorator taskDecorator) {
        this.taskDecorator = taskDecorator;
    }

    /**
     * Set the maximum number of parallel accesses allowed.
     * -1 indicates no concurrency limit at all.
     *
In principle, this limit can be changed at runtime,
     * although it is generally designed as a config time setting.
     * NOTE: Do not switch between -1 and any concrete limit at runtime,
     * as this will lead to inconsistent concurrency counts: A limit
     * of -1 effectively turns off concurrency counting completely.
     * @see #UNBOUNDED_CONCURRENCY
     */
    public void setConcurrencyLimit(int concurrencyLimit) {
        this.concurrencyThrottle.setConcurrencyLimit(concurrencyLimit);
    }

    /**
     * Return the maximum number of parallel accesses allowed.
     */
    public final int getConcurrencyLimit() {
        return this.concurrencyThrottle.getConcurrencyLimit();
    }

    /**
     * Return whether this throttle is currently active.
     * @return {@code true} if the concurrency limit for this instance is active
     * @see #getConcurrencyLimit()
     * @see #setConcurrencyLimit
     */
    public final boolean isThrottleActive() {
        return this.concurrencyThrottle.isThrottleActive();
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task) {
        execute(task, TIMEOUT_INDEFINITE);
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     *
Executes urgent tasks (with 'immediate' timeout) directly,
     * bypassing the concurrency throttle (if active). All other
     * tasks are subject to throttling.
     * @see #TIMEOUT_IMMEDIATE
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task, long startTimeout) {
        Assert.notNull(task, "Runnable must not be null");
        Runnable taskToUse = (this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);

    }

    @Override
    public Future<?> submit(Runnable task) {
        FutureTask<Object> future = new FutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        FutureTask<T> future = new FutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    /**
     * Template method for the actual execution of a task.
     * <p>The default implementation creates a new Thread and starts it.
     * @param task the Runnable to execute
     * @see #setThreadFactory
     * @see #createThread
     * @see java.lang.Thread#start()
     */
    protected void doExecute(Runnable task) {
        Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
        thread.start();
    }

    /**
     * Subclass of the general ConcurrencyThrottleSupport class,
     * making {@code beforeAccess()} and {@code afterAccess()}
     * visible to the surrounding class.
     */
    private static class ConcurrencyThrottleAdapter extends ConcurrencyThrottleSupport {

        @Override
        protected void beforeAccess() {
            super.beforeAccess();
        }

        @Override
        protected void afterAccess() {
            super.afterAccess();
        }
    }

    /**
     * This Runnable calls {@code afterAccess()} after the
     * target Runnable has finished its execution.
     */
    private class ConcurrencyThrottlingRunnable implements Runnable {

        private final Runnable target;

        public ConcurrencyThrottlingRunnable(Runnable target) {
            this.target = target;
        }

        @Override
        public void run() {
            try {
                this.target.run();
            } finally {
                concurrencyThrottle.afterAccess();
            }
        }
    }
}


try {
                this.target.run();
            } finally {
                concurrencyThrottle.afterAccess();
            }

package org.springframework.core.task;

import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrencyThrottleSupport;
import org.springframework.util.CustomizableThreadCreator;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;

/**
 * {@link TaskExecutor} implementation that fires up a new Thread for each task,
 * executing it asynchronously.
 *
 *
Supports limiting concurrent threads through the "concurrencyLimit"
 * bean property. By default, the number of concurrent threads is unlimited.
 *
 *
NOTE: This implementation does not reuse threads! Consider a
 * thread-pooling TaskExecutor implementation instead, in particular for
 * executing a large number of short-lived tasks.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see #setConcurrencyLimit
 * @see SyncTaskExecutor
 * @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
 */
@SuppressWarnings("serial")
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implements AsyncListenableTaskExecutor, Serializable {

    /**
     * Permit any number of concurrent invocations: that is, don't throttle concurrency.
     * @see ConcurrencyThrottleSupport#UNBOUNDED_CONCURRENCY
     */
    public static final int UNBOUNDED_CONCURRENCY = ConcurrencyThrottleSupport.UNBOUNDED_CONCURRENCY;

    /**
     * Switch concurrency 'off': that is, don't allow any concurrent invocations.
     * @see ConcurrencyThrottleSupport#NO_CONCURRENCY
     */
    public static final int NO_CONCURRENCY = ConcurrencyThrottleSupport.NO_CONCURRENCY;

    /**
     * Internal concurrency throttle used by this executor.
     */
    private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter();

    @Nullable
    private ThreadFactory threadFactory;

    @Nullable
    private TaskDecorator taskDecorator;

    /**
     * Create a new SimpleAsyncTaskExecutor with default thread name prefix.
     */
    public SimpleAsyncTaskExecutor() {
        super();
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given thread name prefix.
     * @param threadNamePrefix the prefix to use for the names of newly created threads
     */
    public SimpleAsyncTaskExecutor(String threadNamePrefix) {
        super(threadNamePrefix);
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given external thread factory.
     * @param threadFactory the factory to use for creating new Threads
     */
    public SimpleAsyncTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Specify an external factory to use for creating new Threads,
     * instead of relying on the local properties of this executor.
     *
You may specify an inner ThreadFactory bean or also a ThreadFactory reference
     * obtained from JNDI (on a Jakarta EE server) or some other lookup mechanism.
     * @see #setThreadNamePrefix
     * @see #setThreadPriority
     */
    public void setThreadFactory(@Nullable ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Return the external factory to use for creating new Threads, if any.
     */
    @Nullable
    public final ThreadFactory getThreadFactory() {
        return this.threadFactory;
    }

    /**
     * Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
     * about to be executed.
     *
Note that such a decorator is not necessarily being applied to the
     * user-supplied {@code Runnable}/{@code Callable} but rather to the actual
     * execution callback (which may be a wrapper around the user-supplied task).
     *
The primary use case is to set some execution context around the task's
     * invocation, or to provide some monitoring/statistics for task execution.
     *
NOTE: Exception handling in {@code TaskDecorator} implementations
     * is limited to plain {@code Runnable} execution via {@code execute} calls.
     * In case of {@code #submit} calls, the exposed {@code Runnable} will be a
     * {@code FutureTask} which does not propagate any exceptions; you might
     * have to cast it and call {@code Future#get} to evaluate exceptions.
     * @since 4.3
     */
    public final void setTaskDecorator(TaskDecorator taskDecorator) {
        this.taskDecorator = taskDecorator;
    }

    /**
     * Set the maximum number of parallel accesses allowed.
     * -1 indicates no concurrency limit at all.
     *
In principle, this limit can be changed at runtime,
     * although it is generally designed as a config time setting.
     * NOTE: Do not switch between -1 and any concrete limit at runtime,
     * as this will lead to inconsistent concurrency counts: A limit
     * of -1 effectively turns off concurrency counting completely.
     * @see #UNBOUNDED_CONCURRENCY
     */
    public void setConcurrencyLimit(int concurrencyLimit) {
        this.concurrencyThrottle.setConcurrencyLimit(concurrencyLimit);
    }

    /**
     * Return the maximum number of parallel accesses allowed.
     */
    public final int getConcurrencyLimit() {
        return this.concurrencyThrottle.getConcurrencyLimit();
    }

    /**
     * Return whether this throttle is currently active.
     * @return {@code true} if the concurrency limit for this instance is active
     * @see #getConcurrencyLimit()
     * @see #setConcurrencyLimit
     */
    public final boolean isThrottleActive() {
        return this.concurrencyThrottle.isThrottleActive();
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task) {
        execute(task, TIMEOUT_INDEFINITE);
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     *
Executes urgent tasks (with 'immediate' timeout) directly,
     * bypassing the concurrency throttle (if active). All other
     * tasks are subject to throttling.
     * @see #TIMEOUT_IMMEDIATE
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task, long startTimeout) {
        Assert.notNull(task, "Runnable must not be null");
        Runnable taskToUse = (this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
        if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
            this.concurrencyThrottle.beforeAccess();
            doExecute(new ConcurrencyThrottlingRunnable(taskToUse));
        } else {
            doExecute(taskToUse);
        }
    }

    @Override
    public Future<?> submit(Runnable task) {
        FutureTask<Object> future = new FutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        FutureTask<T> future = new FutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    /**
     * Template method for the actual execution of a task.
     *
The default implementation creates a new Thread and starts it.
     * @param task the Runnable to execute
     * @see #setThreadFactory
     * @see #createThread
     * @see java.lang.Thread#start()
     */
    protected void doExecute(Runnable task) {
        Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
        thread.start();
    }

    /**
     * Subclass of the general ConcurrencyThrottleSupport class,
     * making {@code beforeAccess()} and {@code afterAccess()}
     * visible to the surrounding class.
     */
    private static class ConcurrencyThrottleAdapter extends ConcurrencyThrottleSupport {

        @Override
        protected void beforeAccess() {
            super.beforeAccess();
        }

        @Override
        protected void afterAccess() {
            super.afterAccess();
        }
    }

    /**
     * This Runnable calls {@code afterAccess()} after the
     * target Runnable has finished its execution.
     */
    private class ConcurrencyThrottlingRunnable implements Runnable {

        private final Runnable target;

        public ConcurrencyThrottlingRunnable(Runnable target) {
            this.target = target;
        }

        @Override
        public void run() {


package org.springframework.core.task;

import java.io.Serializable;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ConcurrencyThrottleSupport;
import org.springframework.util.CustomizableThreadCreator;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureTask;

/**
 * {@link TaskExecutor} implementation that fires up a new Thread for each task,
 * executing it asynchronously.
 *
 *
Supports limiting concurrent threads through the "concurrencyLimit"
 * bean property. By default, the number of concurrent threads is unlimited.
 *
 *
NOTE: This implementation does not reuse threads! Consider a
 * thread-pooling TaskExecutor implementation instead, in particular for
 * executing a large number of short-lived tasks.
 *
 * @author Juergen Hoeller
 * @since 2.0
 * @see #setConcurrencyLimit
 * @see SyncTaskExecutor
 * @see org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor
 */
@SuppressWarnings("serial")
public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator implements AsyncListenableTaskExecutor, Serializable {

    /**
     * Permit any number of concurrent invocations: that is, don't throttle concurrency.
     * @see ConcurrencyThrottleSupport#UNBOUNDED_CONCURRENCY
     */
    public static final int UNBOUNDED_CONCURRENCY = ConcurrencyThrottleSupport.UNBOUNDED_CONCURRENCY;

    /**
     * Switch concurrency 'off': that is, don't allow any concurrent invocations.
     * @see ConcurrencyThrottleSupport#NO_CONCURRENCY
     */
    public static final int NO_CONCURRENCY = ConcurrencyThrottleSupport.NO_CONCURRENCY;

    /**
     * Internal concurrency throttle used by this executor.
     */
    private final ConcurrencyThrottleAdapter concurrencyThrottle = new ConcurrencyThrottleAdapter();

    @Nullable
    private ThreadFactory threadFactory;

    @Nullable
    private TaskDecorator taskDecorator;

    /**
     * Create a new SimpleAsyncTaskExecutor with default thread name prefix.
     */
    public SimpleAsyncTaskExecutor() {
        super();
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given thread name prefix.
     * @param threadNamePrefix the prefix to use for the names of newly created threads
     */
    public SimpleAsyncTaskExecutor(String threadNamePrefix) {
        super(threadNamePrefix);
    }

    /**
     * Create a new SimpleAsyncTaskExecutor with the given external thread factory.
     * @param threadFactory the factory to use for creating new Threads
     */
    public SimpleAsyncTaskExecutor(ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Specify an external factory to use for creating new Threads,
     * instead of relying on the local properties of this executor.
     *
You may specify an inner ThreadFactory bean or also a ThreadFactory reference
     * obtained from JNDI (on a Jakarta EE server) or some other lookup mechanism.
     * @see #setThreadNamePrefix
     * @see #setThreadPriority
     */
    public void setThreadFactory(@Nullable ThreadFactory threadFactory) {
        this.threadFactory = threadFactory;
    }

    /**
     * Return the external factory to use for creating new Threads, if any.
     */
    @Nullable
    public final ThreadFactory getThreadFactory() {
        return this.threadFactory;
    }

    /**
     * Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
     * about to be executed.
     *
Note that such a decorator is not necessarily being applied to the
     * user-supplied {@code Runnable}/{@code Callable} but rather to the actual
     * execution callback (which may be a wrapper around the user-supplied task).
     *
The primary use case is to set some execution context around the task's
     * invocation, or to provide some monitoring/statistics for task execution.
     *
NOTE: Exception handling in {@code TaskDecorator} implementations
     * is limi

ted to plain {@code Runnable} execution via {@code execute} calls.
     * In case of {@code #submit} calls, the exposed {@code Runnable} will be a
     * {@code FutureTask} which does not propagate any exceptions; you might
     * have to cast it and call {@code Future#get} to evaluate exceptions.
     * @since 4.3
     */
    public final void setTaskDecorator(TaskDecorator taskDecorator) {
        this.taskDecorator = taskDecorator;
    }

    /**
     * Set the maximum number of parallel accesses allowed.
     * -1 indicates no concurrency limit at all.
     *
In principle, this limit can be changed at runtime,
     * although it is generally designed as a config time setting.
     * NOTE: Do not switch between -1 and any concrete limit at runtime,
     * as this will lead to inconsistent concurrency counts: A limit
     * of -1 effectively turns off concurrency counting completely.
     * @see #UNBOUNDED_CONCURRENCY
     */
    public void setConcurrencyLimit(int concurrencyLimit) {
        this.concurrencyThrottle.setConcurrencyLimit(concurrencyLimit);
    }

    /**
     * Return the maximum number of parallel accesses allowed.
     */
    public final int getConcurrencyLimit() {
        return this.concurrencyThrottle.getConcurrencyLimit();
    }

    /**
     * Return whether this throttle is currently active.
     * @return {@code true} if the concurrency limit for this instance is active
     * @see #getConcurrencyLimit()
     * @see #setConcurrencyLimit
     */
    public final boolean isThrottleActive() {
        return this.concurrencyThrottle.isThrottleActive();
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task) {
        execute(task, TIMEOUT_INDEFINITE);
    }

    /**
     * Executes the given task, within a concurrency throttle
     * if configured (through the superclass's settings).
     *
Executes urgent tasks (with 'immediate' timeout) directly,
     * bypassing the concurrency throttle (if active). All other
     * tasks are subject to throttling.
     * @see #TIMEOUT_IMMEDIATE
     * @see #doExecute(Runnable)
     */
    @Override
    public void execute(Runnable task, long startTimeout) {
        Assert.notNull(task, "Runnable must not be null");
        Runnable taskToUse = (this.taskDecorator != null ? this.taskDecorator.decorate(task) : task);
        if (isThrottleActive() && startTimeout > TIMEOUT_IMMEDIATE) {
            this.concurrencyThrottle.beforeAccess();
            doExecute(new ConcurrencyThrottlingRunnable(taskToUse));
        } else {
            doExecute(taskToUse);
        }
    }

    @Override
    public Future<?> submit(Runnable task) {
        FutureTask<Object> future = new FutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> Future<T> submit(Callable<T> task) {
        FutureTask<T> future = new FutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public ListenableFuture<?> submitListenable(Runnable task) {
        ListenableFutureTask<Object> future = new ListenableFutureTask<>(task, null);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    @Override
    public <T> ListenableFuture<T> submitListenable(Callable<T> task) {
        ListenableFutureTask<T> future = new ListenableFutureTask<>(task);
        execute(future, TIMEOUT_INDEFINITE);
        return future;
    }

    /**
     * Template method for the actual execution of a task.
     *
The default implementation creates a new Thread and starts it.
     * @param task the Runnable to execute
     * @see #setThreadFactory
     * @see #createThread
     * @see java.lang.Thread#start()
     */
    protected void doExecute(Runnable task) {
        Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
        thread.start();
    }

    /**
     * Subclass of the general ConcurrencyThrottleSupport class,
     * making {@code beforeAccess()} and {@code afterAccess()}
     * visible to the surrounding class.
     */
    private static class ConcurrencyThrottleAdapter extends ConcurrencyThrottleSupport {

        @Override
        protected void beforeAccess() {
            super.beforeAccess();
        }

        @Override
        protected void afterAccess() {
            super.afterAccess();
        }
    }

    /**
     * This Runnable calls {@code afterAccess()} after the
     * target Runnable has finished its execution.
     */
    private class ConcurrencyThrottlingRunnable implements Runnable {

        private final Runnable target;

        public ConcurrencyThrottlingRunnable(Runnable target) {
            this.target = target;
        }

        @Override
        public void run() {
            try {
                this.target.run();
            } finally {
                concurrencyThrottle.afterAccess();
            }
        }
    }
}


public static void main(String[] args) throws Exception

package oreilly.video.messaging;

import javax.jms.Connection;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSSender {

{
        Connection connection = new ActiveMQConnectionFactory("tcp://localhost:61616").createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue("EM_TRADE_FILTER.Q");
        MessageProducer sender = session.createProducer(queue);
        TextMessage msg = session.createTextMessage("BUY AAPL 1000 SHARES");
        msg.setStringProperty("State", "open");
        sender.send(msg);
        System.out.println("Message Sent");
        connection.close();
    }
}


        Connection connection = new ActiveMQConnectionFactory("tcp://localhost:61616").createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

package oreilly.video.messaging;

import javax.jms.Connection;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSSender {

    public static void main(String[] args) throws Exception {

        Queue queue = session.createQueue("EM_TRADE_FILTER.Q");
        MessageProducer sender = session.createProducer(queue);
        TextMessage msg = session.createTextMessage("BUY AAPL 1000 SHARES");
        msg.setStringProperty("State", "open");
        sender.send(msg);
        System.out.println("Message Sent");
        connection.close();
    }
}


Queue queue = session.createQueue("EM_TRADE_FILTER.Q");
        MessageProducer sender = session.createProducer(queue);
        TextMessage msg = session.createTextMessage("BUY AAPL 1000 SHARES");
        msg.setStringProperty("State", "open");

package oreilly.video.messaging;

import javax.jms.Connection;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSSender {

    public static void main(String[] args) throws Exception {
        Connection connection = new ActiveMQConnectionFactory("tcp://localhost:61616").createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        sender.send(msg);
        System.out.println("Message Sent");
        connection.close();
    }
}


sender.send(msg);
        System.out.println("Message Sent");
        connection.close();
    }

package oreilly.video.messaging;

import javax.jms.Connection;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSSender {

    public static void main(String[] args) throws Exception {
        Connection connection = new ActiveMQConnectionFactory("tcp://localhost:61616").createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue("EM_TRADE_FILTER.Q");
        MessageProducer sender = session.createProducer(queue);
        TextMessage msg = session.createTextMessage("BUY AAPL 1000 SHARES");
        msg.setStringProperty("State", "open");


package oreilly.video.messaging;

import javax.jms.Connection;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSSender {

    public static void main(String[] args) throws Exception {
        Connection connection = new ActiveMQConnectionFactory("tcp://localhost:61616").createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queu

        MessageProducer sender = session.createProducer(queue);
        TextMessage msg = session.createTextMessage("BUY AAPL 1000 SHARES");
        msg.setStringProperty("State", "open");
        sender.send(msg);
        System.out.println("Message Sent");
        connection.close();
    }
}


package oreilly.video.messaging;

import javax.jms.Connection;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class JMSSender {

    public static void main(String[] args) throws Exception {
        Connection connection = new ActiveMQConnectionFactory("tcp://localhost:61616").createConnection();
        connection.start();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        Queue queue = session.createQueue("EM_TRADE_FILTER.Q");
        MessageProducer sender = session.createProducer(queue);
        TextMessa

ge msg = session.createTextMessage("BUY AAPL 1000 SHARES");
        msg.setStringProperty("State", "open");
        sender.send(msg);
        System.out.println("Message Sent");
        connection.close();
    }
}


@Override
    public boolean hasMorePayloads()

/*
 * Bradamsa - Burp Intruder payloads generator (simplified code - does not work!)
 *
 */
package com.doyensec;

import burp.BurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IIntruderAttack;
import burp.IIntruderPayloadGenerator;
import burp.IIntruderPayloadGeneratorFactory;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;

public class RadamsaPayloadGenerator implements IIntruderPayloadGenerator, IIntruderPayloadGeneratorFactory {

    private final IBurpExtenderCallbacks callbacks;

    private boolean firstInvoke;

    private ArrayList<File> samples;

    private Iterator<File> samplesIte;

    private BradamsaPanel panel;

    public RadamsaPayloadGenerator(BurpExtender burpExt) {
        callbacks = burpExt.getCallbacks();
        panel = (BradamsaPanel) burpExt.getTab().getUiComponent();
        firstInvoke = true;
        samples = new ArrayList<>();
        samplesIte = samples.iterator();
    }

{
        if (firstInvoke) {
            return true;
        }
        return samplesIte.hasNext();
    }

    @Override
    public byte[] getNextPayload(byte[] basePayload) {
        byte[] result = null;
        if (basePayload == null) {
            // Display warning. Battering ram attack type was selected
            JOptionPane.showMessageDialog(null, "Bradamsa can only be used in a sniper attack", "Abort", JOptionPane.ERROR_MESSAGE);
            firstInvoke = false;
        }
        try {
            if (firstInvoke) {
                // Generate samples from Burp's payload
                String cmdLine = panel.getRadamsaCmdLine();
                if (!cmdLine.isEmpty()) {
                    if (panel.getCount() > 9999) {
                        JOptionPane.showMessageDialog(null, "As you've selected an high count number," + " generating all Radamsa samples may take some time.
Your intruder " + "attack will start once all samples are successfully generated.", "Radamsa Samples Generation", JOptionPane.INFORMATION_MESSAGE);
                    }
                    BurpUtils.executeAndPipe(cmdLine, basePayload, callbacks, true);
                    // If enabled, mark all files for deletion before JVM shutdown
                    if (panel.deleteFiles()) {
                        for (File file : panel.getOutputDir().listFiles()) {
                            file.deleteOnExit();
                        }
                    }
                } else {
                    // Display warning. Invalid user input
                    JOptionPane.showMessageDialog(null, "Invalid command line arguments", "Check the 'Bradamsa' tab...", JOptionPane.WARNING_MESSAGE);
                }
                // create samples index
                samples.addAll(Arrays.asList(panel.getOutputDir().listFiles()));
                samplesIte = samples.iterator();
                // prevent further initialization
                firstInvoke = false;
            }
            if (samplesIte.hasNext()) {
                File currentSample = samplesIte.next();
                result = FileUtils.readFileToByteArray(currentSample);
                // If enabled, remove the sample as it has been already used
                if (panel.deleteFiles()) {
                    currentSample.delete();
                }
            }
        } catch (IOException | InterruptedException ex) {
            new PrintWriter(callbacks.getStdout()).println("[!] Bradamsa Exception: RadamsaPayloadGenerator.getNextPayload()");
        }
        return result;
    }

    @Override
    public void reset() {
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
    }

    @Override
    public String getGeneratorName() {
        return "Bradamsa";
    }

    @Override
    public IIntruderPayloadGenerator createNewInstance(IIntruderAttack iia) {
        // Delete previous samples, if applicable
        if (panel.deleteFiles()) {
            for (File file : panel.getOutputDir().listFiles()) {
                file.delete();
            }
        }
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
        return this;
    }
}


/*
 * Bradamsa - Burp Intruder payloads generator (simplified code - does not work!)
 *
 */
package com.doyensec;

import burp.BurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IIntruderAttack;
import burp.IIntruderPayloadGenerator;
import burp.IIntruderPayloadGeneratorFactory;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;

public class RadamsaPayloadGenerator implements IIntruderPayloadGenerator, IIntruderPayloadGeneratorFactory {

    private final IBurpExtenderCallbacks callbacks;

    private boolean firstInvoke;

    private ArrayList<File> samples;

    private Iterator<File> samplesIte;

    private BradamsaPanel panel;

    public RadamsaPayloadGenerator(BurpExtender burpExt) {
        callbacks = burpExt.getCallbacks();
        panel = (BradamsaPanel) burpExt.getTab().getUiComponent();
        firstInvoke = true;
        samples = new ArrayList<>();
        samplesIte = samples.iterator();
    }

    @Override
    public boolean hasMorePayloads() {
        if (firstInvoke) {
            return true;
        }
        return samplesIte.hasNext();
    }

    @Override
    public byte[] getNextPayload(byte[] basePayload) {
        byte[] result = null;
        if (basePayload == null) {
            // Display warning. Battering ram attack type was selected
            JOptionPane.showMessageDialog(null, "Bradamsa can only be used in a sniper attack", "Abort", JOptionPane.ERROR_MESSAGE);
            firstInvoke = false;
        }
        try {
            if (firstInvoke) {
                // Generate samples from Burp's payload
                String cmdLine = panel.getRadamsaCmdLine();
                if (!cmdLine.isEmpty()) {
                    if (panel.getCount() > 9999) {
                        JOptionPane.showMessageDialog(null, "As you've selected an high count number," + " generating all Radamsa samples may take some time.
Your intruder " + "attack will start once all samples are successfully generated.", "Radamsa Samples Generation", JOptionPane.INFORMATION_MESSAGE);
                    }
                    BurpUtils.executeAndPipe(cmdLine, basePayload, callbacks, true);
                    // If enabled, mark all files for deletion before JVM shutdown
                    if (panel.deleteFiles()) {
                        for (File file : panel.getOutputDir().listFiles()) {
                            file.deleteOnExit();
                        }
                    }
                } else {
                    // Display warning. Invalid user input
                    JOptionPane.showMessageDialog(null, "Invalid command line arguments", "Check the 'Bradamsa' tab...", JOptionPane.WARNING_MESSAGE);
                }
                // create samples index
                samples.addAll(Arrays.asList(panel.getOutputDir().listFiles()));
                samplesIte = samples.iterator();
                // prevent further initialization
                firstInvoke = false;
            }
            if (samplesIte.hasNext()) {
                File currentSample = samplesIte.next();
                result = FileUtils.readFileToByteArray(currentSample);
                // If enabled, remove the sample as it has been already used
                if (panel.deleteFiles()) {
                    currentSample.delete();
                }
            }
        } catch (IOException | InterruptedException ex) {
            new PrintWriter(callbacks.getStdout()).println("[!] Bradamsa Exception: RadamsaPayloadGenerator.getNextPayload()");
        }
        return result;
    }

    @Override
    public void reset() {
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
    }

    @Override
    public String getGeneratorName()

    @Override
    public IIntruderPayloadGenerator createNewInstance(IIntruderAttack iia) {
        // Delete previous samples, if applicable
        if (panel.deleteFiles()) {
            for (File file : panel.getOutputDir().listFiles()) {
                file.delete();
            }
        }
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
        return this;
    }
}


/*
 * Bradamsa - Burp Intruder payloads generator (simplified code - does not work!)
 *
 */
package com.doyensec;

import burp.BurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IIntruderAttack;
import burp.IIntruderPayloadGenerator;
import burp.IIntruderPayloadGeneratorFactory;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;

public class RadamsaPayloadGenerator implements IIntruderPayloadGenerator, IIntruderPayloadGeneratorFactory {

    private final IBurpExtenderCallbacks callbacks;

    private boolean firstInvoke;

    private ArrayList<File> samples;

    private Iterator<File> samplesIte;

    private BradamsaPanel panel;

    public RadamsaPayloadGenerator(BurpExtender burpExt) {
        callbacks = burpExt.getCallbacks();
        panel = (BradamsaPanel) burpExt.getTab().getUiComponent();
        firstInvoke = true;
        samples = new ArrayList<>();
        samplesIte = samples.iterator();
    }

    @Override
    public boolean hasMorePayloads() {
        if (firstInvoke) {
            return true;
        }
        return samplesIte.hasNext();
    }

    @Override
    public byte[] getNextPayload(byte[] basePayload) {

if (basePayload == null) {
            // Display warning. Battering ram attack type was selected
            JOptionPane.showMessageDialog(null, "Bradamsa can only be used in a sniper attack", "Abort", JOptionPane.ERROR_MESSAGE);
            firstInvoke = false;
        }
        try {
            if (firstInvoke) {
                // Generate samples from Burp's payload
                String cmdLine = panel.getRadamsaCmdLine();
                if (!cmdLine.isEmpty()) {
                    if (panel.getCount() > 9999) {
                        JOptionPane.showMessageDialog(null, "As you've selected an high count number," + " generating all Radamsa samples may take some time.
Your intruder " + "attack will start once all samples are successfully generated.", "Radamsa Samples Generation", JOptionPane.INFORMATION_MESSAGE);
                    }
                    BurpUtils.executeAndPipe(cmdLine, basePayload, callbacks, true);
                    // If enabled, mark all files for deletion before JVM shutdown
                    if (panel.deleteFiles()) {
                        for (File file : panel.getOutputDir().listFiles()) {
                            file.deleteOnExit();
                        }
                    }
                } else {
                    // Display warning. Invalid user input
                    JOptionPane.showMessageDialog(null, "Invalid command line arguments", "Check the 'Bradamsa' tab...", JOptionPane.WARNING_MESSAGE);
                }
                // create samples index
                samples.addAll(Arrays.asList(panel.getOutputDir().listFiles()));
                samplesIte = samples.iterator();
                // prevent further initialization
                firstInvoke = false;
            }
            if (samplesIte.hasNext()) {
                File currentSample = samplesIte.next();
                result = FileUtils.readFileToByteArray(currentSample);
                // If enabled, remove the sample as it has been already used
                if (panel.deleteFiles()) {
                    currentSample.delete();
                }
            }
        } catch (IOException | InterruptedException ex) {
            new PrintWriter(callbacks.getStdout()).println("[!] Bradamsa Exception: RadamsaPayloadGenerator.getNextPayload()");
        }
        return result;
    }

    @Override
    public void reset() {
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
    }

    @Override
    public String getGeneratorName() {
        return "Bradamsa";
    }

    @Override
    public IIntruderPayloadGenerator createNewInstance(IIntruderAttack iia) {
        // Delete previous samples, if applicable
        if (panel.deleteFiles()) {
            for (File file : panel.getOutputDir().listFiles()) {
                file.delete();
            }
        }
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
        return this;
    }
}


if (basePayload == null) {
            // Display warning. Battering ram attack type was selected
            JOptionPane.showMessageDialog(null, "Bradamsa can only be used in a sniper attack", "Abort", JOptionPane.ERROR_MESSAGE);
            firstInvoke = false;
        }
        try {
            if (firstInvoke) {
                // Generate samples from Burp's payload
                String cmdLine = panel.getRadamsaCmdLine();
                if (!cmdLine.isEmpty()) {
                    if (panel.getCount() > 9999) {
                        JOptionPane.showMessageDialog(null, "As you've selected an high count number," + " generating all Radamsa samples may take some time.
Your intruder " + "attack will start once all samples are successfully generated.", "Radamsa Samples Generation", JOptionPane.INFORMATION_MESSAGE);
                    }
                    BurpUtils.executeAndPipe(cmdLine, basePayload, callbacks, true);
                    // If enabled, mark all files for deletion before JVM shutdown
                    if (panel.deleteFiles()) {
                        for (File file : panel.getOutputDir().listFiles()) {
                            file.deleteOnExit();
                        }
                    }
                } else {
                    // Display warning. Invalid user input
                    JOptionPane.showMessageDialog(null, "Invalid command line arguments", "Check the 'Bradamsa' tab...", JOptionPane.WARNING_MESSAGE);
                }
                // create samples index
                samples.addAll(Arrays.asList(panel.getOutputDir().listFiles()));
                samplesIte = samples.iterator();
                // prevent further initialization
                firstInvoke = false;
            }
            if (samplesIte.hasNext()) {
                File currentSample = samplesIte.next();
                result = FileUtils.readFileToByteArray(currentSample);
                // If enabled, remove the sample as it has been already used
                if (panel.deleteFiles()) {
                    currentSample.delete();
                }
            }
        } catch (IOException | InterruptedException ex) {
            new PrintWriter(callbacks.getStdout()).println("[!] Bradamsa Exception: RadamsaPayloadGenerator.getNextPayload()");
        }

/*
 * Bradamsa - Burp Intruder payloads generator (simplified code - does not work!)
 *
 */
package com.doyensec;

import burp.BurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IIntruderAttack;
import burp.IIntruderPayloadGenerator;
import burp.IIntruderPayloadGeneratorFactory;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;

public class RadamsaPayloadGenerator implements IIntruderPayloadGenerator, IIntruderPayloadGeneratorFactory {

    private final IBurpExtenderCallbacks callbacks;

    private boolean firstInvoke;

    private ArrayList<File> samples;

    private Iterator<File> samplesIte;

    private BradamsaPanel panel;

    public RadamsaPayloadGenerator(BurpExtender burpExt) {
        callbacks = burpExt.getCallbacks();
        panel = (BradamsaPanel) burpExt.getTab().getUiComponent();
        firstInvoke = true;
        samples = new ArrayList<>();
        samplesIte = samples.iterator();
    }

    @Override
    public boolean hasMorePayloads() {
        if (firstInvoke) {
            return true;
        }
        return samplesIte.hasNext();
    }

    @Override
    public byte[] getNextPayload(byte[] basePayload) {
        byte[] result = null;

        return result;
    }

    @Override
    public void reset() {
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
    }

    @Override
    public String getGeneratorName() {
        return "Bradamsa";
    }

    @Override
    public IIntruderPayloadGenerator createNewInstance(IIntruderAttack iia) {
        // Delete previous samples, if applicable
        if (panel.deleteFiles()) {
            for (File file : panel.getOutputDir().listFiles()) {
                file.delete();
            }
        }
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
        return this;
    }
}


/*
 * Bradamsa - Burp Intruder payloads generator (simplified code - does not work!)
 *
 */
package com.doyensec;

import burp.BurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IIntruderAttack;
import burp.IIntruderPayloadGenerator;
import burp.IIntruderPayloadGeneratorFactory;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;

public class RadamsaPayloadGenerator implements IIntruderPayloadGenerator, IIntruderPayloadGeneratorFactory {

    private final IBurpExtenderCallbacks callbacks;

    private boolean firstInvoke;

    private ArrayList<File> samples;

    private Iterator<File> samplesIte;

    private BradamsaPanel panel;

    public RadamsaPayloadGenerator(BurpExtender burpExt) {
        callbacks = burpExt.getCallbacks();
        panel = (BradamsaPanel) burpExt.getTab().getUiComponent();
        firstInvoke = true;
        samples = new ArrayList<>();
        samplesIte = samples.iterator();
    }

    @Override
    public boolean hasMorePayloads() {
        if (firstInvoke) {
            return true;
        }
        return samplesIte.hasNext();
    }

    @Override
    public byte[] getNextPayload(byte[] basePayload) {
        byte[] result = null;
        if (basePayload == null) {
            // Display warning. Battering ram attack type was selected
            JOptionPane.showMessageDialog(null, "Bradamsa can only be used in a sniper attack", "Abort", JOptionPane.ERROR_MESSAGE);
            firstInvoke = false;
        }
        try {
            if (firstInvoke) {
                // Generate samples from Burp's payload
                String cmdLine = panel.getRadamsaCmdLine();
                if (!cmdLine.isEmpty()) {
                    if (panel.getCount() > 9999) {
                        JOptionPane.showMessageDialog(null, "As you've selected an high count number," + " generating all Radamsa samples may take some time.
Your intruder " + "attack will start once all samples are successfully generated.", "Radamsa Samples Generation", JOptionPane.INFORMATION_MESSAGE);
                    }
                    BurpUtils.executeAndPipe(cmdLine, basePayload, callbacks, true);
                    // If enabled, mark all files for deletion before JVM shutdown
                    if (panel.deleteFiles()) {
                        for (File file : panel.getOutputDir().listFiles()) {
                            file.deleteOnExit();
                        }
                    }
                } else {
                    // Display warning. Invalid user input
                    JOptionPane.showMessageDialog(null, "Invalid command line arguments", "Check the 'Bradamsa' tab...", JOptionPane.WARNING_MESSAGE);
                }
                // create samples index
                samples.addAll(Arrays.asList(panel.getOutputDir().listFiles()));
                samplesIte = samples.iterator();
                // prevent further initialization
                firstInvoke = false;
            }
            if (samplesIte.hasNext()) {
                File currentSample = samplesIte.next();
                result = FileUtils.readFileToByteArray(currentSample);
                // If enabled, remove the sample as it has been already used
                if (panel.deleteFiles()) {
                    currentSample.delete();
                }
            }
        } catch (IOException | InterruptedException ex) {
            new PrintWriter(callbacks.getStdout()).println("[!] Bradamsa Exception: RadamsaPayloadGenerator.getNextPayload()");
        }

    @Override
    public void reset() {
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
    }

    @Override
    public String getGeneratorName() {
        return "Bradamsa";
    }

    @Override
    public IIntruderPayloadGenerator createNewInstance(IIntruderAttack iia) {
        // Delete previous samples, if applicable
        if (panel.deleteFiles()) {
            for (File file : panel.getOutputDir().listFiles()) {
                file.delete();
            }
        }
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
        return this;
    }
}


/*
 * Bradamsa - Burp Intruder payloads generator (simplified code - does not work!)
 *
 */
package com.doyensec;

import burp.BurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IIntruderAttack;
import burp.IIntruderPayloadGenerator;
import burp.IIntruderPayloadGeneratorFactory;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;

public class RadamsaPayloadGenerator implements IIntruderPayloadGenerator, IIntruderPayloadGeneratorFactory {

    private final IBurpExtenderCallbacks callbacks;

    private boolean firstInvoke;

    private ArrayList<File> samples;

    private Iterator<File> samplesIte;

    private BradamsaPanel panel;

    public RadamsaPayloadGenerator(BurpExtender burpExt) {
        callbacks = burpExt.getCallbacks();
        panel = (BradamsaPanel) burpExt.getTab().getUiComponent();
        firstInvoke = true;
        samples = new ArrayList<>();
        samplesIte = samples.iterator();
    }

    @Override
    public boolean hasMorePayloads() {
        if (firstInvoke) {
            return true;
        }
        return samplesIte.hasNext();
    }

    @Override
    public byte[] getNextPayload(byte[] basePayload) {
        byte[] result = null;
        if (basePayload == null) {
            // Display warning. Battering ram attack type was selected
            JOptionPane.showMessageDialog(null, "Bradamsa can only be used in a sniper attack", "Abort", JOptionPane.ERROR_MESSAGE);
            firstInvoke = false;
        }
        try {
            if (firstInvoke) {
                // Generate samples from Burp's payload
                String cmdLine = panel.getRadamsaCmdLine();
                if (!cmdLine.isEmpty()) {
                    if (panel.getCount() > 9999) {
                        JOptionPane.showMessageDialog(null, "As you've selected an high count number," + " generating all Radamsa samples may take some time.
Your intruder " + "attack will start once all samples are successfully generated.", "Radamsa Samples Generation", JOptionPane.INFORMATION_MESSAGE);
                    }
                    BurpUtils.executeAndPipe(cmdLine, basePayload, callbacks, true);
                    // If enabled, mark all files for deletion before JVM shutdown
                    if (panel.deleteFiles()) {
                        for (File file : panel.getOutputDir().listFiles()) {
                            file.deleteOnExit();
                        }
                    }
                } else {
                    // Display warning. Invalid user input
                    JOptionPane.showMessageDialog(null, "Invalid command line arguments", "Check the 'Bradamsa' tab...", JOptionPane.WARNING_MESSAGE);
                }
                // create samples index
                samples.addAll(Arrays.asList(panel.getOutputDir().listFiles()));
                samplesIte = samples.iterator();
                // prevent further initialization
                firstInvoke = false;
            }
            if (samplesIte.hasNext()) {
                File currentSample = samplesIte.next();
                result = FileUtils.readFileToByteArray(currentSample);
                // If enabled, remove the sample as it has been already used
                if (panel.deleteFiles()) {
                    currentSample.delete();
                }
            }
        } catch (IOException | InterruptedException ex) {
            new PrintWriter(callbacks.getStdout()).println("[!] Bradamsa Exception: RadamsaPayloadGenerator.getNextPayload()");
        }
        return result;
    }

    @Override
    public void reset() {
        samples.clear();
        samplesIte = samples.iterator();
        firstInvo

    }

    @Override
    public String getGeneratorName() {
        return "Bradamsa";
    }

    @Override
    public IIntruderPayloadGenerator createNewInstance(IIntruderAttack iia) {
        // Delete previous samples, if applicable
        if (panel.deleteFiles()) {
            for (File file : panel.getOutputDir().listFiles()) {
                file.delete();
            }
        }
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
        return this;
    }
}


if (panel.deleteFiles()) {
            for (File file : panel.getOutputDir().listFiles()) {
                file.delete();
            }
        }

/*
 * Bradamsa - Burp Intruder payloads generator (simplified code - does not work!)
 *
 */
package com.doyensec;

import burp.BurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IIntruderAttack;
import burp.IIntruderPayloadGenerator;
import burp.IIntruderPayloadGeneratorFactory;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;

public class RadamsaPayloadGenerator implements IIntruderPayloadGenerator, IIntruderPayloadGeneratorFactory {

    private final IBurpExtenderCallbacks callbacks;

    private boolean firstInvoke;

    private ArrayList<File> samples;

    private Iterator<File> samplesIte;

    private BradamsaPanel panel;

    public RadamsaPayloadGenerator(BurpExtender burpExt) {
        callbacks = burpExt.getCallbacks();
        panel = (BradamsaPanel) burpExt.getTab().getUiComponent();
        firstInvoke = true;
        samples = new ArrayList<>();
        samplesIte = samples.iterator();
    }

    @Override
    public boolean hasMorePayloads() {
        if (firstInvoke) {
            return true;
        }
        return samplesIte.hasNext();
    }

    @Override
    public byte[] getNextPayload(byte[] basePayload) {
        byte[] result = null;
        if (basePayload == null) {
            // Display warning. Battering ram attack type was selected
            JOptionPane.showMessageDialog(null, "Bradamsa can only be used in a sniper attack", "Abort", JOptionPane.ERROR_MESSAGE);
            firstInvoke = false;
        }
        try {
            if (firstInvoke) {
                // Generate samples from Burp's payload
                String cmdLine = panel.getRadamsaCmdLine();
                if (!cmdLine.isEmpty()) {
                    if (panel.getCount() > 9999) {
                        JOptionPane.showMessageDialog(null, "As you've selected an high count number," + " generating all Radamsa samples may take some time.
Your intruder " + "attack will start once all samples are successfully generated.", "Radamsa Samples Generation", JOptionPane.INFORMATION_MESSAGE);
                    }
                    BurpUtils.executeAndPipe(cmdLine, basePayload, callbacks, true);
                    // If enabled, mark all files for deletion before JVM shutdown
                    if (panel.deleteFiles()) {
                        for (File file : panel.getOutputDir().listFiles()) {
                            file.deleteOnExit();
                        }
                    }
                } else {
                    // Display warning. Invalid user input
                    JOptionPane.showMessageDialog(null, "Invalid command line arguments", "Check the 'Bradamsa' tab...", JOptionPane.WARNING_MESSAGE);
                }
                // create samples index
                samples.addAll(Arrays.asList(panel.getOutputDir().listFiles()));
                samplesIte = samples.iterator();
                // prevent further initialization
                firstInvoke = false;
            }
            if (samplesIte.hasNext()) {
                File currentSample = samplesIte.next();
                result = FileUtils.readFileToByteArray(currentSample);
                // If enabled, remove the sample as it has been already used
                if (panel.deleteFiles()) {
                    currentSample.delete();
                }
            }
        } catch (IOException | InterruptedException ex) {
            new PrintWriter(callbacks.getStdout()).println("[!] Bradamsa Exception: RadamsaPayloadGenerator.getNextPayload()");
        }
        return result;
    }

    @Override
    public void reset() {
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
    }

    @Override
    public String getGeneratorName() {
        return "Bradamsa";
    }

    @Override
    public IIntruderPayloadGenerator createNewInstance(IIntruderAttack iia) {
        // Delete previous samples, if applicable

        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
        return this;
    }
}


/*
 * Bradamsa - Burp Intruder payloads generator (simplified code - does not work!)
 *
 */
package com.doyensec;

import burp.BurpExtender;
import burp.IBurpExtenderCallbacks;
import burp.IIntruderAttack;
import burp.IIntruderPayloadGenerator;
import burp.IIntruderPayloadGeneratorFactory;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import javax.swing.JOptionPane;
import org.apache.commons.io.FileUtils;

public class RadamsaPayloadGenerator implements IIntruderPayloadGenerator, IIntruderPayloadGeneratorFactory {

    private final IBurpExtenderCallbacks callbacks;

    private boolean firstInvoke;

    private ArrayList<File> samples;

    private Iterator<File> samplesIte;

    private BradamsaPanel panel;

    public RadamsaPayloadGenerator(BurpExtender burpExt) {
        callbacks = burpExt.getCallbacks();
        panel = (BradamsaPanel) burpExt.getTab().getUiComponent();
        firstInvoke = true;
        samples = new ArrayList<>();
        samplesIte = samples.iterator();
    }

    @Override
    public boolean hasMorePayloads() {
        if (firstInvoke) {
            return true;
        }
        return samplesIte.hasNext();
    }

    @Override
    public byte[] getNextPayload(byte[] basePayload) {
        byte[] result = null;
        if (basePayload == null) {
            // Display warning. Battering ram attack type was selected
            JOptionPane.showMessageDialog(null, "Bradamsa can only be used in a sniper attack", "Abort", JOptionPane.ERROR_MESSAGE);
            firstInvoke = false;
        }
        try {
            if (firstInvoke) {
                // Generate samples from Burp's payload
                String cmdLine = panel.getRadamsaCmdLine();
                if (!cmdLine.isEmpty()) {
                    if (panel.getCount() > 9999) {
                        JOptionPane.showMessageDialog(null, "As you've selected an high count number," + " generating all Radamsa samples may take some time.
Your intruder " + "attack will start once all samples are successfully generated.", "Radamsa Samples Generation", JOptionPane.INFORMATION_MESSAGE);
                    }
                    BurpUtils.executeAndPipe(cmdLine, basePayload, callbacks, true);
                    // If enabled, mark all files for deletion before JVM shutdown
                    if (panel.deleteFiles()) {
                        for (File file : panel.getOutputDir().listFiles()) {
                            file.deleteOnExit();
                        }
                    }
                } else {
                    // Display warning. Invalid user input

   JOptionPane.showMessageDialog(null, "Invalid command line arguments", "Check the 'Bradamsa' tab...", JOptionPane.WARNING_MESSAGE);
                }
                // create samples index
                samples.addAll(Arrays.asList(panel.getOutputDir().listFiles()));
                samplesIte = samples.iterator();
                // prevent further initialization
                firstInvoke = false;
            }
            if (samplesIte.hasNext()) {
                File currentSample = samplesIte.next();
                result = FileUtils.readFileToByteArray(currentSample);
                // If enabled, remove the sample as it has been already used
                if (panel.deleteFiles()) {
                    currentSample.delete();
                }
            }
        } catch (IOException | InterruptedException ex) {
            new PrintWriter(callbacks.getStdout()).println("[!] Bradamsa Exception: RadamsaPayloadGenerator.getNextPayload()");
        }
        return result;
    }

    @Override
    public void reset() {
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
    }

    @Override
    public String getGeneratorName() {
        return "Bradamsa";
    }

    @Override
    public IIntruderPayloadGenerator createNewInstance(IIntruderAttack iia) {
        // Delete previous samples, if applicable
        if (panel.deleteFiles()) {
            for (File file : panel.getOutputDir().listFiles()) {
                file.delete();
            }
        }
        samples.clear();
        samplesIte = samples.iterator();
        firstInvoke = true;
        return this;
    }
}